From cc1879aa0e5ac025bb89d21da97ad3c40df68819 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Mon, 25 Jul 2016 21:03:18 +0200 Subject: [PATCH 001/808] Version bump to 5.0.0-SNAPSHOT --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 39a4341d7e..d1d67ebb44 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ biz.paluch.redis lettuce - 4.3.0-SNAPSHOT + 5.0.0-SNAPSHOT jar lettuce From aac999acc4c163eeacf1b67517df68c817b35e66 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Mon, 25 Jul 2016 21:49:08 +0200 Subject: [PATCH 002/808] Remove deprecated interfaces and methods #156 Interfaces RedisClusterAsyncConnection RedisClusterConnection RedisAsyncConnection RedisConnection BaseRedisAsyncConnection BaseRedisConnection RedisGeoAsyncConnection RedisGeoConnection RedisHashesAsyncConnection RedisHashesConnection RedisHLLAsyncConnection RedisHLLConnection RedisKeysAsyncConnection RedisKeysConnection RedisListsAsyncConnection RedisListsConnection RedisScriptingAsyncConnection RedisScriptingConnection RedisSentinelAsyncConnection RedisServerAsyncConnection RedisServerConnection RedisSetsAsyncConnection RedisSetsConnection RedisSortedSetsAsyncConnection RedisSortedSetsConnection RedisStringsAsyncConnection RedisStringsConnection RedisClient Methods public RedisClient constructors RedisClient.connectAsync RedisClient.connectSentinelAsync RedisClusterClient Methods public RedisClusterClient constructors RedisClusterClient.connectCluster RedisClusterClient.connectClusterAsync deprecated methods on interfaces --- .../redis/AbstractRedisAsyncCommands.java | 47 +- .../redis/AbstractRedisClient.java | 26 +- .../redis/AbstractRedisReactiveCommands.java | 27 +- .../redis/BaseRedisAsyncConnection.java | 200 ----- .../redis/BaseRedisConnection.java | 195 ----- .../com/lambdaworks/redis/ClientOptions.java | 6 +- .../com/lambdaworks/redis/Connections.java | 112 --- .../redis/RedisAsyncCommandsImpl.java | 4 +- .../redis/RedisAsyncConnection.java | 53 -- .../com/lambdaworks/redis/RedisClient.java | 369 +------- .../redis/RedisClusterAsyncConnection.java | 266 ------ .../redis/RedisClusterConnection.java | 268 ------ .../redis/RedisCommandBuilder.java | 5 - .../lambdaworks/redis/RedisConnection.java | 52 -- .../redis/RedisConnectionPool.java | 231 ----- .../redis/RedisGeoAsyncConnection.java | 155 ---- .../lambdaworks/redis/RedisGeoConnection.java | 151 ---- .../redis/RedisHLLAsyncConnection.java | 52 -- .../lambdaworks/redis/RedisHLLConnection.java | 52 -- .../redis/RedisHashesAsyncConnection.java | 281 ------ .../redis/RedisHashesConnection.java | 278 ------ .../redis/RedisKeysAsyncConnection.java | 411 --------- .../redis/RedisKeysConnection.java | 406 --------- .../redis/RedisListsAsyncConnection.java | 222 ----- .../redis/RedisListsConnection.java | 220 ----- .../redis/RedisScriptingAsyncConnection.java | 96 --- .../redis/RedisScriptingConnection.java | 95 -- .../redis/RedisSentinelAsyncConnection.java | 114 --- .../redis/RedisServerAsyncConnection.java | 304 ------- .../redis/RedisServerConnection.java | 304 ------- .../redis/RedisSetsAsyncConnection.java | 292 ------- .../redis/RedisSetsConnection.java | 291 ------- .../redis/RedisSortedSetsAsyncConnection.java | 812 ------------------ .../redis/RedisSortedSetsConnection.java | 807 ----------------- .../redis/RedisStringsAsyncConnection.java | 347 -------- .../redis/RedisStringsConnection.java | 343 -------- .../java/com/lambdaworks/redis/RedisURI.java | 6 +- .../api/async/BaseRedisAsyncCommands.java | 15 + .../redis/api/async/RedisAsyncCommands.java | 3 +- .../api/async/RedisListAsyncCommands.java | 20 - .../api/async/RedisServerAsyncCommands.java | 10 +- .../api/async/RedisStringAsyncCommands.java | 107 ++- .../api/rx/BaseRedisReactiveCommands.java | 25 +- .../api/rx/RedisListReactiveCommands.java | 20 - .../api/rx/RedisServerReactiveCommands.java | 9 - .../api/rx/RedisStringReactiveCommands.java | 104 +-- .../redis/api/sync/RedisCommands.java | 3 +- .../redis/api/sync/RedisHLLCommands.java | 1 - .../redis/api/sync/RedisListCommands.java | 20 - .../redis/api/sync/RedisServerCommands.java | 12 +- .../redis/api/sync/RedisStringCommands.java | 98 +-- .../redis/cluster/ClusterClientOptions.java | 58 +- .../ClusterTopologyRefreshOptions.java | 6 +- ...RedisAdvancedClusterAsyncCommandsImpl.java | 19 +- .../RedisAdvancedClusterAsyncConnection.java | 59 -- .../RedisAdvancedClusterConnection.java | 57 -- ...isAdvancedClusterReactiveCommandsImpl.java | 15 +- .../redis/cluster/RedisClusterClient.java | 79 +- .../StatefulRedisClusterConnectionImpl.java | 11 +- .../async/BaseNodeSelectionAsyncCommands.java | 40 +- .../async/NodeSelectionListAsyncCommands.java | 20 - .../NodeSelectionServerAsyncCommands.java | 8 - .../NodeSelectionStringAsyncCommands.java | 106 +-- .../RedisAdvancedClusterAsyncCommands.java | 3 +- .../api/async/RedisClusterAsyncCommands.java | 3 +- .../api/sync/BaseNodeSelectionCommands.java | 19 +- .../api/sync/NodeSelectionListCommands.java | 20 - .../api/sync/NodeSelectionServerCommands.java | 8 - .../sync/RedisAdvancedClusterCommands.java | 3 +- .../api/sync/RedisClusterCommands.java | 13 +- .../models/slots/ClusterSlotRange.java | 82 +- .../MasterSlaveConnectionProvider.java | 9 - ...DefaultCommandLatencyCollectorOptions.java | 7 +- .../pubsub/RedisPubSubAsyncCommandsImpl.java | 14 +- .../redis/pubsub/RedisPubSubConnection.java | 62 -- .../StatefulRedisPubSubConnectionImpl.java | 9 +- .../api/async/RedisPubSubAsyncCommands.java | 4 +- .../pubsub/api/sync/RedisPubSubCommands.java | 1 - .../resource/DefaultClientResources.java | 6 +- .../RedisSentinelAsyncCommandsImpl.java | 4 +- .../RedisSentinelReactiveCommandsImpl.java | 4 +- .../api/async/RedisSentinelAsyncCommands.java | 4 +- .../api/rx/RedisSentinelReactiveCommands.java | 3 +- .../api/sync/RedisSentinelCommands.java | 3 +- .../support/ClientResourcesFactoryBean.java | 2 +- .../redis/support/PoolingProxyFactory.java | 41 - .../TransparentPoolingInvocationHandler.java | 48 -- .../redis/support/WithConnection.java | 35 - .../redis/api/BaseRedisCommands.java | 14 + .../redis/api/RedisListCommands.java | 22 - .../redis/api/RedisSentinelCommands.java | 5 +- .../redis/api/RedisServerCommands.java | 9 - .../redis/extensibility/LettuceGeoDemo.java | 7 +- .../extensibility/MyExtendedRedisClient.java | 21 +- .../MyExtendedRedisClientTest.java | 21 +- .../java/com/lambdaworks/Connections.java | 20 + .../com/lambdaworks/TestClientResources.java | 2 +- .../apigenerator/CreateAsyncApi.java | 19 +- .../CreateAsyncNodeSelectionClusterApi.java | 2 +- .../apigenerator/CreateReactiveApi.java | 2 +- .../apigenerator/CreateSyncApi.java | 25 +- .../lambdaworks/examples/ConnectToRedis.java | 2 - .../examples/ConnectToRedisCluster.java | 3 - .../lambdaworks/examples/SpringExample.java | 5 +- .../com/lambdaworks/redis/AllTheAPIsTest.java | 100 +-- .../redis/AsyncConnectionTest.java | 16 +- .../lambdaworks/redis/ClientOptionsTest.java | 31 +- .../com/lambdaworks/redis/ClientTest.java | 23 +- .../redis/ConnectionCommandTest.java | 109 +-- .../redis/LettucePerformanceTest.java | 15 +- .../redis/MultiConnectionTest.java | 28 - .../lambdaworks/redis/PoolConnectionTest.java | 224 ----- .../redis/RedisClientConnectionTest.java | 82 -- .../java/com/lambdaworks/redis/TimeTest.java | 29 - .../redis/UnixDomainSocketTest.java | 23 +- .../redis/cluster/AbstractClusterTest.java | 7 +- .../cluster/AdvancedClusterClientTest.java | 26 +- .../cluster/AdvancedClusterReactiveTest.java | 6 +- .../redis/cluster/ByteCodecClusterTest.java | 20 - .../cluster/ClusterClientOptionsTest.java | 15 +- .../redis/cluster/ClusterCommandTest.java | 48 +- .../cluster/ClusterReactiveCommandTest.java | 17 +- .../redis/cluster/ClusterSetup.java | 4 +- .../redis/cluster/ClusterTestUtil.java | 1 - .../redis/cluster/NodeSelectionAsyncTest.java | 5 +- .../redis/cluster/RedisClusterClientTest.java | 101 +-- .../cluster/RedisClusterReadFromTest.java | 15 +- .../redis/cluster/RedisClusterSetupTest.java | 34 +- .../RedisClusterStressScenariosTest.java | 10 +- .../commands/CustomClusterCommandTest.java | 2 +- .../commands/GeoClusterCommandTest.java | 4 +- .../commands/HashClusterCommandTest.java | 6 +- .../commands/ListClusterCommandTest.java | 6 +- .../commands/StringClusterCommandTest.java | 4 +- .../commands/rx/HashClusterRxCommandTest.java | 10 +- .../commands/rx/ListClusterRxCommandTest.java | 8 +- .../rx/StringClusterRxCommandTest.java | 10 +- .../models/slots/ClusterSlotsParserTest.java | 51 -- .../redis/commands/BitCommandPoolTest.java | 29 - .../redis/commands/BitCommandTest.java | 4 +- .../redis/commands/HLLCommandTest.java | 29 - .../redis/commands/HashCommandPoolTest.java | 25 - .../redis/commands/KeyCommandTest.java | 4 +- .../RunOnlyOnceServerCommandTest.java | 41 +- .../redis/commands/ScriptingCommandTest.java | 8 +- .../redis/commands/ServerCommandPoolTest.java | 27 - .../redis/commands/ServerCommandTest.java | 8 +- .../commands/TransactionCommandTest.java | 8 +- .../redis/commands/rx/BitRxCommandTest.java | 4 +- .../commands/rx/CustomRxCommandTest.java | 2 +- .../redis/commands/rx/GeoRxCommandTest.java | 4 +- .../redis/commands/rx/HLLRxCommandTest.java | 17 +- .../redis/commands/rx/HashRxCommandTest.java | 2 +- .../redis/commands/rx/KeyRxCommandTest.java | 2 +- .../redis/commands/rx/ListRxCommandTest.java | 2 +- .../commands/rx/NumericRxCommandTest.java | 2 +- .../commands/rx/ScriptingRxCommandTest.java | 3 +- .../commands/rx/ServerRxCommandTest.java | 14 +- .../redis/commands/rx/SetRxCommandTest.java | 2 +- .../redis/commands/rx/SortRxCommandTest.java | 2 +- .../commands/rx/SortedSetRxCommandTest.java | 2 +- .../commands/rx/StringRxCommandTest.java | 10 +- .../commands/rx/TransactionRxCommandTest.java | 10 +- .../redis/issue42/BreakClientBase.java | 99 --- .../redis/issue42/BreakClientTest.java | 45 - .../redis/issue42/BreakClusterClientTest.java | 76 -- .../redis/masterslave/MasterSlaveTest.java | 4 +- .../redis/protocol/ConnectionFailureTest.java | 22 +- .../redis/pubsub/PubSubCommandTest.java | 2 +- .../redis/reliability/AtLeastOnceTest.java | 194 ++--- .../redis/reliability/AtMostOnceTest.java | 147 ++-- .../resource/DefaultClientResourcesTest.java | 9 +- .../redis/sentinel/SentinelCommandTest.java | 37 +- .../sentinel/SentinelConnectionTest.java | 18 +- .../redis/sentinel/SentinelFailoverTest.java | 85 -- .../redis/sentinel/SentinelRule.java | 2 +- .../sentinel/rx/SentinelRxCommandTest.java | 2 +- .../support/PoolingProxyFactoryTest.java | 55 -- .../redis/support/WithConnectionTest.java | 65 -- .../cluster/EmptyRedisClusterClient.java | 3 +- 180 files changed, 957 insertions(+), 10670 deletions(-) delete mode 100644 src/main/java/com/lambdaworks/redis/BaseRedisAsyncConnection.java delete mode 100644 src/main/java/com/lambdaworks/redis/BaseRedisConnection.java delete mode 100644 src/main/java/com/lambdaworks/redis/Connections.java delete mode 100644 src/main/java/com/lambdaworks/redis/RedisAsyncConnection.java delete mode 100644 src/main/java/com/lambdaworks/redis/RedisClusterAsyncConnection.java delete mode 100644 src/main/java/com/lambdaworks/redis/RedisClusterConnection.java delete mode 100644 src/main/java/com/lambdaworks/redis/RedisConnection.java delete mode 100644 src/main/java/com/lambdaworks/redis/RedisConnectionPool.java delete mode 100644 src/main/java/com/lambdaworks/redis/RedisGeoAsyncConnection.java delete mode 100644 src/main/java/com/lambdaworks/redis/RedisGeoConnection.java delete mode 100644 src/main/java/com/lambdaworks/redis/RedisHLLAsyncConnection.java delete mode 100644 src/main/java/com/lambdaworks/redis/RedisHLLConnection.java delete mode 100644 src/main/java/com/lambdaworks/redis/RedisHashesAsyncConnection.java delete mode 100644 src/main/java/com/lambdaworks/redis/RedisHashesConnection.java delete mode 100644 src/main/java/com/lambdaworks/redis/RedisKeysAsyncConnection.java delete mode 100644 src/main/java/com/lambdaworks/redis/RedisKeysConnection.java delete mode 100644 src/main/java/com/lambdaworks/redis/RedisListsAsyncConnection.java delete mode 100644 src/main/java/com/lambdaworks/redis/RedisListsConnection.java delete mode 100644 src/main/java/com/lambdaworks/redis/RedisScriptingAsyncConnection.java delete mode 100644 src/main/java/com/lambdaworks/redis/RedisScriptingConnection.java delete mode 100644 src/main/java/com/lambdaworks/redis/RedisSentinelAsyncConnection.java delete mode 100644 src/main/java/com/lambdaworks/redis/RedisServerAsyncConnection.java delete mode 100644 src/main/java/com/lambdaworks/redis/RedisServerConnection.java delete mode 100644 src/main/java/com/lambdaworks/redis/RedisSetsAsyncConnection.java delete mode 100644 src/main/java/com/lambdaworks/redis/RedisSetsConnection.java delete mode 100644 src/main/java/com/lambdaworks/redis/RedisSortedSetsAsyncConnection.java delete mode 100644 src/main/java/com/lambdaworks/redis/RedisSortedSetsConnection.java delete mode 100644 src/main/java/com/lambdaworks/redis/RedisStringsAsyncConnection.java delete mode 100644 src/main/java/com/lambdaworks/redis/RedisStringsConnection.java delete mode 100644 src/main/java/com/lambdaworks/redis/cluster/RedisAdvancedClusterAsyncConnection.java delete mode 100644 src/main/java/com/lambdaworks/redis/cluster/RedisAdvancedClusterConnection.java delete mode 100644 src/main/java/com/lambdaworks/redis/pubsub/RedisPubSubConnection.java delete mode 100644 src/main/java/com/lambdaworks/redis/support/PoolingProxyFactory.java delete mode 100644 src/main/java/com/lambdaworks/redis/support/TransparentPoolingInvocationHandler.java delete mode 100644 src/main/java/com/lambdaworks/redis/support/WithConnection.java delete mode 100644 src/test/java/com/lambdaworks/redis/MultiConnectionTest.java delete mode 100644 src/test/java/com/lambdaworks/redis/PoolConnectionTest.java delete mode 100644 src/test/java/com/lambdaworks/redis/TimeTest.java delete mode 100644 src/test/java/com/lambdaworks/redis/commands/BitCommandPoolTest.java delete mode 100644 src/test/java/com/lambdaworks/redis/commands/HashCommandPoolTest.java delete mode 100644 src/test/java/com/lambdaworks/redis/commands/ServerCommandPoolTest.java delete mode 100644 src/test/java/com/lambdaworks/redis/issue42/BreakClientBase.java delete mode 100644 src/test/java/com/lambdaworks/redis/issue42/BreakClientTest.java delete mode 100644 src/test/java/com/lambdaworks/redis/issue42/BreakClusterClientTest.java delete mode 100644 src/test/java/com/lambdaworks/redis/sentinel/SentinelFailoverTest.java delete mode 100644 src/test/java/com/lambdaworks/redis/support/PoolingProxyFactoryTest.java delete mode 100644 src/test/java/com/lambdaworks/redis/support/WithConnectionTest.java diff --git a/src/main/java/com/lambdaworks/redis/AbstractRedisAsyncCommands.java b/src/main/java/com/lambdaworks/redis/AbstractRedisAsyncCommands.java index bb49c23a11..862ef8ef69 100644 --- a/src/main/java/com/lambdaworks/redis/AbstractRedisAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/AbstractRedisAsyncCommands.java @@ -27,12 +27,7 @@ * @author Will Glozer */ public abstract class AbstractRedisAsyncCommands - implements RedisHashesAsyncConnection, RedisKeysAsyncConnection, RedisStringsAsyncConnection, - RedisListsAsyncConnection, RedisSetsAsyncConnection, RedisSortedSetsAsyncConnection, - RedisScriptingAsyncConnection, RedisServerAsyncConnection, RedisHLLAsyncConnection, - BaseRedisAsyncConnection, RedisClusterAsyncConnection, RedisGeoAsyncConnection, - - RedisHashAsyncCommands, RedisKeyAsyncCommands, RedisStringAsyncCommands, RedisListAsyncCommands, + implements RedisHashAsyncCommands, RedisKeyAsyncCommands, RedisStringAsyncCommands, RedisListAsyncCommands, RedisSetAsyncCommands, RedisSortedSetAsyncCommands, RedisScriptingAsyncCommands, RedisServerAsyncCommands, RedisHLLAsyncCommands, BaseRedisAsyncCommands, RedisTransactionalAsyncCommands, RedisGeoAsyncCommands, RedisClusterAsyncCommands { @@ -326,11 +321,6 @@ public RedisFuture evalsha(String digest, ScriptOutputType type, K[] keys return (RedisFuture) dispatch(commandBuilder.evalsha(digest, type, keys, values)); } - @Override - public RedisFuture exists(K key) { - return dispatch(commandBuilder.exists(key)); - } - @Override public RedisFuture exists(K... keys) { return dispatch(commandBuilder.exists(keys)); @@ -555,11 +545,6 @@ public RedisFuture lpush(K key, V... values) { return dispatch(commandBuilder.lpush(key, values)); } - @Override - public RedisFuture lpushx(K key, V value) { - return dispatch(commandBuilder.lpushx(key, value)); - } - @Override public RedisFuture lpushx(K key, V... values) { return dispatch(commandBuilder.lpushx(key, values)); @@ -765,11 +750,6 @@ public RedisFuture rpush(K key, V... values) { return dispatch(commandBuilder.rpush(key, values)); } - @Override - public RedisFuture rpushx(K key, V value) { - return dispatch(commandBuilder.rpushx(key, value)); - } - @Override public RedisFuture rpushx(K key, V... values) { return dispatch(commandBuilder.rpushx(key, values)); @@ -870,11 +850,6 @@ public RedisFuture setrange(K key, long offset, V value) { return dispatch(commandBuilder.setrange(key, offset, value)); } - @Deprecated - public void shutdown() { - dispatch(commandBuilder.shutdown()); - } - @Override public void shutdown(boolean save) { dispatch(commandBuilder.shutdown(save)); @@ -1015,11 +990,6 @@ public RedisFuture sunionstore(K destination, K... keys) { return dispatch(commandBuilder.sunionstore(destination, keys)); } - @Override - public RedisFuture sync() { - return dispatch(commandBuilder.sync()); - } - @Override public RedisFuture strlen(K key) { return dispatch(commandBuilder.strlen(key)); @@ -1549,31 +1519,16 @@ public RedisFuture waitForReplication(int replicas, long timeout) { return dispatch(commandBuilder.wait(replicas, timeout)); } - @Override - public RedisFuture pfadd(K key, V value, V... moreValues) { - return dispatch(commandBuilder.pfadd(key, value, moreValues)); - } - @Override public RedisFuture pfadd(K key, V... values) { return dispatch(commandBuilder.pfadd(key, values)); } - @Override - public RedisFuture pfmerge(K destkey, K sourcekey, K... moreSourceKeys) { - return dispatch(commandBuilder.pfmerge(destkey, sourcekey, moreSourceKeys)); - } - @Override public RedisFuture pfmerge(K destkey, K... sourcekeys) { return dispatch(commandBuilder.pfmerge(destkey, sourcekeys)); } - @Override - public RedisFuture pfcount(K key, K... moreKeys) { - return dispatch(commandBuilder.pfcount(key, moreKeys)); - } - @Override public RedisFuture pfcount(K... keys) { return dispatch(commandBuilder.pfcount(keys)); diff --git a/src/main/java/com/lambdaworks/redis/AbstractRedisClient.java b/src/main/java/com/lambdaworks/redis/AbstractRedisClient.java index 95ce06eacc..aae45992ba 100644 --- a/src/main/java/com/lambdaworks/redis/AbstractRedisClient.java +++ b/src/main/java/com/lambdaworks/redis/AbstractRedisClient.java @@ -6,7 +6,9 @@ import java.util.List; import java.util.Map; import java.util.Set; -import java.util.concurrent.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Supplier; @@ -50,11 +52,6 @@ public abstract class AbstractRedisClient { protected static final PooledByteBufAllocator BUF_ALLOCATOR = PooledByteBufAllocator.DEFAULT; protected static final InternalLogger logger = InternalLoggerFactory.getInstance(RedisClient.class); - /** - * @deprecated use map eventLoopGroups instead. - */ - @Deprecated - protected EventLoopGroup eventLoopGroup; protected EventExecutorGroup genericWorkerPool; protected final Map, EventLoopGroup> eventLoopGroups = new ConcurrentHashMap<>(2); @@ -71,14 +68,6 @@ public abstract class AbstractRedisClient { private final boolean sharedResources; private final AtomicBoolean shutdown = new AtomicBoolean(); - /** - * @deprecated use {@link #AbstractRedisClient(ClientResources)} - */ - @Deprecated - protected AbstractRedisClient() { - this(null); - } - /** * Create a new instance with client resources. * @@ -103,7 +92,7 @@ protected AbstractRedisClient(ClientResources clientResources) { } /** - * Set the default timeout for {@link com.lambdaworks.redis.RedisConnection connections} created by this client. The timeout + * Set the default timeout for connections created by this client. The timeout * applies to connection attempts and non-blocking commands. * * @param timeout Default connection timeout. @@ -179,12 +168,7 @@ private synchronized EventLoopGroup getEventLoopGroup(ConnectionPoint connection if ((connectionPoint == null || connectionPoint.getSocket() == null) && !eventLoopGroups.containsKey(NioEventLoopGroup.class)) { - - if (eventLoopGroup == null) { - eventLoopGroup = clientResources.eventLoopGroupProvider().allocate(NioEventLoopGroup.class); - } - - eventLoopGroups.put(NioEventLoopGroup.class, eventLoopGroup); + eventLoopGroups.put(NioEventLoopGroup.class, clientResources.eventLoopGroupProvider().allocate(NioEventLoopGroup.class)); } if (connectionPoint != null && connectionPoint.getSocket() != null) { diff --git a/src/main/java/com/lambdaworks/redis/AbstractRedisReactiveCommands.java b/src/main/java/com/lambdaworks/redis/AbstractRedisReactiveCommands.java index 8d9326fc10..194c4d50f0 100644 --- a/src/main/java/com/lambdaworks/redis/AbstractRedisReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/AbstractRedisReactiveCommands.java @@ -546,11 +546,6 @@ public Observable lpush(K key, V... values) { return createObservable(() -> commandBuilder.lpush(key, values)); } - @Override - public Observable lpushx(K key, V value) { - return createObservable(() -> commandBuilder.lpushx(key, value)); - } - @Override public Observable lpushx(K key, V... values) { return createObservable(() -> commandBuilder.lpushx(key, values)); @@ -754,11 +749,6 @@ public Observable rpush(K key, V... values) { return createObservable(() -> commandBuilder.rpush(key, values)); } - @Override - public Observable rpushx(K key, V value) { - return createObservable(() -> commandBuilder.rpushx(key, value)); - } - @Override public Observable rpushx(K key, V... values) { return createObservable(() -> commandBuilder.rpushx(key, values)); @@ -993,11 +983,6 @@ public Observable sunionstore(K destination, K... keys) { return createObservable(() -> commandBuilder.sunionstore(destination, keys)); } - @Override - public Observable sync() { - return createObservable(commandBuilder::sync); - } - @Override public Observable strlen(K key) { return createObservable(() -> commandBuilder.strlen(key)); @@ -1760,7 +1745,6 @@ public Observable geodist(K key, V from, V to, GeoArgs.Unit unit) { return createDissolvingObservable(() -> commandBuilder.geodist(key, from, to, unit)); } - @Override public Observable dispatch(ProtocolKeyword type, CommandOutput output) { LettuceAssert.notNull(type, "Command type must not be null"); @@ -1769,7 +1753,6 @@ public Observable dispatch(ProtocolKeyword type, CommandOutput o return createDissolvingObservable(() -> new Command<>(type, output)); } - @Override public Observable dispatch(ProtocolKeyword type, CommandOutput output, CommandArgs args) { LettuceAssert.notNull(type, "Command type must not be null"); @@ -1853,4 +1836,14 @@ public void reset() { public StatefulConnection getConnection() { return connection; } + + @Override + public void setAutoFlushCommands(boolean autoFlush) { + connection.setAutoFlushCommands(autoFlush); + } + + @Override + public void flushCommands() { + connection.flushCommands(); + } } diff --git a/src/main/java/com/lambdaworks/redis/BaseRedisAsyncConnection.java b/src/main/java/com/lambdaworks/redis/BaseRedisAsyncConnection.java deleted file mode 100644 index c1062301a8..0000000000 --- a/src/main/java/com/lambdaworks/redis/BaseRedisAsyncConnection.java +++ /dev/null @@ -1,200 +0,0 @@ -package com.lambdaworks.redis; - -import java.io.Closeable; -import java.util.List; -import java.util.Map; - -import com.lambdaworks.redis.api.async.BaseRedisAsyncCommands; -import com.lambdaworks.redis.output.CommandOutput; -import com.lambdaworks.redis.protocol.CommandArgs; -import com.lambdaworks.redis.protocol.ProtocolKeyword; - -/** - * - * Basic asynchronous executed commands. - * - * @author Mark Paluch - * @param Key type. - * @param Value type. - * @since 3.0 - * @deprecated Use {@link BaseRedisAsyncCommands} - */ -@Deprecated -public interface BaseRedisAsyncConnection extends Closeable, BaseRedisAsyncCommands { - - /** - * Post a message to a channel. - * - * @param channel the channel type: key - * @param message the message type: value - * @return RedisFuture<Long> integer-reply the number of clients that received the message. - */ - RedisFuture publish(K channel, V message); - - /** - * Lists the currently *active channels*. - * - * @return RedisFuture<List<K>> array-reply a list of active channels, optionally matching the specified - * pattern. - */ - RedisFuture> pubsubChannels(); - - /** - * Lists the currently *active channels*. - * - * @param channel the key - * @return RedisFuture<List<K>> array-reply a list of active channels, optionally matching the specified - * pattern. - */ - RedisFuture> pubsubChannels(K channel); - - /** - * Returns the number of subscribers (not counting clients subscribed to patterns) for the specified channels. - * - * @param channels channel keys - * @return array-reply a list of channels and number of subscribers for every channel. - */ - RedisFuture> pubsubNumsub(K... channels); - - /** - * Returns the number of subscriptions to patterns. - * - * @return RedisFuture<Long> integer-reply the number of patterns all the clients are subscribed to. - */ - RedisFuture pubsubNumpat(); - - /** - * Echo the given string. - * - * @param msg the message type: value - * @return RedisFuture<V> bulk-string-reply - */ - RedisFuture echo(V msg); - - /** - * Return the role of the instance in the context of replication. - * - * @return RedisFuture<List<Object>> array-reply where the first element is one of master, slave, sentinel and - * the additional elements are role-specific. - */ - RedisFuture> role(); - - /** - * Ping the server. - * - * @return RedisFuture<String> simple-string-reply - */ - RedisFuture ping(); - - /** - * Close the connection. - * - * @return RedisFuture<String> simple-string-reply always OK. - */ - RedisFuture quit(); - - /** - * Create a SHA1 digest from a Lua script. - * - * @param script script content - * @return the SHA1 value - */ - String digest(V script); - - /** - * Discard all commands issued after MULTI. - * - * @return RedisFuture<String> simple-string-reply always {@code OK}. - */ - RedisFuture discard(); - - /** - * Execute all commands issued after MULTI. - * - * @return RedisFuture<List<Object>> array-reply each element being the reply to each of the commands in the - * atomic transaction. - * - * When using {@code WATCH}, {@code EXEC} can return a - */ - RedisFuture> exec(); - - /** - * Mark the start of a transaction block. - * - * @return RedisFuture<String> simple-string-reply always {@code OK}. - */ - RedisFuture multi(); - - /** - * Watch the given keys to determine execution of the MULTI/EXEC block. - * - * @param keys the key - * @return RedisFuture<String> simple-string-reply always {@code OK}. - */ - RedisFuture watch(K... keys); - - /** - * Forget about all watched keys. - * - * @return RedisFuture<String> simple-string-reply always {@code OK}. - */ - RedisFuture unwatch(); - - /** - * Wait for replication. - * - * @param replicas minimum number of replicas - * @param timeout timeout in milliseconds - * @return number of replicas - */ - RedisFuture waitForReplication(int replicas, long timeout); - - /** - * Dispatch a command to the Redis Server. Please note the command output type must fit to the command response. - * - * @param type the command, must not be {@literal null}. - * @param output the command output, must not be {@literal null}. - * @param response type - * @return the command response - */ - RedisFuture dispatch(ProtocolKeyword type, CommandOutput output); - - /** - * Dispatch a command to the Redis Server. Please note the command output type must fit to the command response. - * - * @param type the command, must not be {@literal null}. - * @param output the command output, must not be {@literal null}. - * @param args the command arguments, must not be {@literal null}. - * @param response type - * @return the command response - */ - RedisFuture dispatch(ProtocolKeyword type, CommandOutput output, CommandArgs args); - - /** - * Close the connection. The connection will become not usable anymore as soon as this method was called. - */ - @Override - void close(); - - /** - * - * @return true if the connection is open (connected and not closed). - */ - boolean isOpen(); - - /** - * Disable or enable auto-flush behavior. Default is {@literal true}. If autoFlushCommands is disabled, multiple commands - * can be issued without writing them actually to the transport. Commands are buffered until a {@link #flushCommands()} is - * issued. After calling {@link #flushCommands()} commands are sent to the transport and executed by Redis. - * - * @param autoFlush state of autoFlush. - */ - void setAutoFlushCommands(boolean autoFlush); - - /** - * Flush pending commands. This commands forces a flush on the channel and can be used to buffer ("pipeline") commands to - * achieve batching. No-op if channel is not connected. - */ - void flushCommands(); - -} diff --git a/src/main/java/com/lambdaworks/redis/BaseRedisConnection.java b/src/main/java/com/lambdaworks/redis/BaseRedisConnection.java deleted file mode 100644 index e8418d786a..0000000000 --- a/src/main/java/com/lambdaworks/redis/BaseRedisConnection.java +++ /dev/null @@ -1,195 +0,0 @@ -package com.lambdaworks.redis; - -import java.io.Closeable; -import java.util.List; -import java.util.Map; - -import com.lambdaworks.redis.output.CommandOutput; -import com.lambdaworks.redis.protocol.CommandArgs; -import com.lambdaworks.redis.protocol.ProtocolKeyword; - -/** - * - * Basic synchronous executed commands. - * - * @param Key type. - * @param Value type. - * @author Mark Paluch - * @since 3.0 - * @deprecated Use {@link com.lambdaworks.redis.api.sync.BaseRedisCommands} - */ -@Deprecated -public interface BaseRedisConnection extends Closeable { - - /** - * Post a message to a channel. - * - * @param channel the channel type: key - * @param message the message type: value - * @return Long integer-reply the number of clients that received the message. - */ - Long publish(K channel, V message); - - /** - * Lists the currently *active channels*. - * - * @return List<K> array-reply a list of active channels, optionally matching the specified pattern. - */ - List pubsubChannels(); - - /** - * Lists the currently *active channels*. - * - * @param channel the key - * @return List<K> array-reply a list of active channels, optionally matching the specified pattern. - */ - List pubsubChannels(K channel); - - /** - * Returns the number of subscribers (not counting clients subscribed to patterns) for the specified channels. - * - * @param channels channel keys - * @return array-reply a list of channels and number of subscribers for every channel. - */ - Map pubsubNumsub(K... channels); - - /** - * Returns the number of subscriptions to patterns. - * - * @return Long integer-reply the number of patterns all the clients are subscribed to. - */ - Long pubsubNumpat(); - - /** - * Echo the given string. - * - * @param msg the message type: value - * @return V bulk-string-reply - */ - V echo(V msg); - - /** - * Return the role of the instance in the context of replication. - * - * @return List<Object> array-reply where the first element is one of master, slave, sentinel and the additional - * elements are role-specific. - */ - List role(); - - /** - * Ping the server. - * - * @return String simple-string-reply - */ - String ping(); - - /** - * Switch connection to Read-Only mode when connecting to a cluster. - * - * @return String simple-string-reply. - */ - String readOnly(); - - /** - * Switch connection to Read-Write mode (default) when connecting to a cluster. - * - * @return String simple-string-reply. - */ - String readWrite(); - - /** - * Close the connection. - * - * @return String simple-string-reply always OK. - */ - String quit(); - - /** - * Create a SHA1 digest from a Lua script. - * - * @param script script content - * @return the SHA1 value - */ - String digest(V script); - - /** - * Discard all commands issued after MULTI. - * - * @return String simple-string-reply always {@code OK}. - */ - String discard(); - - /** - * Execute all commands issued after MULTI. - * - * @return List<Object> array-reply each element being the reply to each of the commands in the atomic transaction. - * - * When using {@code WATCH}, {@code EXEC} can return a - */ - List exec(); - - /** - * Mark the start of a transaction block. - * - * @return String simple-string-reply always {@code OK}. - */ - String multi(); - - /** - * Watch the given keys to determine execution of the MULTI/EXEC block. - * - * @param keys the key - * @return String simple-string-reply always {@code OK}. - */ - String watch(K... keys); - - /** - * Forget about all watched keys. - * - * @return String simple-string-reply always {@code OK}. - */ - String unwatch(); - - /** - * Wait for replication. - * - * @param replicas minimum number of replicas - * @param timeout timeout in milliseconds - * @return number of replicas - */ - Long waitForReplication(int replicas, long timeout); - - /** - * Dispatch a command to the Redis Server. Please note the command output type must fit to the command response. - * - * @param type the command, must not be {@literal null}. - * @param output the command output, must not be {@literal null}. - * @param response type - * @return the command response - */ - T dispatch(ProtocolKeyword type, CommandOutput output); - - /** - * Dispatch a command to the Redis Server. Please note the command output type must fit to the command response. - * - * @param type the command, must not be {@literal null}. - * @param output the command output, must not be {@literal null}. - * @param args the command arguments, must not be {@literal null}. - * @param response type - * @return the command response - */ - T dispatch(ProtocolKeyword type, CommandOutput output, CommandArgs args); - - /** - * Close the connection. The connection will become not usable anymore as soon as this method was called. - */ - @Override - void close(); - - /** - * - * @return true if the connection is open (connected and not closed). - */ - boolean isOpen(); - -} diff --git a/src/main/java/com/lambdaworks/redis/ClientOptions.java b/src/main/java/com/lambdaworks/redis/ClientOptions.java index 64039f1ac9..bd9f162f39 100644 --- a/src/main/java/com/lambdaworks/redis/ClientOptions.java +++ b/src/main/java/com/lambdaworks/redis/ClientOptions.java @@ -93,11 +93,7 @@ public static class Builder { private SocketOptions socketOptions = DEFAULT_SOCKET_OPTIONS; private SslOptions sslOptions = DEFAULT_SSL_OPTIONS; - /** - * @deprecated Use {@link ClientOptions#builder()} - */ - @Deprecated - public Builder() { + protected Builder() { } /** diff --git a/src/main/java/com/lambdaworks/redis/Connections.java b/src/main/java/com/lambdaworks/redis/Connections.java deleted file mode 100644 index 20d95eb58b..0000000000 --- a/src/main/java/com/lambdaworks/redis/Connections.java +++ /dev/null @@ -1,112 +0,0 @@ -package com.lambdaworks.redis; - -import java.util.concurrent.ExecutionException; - -import com.lambdaworks.redis.internal.LettuceAssert; - -/** - * Utility for checking a connection's state. - * - * @author Mark Paluch - * @since 3.0 - */ -class Connections { - - /** - * Utility constructor. - */ - private Connections() { - - } - - /** - * - * @param connection must be either a {@link com.lambdaworks.redis.RedisAsyncConnection} or - * {@link com.lambdaworks.redis.RedisConnection} and must not be {@literal null} - * @return true if the connection is valid (ping works) - * @throws java.lang.NullPointerException if connection is null - * @throws java.lang.IllegalArgumentException if connection is not a supported type - */ - public static final boolean isValid(Object connection) { - - LettuceAssert.notNull(connection, "Connection must not be null"); - if (connection instanceof RedisAsyncConnection) { - RedisAsyncConnection redisAsyncConnection = (RedisAsyncConnection) connection; - try { - redisAsyncConnection.ping().get(); - return true; - } catch (ExecutionException | RuntimeException e) { - return false; - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - throw new RedisCommandInterruptedException(e); - } - } - - if (connection instanceof RedisConnection) { - RedisConnection redisConnection = (RedisConnection) connection; - try { - redisConnection.ping(); - return true; - } catch (RuntimeException e) { - return false; - } - } - - throw new IllegalArgumentException("Connection class " + connection.getClass() + " not supported"); - } - - /** - * - * @param connection must be either a {@link com.lambdaworks.redis.RedisAsyncConnection} or - * {@link com.lambdaworks.redis.RedisConnection} and must not be {@literal null} - * @return true if the connection is open. - * @throws java.lang.NullPointerException if connection is null - * @throws java.lang.IllegalArgumentException if connection is not a supported type - */ - public static final boolean isOpen(Object connection) { - - LettuceAssert.notNull(connection, "Connection must not be null"); - if (connection instanceof RedisAsyncConnection) { - RedisAsyncConnection redisAsyncConnection = (RedisAsyncConnection) connection; - return redisAsyncConnection.isOpen(); - } - - if (connection instanceof RedisConnection) { - RedisConnection redisConnection = (RedisConnection) connection; - return redisConnection.isOpen(); - } - - throw new IllegalArgumentException("Connection class " + connection.getClass() + " not supported"); - } - - /** - * Closes silently a connection. - * - * @param connection must be either a {@link com.lambdaworks.redis.RedisAsyncConnection} or - * {@link com.lambdaworks.redis.RedisConnection} and must not be {@literal null} - * @throws java.lang.NullPointerException if connection is null - * @throws java.lang.IllegalArgumentException if connection is not a supported type - */ - public static void close(Object connection) { - - LettuceAssert.notNull(connection, "Connection must not be null"); - try { - if (connection instanceof RedisAsyncConnection) { - RedisAsyncConnection redisAsyncConnection = (RedisAsyncConnection) connection; - redisAsyncConnection.close(); - return; - } - - if (connection instanceof RedisConnection) { - RedisConnection redisConnection = (RedisConnection) connection; - redisConnection.close(); - return; - } - } catch (RuntimeException e) { - return; - } - throw new IllegalArgumentException("Connection class " + connection.getClass() + " not supported"); - - } -} diff --git a/src/main/java/com/lambdaworks/redis/RedisAsyncCommandsImpl.java b/src/main/java/com/lambdaworks/redis/RedisAsyncCommandsImpl.java index bd223a9928..41c17da718 100644 --- a/src/main/java/com/lambdaworks/redis/RedisAsyncCommandsImpl.java +++ b/src/main/java/com/lambdaworks/redis/RedisAsyncCommandsImpl.java @@ -14,8 +14,8 @@ * @param Value type. * @author Mark Paluch */ -public class RedisAsyncCommandsImpl extends AbstractRedisAsyncCommands implements RedisAsyncConnection, - RedisClusterAsyncConnection, RedisAsyncCommands, RedisClusterAsyncCommands { +public class RedisAsyncCommandsImpl extends AbstractRedisAsyncCommands + implements RedisAsyncCommands, RedisClusterAsyncCommands { /** * Initialize a new instance. diff --git a/src/main/java/com/lambdaworks/redis/RedisAsyncConnection.java b/src/main/java/com/lambdaworks/redis/RedisAsyncConnection.java deleted file mode 100644 index dc68fe22e9..0000000000 --- a/src/main/java/com/lambdaworks/redis/RedisAsyncConnection.java +++ /dev/null @@ -1,53 +0,0 @@ -package com.lambdaworks.redis; - -import java.util.concurrent.TimeUnit; - -import com.lambdaworks.redis.api.StatefulRedisConnection; -import com.lambdaworks.redis.api.async.RedisAsyncCommands; -import com.lambdaworks.redis.api.async.RedisTransactionalAsyncCommands; - -/** - * A complete asynchronous and thread-safe Redis API with 400+ Methods. - * - * @param Key type. - * @param Value type. - * @author Mark Paluch - * @since 3.0 - * @deprecated Use {@link RedisAsyncCommands} - */ -@Deprecated -public interface RedisAsyncConnection extends RedisHashesAsyncConnection, RedisKeysAsyncConnection, - RedisStringsAsyncConnection, RedisListsAsyncConnection, RedisSetsAsyncConnection, - RedisSortedSetsAsyncConnection, RedisScriptingAsyncConnection, RedisServerAsyncConnection, - RedisHLLAsyncConnection, RedisGeoAsyncConnection, BaseRedisAsyncConnection, - RedisClusterAsyncConnection { - /** - * Set the default timeout for operations. - * - * @param timeout the timeout value - * @param unit the unit of the timeout value - */ - void setTimeout(long timeout, TimeUnit unit); - - /** - * Authenticate to the server. - * - * @param password the password - * @return String simple-string-reply - */ - String auth(String password); - - /** - * Change the selected database for the current connection. - * - * @param db the database number - * @return String simple-string-reply - */ - String select(int db); - - /** - * @return the underlying connection. - */ - StatefulRedisConnection getStatefulConnection(); - -} diff --git a/src/main/java/com/lambdaworks/redis/RedisClient.java b/src/main/java/com/lambdaworks/redis/RedisClient.java index 7564015e89..eaf06353d4 100644 --- a/src/main/java/com/lambdaworks/redis/RedisClient.java +++ b/src/main/java/com/lambdaworks/redis/RedisClient.java @@ -2,12 +2,22 @@ package com.lambdaworks.redis; +import static com.lambdaworks.redis.LettuceStrings.isEmpty; +import static com.lambdaworks.redis.LettuceStrings.isNotEmpty; +import static com.lambdaworks.redis.internal.LettuceClassUtils.isPresent; + +import java.net.ConnectException; +import java.net.SocketAddress; +import java.util.List; +import java.util.Queue; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.function.Supplier; + import com.lambdaworks.redis.api.StatefulRedisConnection; -import com.lambdaworks.redis.api.async.RedisAsyncCommands; -import com.lambdaworks.redis.api.sync.RedisCommands; import com.lambdaworks.redis.codec.RedisCodec; import com.lambdaworks.redis.codec.StringCodec; -import com.lambdaworks.redis.codec.Utf8StringCodec; import com.lambdaworks.redis.internal.LettuceAssert; import com.lambdaworks.redis.internal.LettuceFactories; import com.lambdaworks.redis.protocol.CommandHandler; @@ -19,20 +29,6 @@ import com.lambdaworks.redis.resource.SocketAddressResolver; import com.lambdaworks.redis.sentinel.StatefulRedisSentinelConnectionImpl; import com.lambdaworks.redis.sentinel.api.StatefulRedisSentinelConnection; -import com.lambdaworks.redis.sentinel.api.async.RedisSentinelAsyncCommands; - -import java.net.ConnectException; -import java.net.SocketAddress; -import java.util.List; -import java.util.Queue; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import java.util.function.Supplier; - -import static com.lambdaworks.redis.LettuceStrings.isEmpty; -import static com.lambdaworks.redis.LettuceStrings.isNotEmpty; -import static com.lambdaworks.redis.internal.LettuceClassUtils.isPresent; /** * A scalable thread-safe Redis client. Multiple threads may share one connection if they avoid @@ -62,48 +58,9 @@ protected RedisClient(ClientResources clientResources, RedisURI redisURI) { /** * Creates a uri-less RedisClient. You can connect to different Redis servers but you must supply a {@link RedisURI} on * connecting. Methods without having a {@link RedisURI} will fail with a {@link java.lang.IllegalStateException}. - * - * @deprecated Use the factory method {@link #create()} - */ - @Deprecated - public RedisClient() { - this(EMPTY_URI); - } - - /** - * Create a new client that connects to the supplied host on the default port. - * - * @param host Server hostname. - * @deprecated Use the factory method {@link #create(String)} - */ - @Deprecated - public RedisClient(String host) { - this(host, RedisURI.DEFAULT_REDIS_PORT); - } - - /** - * Create a new client that connects to the supplied host and port. Connection attempts and non-blocking commands will - * {@link #setDefaultTimeout timeout} after 60 seconds. - * - * @param host Server hostname. - * @param port Server port. - * @deprecated Use the factory method {@link #create(RedisURI)} - */ - @Deprecated - public RedisClient(String host, int port) { - this(RedisURI.Builder.redis(host, port).build()); - } - - /** - * Create a new client that connects to the supplied host and port. Connection attempts and non-blocking commands will - * {@link #setDefaultTimeout timeout} after 60 seconds. - * - * @param redisURI Redis URI. - * @deprecated Use the factory method {@link #create(RedisURI)} */ - @Deprecated - public RedisClient(RedisURI redisURI) { - this(null, redisURI); + protected RedisClient() { + this(null, EMPTY_URI); } /** @@ -185,136 +142,6 @@ public static RedisClient create(ClientResources clientResources, RedisURI redis return new RedisClient(clientResources, redisURI); } - /** - * Creates a connection pool for synchronous connections. 5 max idle connections and 20 max active connections. Please keep - * in mind to free all collections and close the pool once you do not need it anymore. Requires Apache commons-pool2 - * dependency. - * - * @return a new {@link RedisConnectionPool} instance - */ - public RedisConnectionPool> pool() { - return pool(5, 20); - } - - /** - * Creates a connection pool for synchronous connections. Please keep in mind to free all collections and close the pool - * once you do not need it anymore. Requires Apache commons-pool2 dependency. - * - * @param maxIdle max idle connections in pool - * @param maxActive max active connections in pool - * @return a new {@link RedisConnectionPool} instance - */ - public RedisConnectionPool> pool(int maxIdle, int maxActive) { - return pool(newStringStringCodec(), maxIdle, maxActive); - } - - /** - * Creates a connection pool for synchronous connections. Please keep in mind to free all collections and close the pool - * once you do not need it anymore. Requires Apache commons-pool2 dependency. - * - * @param codec Use this codec to encode/decode keys and values, must not be {@literal null} - * @param maxIdle max idle connections in pool - * @param maxActive max active connections in pool - * @param Key type - * @param Value type - * @return a new {@link RedisConnectionPool} instance - */ - @SuppressWarnings("unchecked") - public RedisConnectionPool> pool(final RedisCodec codec, int maxIdle, int maxActive) { - - checkPoolDependency(); - checkForRedisURI(); - LettuceAssert.notNull(codec, "RedisCodec must not be null"); - - long maxWait = makeTimeout(); - RedisConnectionPool> pool = new RedisConnectionPool<>( - new RedisConnectionPool.RedisConnectionProvider>() { - @Override - public RedisCommands createConnection() { - return connect(codec, redisURI).sync(); - } - - @Override - @SuppressWarnings("rawtypes") - public Class> getComponentType() { - return (Class) RedisCommands.class; - } - }, maxActive, maxIdle, maxWait); - - pool.addListener(closeableResources::remove); - - closeableResources.add(pool); - - return pool; - } - - protected long makeTimeout() { - return TimeUnit.MILLISECONDS.convert(timeout, unit); - } - - /** - * Creates a connection pool for asynchronous connections. 5 max idle connections and 20 max active connections. Please keep - * in mind to free all collections and close the pool once you do not need it anymore. Requires Apache commons-pool2 - * dependency. - * - * @return a new {@link RedisConnectionPool} instance - */ - public RedisConnectionPool> asyncPool() { - return asyncPool(5, 20); - } - - /** - * Creates a connection pool for asynchronous connections. Please keep in mind to free all collections and close the pool - * once you do not need it anymore. Requires Apache commons-pool2 dependency. - * - * @param maxIdle max idle connections in pool - * @param maxActive max active connections in pool - * @return a new {@link RedisConnectionPool} instance - */ - public RedisConnectionPool> asyncPool(int maxIdle, int maxActive) { - return asyncPool(newStringStringCodec(), maxIdle, maxActive); - } - - /** - * Creates a connection pool for asynchronous connections. Please keep in mind to free all collections and close the pool - * once you do not need it anymore. Requires Apache commons-pool2 dependency. - * - * @param codec Use this codec to encode/decode keys and values, must not be {@literal null} - * @param maxIdle max idle connections in pool - * @param maxActive max active connections in pool - * @param Key type - * @param Value type - * @return a new {@link RedisConnectionPool} instance - */ - public RedisConnectionPool> asyncPool(final RedisCodec codec, int maxIdle, - int maxActive) { - - checkPoolDependency(); - checkForRedisURI(); - LettuceAssert.notNull(codec, "RedisCodec must not be null"); - - long maxWait = makeTimeout(); - RedisConnectionPool> pool = new RedisConnectionPool<>( - new RedisConnectionPool.RedisConnectionProvider>() { - @Override - public RedisAsyncCommands createConnection() { - return connectStandalone(codec, redisURI, defaultTimeout()).async(); - } - - @Override - @SuppressWarnings({ "rawtypes", "unchecked" }) - public Class> getComponentType() { - return (Class) RedisAsyncCommands.class; - } - }, maxActive, maxIdle, maxWait); - - pool.addListener(closeableResources::remove); - - closeableResources.add(pool); - - return pool; - } - /** * Open a new connection to a Redis server that treats keys and values as UTF-8 strings. * @@ -361,59 +188,6 @@ public StatefulRedisConnection connect(RedisCodec codec, Redi return connectStandalone(codec, redisURI, Timeout.from(redisURI)); } - /** - * Open a new asynchronous connection to a Redis server that treats keys and values as UTF-8 strings. - * - * @return A new connection - */ - @Deprecated - public RedisAsyncCommands connectAsync() { - return connect(newStringStringCodec()).async(); - } - - /** - * Open a new asynchronous connection to a Redis server. Use the supplied {@link RedisCodec codec} to encode/decode keys and - * values. - * - * @param codec Use this codec to encode/decode keys and values, must not be {@literal null} - * @param Key type - * @param Value type - * @return A new connection - * @deprecated Use {@code connect(codec).async()} - */ - @Deprecated - public RedisAsyncCommands connectAsync(RedisCodec codec) { - return connectStandalone(codec, redisURI, defaultTimeout()).async(); - } - - /** - * Open a new asynchronous connection to a Redis server using the supplied {@link RedisURI} that treats keys and values as - * UTF-8 strings. - * - * @param redisURI the Redis server to connect to, must not be {@literal null} - * @return A new connection - * @deprecated Use {@code connect(redisURI).async()} - */ - @Deprecated - public RedisAsyncCommands connectAsync(RedisURI redisURI) { - return connectStandalone(newStringStringCodec(), redisURI, Timeout.from(redisURI)).async(); - } - - /** - * Open a new asynchronous connection to a Redis server using the supplied {@link RedisURI} and the supplied - * {@link RedisCodec codec} to encode/decode keys. - * - * @param codec Use this codec to encode/decode keys and values, must not be {@literal null} - * @param redisURI the Redis server to connect to, must not be {@literal null} - * @param Key type - * @param Value type - * @return A new connection - * @deprecated Use {@code connect(codec, redisURI).async()} - */ - @Deprecated - public RedisAsyncCommands connectAsync(RedisCodec codec, RedisURI redisURI) { - return connectStandalone(codec, redisURI, Timeout.from(redisURI)).async(); - } private StatefulRedisConnection connectStandalone(RedisCodec codec, RedisURI redisURI, Timeout timeout) { @@ -571,64 +345,6 @@ public StatefulRedisSentinelConnection connectSentinel(RedisCodec connectSentinelAsync() { - return connectSentinel(newStringStringCodec(), redisURI, defaultTimeout()).async(); - } - - /** - * Open a new asynchronous connection to a Redis Sentinela nd use the supplied {@link RedisCodec codec} to encode/decode - * keys and values. You must supply a valid RedisURI containing one or more sentinels. - * - * @param codec Use this codec to encode/decode keys and values, must not be {@literal null} - * @param Key type - * @param Value type - * @return a new connection - * @deprecated Use {@code connectSentinel(codec).async()} - */ - @Deprecated - public RedisSentinelAsyncCommands connectSentinelAsync(RedisCodec codec) { - checkForRedisURI(); - return connectSentinel(codec, redisURI, defaultTimeout()).async(); - } - - /** - * Open a new asynchronous connection to a Redis Sentinel using the supplied {@link RedisURI} that treats keys and values as - * UTF-8 strings. You must supply a valid RedisURI containing a redis host or one or more sentinels. - * - * @param redisURI the Redis server to connect to, must not be {@literal null} - * @return A new connection - * @deprecated Use {@code connectSentinel(redisURI).async()} - */ - @Deprecated - public RedisSentinelAsyncCommands connectSentinelAsync(RedisURI redisURI) { - return connectSentinel(newStringStringCodec(), redisURI, Timeout.from(redisURI)).async(); - } - - /** - * Open a new asynchronous connection to a Redis Sentinel using the supplied {@link RedisURI} and use the supplied - * {@link RedisCodec codec} to encode/decode keys and values. You must supply a valid RedisURI containing a redis host or - * one or more sentinels. - * - * @param codec Use this codec to encode/decode keys and values, must not be {@literal null} - * @param redisURI the Redis server to connect to, must not be {@literal null} - * @param Key type - * @param Value type - * @return A new connection - * @deprecated Use {@code connectSentinel(codec, redisURI).async()} - */ - @Deprecated - public RedisSentinelAsyncCommands connectSentinelAsync(RedisCodec codec, RedisURI redisURI) { - return connectSentinel(codec, redisURI, Timeout.from(redisURI)).async(); - } - private StatefulRedisSentinelConnection connectSentinel(RedisCodec codec, RedisURI redisURI, Timeout timeout) { assertNotNull(codec); @@ -689,22 +405,6 @@ private StatefulRedisSentinelConnection connectSentinel(RedisCodec< return connection; } - /** - * Create a new instance of {@link StatefulRedisPubSubConnectionImpl} or a subclass. - * - * @param commandHandler the command handler - * @param codec codec - * @param Key-Type - * @param Value Type - * @return new instance of StatefulRedisPubSubConnectionImpl - * @deprecated Use {@link #newStatefulRedisPubSubConnection(PubSubCommandHandler, RedisCodec, long, TimeUnit)} - */ - @Deprecated - protected StatefulRedisPubSubConnectionImpl newStatefulRedisPubSubConnection( - PubSubCommandHandler commandHandler, RedisCodec codec) { - return newStatefulRedisPubSubConnection(commandHandler, codec, timeout, unit); - } - /** * Create a new instance of {@link StatefulRedisPubSubConnectionImpl} or a subclass. * @@ -721,22 +421,6 @@ protected StatefulRedisPubSubConnectionImpl newStatefulRedisPubSubC return new StatefulRedisPubSubConnectionImpl<>(commandHandler, codec, timeout, unit); } - /** - * Create a new instance of {@link StatefulRedisSentinelConnectionImpl} or a subclass. - * - * @param commandHandler the command handler - * @param codec codec - * @param Key-Type - * @param Value Type - * @return new instance of StatefulRedisSentinelConnectionImpl - * @deprecated Use {@link #newStatefulRedisSentinelConnection(CommandHandler, RedisCodec, long, TimeUnit)} - */ - @Deprecated - protected StatefulRedisSentinelConnectionImpl newStatefulRedisSentinelConnection( - CommandHandler commandHandler, RedisCodec codec) { - return newStatefulRedisSentinelConnection(commandHandler, codec, timeout, unit); - } - /** * Create a new instance of {@link StatefulRedisSentinelConnectionImpl} or a subclass. * @@ -753,22 +437,6 @@ protected StatefulRedisSentinelConnectionImpl newStatefulRedisSenti return new StatefulRedisSentinelConnectionImpl<>(commandHandler, codec, timeout, unit); } - /** - * Create a new instance of {@link StatefulRedisConnectionImpl} or a subclass. - * - * @param commandHandler the command handler - * @param codec codec - * @param Key-Type - * @param Value Type - * @return new instance of StatefulRedisConnectionImpl - * @deprecated use {@link #newStatefulRedisConnection(CommandHandler, RedisCodec, long, TimeUnit)} - */ - @Deprecated - protected StatefulRedisConnectionImpl newStatefulRedisConnection(CommandHandler commandHandler, - RedisCodec codec) { - return newStatefulRedisConnection(commandHandler, codec, timeout, unit); - } - /** * Create a new instance of {@link StatefulRedisConnectionImpl} or a subclass. * @@ -826,7 +494,7 @@ public ClientResources getResources() { return clientResources; } - protected SocketAddress getSocketAddress(RedisURI redisURI) + private SocketAddress getSocketAddress(RedisURI redisURI) throws InterruptedException, TimeoutException, ExecutionException { SocketAddress redisAddress; @@ -847,9 +515,10 @@ protected SocketAddress getSocketAddress(RedisURI redisURI) } private SocketAddress lookupRedis(RedisURI sentinelUri) throws InterruptedException, TimeoutException, ExecutionException { - RedisSentinelAsyncCommands connection = connectSentinel(sentinelUri).async(); + StatefulRedisSentinelConnection connection = connectSentinel( + sentinelUri); try { - return connection.getMasterAddrByName(sentinelUri.getSentinelMasterId()).get(timeout, unit); + return connection.async().getMasterAddrByName(sentinelUri.getSentinelMasterId()).get(timeout, unit); } finally { connection.close(); } diff --git a/src/main/java/com/lambdaworks/redis/RedisClusterAsyncConnection.java b/src/main/java/com/lambdaworks/redis/RedisClusterAsyncConnection.java deleted file mode 100644 index 4cc2a4435e..0000000000 --- a/src/main/java/com/lambdaworks/redis/RedisClusterAsyncConnection.java +++ /dev/null @@ -1,266 +0,0 @@ -package com.lambdaworks.redis; - -import java.util.List; -import java.util.concurrent.TimeUnit; - -import com.lambdaworks.redis.cluster.api.async.RedisClusterAsyncCommands; - -/** - * A complete asynchronous and thread-safe cluster Redis API with 400+ Methods. - * - * @param Key type. - * @param Value type. - * @author Mark Paluch - * @since 3.0 - * @deprecated Use {@link RedisClusterAsyncCommands} - */ -@Deprecated -public interface RedisClusterAsyncConnection extends RedisHashesAsyncConnection, RedisKeysAsyncConnection, - RedisStringsAsyncConnection, RedisListsAsyncConnection, RedisSetsAsyncConnection, - RedisSortedSetsAsyncConnection, RedisScriptingAsyncConnection, RedisServerAsyncConnection, - RedisHLLAsyncConnection, RedisGeoAsyncConnection, BaseRedisAsyncConnection { - - /** - * Set the default timeout for operations. - * - * @param timeout the timeout value - * @param unit the unit of the timeout value - */ - void setTimeout(long timeout, TimeUnit unit); - - /** - * Authenticate to the server. - * - * @param password the password - * @return String simple-string-reply - */ - String auth(String password); - - /** - * Meet another cluster node to include the node into the cluster. The command starts the cluster handshake and returns with - * {@literal OK} when the node was added to the cluster. - * - * @param ip IP address of the host - * @param port port number. - * @return String simple-string-reply - */ - RedisFuture clusterMeet(String ip, int port); - - /** - * Blacklist and remove the cluster node from the cluster. - * - * @param nodeId the node Id - * @return String simple-string-reply - */ - RedisFuture clusterForget(String nodeId); - - /** - * Adds slots to the cluster node. The current node will become the master for the specified slots. - * - * @param slots one or more slots from {@literal 0} to {@literal 16384} - * @return String simple-string-reply - */ - RedisFuture clusterAddSlots(int... slots); - - /** - * Removes slots from the cluster node. - * - * @param slots one or more slots from {@literal 0} to {@literal 16384} - * @return String simple-string-reply - */ - RedisFuture clusterDelSlots(int... slots); - - /** - * Assign a slot to a node. The command migrates the specified slot from the current node to the specified node in - * {@code nodeId} - * - * @param slot the slot - * @param nodeId the id of the node that will become the master for the slot - * @return String simple-string-reply - */ - RedisFuture clusterSetSlotNode(int slot, String nodeId); - - /** - * Clears migrating / importing state from the slot. - * - * @param slot the slot - * @return String simple-string-reply - */ - RedisFuture clusterSetSlotStable(int slot); - - /** - * Flag a slot as {@literal MIGRATING} (outgoing) towards the node specified in {@code nodeId}. The slot must be handled by - * the current node in order to be migrated. - * - * @param slot the slot - * @param nodeId the id of the node is targeted to become the master for the slot - * @return String simple-string-reply - */ - RedisFuture clusterSetSlotMigrating(int slot, String nodeId); - - /** - * Flag a slot as {@literal IMPORTING} (incoming) from the node specified in {@code nodeId}. - * - * @param slot the slot - * @param nodeId the id of the node is the master of the slot - * @return String simple-string-reply - */ - RedisFuture clusterSetSlotImporting(int slot, String nodeId); - - /** - * Get information and statistics about the cluster viewed by the current node. - * - * @return String bulk-string-reply as a collection of text lines. - */ - RedisFuture clusterInfo(); - - /** - * Obtain the nodeId for the currently connected node. - * - * @return String simple-string-reply - */ - RedisFuture clusterMyId(); - - /** - * Obtain details about all cluster nodes. Can be parsed using - * {@link com.lambdaworks.redis.cluster.models.partitions.ClusterPartitionParser#parse} - * - * @return String bulk-string-reply as a collection of text lines - */ - RedisFuture clusterNodes(); - - /** - * List slaves for a certain node identified by its {@code nodeId}. Can be parsed using - * {@link com.lambdaworks.redis.cluster.models.partitions.ClusterPartitionParser#parse} - * - * @param nodeId node id of the master node - * @return List<String> array-reply list of slaves. The command returns data in the same format as - * {@link #clusterNodes()} but one line per slave. - */ - RedisFuture> clusterSlaves(String nodeId); - - /** - * Retrieve the list of keys within the {@code slot}. - * - * @param slot the slot - * @param count maximal number of keys - * @return List<K> array-reply list of keys - */ - RedisFuture> clusterGetKeysInSlot(int slot, int count); - - /** - * Returns the number of keys in the specified Redis Cluster hash {@code slot}. - * - * @param slot the slot - * @return Integer reply: The number of keys in the specified hash slot, or an error if the hash slot is invalid. - */ - RedisFuture clusterCountKeysInSlot(int slot); - - /** - * Returns the number of failure reports for the specified node. Failure reports are the way Redis Cluster uses in order to - * promote a {@literal PFAIL} state, that means a node is not reachable, to a {@literal FAIL} state, that means that the - * majority of masters in the cluster agreed within a window of time that the node is not reachable. - * - * @param nodeId the node id - * @return Integer reply: The number of active failure reports for the node. - */ - RedisFuture clusterCountFailureReports(String nodeId); - - /** - * Returns an integer identifying the hash slot the specified key hashes to. This command is mainly useful for debugging and - * testing, since it exposes via an API the underlying Redis implementation of the hashing algorithm. Basically the same as - * {@link com.lambdaworks.redis.cluster.SlotHash#getSlot(byte[])}. If not, call Houston and report that we've got a problem. - * - * @param key the key. - * @return Integer reply: The hash slot number. - */ - RedisFuture clusterKeyslot(K key); - - /** - * Forces a node to save the nodes.conf configuration on disk. - * - * @return String simple-string-reply: {@code OK} or an error if the operation fails. - */ - RedisFuture clusterSaveconfig(); - - /** - * This command sets a specific config epoch in a fresh node. It only works when: - *
    - *
  • The nodes table of the node is empty.
  • - *
  • The node current config epoch is zero.
  • - *
- * - * @param configEpoch the config epoch - * @return String simple-string-reply: {@code OK} or an error if the operation fails. - */ - RedisFuture clusterSetConfigEpoch(long configEpoch); - - /** - * Get array of cluster slots to node mappings. - * - * @return RedisFuture<List<Object>> array-reply nested list of slot ranges with IP/Port mappings. - */ - RedisFuture> clusterSlots(); - - /** - * - * @return String simple-string-reply - */ - RedisFuture asking(); - - /** - * Turn this node into a slave of the node with the id {@code nodeId}. - * - * @param nodeId master node id - * @return String simple-string-reply - */ - RedisFuture clusterReplicate(String nodeId); - - /** - * Failover a cluster node. Turns the currently connected node into a master and the master into its slave. - * - * @param force do not coordinate with master if {@literal true} - * @return String simple-string-reply - */ - RedisFuture clusterFailover(boolean force); - - /** - * Reset a node performing a soft or hard reset: - *
    - *
  • All other nodes are forgotten
  • - *
  • All the assigned / open slots are released
  • - *
  • If the node is a slave, it turns into a master
  • - *
  • Only for hard reset: a new Node ID is generated
  • - *
  • Only for hard reset: currentEpoch and configEpoch are set to 0
  • - *
  • The new configuration is saved and the cluster state updated
  • - *
  • If the node was a slave, the whole data set is flushed away
  • - *
- * - * @param hard {@literal true} for hard reset. Generates a new nodeId and currentEpoch/configEpoch are set to 0 - * @return String simple-string-reply - */ - RedisFuture clusterReset(boolean hard); - - /** - * Delete all the slots associated with the specified node. The number of deleted slots is returned. - * - * @return String simple-string-reply - */ - RedisFuture clusterFlushslots(); - - /** - * Tells a Redis cluster slave node that the client is ok reading possibly stale data and is not interested in running write - * queries. - * - * @return String simple-string-reply - */ - RedisFuture readOnly(); - - /** - * Resets readOnly flag. - * - * @return String simple-string-reply - */ - RedisFuture readWrite(); - -} diff --git a/src/main/java/com/lambdaworks/redis/RedisClusterConnection.java b/src/main/java/com/lambdaworks/redis/RedisClusterConnection.java deleted file mode 100644 index 6ddc5654f6..0000000000 --- a/src/main/java/com/lambdaworks/redis/RedisClusterConnection.java +++ /dev/null @@ -1,268 +0,0 @@ -package com.lambdaworks.redis; - -import java.util.List; -import java.util.concurrent.TimeUnit; - -import com.lambdaworks.redis.api.sync.BaseRedisCommands; - -/** - * A complete synchronous and thread-safe cluster Redis API with 400+ Methods. - * - * @param Key type. - * @param Value type. - * @author Mark Paluch - * @since 3.0 - * @deprecated Use {@link com.lambdaworks.redis.cluster.api.sync.RedisClusterCommands} - */ -@Deprecated -public interface RedisClusterConnection extends RedisHashesConnection, RedisKeysConnection, - RedisStringsConnection, RedisListsConnection, RedisSetsConnection, RedisSortedSetsConnection, - RedisScriptingConnection, RedisServerConnection, RedisHLLConnection, RedisGeoConnection, - BaseRedisConnection, AutoCloseable { - - /** - * Set the default timeout for operations. - * - * @param timeout the timeout value - * @param unit the unit of the timeout value - */ - void setTimeout(long timeout, TimeUnit unit); - - /** - * Authenticate to the server. - * - * @param password the password - * @return String simple-string-reply - */ - String auth(String password); - - /** - * Meet another cluster node to include the node into the cluster. The command starts the cluster handshake and returns with - * {@literal OK} when the node was added to the cluster. - * - * @param ip IP address of the host - * @param port port number. - * @return String simple-string-reply - */ - String clusterMeet(String ip, int port); - - /** - * Blacklist and remove the cluster node from the cluster. - * - * @param nodeId the node Id - * @return String simple-string-reply - */ - String clusterForget(String nodeId); - - /** - * Adds slots to the cluster node. The current node will become the master for the specified slots. - * - * @param slots one or more slots from {@literal 0} to {@literal 16384} - * @return String simple-string-reply - */ - String clusterAddSlots(int... slots); - - /** - * Removes slots from the cluster node. - * - * @param slots one or more slots from {@literal 0} to {@literal 16384} - * @return String simple-string-reply - */ - String clusterDelSlots(int... slots); - - /** - * Assign a slot to a node. The command migrates the specified slot from the current node to the specified node in - * {@code nodeId} - * - * @param slot the slot - * @param nodeId the id of the node that will become the master for the slot - * @return String simple-string-reply - */ - String clusterSetSlotNode(int slot, String nodeId); - - /** - * Clears migrating / importing state from the slot. - * - * @param slot the slot - * @return String simple-string-reply - */ - String clusterSetSlotStable(int slot); - - /** - * Flag a slot as {@literal MIGRATING} (outgoing) towards the node specified in {@code nodeId}. The slot must be handled by - * the current node in order to be migrated. - * - * @param slot the slot - * @param nodeId the id of the node is targeted to become the master for the slot - * @return String simple-string-reply - */ - String clusterSetSlotMigrating(int slot, String nodeId); - - /** - * Flag a slot as {@literal IMPORTING} (incoming) from the node specified in {@code nodeId}. - * - * @param slot the slot - * @param nodeId the id of the node is the master of the slot - * @return String simple-string-reply - */ - String clusterSetSlotImporting(int slot, String nodeId); - - /** - * Get information and statistics about the cluster viewed by the current node. - * - * @return String bulk-string-reply as a collection of text lines. - */ - String clusterInfo(); - - /** - * Obtain the nodeId for the currently connected node. - * - * @return String simple-string-reply - */ - String clusterMyId(); - - /** - * Obtain details about all cluster nodes. Can be parsed using - * {@link com.lambdaworks.redis.cluster.models.partitions.ClusterPartitionParser#parse} - * - * @return String bulk-string-reply as a collection of text lines - */ - String clusterNodes(); - - /** - * List slaves for a certain node identified by its {@code nodeId}. Can be parsed using - * {@link com.lambdaworks.redis.cluster.models.partitions.ClusterPartitionParser#parse} - * - * @param nodeId node id of the master node - * @return List<String> array-reply list of slaves. The command returns data in the same format as - * {@link #clusterNodes()} but one line per slave. - */ - List clusterSlaves(String nodeId); - - /** - * Retrieve the list of keys within the {@code slot}. - * - * @param slot the slot - * @param count maximal number of keys - * @return List<K> array-reply list of keys - */ - List clusterGetKeysInSlot(int slot, int count); - - /** - * Returns the number of keys in the specified Redis Cluster hash {@code slot}. - * - * @param slot the slot - * @return Integer reply: The number of keys in the specified hash slot, or an error if the hash slot is invalid. - */ - Long clusterCountKeysInSlot(int slot); - - /** - * Returns the number of failure reports for the specified node. Failure reports are the way Redis Cluster uses in order to - * promote a {@literal PFAIL} state, that means a node is not reachable, to a {@literal FAIL} state, that means that the - * majority of masters in the cluster agreed within a window of time that the node is not reachable. - * - * @param nodeId the node id - * @return Integer reply: The number of active failure reports for the node. - */ - Long clusterCountFailureReports(String nodeId); - - /** - * Returns an integer identifying the hash slot the specified key hashes to. This command is mainly useful for debugging and - * testing, since it exposes via an API the underlying Redis implementation of the hashing algorithm. Basically the same as - * {@link com.lambdaworks.redis.cluster.SlotHash#getSlot(byte[])}. If not, call Houston and report that we've got a problem. - * - * @param key the key. - * @return Integer reply: The hash slot number. - */ - Long clusterKeyslot(K key); - - /** - * Forces a node to save the nodes.conf configuration on disk. - * - * @return String simple-string-reply: {@code OK} or an error if the operation fails. - */ - String clusterSaveconfig(); - - /** - * This command sets a specific config epoch in a fresh node. It only works when: - *
    - *
  • The nodes table of the node is empty.
  • - *
  • The node current config epoch is zero.
  • - *
- * - * @param configEpoch the config epoch - * @return String simple-string-reply: {@code OK} or an error if the operation fails. - */ - String clusterSetConfigEpoch(long configEpoch); - - /** - * Get array of cluster slots to node mappings. - * - * @return List<Object> array-reply nested list of slot ranges with IP/Port mappings. - */ - List clusterSlots(); - - /** - * The asking command is required after a {@code -ASK} redirection. The client should issue {@code ASKING} before to - * actually send the command to the target instance. See the Redis Cluster specification for more information. - * - * @return String simple-string-reply - */ - String asking(); - - /** - * Turn this node into a slave of the node with the id {@code nodeId}. - * - * @param nodeId master node id - * @return String simple-string-reply - */ - String clusterReplicate(String nodeId); - - /** - * Failover a cluster node. Turns the currently connected node into a master and the master into its slave. - * - * @param force do not coordinate with master if {@literal true} - * @return String simple-string-reply - */ - String clusterFailover(boolean force); - - /** - * Reset a node performing a soft or hard reset: - *
    - *
  • All other nodes are forgotten
  • - *
  • All the assigned / open slots are released
  • - *
  • If the node is a slave, it turns into a master
  • - *
  • Only for hard reset: a new Node ID is generated
  • - *
  • Only for hard reset: currentEpoch and configEpoch are set to 0
  • - *
  • The new configuration is saved and the cluster state updated
  • - *
  • If the node was a slave, the whole data set is flushed away
  • - *
- * - * @param hard {@literal true} for hard reset. Generates a new nodeId and currentEpoch/configEpoch are set to 0 - * @return String simple-string-reply - */ - String clusterReset(boolean hard); - - /** - * Delete all the slots associated with the specified node. The number of deleted slots is returned. - * - * @return String simple-string-reply - */ - String clusterFlushslots(); - - /** - * Tells a Redis cluster slave node that the client is ok reading possibly stale data and is not interested in running write - * queries. - * - * @return String simple-string-reply - */ - String readOnly(); - - /** - * Resets readOnly flag. - * - * @return String simple-string-reply - */ - String readWrite(); - -} diff --git a/src/main/java/com/lambdaworks/redis/RedisCommandBuilder.java b/src/main/java/com/lambdaworks/redis/RedisCommandBuilder.java index 10fd532db5..fa4317ff40 100644 --- a/src/main/java/com/lambdaworks/redis/RedisCommandBuilder.java +++ b/src/main/java/com/lambdaworks/redis/RedisCommandBuilder.java @@ -1115,11 +1115,6 @@ public Command setrange(K key, long offset, V value) { return createCommand(SETRANGE, new IntegerOutput(codec), args); } - @Deprecated - public Command shutdown() { - return createCommand(SHUTDOWN, new StatusOutput(codec)); - } - public Command shutdown(boolean save) { CommandArgs args = new CommandArgs(codec); return createCommand(SHUTDOWN, new StatusOutput(codec), save ? args.add(SAVE) : args.add(NOSAVE)); diff --git a/src/main/java/com/lambdaworks/redis/RedisConnection.java b/src/main/java/com/lambdaworks/redis/RedisConnection.java deleted file mode 100644 index 007c3a9c54..0000000000 --- a/src/main/java/com/lambdaworks/redis/RedisConnection.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.lambdaworks.redis; - -import java.util.concurrent.TimeUnit; - -import com.lambdaworks.redis.api.StatefulRedisConnection; -import com.lambdaworks.redis.api.sync.*; - -/** - * - * A complete synchronous and thread-safe Redis API with 400+ Methods. - * - * @param Key type. - * @param Value type. - * @author Mark Paluch - * @since 3.0 - * @deprecated Use {@link RedisCommands} - */ -@Deprecated -public interface RedisConnection extends RedisHashesConnection, RedisKeysConnection, - RedisStringsConnection, RedisListsConnection, RedisSetsConnection, RedisSortedSetsConnection, - RedisScriptingConnection, RedisServerConnection, RedisHLLConnection, RedisGeoConnection, - BaseRedisConnection, RedisClusterConnection, RedisTransactionalCommands { - - /** - * Set the default timeout for operations. - * - * @param timeout the timeout value - * @param unit the unit of the timeout value - */ - void setTimeout(long timeout, TimeUnit unit); - - /** - * Authenticate to the server. - * - * @param password the password - * @return String simple-string-reply - */ - String auth(String password); - - /** - * Change the selected database for the current connection. - * - * @param db the database number - * @return String simple-string-reply - */ - String select(int db); - - /** - * @return the underlying connection. - */ - StatefulRedisConnection getStatefulConnection(); -} diff --git a/src/main/java/com/lambdaworks/redis/RedisConnectionPool.java b/src/main/java/com/lambdaworks/redis/RedisConnectionPool.java deleted file mode 100644 index a3051da4b4..0000000000 --- a/src/main/java/com/lambdaworks/redis/RedisConnectionPool.java +++ /dev/null @@ -1,231 +0,0 @@ -package com.lambdaworks.redis; - -import java.io.Closeable; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Proxy; -import java.util.Collections; -import java.util.Set; - -import com.lambdaworks.redis.internal.AbstractInvocationHandler; -import org.apache.commons.pool2.BasePooledObjectFactory; -import org.apache.commons.pool2.PooledObject; -import org.apache.commons.pool2.PooledObjectFactory; -import org.apache.commons.pool2.impl.DefaultPooledObject; -import org.apache.commons.pool2.impl.GenericObjectPool; -import org.apache.commons.pool2.impl.GenericObjectPoolConfig; - -/** - * Connection pool for redis connections. - * - * @author Mark Paluch - * @param Connection type. - * @since 3.0 - */ -public class RedisConnectionPool implements Closeable { - - private final RedisConnectionProvider redisConnectionProvider; - private GenericObjectPool objectPool; - private CloseEvents closeEvents = new CloseEvents(); - - /** - * Create a new connection pool - * - * @param redisConnectionProvider the connection provider - * @param maxActive max active connections - * @param maxIdle max idle connections - * @param maxWait max wait time (ms) for a connection - */ - public RedisConnectionPool(RedisConnectionProvider redisConnectionProvider, int maxActive, int maxIdle, long maxWait) { - this.redisConnectionProvider = redisConnectionProvider; - - GenericObjectPoolConfig config = new GenericObjectPoolConfig(); - config.setMaxIdle(maxIdle); - config.setMaxTotal(maxActive); - config.setMaxWaitMillis(maxWait); - config.setTestOnBorrow(true); - - objectPool = new GenericObjectPool(createFactory(redisConnectionProvider), config); - } - - private PooledObjectFactory createFactory(final RedisConnectionProvider redisConnectionProvider) { - return new BasePooledObjectFactory() { - - @SuppressWarnings("unchecked") - @Override - public T create() throws Exception { - - T connection = redisConnectionProvider.createConnection(); - PooledConnectionInvocationHandler h = new PooledConnectionInvocationHandler(connection, - RedisConnectionPool.this); - - Object proxy = Proxy.newProxyInstance(getClass().getClassLoader(), - new Class[] { redisConnectionProvider.getComponentType() }, h); - - return (T) proxy; - } - - @Override - public PooledObject wrap(T obj) { - return new DefaultPooledObject(obj); - } - - @Override - public boolean validateObject(PooledObject p) { - return Connections.isOpen(p.getObject()); - } - - @Override - @SuppressWarnings("unchecked") - public void destroyObject(PooledObject p) throws Exception { - - T object = p.getObject(); - if (Proxy.isProxyClass(object.getClass())) { - PooledConnectionInvocationHandler invocationHandler = (PooledConnectionInvocationHandler) Proxy - .getInvocationHandler(object); - - object = invocationHandler.getConnection(); - } - - Connections.close(object); - } - }; - } - - /** - * Allocate a connection from the pool. It must be returned using freeConnection (or alternatively call {@code close()} on - * the connection). - * - * The connections returned by this method are proxies to the underlying connections. - * - * @return a pooled connection. - */ - public T allocateConnection() { - try { - return objectPool.borrowObject(); - } catch (RedisException e) { - throw e; - } catch (Exception e) { - throw new RedisException(e.getMessage(), e); - } - } - - /** - * Return a connection into the pool. - * - * @param t the connection. - */ - public void freeConnection(T t) { - objectPool.returnObject(t); - } - - /** - * - * @return the number of idle connections - */ - public int getNumIdle() { - return objectPool.getNumIdle(); - } - - /** - * - * @return the number of active connections. - */ - public int getNumActive() { - return objectPool.getNumActive(); - } - - /** - * Close the pool and close all idle connections. Active connections won't be closed. - */ - @Override - public void close() { - objectPool.close(); - objectPool = null; - - closeEvents.fireEventClosed(this); - closeEvents = null; - } - - /** - * - * @return the component type (pool resource type). - */ - public Class getComponentType() { - return redisConnectionProvider.getComponentType(); - } - - /** - * Adds a CloseListener. - * - * @param listener the listener - */ - void addListener(CloseEvents.CloseListener listener) { - closeEvents.addListener(listener); - } - - /** - * Invocation handler which takes care of connection.close(). Connections are returned to the pool on a close()-call. - * - * @author Mark Paluch - * @param Connection type. - * @since 3.0 - */ - static class PooledConnectionInvocationHandler extends AbstractInvocationHandler { - public static final Set DISABLED_METHODS = Collections.singleton("getStatefulConnection"); - - private T connection; - private final RedisConnectionPool pool; - - public PooledConnectionInvocationHandler(T connection, RedisConnectionPool pool) { - this.connection = connection; - this.pool = pool; - - } - - @SuppressWarnings("unchecked") - @Override - protected Object handleInvocation(Object proxy, Method method, Object[] args) throws Throwable { - - if (DISABLED_METHODS.contains(method.getName())) { - throw new UnsupportedOperationException( - "Calls to " + method.getName() + " are not supported on pooled connections"); - } - - if (connection == null) { - throw new RedisException("Connection is deallocated and cannot be used anymore."); - } - - if (method.getName().equals("close")) { - if (pool.objectPool == null) { - return method.invoke(connection, args); - } - pool.freeConnection((T) proxy); - return null; - } - - try { - return method.invoke(connection, args); - } catch (InvocationTargetException e) { - throw e.getTargetException(); - } - } - - public T getConnection() { - return connection; - } - } - - /** - * Connection provider for redis connections. - * - * @author Mark Paluch - * @param Connection type. - * @since 3.0 - */ - interface RedisConnectionProvider { - T createConnection(); - - Class getComponentType(); - } -} diff --git a/src/main/java/com/lambdaworks/redis/RedisGeoAsyncConnection.java b/src/main/java/com/lambdaworks/redis/RedisGeoAsyncConnection.java deleted file mode 100644 index b1adf42531..0000000000 --- a/src/main/java/com/lambdaworks/redis/RedisGeoAsyncConnection.java +++ /dev/null @@ -1,155 +0,0 @@ -package com.lambdaworks.redis; - -import java.util.List; -import java.util.Set; - -import com.lambdaworks.redis.GeoArgs.Unit; - -/** - * Asynchronous executed commands for Geo-Commands. - * - * @author Mark Paluch - * @since 3.3 - * @deprecated Use {@link com.lambdaworks.redis.api.async.RedisGeoAsyncCommands} - */ -@Deprecated -public interface RedisGeoAsyncConnection { - - /** - * Single geo add. - * - * @param key the key of the geo set - * @param longitude the longitude coordinate according to WGS84 - * @param latitude the latitude coordinate according to WGS84 - * @param member the member to add - * @return Long integer-reply the number of elements that were added to the set - */ - RedisFuture geoadd(K key, double longitude, double latitude, V member); - - /** - * Multi geo add. - * - * @param key the key of the geo set - * @param lngLatMember triplets of double longitude, double latitude and V member - * @return Long integer-reply the number of elements that were added to the set - */ - RedisFuture geoadd(K key, Object... lngLatMember); - - /** - * Retrieve Geohash strings representing the position of one or more elements in a sorted set value representing a geospatial index. - * - * @param key the key of the geo set - * @param members the members - * @return bulk reply Geohash strings in the order of {@code members}. Returns {@literal null} if a member is not found. - */ - RedisFuture> geohash(K key, V... members); - - /** - * Retrieve members selected by distance with the center of {@code longitude} and {@code latitude}. - * - * @param key the key of the geo set - * @param longitude the longitude coordinate according to WGS84 - * @param latitude the latitude coordinate according to WGS84 - * @param distance radius distance - * @param unit distance unit - * @return bulk reply - */ - RedisFuture> georadius(K key, double longitude, double latitude, double distance, GeoArgs.Unit unit); - - /** - * Retrieve members selected by distance with the center of {@code longitude} and {@code latitude}. - * - * @param key the key of the geo set - * @param longitude the longitude coordinate according to WGS84 - * @param latitude the latitude coordinate according to WGS84 - * @param distance radius distance - * @param unit distance unit - * @param geoArgs args to control the result - * @return nested multi-bulk reply. The {@link GeoWithin} contains only fields which were requested by {@link GeoArgs} - */ - RedisFuture>> georadius(K key, double longitude, double latitude, double distance, GeoArgs.Unit unit, - GeoArgs geoArgs); - - /** - * Perform a {@link #georadius(Object, double, double, double, GeoArgs.Unit, GeoArgs)} query and store the results in a - * sorted set. - * - * @param key the key of the geo set - * @param longitude the longitude coordinate according to WGS84 - * @param latitude the latitude coordinate according to WGS84 - * @param distance radius distance - * @param unit distance unit - * @param geoRadiusStoreArgs args to store either the resulting elements with their distance or the resulting elements with - * their locations a sorted set. - * @return Long integer-reply the number of elements in the result - */ - RedisFuture georadius(K key, double longitude, double latitude, double distance, GeoArgs.Unit unit, - GeoRadiusStoreArgs geoRadiusStoreArgs); - - /** - * Retrieve members selected by distance with the center of {@code member}. The member itself is always contained in the - * results. - * - * @param key the key of the geo set - * @param member reference member - * @param distance radius distance - * @param unit distance unit - * @return set of members - */ - RedisFuture> georadiusbymember(K key, V member, double distance, GeoArgs.Unit unit); - - /** - * - * Retrieve members selected by distance with the center of {@code member}. The member itself is always contained in the - * results. - * - * @param key the key of the geo set - * @param member reference member - * @param distance radius distance - * @param unit distance unit - * @param geoArgs args to control the result - * @return nested multi-bulk reply. The {@link GeoWithin} contains only fields which were requested by {@link GeoArgs} - */ - RedisFuture>> georadiusbymember(K key, V member, double distance, GeoArgs.Unit unit, GeoArgs geoArgs); - - /** - * Perform a {@link #georadiusbymember(Object, Object, double, GeoArgs.Unit, GeoArgs)} query and store the results in a - * sorted set. - * - * @param key the key of the geo set - * @param member reference member - * @param distance radius distance - * @param unit distance unit - * @param geoRadiusStoreArgs args to store either the resulting elements with their distance or the resulting elements with - * their locations a sorted set. - * @return Long integer-reply the number of elements in the result - */ - RedisFuture georadiusbymember(K key, V member, double distance, GeoArgs.Unit unit, - GeoRadiusStoreArgs geoRadiusStoreArgs); - - /** - * Get geo coordinates for the {@code members}. - * - * @param key the key of the geo set - * @param members the members - * - * @return a list of {@link GeoCoordinates}s representing the x,y position of each element specified in the arguments. For - * missing elements {@literal null} is returned. - */ - RedisFuture> geopos(K key, V... members); - - /** - * - * Retrieve distance between points {@code from} and {@code to}. If one or more elements are missing {@literal null} is - * returned. Default in meters by , otherwise according to {@code unit} - * - * @param key the key of the geo set - * @param from from member - * @param to to member - * @param unit distance unit - * - * @return distance between points {@code from} and {@code to}. If one or more elements are missing {@literal null} is - * returned. - */ - RedisFuture geodist(K key, V from, V to, GeoArgs.Unit unit); -} diff --git a/src/main/java/com/lambdaworks/redis/RedisGeoConnection.java b/src/main/java/com/lambdaworks/redis/RedisGeoConnection.java deleted file mode 100644 index c973bbef4e..0000000000 --- a/src/main/java/com/lambdaworks/redis/RedisGeoConnection.java +++ /dev/null @@ -1,151 +0,0 @@ -package com.lambdaworks.redis; - -import java.util.List; -import java.util.Set; - -import com.lambdaworks.redis.GeoArgs.Unit; - -/** - * Synchronous executed commands for Geo-Commands. - * - * @author Mark Paluch - * @since 3.3 - * @deprecated Use {@link com.lambdaworks.redis.api.sync.RedisGeoCommands} - */ -@Deprecated -public interface RedisGeoConnection { - - /** - * Single geo add. - * - * @param key the key of the geo set - * @param longitude the longitude coordinate according to WGS84 - * @param latitude the latitude coordinate according to WGS84 - * @param member the member to add - * @return Long integer-reply the number of elements that were added to the set - */ - Long geoadd(K key, double longitude, double latitude, V member); - - /** - * Multi geo add. - * - * @param key the key of the geo set - * @param lngLatMember triplets of double longitude, double latitude and V member - * @return Long integer-reply the number of elements that were added to the set - */ - Long geoadd(K key, Object... lngLatMember); - - /** - * Retrieve Geohash strings representing the position of one or more elements in a sorted set value representing a geospatial index. - * - * @param key the key of the geo set - * @param members the members - * @return bulk reply Geohash strings in the order of {@code members}. Returns {@literal null} if a member is not found. - */ - List geohash(K key, V... members); - - /** - * Retrieve members selected by distance with the center of {@code longitude} and {@code latitude}. - * - * @param key the key of the geo set - * @param longitude the longitude coordinate according to WGS84 - * @param latitude the latitude coordinate according to WGS84 - * @param distance radius distance - * @param unit distance unit - * @return bulk reply - */ - Set georadius(K key, double longitude, double latitude, double distance, GeoArgs.Unit unit); - - /** - * Retrieve members selected by distance with the center of {@code longitude} and {@code latitude}. - * - * @param key the key of the geo set - * @param longitude the longitude coordinate according to WGS84 - * @param latitude the latitude coordinate according to WGS84 - * @param distance radius distance - * @param unit distance unit - * @param geoArgs args to control the result - * @return nested multi-bulk reply. The {@link GeoWithin} contains only fields which were requested by {@link GeoArgs} - */ - List> georadius(K key, double longitude, double latitude, double distance, GeoArgs.Unit unit, GeoArgs geoArgs); - - /** - * Perform a {@link #georadius(Object, double, double, double, Unit)} query and store the results in a sorted set. - * - * @param key the key of the geo set - * @param longitude the longitude coordinate according to WGS84 - * @param latitude the latitude coordinate according to WGS84 - * @param distance radius distance - * @param unit distance unit - * @param geoRadiusStoreArgs args to store either the resulting elements with their distance or the resulting elements with - * their locations a sorted set. - * @return Long integer-reply the number of elements in the result - */ - Long georadius(K key, double longitude, double latitude, double distance, GeoArgs.Unit unit, - GeoRadiusStoreArgs geoRadiusStoreArgs); - - /** - * Retrieve members selected by distance with the center of {@code member}. The member itself is always contained in the - * results. - * - * @param key the key of the geo set - * @param member reference member - * @param distance radius distance - * @param unit distance unit - * @return set of members - */ - Set georadiusbymember(K key, V member, double distance, GeoArgs.Unit unit); - - /** - * - * Retrieve members selected by distance with the center of {@code member}. The member itself is always contained in the - * results. - * - * @param key the key of the geo set - * @param member reference member - * @param distance radius distance - * @param unit distance unit - * @param geoArgs args to control the result - * @return nested multi-bulk reply. The {@link GeoWithin} contains only fields which were requested by {@link GeoArgs} - */ - List> georadiusbymember(K key, V member, double distance, GeoArgs.Unit unit, GeoArgs geoArgs); - - /** - * Perform a {@link #georadiusbymember(Object, Object, double, Unit, GeoArgs)} query and store the results in a sorted set. - * - * @param key the key of the geo set - * @param member reference member - * @param distance radius distance - * @param unit distance unit - * @param geoRadiusStoreArgs args to store either the resulting elements with their distance or the resulting elements with - * their locations a sorted set. - * @return Long integer-reply the number of elements in the result - */ - Long georadiusbymember(K key, V member, double distance, GeoArgs.Unit unit, GeoRadiusStoreArgs geoRadiusStoreArgs); - - /** - * Get geo coordinates for the {@code members}. - * - * @param key the key of the geo set - * @param members the members - * - * @return a list of {@link GeoCoordinates}s representing the x,y position of each element specified in the arguments. For - * missing elements {@literal null} is returned. - */ - List geopos(K key, V... members); - - /** - * - * Retrieve distance between points {@code from} and {@code to}. If one or more elements are missing {@literal null} is - * returned. Default in meters by, otherwise according to {@code unit} - * - * @param key the key of the geo set - * @param from from member - * @param to to member - * @param unit distance unit - * - * @return distance between points {@code from} and {@code to}. If one or more elements are missing {@literal null} is - * returned. - */ - Double geodist(K key, V from, V to, GeoArgs.Unit unit); -} diff --git a/src/main/java/com/lambdaworks/redis/RedisHLLAsyncConnection.java b/src/main/java/com/lambdaworks/redis/RedisHLLAsyncConnection.java deleted file mode 100644 index 9ba08ec3ba..0000000000 --- a/src/main/java/com/lambdaworks/redis/RedisHLLAsyncConnection.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.lambdaworks.redis; - -import com.lambdaworks.redis.api.async.RedisHLLAsyncCommands; - -/** - * Asynchronous executed commands for HyperLogLog (PF* commands). - * - * @param Key type. - * @param Value type. - * @author Mark Paluch - * @since 3.0 - * @deprecated Use {@link RedisHLLAsyncCommands} - */ -@Deprecated -public interface RedisHLLAsyncConnection { - /** - * Adds the specified elements to the specified HyperLogLog. - * - * @param key the key - * @param value the value - * @param moreValues more values - * - * @return RedisFuture<Long> integer-reply specifically: - * - * 1 if at least 1 HyperLogLog internal register was altered. 0 otherwise. - */ - RedisFuture pfadd(K key, V value, V... moreValues); - - /** - * Merge N different HyperLogLogs into a single one. - * - * @param destkey the destination key - * @param sourcekey the source key - * @param moreSourceKeys more source keys - * - * @return RedisFuture<String> simple-string-reply The command just returns {@code OK}. - */ - RedisFuture pfmerge(K destkey, K sourcekey, K... moreSourceKeys); - - /** - * Return the approximated cardinality of the set(s) observed by the HyperLogLog at key(s). - * - * @param key the key - * @param moreKeys more keys - * - * @return RedisFuture<Long> integer-reply specifically: - * - * The approximated number of unique elements observed via {@code PFADD}. - */ - RedisFuture pfcount(K key, K... moreKeys); - -} diff --git a/src/main/java/com/lambdaworks/redis/RedisHLLConnection.java b/src/main/java/com/lambdaworks/redis/RedisHLLConnection.java deleted file mode 100644 index 18053be98d..0000000000 --- a/src/main/java/com/lambdaworks/redis/RedisHLLConnection.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.lambdaworks.redis; - -import com.lambdaworks.redis.api.sync.RedisHLLCommands; - -/** - * Synchronous executed commands for HyperLogLog (PF* commands). - * - * @param Key type. - * @param Value type. - * @author Mark Paluch - * @since 3.0 - * @deprecated Use {@link RedisHLLCommands} - */ -@Deprecated -public interface RedisHLLConnection { - /** - * Adds the specified elements to the specified HyperLogLog. - * - * @param key the key - * @param value the value - * @param moreValues more values - * - * @return Long integer-reply specifically: - * - * 1 if at least 1 HyperLogLog internal register was altered. 0 otherwise. - */ - Long pfadd(K key, V value, V... moreValues); - - /** - * Merge N different HyperLogLogs into a single one. - * - * @param destkey the destination key - * @param sourcekey the source key - * @param moreSourceKeys more source keys - * - * @return Long simple-string-reply The command just returns {@code OK}. - */ - String pfmerge(K destkey, K sourcekey, K... moreSourceKeys); - - /** - * Return the approximated cardinality of the set(s) observed by the HyperLogLog at key(s). - * - * @param key the key - * @param moreKeys more keys - * - * @return Long integer-reply specifically: - * - * The approximated number of unique elements observed via {@code PFADD}. - */ - Long pfcount(K key, K... moreKeys); - -} diff --git a/src/main/java/com/lambdaworks/redis/RedisHashesAsyncConnection.java b/src/main/java/com/lambdaworks/redis/RedisHashesAsyncConnection.java deleted file mode 100644 index 39a3c3fd7a..0000000000 --- a/src/main/java/com/lambdaworks/redis/RedisHashesAsyncConnection.java +++ /dev/null @@ -1,281 +0,0 @@ -package com.lambdaworks.redis; - -import java.util.List; -import java.util.Map; - -import com.lambdaworks.redis.api.async.RedisHashAsyncCommands; -import com.lambdaworks.redis.output.KeyStreamingChannel; -import com.lambdaworks.redis.output.KeyValueStreamingChannel; -import com.lambdaworks.redis.output.ValueStreamingChannel; - -/** - * Asynchronous executed commands for Hashes (Key-Value pairs). - * - * @param Key type. - * @param Value type. - * @author Mark Paluch - * @since 3.0 - * @deprecated Use {@link RedisHashAsyncCommands} - */ -@Deprecated -public interface RedisHashesAsyncConnection { - - /** - * Delete one or more hash fields. - * - * @param key the key - * @param fields the field type: key - * @return RedisFuture<Long> integer-reply the number of fields that were removed from the hash, not including - * specified but non existing fields. - */ - RedisFuture hdel(K key, K... fields); - - /** - * Determine if a hash field exists. - * - * @param key the key - * @param field the field type: key - * @return RedisFuture<Boolean> integer-reply specifically: - * - * {@literal true} if the hash contains {@code field}. {@literal false} if the hash does not contain {@code field}, - * or {@code key} does not exist. - */ - RedisFuture hexists(K key, K field); - - /** - * Get the value of a hash field. - * - * @param key the key - * @param field the field type: key - * @return RedisFuture<V> bulk-string-reply the value associated with {@code field}, or {@code null} when - * {@code field} is not present in the hash or {@code key} does not exist. - */ - RedisFuture hget(K key, K field); - - /** - * Increment the integer value of a hash field by the given number. - * - * @param key the key - * @param field the field type: key - * @param amount the increment type: long - * @return RedisFuture<Long> integer-reply the value at {@code field} after the increment operation. - */ - RedisFuture hincrby(K key, K field, long amount); - - /** - * Increment the float value of a hash field by the given amount. - * - * @param key the key - * @param field the field type: key - * @param amount the increment type: double - * @return RedisFuture<Double;> bulk-string-reply the value of {@code field} after the increment. - */ - RedisFuture hincrbyfloat(K key, K field, double amount); - - /** - * Get all the fields and values in a hash. - * - * @param key the key - * @return RedisFuture<Map<K,V>> array-reply list of fields and their values stored in the hash, or an empty - * list when {@code key} does not exist. - */ - RedisFuture> hgetall(K key); - - /** - * Stream over all the fields and values in a hash. - * - * @param channel the channel - * @param key the key - * - * @return RedisFuture<Long> count of the keys. - */ - RedisFuture hgetall(KeyValueStreamingChannel channel, K key); - - /** - * Get all the fields in a hash. - * - * @param key the key - * @return RedisFuture<List<K>> array-reply list of fields in the hash, or an empty list when {@code key} does - * not exist. - */ - RedisFuture> hkeys(K key); - - /** - * Get all the fields in a hash. - * - * @param channel the channel - * @param key the key - * - * @return RedisFuture<Long> count of the keys. - */ - RedisFuture hkeys(KeyStreamingChannel channel, K key); - - /** - * Get the number of fields in a hash. - * - * @param key the key - * @return RedisFuture<Long> integer-reply number of fields in the hash, or {@literal false} when {@code key} does not - * exist. - */ - RedisFuture hlen(K key); - - /** - * Get the values of all the given hash fields. - * - * @param key the key - * @param fields the field type: key - * @return RedisFuture<List<V>> array-reply list of values associated with the given fields, in the same - */ - RedisFuture> hmget(K key, K... fields); - - /** - * Stream over the values of all the given hash fields. - * - * @param channel the channel - * @param key the key - * @param fields the fields - * - * @return RedisFuture<Long> count of the keys - */ - RedisFuture hmget(ValueStreamingChannel channel, K key, K... fields); - - /** - * Set multiple hash fields to multiple values. - * - * @param key the key - * @param map the null - * @return RedisFuture<String> simple-string-reply - */ - RedisFuture hmset(K key, Map map); - - /** - * Incrementally iterate hash fields and associated values. - * - * @param key the key - * @return RedisFuture<MapScanCursor<K, V>> scan cursor. - */ - RedisFuture> hscan(K key); - - /** - * Incrementally iterate hash fields and associated values. - * - * @param key the key - * @param scanArgs scan arguments - * @return RedisFuture<MapScanCursor<K, V>> scan cursor. - */ - RedisFuture> hscan(K key, ScanArgs scanArgs); - - /** - * Incrementally iterate hash fields and associated values. - * - * @param key the key - * @param scanCursor cursor to resume from a previous scan, must not be {@literal null} - * @param scanArgs scan arguments - * @return RedisFuture<MapScanCursor<K, V>> scan cursor. - */ - RedisFuture> hscan(K key, ScanCursor scanCursor, ScanArgs scanArgs); - - /** - * Incrementally iterate hash fields and associated values. - * - * @param key the key - * @param scanCursor cursor to resume from a previous scan, must not be {@literal null} - * @return RedisFuture<MapScanCursor<K, V>> scan cursor. - */ - RedisFuture> hscan(K key, ScanCursor scanCursor); - - /** - * Incrementally iterate hash fields and associated values. - * - * @param channel streaming channel that receives a call for every key-value pair - * @param key the key - * @return RedisFuture<StreamScanCursor> scan cursor. - */ - RedisFuture hscan(KeyValueStreamingChannel channel, K key); - - /** - * Incrementally iterate hash fields and associated values. - * - * @param channel streaming channel that receives a call for every key-value pair - * @param key the key - * @param scanArgs scan arguments - * @return RedisFuture<StreamScanCursor> scan cursor. - */ - RedisFuture hscan(KeyValueStreamingChannel channel, K key, ScanArgs scanArgs); - - /** - * Incrementally iterate hash fields and associated values. - * - * @param channel streaming channel that receives a call for every key-value pair - * @param key the key - * @param scanCursor cursor to resume from a previous scan, must not be {@literal null} - * @param scanArgs scan arguments - * @return RedisFuture<StreamScanCursor> scan cursor. - */ - RedisFuture hscan(KeyValueStreamingChannel channel, K key, ScanCursor scanCursor, ScanArgs scanArgs); - - /** - * Incrementally iterate hash fields and associated values. - * - * @param channel streaming channel that receives a call for every key-value pair - * @param key the key - * @param scanCursor cursor to resume from a previous scan, must not be {@literal null} - * @return RedisFuture<StreamScanCursor> scan cursor. - */ - RedisFuture hscan(KeyValueStreamingChannel channel, K key, ScanCursor scanCursor); - - /** - * Set the string value of a hash field. - * - * @param key the key - * @param field the field type: key - * @param value the value - * @return RedisFuture<Boolean> integer-reply specifically: - * - * {@literal true} if {@code field} is a new field in the hash and {@code value} was set. {@literal false} if - * {@code field} already exists in the hash and the value was updated. - */ - RedisFuture hset(K key, K field, V value); - - /** - * Set the value of a hash field, only if the field does not exist. - * - * @param key the key - * @param field the field type: key - * @param value the value - * @return RedisFuture<Boolean> integer-reply specifically: - * - * {@code 1} if {@code field} is a new field in the hash and {@code value} was set. {@code 0} if {@code field} - * already exists in the hash and no operation was performed. - */ - RedisFuture hsetnx(K key, K field, V value); - - /** - * Get the string length of the field value in a hash. - * - * @param key the key - * @param field the field type: key - * @return RedisFuture<Long> integer-reply the string length of the {@code field} value, or {@code 0} when - * {@code field} is not present in the hash or {@code key} does not exist at all. - */ - RedisFuture hstrlen(K key, K field); - - /** - * Get all the values in a hash. - * - * @param key the key - * @return RedisFuture<List<V>> array-reply list of values in the hash, or an empty list when {@code key} does - * not exist. - */ - RedisFuture> hvals(K key); - - /** - * Stream over all the values in a hash. - * - * @param channel streaming channel that receives a call for every value - * @param key the key - * - * @return RedisFuture<Long> count of the keys. - */ - RedisFuture hvals(ValueStreamingChannel channel, K key); -} diff --git a/src/main/java/com/lambdaworks/redis/RedisHashesConnection.java b/src/main/java/com/lambdaworks/redis/RedisHashesConnection.java deleted file mode 100644 index 99e2520b1e..0000000000 --- a/src/main/java/com/lambdaworks/redis/RedisHashesConnection.java +++ /dev/null @@ -1,278 +0,0 @@ -package com.lambdaworks.redis; - -import java.util.List; -import java.util.Map; - -import com.lambdaworks.redis.api.sync.RedisHashCommands; -import com.lambdaworks.redis.output.KeyStreamingChannel; -import com.lambdaworks.redis.output.KeyValueStreamingChannel; -import com.lambdaworks.redis.output.ValueStreamingChannel; - -/** - * Synchronous executed commands for Hashes (Key-Value pairs). - * - * @param Key type. - * @param Value type. - * @author Mark Paluch - * @since 3.0 - * @deprecated Use {@link RedisHashCommands} - */ -@Deprecated -public interface RedisHashesConnection { - - /** - * Delete one or more hash fields. - * - * @param key the key - * @param fields the field type: key - * @return Long integer-reply the number of fields that were removed from the hash, not including specified but non existing - * fields. - */ - Long hdel(K key, K... fields); - - /** - * Determine if a hash field exists. - * - * @param key the key - * @param field the field type: key - * @return Boolean integer-reply specifically: - * - * {@literal true} if the hash contains {@code field}. {@literal false} if the hash does not contain {@code field}, - * or {@code key} does not exist. - */ - Boolean hexists(K key, K field); - - /** - * Get the value of a hash field. - * - * @param key the key - * @param field the field type: key - * @return V bulk-string-reply the value associated with {@code field}, or {@literal null} when {@code field} is not present - * in the hash or {@code key} does not exist. - */ - V hget(K key, K field); - - /** - * Increment the integer value of a hash field by the given number. - * - * @param key the key - * @param field the field type: key - * @param amount the increment type: long - * @return Long integer-reply the value at {@code field} after the increment operation. - */ - Long hincrby(K key, K field, long amount); - - /** - * Increment the float value of a hash field by the given amount. - * - * @param key the key - * @param field the field type: key - * @param amount the increment type: double - * @return Double bulk-string-reply the value of {@code field} after the increment. - */ - Double hincrbyfloat(K key, K field, double amount); - - /** - * Get all the fields and values in a hash. - * - * @param key the key - * @return Map<K,V> array-reply list of fields and their values stored in the hash, or an empty list when {@code key} - * does not exist. - */ - Map hgetall(K key); - - /** - * Stream over all the fields and values in a hash. - * - * @param channel the channel - * @param key the key - * - * @return Long count of the keys. - */ - Long hgetall(KeyValueStreamingChannel channel, K key); - - /** - * Get all the fields in a hash. - * - * @param key the key - * @return List<K> array-reply list of fields in the hash, or an empty list when {@code key} does not exist. - */ - List hkeys(K key); - - /** - * Stream over all the fields in a hash. - * - * @param channel the channel - * @param key the key - * - * @return Long count of the keys. - */ - Long hkeys(KeyStreamingChannel channel, K key); - - /** - * Get the number of fields in a hash. - * - * @param key the key - * @return Long integer-reply number of fields in the hash, or {@code 0} when {@code key} does not exist. - */ - Long hlen(K key); - - /** - * Get the values of all the given hash fields. - * - * @param key the key - * @param fields the field type: key - * @return List<V> array-reply list of values associated with the given fields, in the same - */ - List hmget(K key, K... fields); - - /** - * Stream over the values of all the given hash fields. - * - * @param channel the channel - * @param key the key - * @param fields the fields - * - * @return Long count of the keys - */ - Long hmget(ValueStreamingChannel channel, K key, K... fields); - - /** - * Set multiple hash fields to multiple values. - * - * @param key the key - * @param map the null - * @return String simple-string-reply - */ - String hmset(K key, Map map); - - /** - * Incrementally iterate hash fields and associated values. - * - * @param key the key - * @return MapScanCursor<K, V> map scan cursor. - */ - MapScanCursor hscan(K key); - - /** - * Incrementally iterate hash fields and associated values. - * - * @param key the key - * @param scanArgs scan arguments - * @return MapScanCursor<K, V> map scan cursor. - */ - MapScanCursor hscan(K key, ScanArgs scanArgs); - - /** - * Incrementally iterate hash fields and associated values. - * - * @param key the key - * @param scanCursor cursor to resume from a previous scan, must not be {@literal null} - * @param scanArgs scan arguments - * @return MapScanCursor<K, V> map scan cursor. - */ - MapScanCursor hscan(K key, ScanCursor scanCursor, ScanArgs scanArgs); - - /** - * Incrementally iterate hash fields and associated values. - * - * @param key the key - * @param scanCursor cursor to resume from a previous scan, must not be {@literal null} - * @return MapScanCursor<K, V> map scan cursor. - */ - MapScanCursor hscan(K key, ScanCursor scanCursor); - - /** - * Incrementally iterate hash fields and associated values. - * - * @param channel streaming channel that receives a call for every key-value pair - * @param key the key - * @return StreamScanCursor scan cursor. - */ - StreamScanCursor hscan(KeyValueStreamingChannel channel, K key); - - /** - * Incrementally iterate hash fields and associated values. - * - * @param channel streaming channel that receives a call for every key-value pair - * @param key the key - * @param scanArgs scan arguments - * @return StreamScanCursor scan cursor. - */ - StreamScanCursor hscan(KeyValueStreamingChannel channel, K key, ScanArgs scanArgs); - - /** - * Incrementally iterate hash fields and associated values. - * - * @param channel streaming channel that receives a call for every key-value pair - * @param key the key - * @param scanCursor cursor to resume from a previous scan, must not be {@literal null} - * @param scanArgs scan arguments - * @return StreamScanCursor scan cursor. - */ - StreamScanCursor hscan(KeyValueStreamingChannel channel, K key, ScanCursor scanCursor, ScanArgs scanArgs); - - /** - * Incrementally iterate hash fields and associated values. - * - * @param channel streaming channel that receives a call for every key-value pair - * @param key the key - * @param scanCursor cursor to resume from a previous scan, must not be {@literal null} - * @return StreamScanCursor scan cursor. - */ - StreamScanCursor hscan(KeyValueStreamingChannel channel, K key, ScanCursor scanCursor); - - /** - * Set the string value of a hash field. - * - * @param key the key - * @param field the field type: key - * @param value the value - * @return Boolean integer-reply specifically: - * - * {@literal true} if {@code field} is a new field in the hash and {@code value} was set. {@literal false} if - * {@code field} already exists in the hash and the value was updated. - */ - Boolean hset(K key, K field, V value); - - /** - * Set the value of a hash field, only if the field does not exist. - * - * @param key the key - * @param field the field type: key - * @param value the value - * @return Boolean integer-reply specifically: - * - * {@code 1} if {@code field} is a new field in the hash and {@code value} was set. {@code 0} if {@code field} - * already exists in the hash and no operation was performed. - */ - Boolean hsetnx(K key, K field, V value); - - /** - * Get the string length of the field value in a hash. - * - * @param key the key - * @param field the field type: key - * @return Long integer-reply the string length of the {@code field} value, or {@code 0} when {@code field} is not present - * in the hash or {@code key} does not exist at all. - */ - Long hstrlen(K key, K field); - - /** - * Get all the values in a hash. - * - * @param key the key - * @return List<V> array-reply list of values in the hash, or an empty list when {@code key} does not exist. - */ - List hvals(K key); - - /** - * Stream over all the values in a hash. - * - * @param channel streaming channel that receives a call for every value - * @param key the key - * - * @return Long count of the keys. - */ - Long hvals(ValueStreamingChannel channel, K key); -} diff --git a/src/main/java/com/lambdaworks/redis/RedisKeysAsyncConnection.java b/src/main/java/com/lambdaworks/redis/RedisKeysAsyncConnection.java deleted file mode 100644 index bcd7a3efa6..0000000000 --- a/src/main/java/com/lambdaworks/redis/RedisKeysAsyncConnection.java +++ /dev/null @@ -1,411 +0,0 @@ -package com.lambdaworks.redis; - -import java.util.Date; -import java.util.List; - -import com.lambdaworks.redis.output.KeyStreamingChannel; -import com.lambdaworks.redis.output.ValueStreamingChannel; - -/** - * Asynchronous executed commands for Keys (Key manipulation/querying). - * - * @param Key type. - * @param Value type. - * @author Mark Paluch - * @since 3.0 - * @deprecated Use {@literal RedisKeyAsyncCommands} - */ -@Deprecated -public interface RedisKeysAsyncConnection { - - /** - * Delete one or more keys. - * - * @param keys the keys - * @return RedisFuture<Long> integer-reply The number of keys that were removed. - */ - RedisFuture del(K... keys); - - /** - * Unlink one or more keys (non blocking DEL). - * - * @param keys the keys - * @return RedisFuture<Long> integer-reply The number of keys that were removed. - */ - RedisFuture unlink(K... keys); - - /** - * Return a serialized version of the value stored at the specified key. - * - * @param key the key - * @return RedisFuture<byte[]>bulk-string-reply the serialized value. - */ - RedisFuture dump(K key); - - /** - * Determine if a key exists. - * - * @param key the key - * @return RedisFuture<Boolean> integer-reply specifically: - * - * {@literal true} if the key exists. {@literal false} if the key does not exist. - * @deprecated Use {@link #exists(Object[])} instead - */ - @Deprecated - RedisFuture exists(K key); - - /** - * Determine how many keys exist. - * - * @param keys the keys - * @return Long integer-reply specifically: Number of existing keys - */ - RedisFuture exists(K... keys); - - /** - * Set a key's time to live in seconds. - * - * @param key the key - * @param seconds the seconds type: long - * @return RedisFuture<Boolean> integer-reply specifically: - * - * {@literal true} if the timeout was set. {@literal false} if {@code key} does not exist or the timeout could not - * be set. - */ - RedisFuture expire(K key, long seconds); - - /** - * Set the expiration for a key as a UNIX timestamp. - * - * @param key the key - * @param timestamp the timestamp type: posix time - * @return RedisFuture<Boolean> integer-reply specifically: - * - * {@literal true} if the timeout was set. {@literal false} if {@code key} does not exist or the timeout could not - * be set (see: {@code EXPIRE}). - */ - RedisFuture expireat(K key, Date timestamp); - - /** - * Set the expiration for a key as a UNIX timestamp. - * - * @param key the key - * @param timestamp the timestamp type: posix time - * @return RedisFuture<Boolean> integer-reply specifically: - * - * {@literal true} if the timeout was set. {@literal false} if {@code key} does not exist or the timeout could not - * be set (see: {@code EXPIRE}). - */ - RedisFuture expireat(K key, long timestamp); - - /** - * Find all keys matching the given pattern. - * - * @param pattern the pattern type: patternkey (pattern) - * @return RedisFuture<List<K>> array-reply list of keys matching {@code pattern}. - */ - RedisFuture> keys(K pattern); - - /** - * Find all keys matching the given pattern. - * - * @param channel the channel - * @param pattern the pattern - * - * @return RedisFuture<Long> array-reply list of keys matching {@code pattern}. - */ - RedisFuture keys(KeyStreamingChannel channel, K pattern); - - /** - * Atomically transfer a key from a Redis instance to another one. - * - * @param host the host - * @param port the port - * @param key the key - * @param db the database - * @param timeout the timeout in milliseconds - * - * @return RedisFuture<String> simple-string-reply The command returns OK on success. - */ - RedisFuture migrate(String host, int port, K key, int db, long timeout); - - /** - * Atomically transfer one or more keys from a Redis instance to another one. - * - * @param host the host - * @param port the port - * @param db the database - * @param timeout the timeout in milliseconds - * @param migrateArgs migrate args that allow to configure further options - * @return String simple-string-reply The command returns OK on success. - */ - RedisFuture migrate(String host, int port, int db, long timeout, MigrateArgs migrateArgs); - - /** - * Move a key to another database. - * - * @param key the key - * @param db the db type: long - * @return RedisFuture<Boolean> integer-reply specifically: - */ - RedisFuture move(K key, int db); - - /** - * returns the kind of internal representation used in order to store the value associated with a key. - * - * @param key the key - * @return RedisFuture<String> - */ - RedisFuture objectEncoding(K key); - - /** - * returns the number of seconds since the object stored at the specified key is idle (not requested by read or write - * operations). - * - * @param key the key - * @return RedisFuture<Long> number of seconds since the object stored at the specified key is idle. - */ - RedisFuture objectIdletime(K key); - - /** - * returns the number of references of the value associated with the specified key. - * - * @param key the key - * @return RedisFuture<Long> - */ - RedisFuture objectRefcount(K key); - - /** - * Remove the expiration from a key. - * - * @param key the key - * @return RedisFuture<Boolean> integer-reply specifically: - * - * {@literal true} if the timeout was removed. {@literal false} if {@code key} does not exist or does not have an - * associated timeout. - */ - RedisFuture persist(K key); - - /** - * Set a key's time to live in milliseconds. - * - * @param key the key - * @param milliseconds the milliseconds type: long - * @return integer-reply, specifically: - * - * {@literal true} if the timeout was set. {@literal false} if {@code key} does not exist or the timeout could not - * be set. - */ - RedisFuture pexpire(K key, long milliseconds); - - /** - * Set the expiration for a key as a UNIX timestamp specified in milliseconds. - * - * @param key the key - * @param timestamp the milliseconds-timestamp type: posix time - * @return RedisFuture<Boolean> integer-reply specifically: - * - * {@literal true} if the timeout was set. {@literal false} if {@code key} does not exist or the timeout could not - * be set (see: {@code EXPIRE}). - */ - RedisFuture pexpireat(K key, Date timestamp); - - /** - * Set the expiration for a key as a UNIX timestamp specified in milliseconds. - * - * @param key the key - * @param timestamp the milliseconds-timestamp type: posix time - * @return RedisFuture<Boolean> integer-reply specifically: - * - * {@literal true} if the timeout was set. {@literal false} if {@code key} does not exist or the timeout could not - * be set (see: {@code EXPIRE}). - */ - RedisFuture pexpireat(K key, long timestamp); - - /** - * Get the time to live for a key in milliseconds. - * - * @param key the key - * @return RedisFuture<Long> integer-reply TTL in milliseconds, or a negative value in order to signal an error (see - * the description above). - */ - RedisFuture pttl(K key); - - /** - * Return a random key from the keyspace. - * - * @return RedisFuture<V> bulk-string-reply the random key, or {@literal null} when the database is empty. - */ - RedisFuture randomkey(); - - /** - * Rename a key. - * - * @param key the key - * @param newKey the newkey type: key - * @return RedisFuture<String> simple-string-reply - */ - RedisFuture rename(K key, K newKey); - - /** - * Rename a key, only if the new key does not exist. - * - * @param key the key - * @param newKey the newkey type: key - * @return RedisFuture<Boolean> integer-reply specifically: - * - * {@literal true} if {@code key} was renamed to {@code newkey}. {@literal false} if {@code newkey} already exists. - */ - RedisFuture renamenx(K key, K newKey); - - /** - * Create a key using the provided serialized value, previously obtained using DUMP. - * - * @param key the key - * @param ttl the ttl type: long - * @param value the serialized-value type: string - * @return RedisFuture<String> simple-string-reply The command returns OK on success. - */ - RedisFuture restore(K key, long ttl, byte[] value); - - /** - * Sort the elements in a list, set or sorted set. - * - * @param key the key - * @return RedisFuture<List<V>> array-reply list of sorted elements. - */ - RedisFuture> sort(K key); - - /** - * Sort the elements in a list, set or sorted set. - * - * @param channel streaming channel that receives a call for every value - * @param key the key - * @return RedisFuture<Long> number of values. - */ - RedisFuture sort(ValueStreamingChannel channel, K key); - - /** - * Sort the elements in a list, set or sorted set. - * - * @param key the key - * @param sortArgs sort arguments - * @return RedisFuture<List<V>> array-reply list of sorted elements. - */ - RedisFuture> sort(K key, SortArgs sortArgs); - - /** - * Sort the elements in a list, set or sorted set. - * - * @param channel streaming channel that receives a call for every value - * @param key the key - * @param sortArgs sort arguments - * @return RedisFuture<Long> number of values. - */ - RedisFuture sort(ValueStreamingChannel channel, K key, SortArgs sortArgs); - - /** - * Sort the elements in a list, set or sorted set. - * - * @param key the key - * @param sortArgs sort arguments - * @param destination the destination key to store sort results - * @return RedisFuture<Long> number of values. - */ - RedisFuture sortStore(K key, SortArgs sortArgs, K destination); - - /** - * Touch one or more keys. Touch sets the last accessed time for a key. Non-exsitent keys wont get created. - * - * @param keys the keys - * @return RedisFuture<Long> integer-reply the number of found keys. - */ - RedisFuture touch(K... keys); - - /** - * Get the time to live for a key. - * - * @param key the key - * @return RedisFuture<Long> integer-reply TTL in seconds, or a negative value in order to signal an error (see the - * description above). - */ - RedisFuture ttl(K key); - - /** - * Determine the type stored at key. - * - * @param key the key - * @return RedisFuture<String> simple-string-reply type of {@code key}, or {@code none} when {@code key} does not - * exist. - */ - RedisFuture type(K key); - - /** - * Incrementally iterate the keys space. - * - * @return RedisFuture<KeyScanCursor<K>> scan cursor. - */ - RedisFuture> scan(); - - /** - * Incrementally iterate the keys space. - * - * @param scanArgs scan arguments - * @return RedisFuture<KeyScanCursor<K>> scan cursor. - */ - RedisFuture> scan(ScanArgs scanArgs); - - /** - * Incrementally iterate the keys space. - * - * @param scanCursor cursor to resume from a previous scan, must not be {@literal null} - * @param scanArgs scan arguments - * @return RedisFuture<KeyScanCursor<K>> scan cursor. - */ - RedisFuture> scan(ScanCursor scanCursor, ScanArgs scanArgs); - - /** - * Incrementally iterate the keys space. - * - * @param scanCursor cursor to resume from a previous scan, must not be {@literal null} - * @return RedisFuture<KeyScanCursor<K>> scan cursor. - */ - RedisFuture> scan(ScanCursor scanCursor); - - /** - * Incrementally iterate the keys space. - * - * @param channel streaming channel that receives a call for every key - * @return RedisFuture<StreamScanCursor> scan cursor. - */ - RedisFuture scan(KeyStreamingChannel channel); - - /** - * Incrementally iterate the keys space. - * - * @param channel streaming channel that receives a call for every key - * @param scanArgs scan arguments - * @return RedisFuture<StreamScanCursor> scan cursor. - */ - RedisFuture scan(KeyStreamingChannel channel, ScanArgs scanArgs); - - /** - * Incrementally iterate the keys space. - * - * @param channel streaming channel that receives a call for every key - * @param scanCursor cursor to resume from a previous scan, must not be {@literal null} - * @param scanArgs scan arguments - * @return RedisFuture<StreamScanCursor> scan cursor. - */ - RedisFuture scan(KeyStreamingChannel channel, ScanCursor scanCursor, ScanArgs scanArgs); - - /** - * Incrementally iterate the keys space. - * - * @param channel streaming channel that receives a call for every key - * @param scanCursor cursor to resume from a previous scan, must not be {@literal null} - * @return RedisFuture<StreamScanCursor> scan cursor. - */ - RedisFuture scan(KeyStreamingChannel channel, ScanCursor scanCursor); - -} diff --git a/src/main/java/com/lambdaworks/redis/RedisKeysConnection.java b/src/main/java/com/lambdaworks/redis/RedisKeysConnection.java deleted file mode 100644 index 93855efdeb..0000000000 --- a/src/main/java/com/lambdaworks/redis/RedisKeysConnection.java +++ /dev/null @@ -1,406 +0,0 @@ -package com.lambdaworks.redis; - -import java.util.Date; -import java.util.List; - -import com.lambdaworks.redis.output.KeyStreamingChannel; -import com.lambdaworks.redis.output.ValueStreamingChannel; - -/** - * Synchronous executed commands for Keys (Key manipulation/querying). - * - * @param Key type. - * @param Value type. - * @author Mark Paluch - * @since 3.0 - * @deprecated Use {@literal RedisKeyCommands} - */ -@Deprecated -public interface RedisKeysConnection { - - /** - * Delete one or more keys. - * - * @param keys the keys - * @return Long integer-reply The number of keys that were removed. - */ - Long del(K... keys); - - /** - * Unlink one or more keys (non blocking DEL). - * - * @param keys the keys - * @return Long integer-reply The number of keys that were removed. - */ - Long unlink(K... keys); - - /** - * Return a serialized version of the value stored at the specified key. - * - * @param key the key - * @return byte[] bulk-string-reply the serialized value. - */ - byte[] dump(K key); - - /** - * Determine if a key exists. - * - * @param key the key - * @return Boolean integer-reply specifically: - * - * {@literal true} if the key exists. {@literal false} if the key does not exist. - * @deprecated Use {@link #exists(Object[])} instead - */ - @Deprecated - Boolean exists(K key); - - /** - * Determine how many keys exist. - * - * @param keys the keys - * @return Long integer-reply specifically: Number of existing keys - */ - Long exists(K... keys); - - /** - * Set a key's time to live in seconds. - * - * @param key the key - * @param seconds the seconds type: long - * @return Boolean integer-reply specifically: - * - * {@literal true} if the timeout was set. {@literal false} if {@code key} does not exist or the timeout could not - * be set. - */ - Boolean expire(K key, long seconds); - - /** - * Set the expiration for a key as a UNIX timestamp. - * - * @param key the key - * @param timestamp the timestamp type: posix time - * @return Boolean integer-reply specifically: - * - * {@literal true} if the timeout was set. {@literal false} if {@code key} does not exist or the timeout could not - * be set (see: {@code EXPIRE}). - */ - Boolean expireat(K key, Date timestamp); - - /** - * Set the expiration for a key as a UNIX timestamp. - * - * @param key the key - * @param timestamp the timestamp type: posix time - * @return Boolean integer-reply specifically: - * - * {@literal true} if the timeout was set. {@literal false} if {@code key} does not exist or the timeout could not - * be set (see: {@code EXPIRE}). - */ - Boolean expireat(K key, long timestamp); - - /** - * Find all keys matching the given pattern. - * - * @param pattern the pattern type: patternkey (pattern) - * @return List<K> array-reply list of keys matching {@code pattern}. - */ - List keys(K pattern); - - /** - * Find all keys matching the given pattern. - * - * @param channel the channel - * @param pattern the pattern - * @return Long array-reply list of keys matching {@code pattern}. - */ - Long keys(KeyStreamingChannel channel, K pattern); - - /** - * Atomically transfer a key from a Redis instance to another one. - * - * @param host the host - * @param port the port - * @param key the key - * @param db the database - * @param timeout the timeout in milliseconds - * @return String simple-string-reply The command returns OK on success. - */ - String migrate(String host, int port, K key, int db, long timeout); - - /** - * Atomically transfer one or more keys from a Redis instance to another one. - * - * @param host the host - * @param port the port - * @param db the database - * @param timeout the timeout in milliseconds - * @param migrateArgs migrate args that allow to configure further options - * @return String simple-string-reply The command returns OK on success. - */ - String migrate(String host, int port, int db, long timeout, MigrateArgs migrateArgs); - - /** - * Move a key to another database. - * - * @param key the key - * @param db the db type: long - * @return Boolean integer-reply specifically: - */ - Boolean move(K key, int db); - - /** - * returns the kind of internal representation used in order to store the value associated with a key. - * - * @param key the key - * @return String - */ - String objectEncoding(K key); - - /** - * returns the number of seconds since the object stored at the specified key is idle (not requested by read or write - * operations). - * - * @param key the key - * @return number of seconds since the object stored at the specified key is idle. - */ - Long objectIdletime(K key); - - /** - * returns the number of references of the value associated with the specified key. - * - * @param key the key - * @return Long - */ - Long objectRefcount(K key); - - /** - * Remove the expiration from a key. - * - * @param key the key - * @return Boolean integer-reply specifically: - * - * {@literal true} if the timeout was removed. {@literal false} if {@code key} does not exist or does not have an - * associated timeout. - */ - Boolean persist(K key); - - /** - * Set a key's time to live in milliseconds. - * - * @param key the key - * @param milliseconds the milliseconds type: long - * @return integer-reply, specifically: - * - * {@literal true} if the timeout was set. {@literal false} if {@code key} does not exist or the timeout could not - * be set. - */ - Boolean pexpire(K key, long milliseconds); - - /** - * Set the expiration for a key as a UNIX timestamp specified in milliseconds. - * - * @param key the key - * @param timestamp the milliseconds-timestamp type: posix time - * @return Boolean integer-reply specifically: - * - * {@literal true} if the timeout was set. {@literal false} if {@code key} does not exist or the timeout could not - * be set (see: {@code EXPIRE}). - */ - Boolean pexpireat(K key, Date timestamp); - - /** - * Set the expiration for a key as a UNIX timestamp specified in milliseconds. - * - * @param key the key - * @param timestamp the milliseconds-timestamp type: posix time - * @return Boolean integer-reply specifically: - * - * {@literal true} if the timeout was set. {@literal false} if {@code key} does not exist or the timeout could not - * be set (see: {@code EXPIRE}). - */ - Boolean pexpireat(K key, long timestamp); - - /** - * Get the time to live for a key in milliseconds. - * - * @param key the key - * @return Long integer-reply TTL in milliseconds, or a negative value in order to signal an error (see the description - * above). - */ - Long pttl(K key); - - /** - * Return a random key from the keyspace. - * - * @return V bulk-string-reply the random key, or {@literal null} when the database is empty. - */ - V randomkey(); - - /** - * Rename a key. - * - * @param key the key - * @param newKey the newkey type: key - * @return String simple-string-reply - */ - String rename(K key, K newKey); - - /** - * Rename a key, only if the new key does not exist. - * - * @param key the key - * @param newKey the newkey type: key - * @return Boolean integer-reply specifically: - * - * {@literal true} if {@code key} was renamed to {@code newkey}. {@literal false} if {@code newkey} already exists. - */ - Boolean renamenx(K key, K newKey); - - /** - * Create a key using the provided serialized value, previously obtained using DUMP. - * - * @param key the key - * @param ttl the ttl type: long - * @param value the serialized-value type: string - * @return String simple-string-reply The command returns OK on success. - */ - String restore(K key, long ttl, byte[] value); - - /** - * Sort the elements in a list, set or sorted set. - * - * @param key the key - * @return List<V> array-reply list of sorted elements. - */ - List sort(K key); - - /** - * Sort the elements in a list, set or sorted set. - * - * @param channel streaming channel that receives a call for every value - * @param key the key - * @return Long number of values. - */ - Long sort(ValueStreamingChannel channel, K key); - - /** - * Sort the elements in a list, set or sorted set. - * - * @param key the key - * @param sortArgs sort arguments - * @return List<V> array-reply list of sorted elements. - */ - List sort(K key, SortArgs sortArgs); - - /** - * Sort the elements in a list, set or sorted set. - * - * @param channel streaming channel that receives a call for every value - * @param key the key - * @param sortArgs sort arguments - * @return Long number of values. - */ - Long sort(ValueStreamingChannel channel, K key, SortArgs sortArgs); - - /** - * Sort the elements in a list, set or sorted set. - * - * @param key the key - * @param sortArgs sort arguments - * @param destination the destination key to store sort results - * @return Long number of values. - */ - Long sortStore(K key, SortArgs sortArgs, K destination); - - /** - * Touch one or more keys. Touch sets the last accessed time for a key. Non-exsitent keys wont get created. - * - * @param keys the keys - * @return Long integer-reply the number of found keys. - */ - Long touch(K... keys); - - /** - * Get the time to live for a key. - * - * @param key the key - * @return Long integer-reply TTL in seconds, or a negative value in order to signal an error (see the description above). - */ - Long ttl(K key); - - /** - * Determine the type stored at key. - * - * @param key the key - * @return String simple-string-reply type of {@code key}, or {@code none} when {@code key} does not exist. - */ - String type(K key); - - /** - * Incrementally iterate the keys space. - * - * @return KeyScanCursor<K> scan cursor. - */ - KeyScanCursor scan(); - - /** - * Incrementally iterate the keys space. - * - * @param scanArgs scan arguments - * @return KeyScanCursor<K> scan cursor. - */ - KeyScanCursor scan(ScanArgs scanArgs); - - /** - * Incrementally iterate the keys space. - * - * @param scanCursor cursor to resume from a previous scan, must not be {@literal null} - * @param scanArgs scan arguments - * @return KeyScanCursor<K> scan cursor. - */ - KeyScanCursor scan(ScanCursor scanCursor, ScanArgs scanArgs); - - /** - * Incrementally iterate the keys space. - * - * @param scanCursor cursor to resume from a previous scan, must not be {@literal null} - * @return KeyScanCursor<K> scan cursor. - */ - KeyScanCursor scan(ScanCursor scanCursor); - - /** - * Incrementally iterate the keys space. - * - * @param channel streaming channel that receives a call for every key - * @return StreamScanCursor scan cursor. - */ - StreamScanCursor scan(KeyStreamingChannel channel); - - /** - * Incrementally iterate the keys space. - * - * @param channel streaming channel that receives a call for every key - * @param scanArgs scan arguments - * @return StreamScanCursor scan cursor. - */ - StreamScanCursor scan(KeyStreamingChannel channel, ScanArgs scanArgs); - - /** - * Incrementally iterate the keys space. - * - * @param channel streaming channel that receives a call for every key - * @param scanCursor cursor to resume from a previous scan, must not be {@literal null} - * @param scanArgs scan arguments - * @return StreamScanCursor scan cursor. - */ - StreamScanCursor scan(KeyStreamingChannel channel, ScanCursor scanCursor, ScanArgs scanArgs); - - /** - * Incrementally iterate the keys space. - * - * @param channel streaming channel that receives a call for every key - * @param scanCursor cursor to resume from a previous scan, must not be {@literal null} - * @return StreamScanCursor scan cursor. - */ - StreamScanCursor scan(KeyStreamingChannel channel, ScanCursor scanCursor); -} diff --git a/src/main/java/com/lambdaworks/redis/RedisListsAsyncConnection.java b/src/main/java/com/lambdaworks/redis/RedisListsAsyncConnection.java deleted file mode 100644 index 8bf311ff88..0000000000 --- a/src/main/java/com/lambdaworks/redis/RedisListsAsyncConnection.java +++ /dev/null @@ -1,222 +0,0 @@ -package com.lambdaworks.redis; - -import java.util.List; - -import com.lambdaworks.redis.api.async.RedisListAsyncCommands; -import com.lambdaworks.redis.output.ValueStreamingChannel; - -/** - * Asynchronous executed commands for Lists. - * - * @param Key type. - * @param Value type. - * @author Mark Paluch - * @since 3.0 - * @deprecated Use {@link RedisListAsyncCommands} - */ -@Deprecated -public interface RedisListsAsyncConnection { - - /** - * Remove and get the first element in a list, or block until one is available. - * - * @param timeout the timeout in seconds - * @param keys the keys - * @return RedisFuture<KeyValue<K,V>> array-reply specifically: - * - * A {@literal null} multi-bulk when no element could be popped and the timeout expired. A two-element multi-bulk - * with the first element being the name of the key where an element was popped and the second element being the - * value of the popped element. - */ - RedisFuture> blpop(long timeout, K... keys); - - /** - * Remove and get the last element in a list, or block until one is available. - * - * @param timeout the timeout in seconds - * @param keys the keys - * @return RedisFuture<KeyValue<K,V>> array-reply specifically: - * - * A {@literal null} multi-bulk when no element could be popped and the timeout expired. A two-element multi-bulk - * with the first element being the name of the key where an element was popped and the second element being the - * value of the popped element. - */ - RedisFuture> brpop(long timeout, K... keys); - - /** - * Pop a value from a list, push it to another list and return it; or block until one is available. - * - * @param timeout the timeout in seconds - * @param source the source key - * @param destination the destination type: key - * @return RedisFuture<V> bulk-string-reply the element being popped from {@code source} and pushed to - * {@code destination}. If {@code timeout} is reached, a - */ - RedisFuture brpoplpush(long timeout, K source, K destination); - - /** - * Get an element from a list by its index. - * - * @param key the key - * @param index the index type: long - * @return RedisFuture<V> bulk-string-reply the requested element, or {@literal null} when {@code index} is out of - * range. - */ - RedisFuture lindex(K key, long index); - - /** - * Insert an element before or after another element in a list. - * - * @param key the key - * @param before the before - * @param pivot the pivot - * @param value the value - * @return RedisFuture<Long> integer-reply the length of the list after the insert operation, or {@code -1} when the - * value {@code pivot} was not found. - */ - RedisFuture linsert(K key, boolean before, V pivot, V value); - - /** - * Get the length of a list. - * - * @param key the key - * @return RedisFuture<Long> integer-reply the length of the list at {@code key}. - */ - RedisFuture llen(K key); - - /** - * Remove and get the first element in a list. - * - * @param key the key - * @return RedisFuture<V> bulk-string-reply the value of the first element, or {@literal null} when {@code key} does - * not exist. - */ - RedisFuture lpop(K key); - - /** - * Prepend one or multiple values to a list. - * - * @param key the key - * @param values the value - * @return RedisFuture<Long> integer-reply the length of the list after the push operations. - */ - RedisFuture lpush(K key, V... values); - - /** - * Prepend a value to a list, only if the list exists. - * - * @param key the key - * @param value the value - * @return RedisFuture<Long> integer-reply the length of the list after the push operation. - * @deprecated Use {@link #lpushx(Object, Object[])} - */ - @Deprecated - RedisFuture lpushx(K key, V value); - - /** - * Prepend values to a list, only if the list exists. - * - * @param key the key - * @param values the values - * @return Long integer-reply the length of the list after the push operation. - */ - RedisFuture lpushx(K key, V... values); - - /** - * Get a range of elements from a list. - * - * @param key the key - * @param start the start type: long - * @param stop the stop type: long - * @return RedisFuture<List<V>> array-reply list of elements in the specified range. - */ - RedisFuture> lrange(K key, long start, long stop); - - /** - * Get a range of elements from a list. - * - * @param channel the channel - * @param key the key - * @param start the start type: long - * @param stop the stop type: long - * @return RedisFuture<Long> count of elements in the specified range. - */ - RedisFuture lrange(ValueStreamingChannel channel, K key, long start, long stop); - - /** - * Remove elements from a list. - * - * @param key the key - * @param count the count type: long - * @param value the value - * @return RedisFuture<Long> integer-reply the number of removed elements. - */ - RedisFuture lrem(K key, long count, V value); - - /** - * Set the value of an element in a list by its index. - * - * @param key the key - * @param index the index type: long - * @param value the value - * @return RedisFuture<String> simple-string-reply - */ - RedisFuture lset(K key, long index, V value); - - /** - * Trim a list to the specified range. - * - * @param key the key - * @param start the start type: long - * @param stop the stop type: long - * @return RedisFuture<String> simple-string-reply - */ - RedisFuture ltrim(K key, long start, long stop); - - /** - * Remove and get the last element in a list. - * - * @param key the key - * @return RedisFuture<V> bulk-string-reply the value of the last element, or {@literal null} when {@code key} does - * not exist. - */ - RedisFuture rpop(K key); - - /** - * Remove the last element in a list, append it to another list and return it. - * - * @param source the source key - * @param destination the destination type: key - * @return RedisFuture<V> bulk-string-reply the element being popped and pushed. - */ - RedisFuture rpoplpush(K source, K destination); - - /** - * Append one or multiple values to a list. - * - * @param key the key - * @param values the value - * @return RedisFuture<Long> integer-reply the length of the list after the push operation. - */ - RedisFuture rpush(K key, V... values); - - /** - * Append a value to a list, only if the list exists. - * - * @param key the key - * @param value the value - * @return RedisFuture<Long> integer-reply the length of the list after the push operation. - * @deprecated Use {@link #rpushx(java.lang.Object, java.lang.Object[])} - */ - @Deprecated - RedisFuture rpushx(K key, V value); - - /** - * Append values to a list, only if the list exists. - * - * @param key the key - * @param values the values - * @return RedisFuture<Long> integer-reply the length of the list after the push operation. - */ - RedisFuture rpushx(K key, V... values); -} diff --git a/src/main/java/com/lambdaworks/redis/RedisListsConnection.java b/src/main/java/com/lambdaworks/redis/RedisListsConnection.java deleted file mode 100644 index bcdd3b9124..0000000000 --- a/src/main/java/com/lambdaworks/redis/RedisListsConnection.java +++ /dev/null @@ -1,220 +0,0 @@ -package com.lambdaworks.redis; - -import java.util.List; - -import com.lambdaworks.redis.api.sync.RedisListCommands; -import com.lambdaworks.redis.output.ValueStreamingChannel; - -/** - * - * Synchronous executed commands for Lists. - * - * @param Key type. - * @param Value type. - * @author Mark Paluch - * @since 3.0 - * @deprecated Use {@literal RedisListCommands} - */ -@Deprecated -public interface RedisListsConnection { - - /** - * Remove and get the first element in a list, or block until one is available. - * - * @param timeout the timeout in seconds - * @param keys the keys - * @return KeyValue<K,V> array-reply specifically: - * - * A {@literal null} multi-bulk when no element could be popped and the timeout expired. A two-element multi-bulk - * with the first element being the name of the key where an element was popped and the second element being the - * value of the popped element. - */ - KeyValue blpop(long timeout, K... keys); - - /** - * Remove and get the last element in a list, or block until one is available. - * - * @param timeout the timeout in seconds - * @param keys the keys - * @return KeyValue<K,V> array-reply specifically: - * - * A {@literal null} multi-bulk when no element could be popped and the timeout expired. A two-element multi-bulk - * with the first element being the name of the key where an element was popped and the second element being the - * value of the popped element. - */ - KeyValue brpop(long timeout, K... keys); - - /** - * Pop a value from a list, push it to another list and return it; or block until one is available. - * - * @param timeout the timeout in seconds - * @param source the source key - * @param destination the destination type: key - * @return V bulk-string-reply the element being popped from {@code source} and pushed to {@code destination}. If - * {@code timeout} is reached, a - */ - V brpoplpush(long timeout, K source, K destination); - - /** - * Get an element from a list by its index. - * - * @param key the key - * @param index the index type: long - * @return V bulk-string-reply the requested element, or {@literal null} when {@code index} is out of range. - */ - V lindex(K key, long index); - - /** - * Insert an element before or after another element in a list. - * - * @param key the key - * @param before the before - * @param pivot the pivot - * @param value the value - * @return Long integer-reply the length of the list after the insert operation, or {@code -1} when the value {@code pivot} - * was not found. - */ - Long linsert(K key, boolean before, V pivot, V value); - - /** - * Get the length of a list. - * - * @param key the key - * @return Long integer-reply the length of the list at {@code key}. - */ - Long llen(K key); - - /** - * Remove and get the first element in a list. - * - * @param key the key - * @return V bulk-string-reply the value of the first element, or {@literal null} when {@code key} does not exist. - */ - V lpop(K key); - - /** - * Prepend one or multiple values to a list. - * - * @param key the key - * @param values the value - * @return Long integer-reply the length of the list after the push operations. - */ - Long lpush(K key, V... values); - - /** - * Prepend a value to a list, only if the list exists. - * - * @param key the key - * @param value the value - * @return Long integer-reply the length of the list after the push operation. - * @deprecated Use {@link #lpushx(Object, Object[])} - */ - @Deprecated - Long lpushx(K key, V value); - - /** - * Prepend values to a list, only if the list exists. - * - * @param key the key - * @param values the values - * @return Long integer-reply the length of the list after the push operation. - */ - Long lpushx(K key, V... values); - - /** - * Get a range of elements from a list. - * - * @param key the key - * @param start the start type: long - * @param stop the stop type: long - * @return List<V> array-reply list of elements in the specified range. - */ - List lrange(K key, long start, long stop); - - /** - * Get a range of elements from a list. - * - * @param channel the channel - * @param key the key - * @param start the start type: long - * @param stop the stop type: long - * @return Long count of elements in the specified range. - */ - Long lrange(ValueStreamingChannel channel, K key, long start, long stop); - - /** - * Remove elements from a list. - * - * @param key the key - * @param count the count type: long - * @param value the value - * @return Long integer-reply the number of removed elements. - */ - Long lrem(K key, long count, V value); - - /** - * Set the value of an element in a list by its index. - * - * @param key the key - * @param index the index type: long - * @param value the value - * @return String simple-string-reply - */ - String lset(K key, long index, V value); - - /** - * Trim a list to the specified range. - * - * @param key the key - * @param start the start type: long - * @param stop the stop type: long - * @return String simple-string-reply - */ - String ltrim(K key, long start, long stop); - - /** - * Remove and get the last element in a list. - * - * @param key the key - * @return V bulk-string-reply the value of the last element, or {@literal null} when {@code key} does not exist. - */ - V rpop(K key); - - /** - * Remove the last element in a list, append it to another list and return it. - * - * @param source the source key - * @param destination the destination type: key - * @return V bulk-string-reply the element being popped and pushed. - */ - V rpoplpush(K source, K destination); - - /** - * Append one or multiple values to a list. - * - * @param key the key - * @param values the value - * @return Long integer-reply the length of the list after the push operation. - */ - Long rpush(K key, V... values); - - /** - * Append a value to a list, only if the list exists. - * - * @param key the key - * @param value the value - * @return Long integer-reply the length of the list after the push operation. - * @deprecated Use {@link #rpushx(Object, Object[])} - */ - @Deprecated - Long rpushx(K key, V value); - - /** - * Append values to a list, only if the list exists. - * - * @param key the key - * @param values the values - * @return Long integer-reply the length of the list after the push operation. - */ - Long rpushx(K key, V... values); -} diff --git a/src/main/java/com/lambdaworks/redis/RedisScriptingAsyncConnection.java b/src/main/java/com/lambdaworks/redis/RedisScriptingAsyncConnection.java deleted file mode 100644 index 52cb17b7c1..0000000000 --- a/src/main/java/com/lambdaworks/redis/RedisScriptingAsyncConnection.java +++ /dev/null @@ -1,96 +0,0 @@ -package com.lambdaworks.redis; - -import java.util.List; - -import com.lambdaworks.redis.api.async.RedisScriptingAsyncCommands; - -/** - * Asynchronous executed commands for Scripting. - * - * @param Key type. - * @param Value type. - * @author Mark Paluch - * @since 3.0 - * @deprecated Use {@literal RedisScriptingAsyncCommands} - */ -@Deprecated -public interface RedisScriptingAsyncConnection { - /** - * Execute a Lua script server side. - * - * @param script Lua 5.1 script. - * @param type output type - * @param keys key names - * @param expected return type - * @return script result - */ - RedisFuture eval(String script, ScriptOutputType type, K... keys); - - /** - * Execute a Lua script server side. - * - * @param script Lua 5.1 script. - * @param type the type - * @param keys the keys - * @param values the values - * @param expected return type - * @return script result - */ - RedisFuture eval(String script, ScriptOutputType type, K[] keys, V... values); - - /** - * Evaluates a script cached on the server side by its SHA1 digest - * - * @param digest SHA1 of the script - * @param type the type - * @param keys the keys - * @param expected return type - * @return script result - */ - RedisFuture evalsha(String digest, ScriptOutputType type, K... keys); - - /** - * Execute a Lua script server side. - * - * @param digest SHA1 of the script - * @param type the type - * @param keys the keys - * @param values the values - * @param expected return type - * @return script result - */ - RedisFuture evalsha(String digest, ScriptOutputType type, K[] keys, V... values); - - /** - * Check existence of scripts in the script cache. - * - * @param digests script digests - * @return RedisFuture<List<Boolean>> array-reply The command returns an array of integers that correspond to - * the specified SHA1 digest arguments. For every corresponding SHA1 digest of a script that actually exists in the - * script cache, an 1 is returned, otherwise 0 is returned. - */ - RedisFuture> scriptExists(String... digests); - - /** - * Remove all the scripts from the script cache. - * - * @return RedisFuture<String> simple-string-reply - */ - RedisFuture scriptFlush(); - - /** - * Kill the script currently in execution. - * - * @return RedisFuture<String> simple-string-reply - */ - RedisFuture scriptKill(); - - /** - * Load the specified Lua script into the script cache. - * - * @param script script content - * @return RedisFuture<String> bulk-string-reply This command returns the SHA1 digest of the script added into the - * script cache. - */ - RedisFuture scriptLoad(V script); -} diff --git a/src/main/java/com/lambdaworks/redis/RedisScriptingConnection.java b/src/main/java/com/lambdaworks/redis/RedisScriptingConnection.java deleted file mode 100644 index 04e3fd8b75..0000000000 --- a/src/main/java/com/lambdaworks/redis/RedisScriptingConnection.java +++ /dev/null @@ -1,95 +0,0 @@ -package com.lambdaworks.redis; - -import java.util.List; - -import com.lambdaworks.redis.api.sync.RedisScriptingCommands; - -/** - * Synchronous executed commands for Scripting. - * - * @param Key type. - * @param Value type. - * @author Mark Paluch - * @since 3.0 - * @deprecated Use {@link RedisScriptingCommands} - */ -@Deprecated -public interface RedisScriptingConnection { - /** - * Execute a Lua script server side. - * - * @param script Lua 5.1 script. - * @param type output type - * @param keys key names - * @param expected return type - * @return script result - */ - T eval(String script, ScriptOutputType type, K... keys); - - /** - * Execute a Lua script server side. - * - * @param script Lua 5.1 script. - * @param type the type - * @param keys the keys - * @param values the values - * @param expected return type - * @return script result - */ - T eval(String script, ScriptOutputType type, K[] keys, V... values); - - /** - * Evaluates a script cached on the server side by its SHA1 digest - * - * @param digest SHA1 of the script - * @param type the type - * @param keys the keys - * @param expected return type - * @return script result - */ - T evalsha(String digest, ScriptOutputType type, K... keys); - - /** - * Execute a Lua script server side. - * - * @param digest SHA1 of the script - * @param type the type - * @param keys the keys - * @param values the values - * @param expected return type - * @return script result - */ - T evalsha(String digest, ScriptOutputType type, K[] keys, V... values); - - /** - * Check existence of scripts in the script cache. - * - * @param digests script digests - * @return List<Boolean> array-reply The command returns an array of integers that correspond to the specified SHA1 - * digest arguments. For every corresponding SHA1 digest of a script that actually exists in the script cache, an 1 - * is returned, otherwise 0 is returned. - */ - List scriptExists(String... digests); - - /** - * Remove all the scripts from the script cache. - * - * @return String simple-string-reply - */ - String scriptFlush(); - - /** - * Kill the script currently in execution. - * - * @return String simple-string-reply - */ - String scriptKill(); - - /** - * Load the specified Lua script into the script cache. - * - * @param script script content - * @return String bulk-string-reply This command returns the SHA1 digest of the script added into the script cache. - */ - String scriptLoad(V script); -} diff --git a/src/main/java/com/lambdaworks/redis/RedisSentinelAsyncConnection.java b/src/main/java/com/lambdaworks/redis/RedisSentinelAsyncConnection.java deleted file mode 100644 index 051b210fb6..0000000000 --- a/src/main/java/com/lambdaworks/redis/RedisSentinelAsyncConnection.java +++ /dev/null @@ -1,114 +0,0 @@ -package com.lambdaworks.redis; - -import java.io.Closeable; -import java.net.SocketAddress; -import java.util.List; -import java.util.Map; - -import com.lambdaworks.redis.sentinel.api.async.RedisSentinelAsyncCommands; - -/** - * Asynchronous executed commands for Sentinel. - * - * @param Key type. - * @param Value type. - * @author Mark Paluch - * @since 3.0 - * @deprecated Use {@link RedisSentinelAsyncCommands} - */ -@Deprecated -public interface RedisSentinelAsyncConnection extends Closeable { - - /** - * Return the ip and port number of the master with that name. - * - * @param key the key - * @return Future<SocketAddress> - */ - RedisFuture getMasterAddrByName(K key); - - /** - * Enumerates all the monitored masters and their states. - * - * @return RedisFuture<Map<K, V>> - */ - RedisFuture>> masters(); - - /** - * Show the state and info of the specified master. - * - * @param key the key - * @return RedisFuture<Map<K, V>> - */ - RedisFuture> master(K key); - - /** - * Provides a list of slaves for the master with the specified name. - * - * @param key the key - * @return RedisFuture<List<Map<K, V>>> - */ - RedisFuture>> slaves(K key); - - /** - * This command will reset all the masters with matching name. - * - * @param key the key - * @return RedisFuture<Long> - */ - RedisFuture reset(K key); - - /** - * Perform a failover. - * - * @param key the master id - * @return RedisFuture<String> - */ - RedisFuture failover(K key); - - /** - * This command tells the Sentinel to start monitoring a new master with the specified name, ip, port, and quorum. - * - * @param key the key - * @param ip the IP address - * @param port the port - * @param quorum the quorum count - * @return RedisFuture<String> - */ - RedisFuture monitor(K key, String ip, int port, int quorum); - - /** - * Multiple option / value pairs can be specified (or none at all). - * - * @param key the key - * @param option the option - * @param value the value - * - * @return RedisFuture<String> simple-string-reply {@code OK} if {@code SET} was executed correctly. - */ - RedisFuture set(K key, String option, V value); - - /** - * remove the specified master. - * - * @param key the key - * @return RedisFuture<String> - */ - RedisFuture remove(K key); - - /** - * Ping the server. - * - * @return RedisFuture<String> simple-string-reply - */ - RedisFuture ping(); - - @Override - void close(); - - /** - * - * @return true if the connection is open (connected and not closed). - */ - boolean isOpen(); -} diff --git a/src/main/java/com/lambdaworks/redis/RedisServerAsyncConnection.java b/src/main/java/com/lambdaworks/redis/RedisServerAsyncConnection.java deleted file mode 100644 index b4ca65b0c2..0000000000 --- a/src/main/java/com/lambdaworks/redis/RedisServerAsyncConnection.java +++ /dev/null @@ -1,304 +0,0 @@ -package com.lambdaworks.redis; - -import java.util.Date; -import java.util.List; - -import com.lambdaworks.redis.api.async.RedisServerAsyncCommands; -import com.lambdaworks.redis.protocol.CommandType; - -/** - * Asynchronous executed commands for Server Control. - * - * @param Key type. - * @param Value type. - * @author Mark Paluch - * @since 3.0 - * @deprecated Use {@link RedisServerAsyncCommands} - */ -@Deprecated -public interface RedisServerAsyncConnection { - /** - * Asynchronously rewrite the append-only file. - * - * @return RedisFuture<String> simple-string-reply always {@code OK}. - */ - RedisFuture bgrewriteaof(); - - /** - * Asynchronously save the dataset to disk. - * - * @return RedisFuture<String> simple-string-reply - */ - RedisFuture bgsave(); - - /** - * Get the current connection name. - * - * @return RedisFuture<K> bulk-string-reply The connection name, or a null bulk reply if no name is set. - */ - RedisFuture clientGetname(); - - /** - * Set the current connection name. - * - * @param name the client name - * @return RedisFuture<String> simple-string-reply {@code OK} if the connection name was successfully set. - */ - RedisFuture clientSetname(K name); - - /** - * Kill the connection of a client identified by ip:port. - * - * @param addr the addr in format ip:port - * @return RedisFuture<String> simple-string-reply {@code OK} if the connection exists and has been closed - */ - RedisFuture clientKill(String addr); - - /** - * Kill connections of clients which are filtered by {@code killArgs} - * - * @param killArgs args for the kill operation - * @return RedisFuture<Long> integer-reply number of killed connections - */ - RedisFuture clientKill(KillArgs killArgs); - - /** - * Stop processing commands from clients for some time. - * - * @param timeout the timeout value in milliseconds - * @return RedisFuture<String> simple-string-reply The command returns OK or an error if the timeout is invalid. - */ - RedisFuture clientPause(long timeout); - - /** - * Get the list of client connections. - * - * @return RedisFuture<String> bulk-string-reply a unique string, formatted as follows: One client connection per line - * (separated by LF), each line is composed of a succession of property=value fields separated by a space character. - */ - RedisFuture clientList(); - - /** - * Returns an array reply of details about all Redis commands. - * - * @return RedisFuture<List<Object>> array-reply - */ - RedisFuture> command(); - - /** - * Returns an array reply of details about the requested commands. - * - * @param commands the commands to query for - * @return RedisFuture<List<Object>> array-reply - */ - RedisFuture> commandInfo(String... commands); - - /** - * Returns an array reply of details about the requested commands. - * - * @param commands the commands to query for - * @return RedisFuture<List<Object>> array-reply - */ - RedisFuture> commandInfo(CommandType... commands); - - /** - * Get total number of Redis commands. - * - * @return RedisFuture<Long> integer-reply of number of total commands in this Redis server. - */ - RedisFuture commandCount(); - - /** - * Get the value of a configuration parameter. - * - * @param parameter the parameter - * @return RedisFuture<List<String>> bulk-string-reply - */ - RedisFuture> configGet(String parameter); - - /** - * Reset the stats returned by INFO. - * - * @return RedisFuture<String> simple-string-reply always {@code OK}. - */ - RedisFuture configResetstat(); - - /** - * Rewrite the configuration file with the in memory configuration. - * - * @return RedisFuture<String> simple-string-reply {@code OK} when the configuration was rewritten properly. Otherwise - * an error is returned. - */ - RedisFuture configRewrite(); - - /** - * Set a configuration parameter to the given value. - * - * @param parameter the parameter name - * @param value the parameter value - * @return RedisFuture<String> simple-string-reply: {@code OK} when the configuration was set properly. Otherwise an - * error is returned. - */ - RedisFuture configSet(String parameter, String value); - - /** - * Return the number of keys in the selected database. - * - * @return RedisFuture<Long> integer-reply - */ - RedisFuture dbsize(); - - /** - * Get debugging information about a key. - * - * @param key the key - * @return RedisFuture<String> simple-string-reply - */ - RedisFuture debugObject(K key); - - /** - * Make the server crash: Invalid pointer access. - */ - void debugSegfault(); - - /** - * Make the server crash: Out of memory. - */ - void debugOom(); - - /** - * Get debugging information about the internal hash-table state. - * - * @param db the database number - * @return String simple-string-reply - */ - RedisFuture debugHtstats(int db); - - /** - * Remove all keys from all databases. - * - * @return RedisFuture<String> simple-string-reply - */ - RedisFuture flushall(); - - /** - * Remove all keys asynchronously from all databases. - * - * @return String simple-string-reply - */ - RedisFuture flushallAsync(); - - /** - * Remove all keys from the current database. - * - * @return RedisFuture<String> simple-string-reply - */ - RedisFuture flushdb(); - - /** - * Remove all keys asynchronously from the current database. - * - * @return String simple-string-reply - */ - RedisFuture flushdbAsync(); - - /** - * Get information and statistics about the server. - * - * @return RedisFuture<String> bulk-string-reply as a collection of text lines. - */ - RedisFuture info(); - - /** - * Get information and statistics about the server. - * - * @param section the section type: string - * @return RedisFuture<String> bulk-string-reply as a collection of text lines. - */ - RedisFuture info(String section); - - /** - * Get the UNIX time stamp of the last successful save to disk. - * - * @return RedisFuture<Date> integer-reply an UNIX time stamp. - */ - RedisFuture lastsave(); - - /** - * Synchronously save the dataset to disk. - * - * @return RedisFuture<String> simple-string-reply The commands returns OK on success. - */ - RedisFuture save(); - - /** - * Synchronously save the dataset to disk and then shut down the server. - * - * @param save {@literal true} force save operation - */ - void shutdown(boolean save); - - /** - * Make the server a slave of another instance. - * - * @param host the host type: string - * @param port the port type: string - * @return RedisFuture<String> simple-string-reply - */ - RedisFuture slaveof(String host, int port); - - /** - * Promote server as master. - * - * @return RedisFuture<String> simple-string-reply - */ - RedisFuture slaveofNoOne(); - - /** - * Read the slow log. - * - * @return List<Object> deeply nested multi bulk replies - */ - RedisFuture> slowlogGet(); - - /** - * Read the slow log. - * - * @param count the count - * @return List<Object> deeply nested multi bulk replies - */ - RedisFuture> slowlogGet(int count); - - /** - * Obtaining the current length of the slow log. - * - * @return RedisFuture<Long> length of the slow log. - */ - RedisFuture slowlogLen(); - - /** - * Resetting the slow log. - * - * @return RedisFuture<String> simple-string-reply The commands returns OK on success. - */ - RedisFuture slowlogReset(); - - /** - * Internal command used for replication. - * - * @return RedisFuture<String> - */ - @Deprecated - RedisFuture sync(); - - /** - * Return the current server time. - * - * @return RedisFuture<List<V>> array-reply specifically: - * - * A multi bulk reply containing two elements: - * - * unix time in seconds. microseconds. - */ - RedisFuture> time(); -} diff --git a/src/main/java/com/lambdaworks/redis/RedisServerConnection.java b/src/main/java/com/lambdaworks/redis/RedisServerConnection.java deleted file mode 100644 index 0a3f393fa0..0000000000 --- a/src/main/java/com/lambdaworks/redis/RedisServerConnection.java +++ /dev/null @@ -1,304 +0,0 @@ -package com.lambdaworks.redis; - -import java.util.Date; -import java.util.List; - -import com.lambdaworks.redis.api.sync.RedisServerCommands; -import com.lambdaworks.redis.protocol.CommandType; - -/** - * Synchronous executed commands for Server Control. - * - * @param Key type. - * @param Value type. - * @author Mark Paluch - * @since 3.0 - * @deprecated Use {@link RedisServerCommands} - */ -@Deprecated -public interface RedisServerConnection extends RedisServerCommands { - /** - * Asynchronously rewrite the append-only file. - * - * @return String simple-string-reply always {@code OK}. - */ - String bgrewriteaof(); - - /** - * Asynchronously save the dataset to disk. - * - * @return String simple-string-reply - */ - String bgsave(); - - /** - * Get the current connection name. - * - * @return K bulk-string-reply The connection name, or a null bulk reply if no name is set. - */ - K clientGetname(); - - /** - * Set the current connection name. - * - * @param name the client name - * @return simple-string-reply {@code OK} if the connection name was successfully set. - */ - String clientSetname(K name); - - /** - * Kill the connection of a client identified by ip:port. - * - * @param addr ip:port - * @return String simple-string-reply {@code OK} if the connection exists and has been closed - */ - String clientKill(String addr); - - /** - * Kill connections of clients which are filtered by {@code killArgs} - * - * @param killArgs args for the kill operation - * @return Long integer-reply number of killed connections - */ - Long clientKill(KillArgs killArgs); - - /** - * Stop processing commands from clients for some time. - * - * @param timeout the timeout value in milliseconds - * @return String simple-string-reply The command returns OK or an error if the timeout is invalid. - */ - String clientPause(long timeout); - - /** - * Get the list of client connections. - * - * @return String bulk-string-reply a unique string, formatted as follows: One client connection per line (separated by LF), - * each line is composed of a succession of property=value fields separated by a space character. - */ - String clientList(); - - /** - * Returns an array reply of details about all Redis commands. - * - * @return List<Object> array-reply - */ - List command(); - - /** - * Returns an array reply of details about the requested commands. - * - * @param commands the commands to query for - * @return List<Object> array-reply - */ - List commandInfo(String... commands); - - /** - * Returns an array reply of details about the requested commands. - * - * @param commands the commands to query for - * @return List<Object> array-reply - */ - List commandInfo(CommandType... commands); - - /** - * Get total number of Redis commands. - * - * @return Long integer-reply of number of total commands in this Redis server. - */ - Long commandCount(); - - /** - * Get the value of a configuration parameter. - * - * @param parameter name of the parameter - * @return List<String> bulk-string-reply - */ - List configGet(String parameter); - - /** - * Reset the stats returned by INFO. - * - * @return String simple-string-reply always {@code OK}. - */ - String configResetstat(); - - /** - * Rewrite the configuration file with the in memory configuration. - * - * @return String simple-string-reply {@code OK} when the configuration was rewritten properly. Otherwise an error is - * returned. - */ - String configRewrite(); - - /** - * Set a configuration parameter to the given value. - * - * @param parameter the parameter name - * @param value the parameter value - * @return String simple-string-reply: {@code OK} when the configuration was set properly. Otherwise an error is returned. - */ - String configSet(String parameter, String value); - - /** - * Return the number of keys in the selected database. - * - * @return Long integer-reply - */ - Long dbsize(); - - /** - * Get debugging information about a key. - * - * @param key the key - * @return String simple-string-reply - */ - String debugObject(K key); - - /** - * Make the server crash: Invalid pointer access. - */ - void debugSegfault(); - - /** - * Make the server crash: Out of memory. - */ - void debugOom(); - - /** - * Get debugging information about the internal hash-table state. - * - * @param db the database number - * @return String simple-string-reply - */ - String debugHtstats(int db); - - /** - * Remove all keys from all databases. - * - * @return String simple-string-reply - */ - String flushall(); - - /** - * Remove all keys asynchronously from all databases. - * - * @return String simple-string-reply - */ - String flushallAsync(); - - /** - * Remove all keys from the current database. - * - * @return String simple-string-reply - */ - String flushdb(); - - /** - * Remove all keys asynchronously from the current database. - * - * @return String simple-string-reply - */ - String flushdbAsync(); - - /** - * Get information and statistics about the server. - * - * @return String bulk-string-reply as a collection of text lines. - */ - String info(); - - /** - * Get information and statistics about the server. - * - * @param section the section type: string - * @return String bulk-string-reply as a collection of text lines. - */ - String info(String section); - - /** - * Get the UNIX time stamp of the last successful save to disk. - * - * @return Date integer-reply an UNIX time stamp. - */ - Date lastsave(); - - /** - * Synchronously save the dataset to disk. - * - * @return String simple-string-reply The commands returns OK on success. - */ - String save(); - - /** - * Synchronously save the dataset to disk and then shut down the server. - * - * @param save {@literal true} force save operation - */ - void shutdown(boolean save); - - /** - * Make the server a slave of another instance, or promote it as master. - * - * @param host the host type: string - * @param port the port type: string - * @return String simple-string-reply - */ - String slaveof(String host, int port); - - /** - * Promote server as master. - * - * @return String simple-string-reply - */ - String slaveofNoOne(); - - /** - * Read the slow log. - * - * @return List<Object> deeply nested multi bulk replies - */ - List slowlogGet(); - - /** - * Read the slow log. - * - * @param count the count - * @return List<Object> deeply nested multi bulk replies - */ - List slowlogGet(int count); - - /** - * Obtaining the current length of the slow log. - * - * @return Long length of the slow log. - */ - Long slowlogLen(); - - /** - * Resetting the slow log. - * - * @return String simple-string-reply The commands returns OK on success. - */ - String slowlogReset(); - - /** - * Internal command used for replication. - * - * @return String simple-string-reply - */ - @Deprecated - String sync(); - - /** - * Return the current server time. - * - * @return List<V> array-reply specifically: - * - * A multi bulk reply containing two elements: - * - * unix time in seconds. microseconds. - */ - List time(); - -} diff --git a/src/main/java/com/lambdaworks/redis/RedisSetsAsyncConnection.java b/src/main/java/com/lambdaworks/redis/RedisSetsAsyncConnection.java deleted file mode 100644 index 1a5c4aa759..0000000000 --- a/src/main/java/com/lambdaworks/redis/RedisSetsAsyncConnection.java +++ /dev/null @@ -1,292 +0,0 @@ -package com.lambdaworks.redis; - -import java.util.List; -import java.util.Set; - -import com.lambdaworks.redis.api.async.RedisSetAsyncCommands; -import com.lambdaworks.redis.output.ValueStreamingChannel; - -/** - * Asynchronous executed commands for Sets. - * - * @param Key type. - * @param Value type. - * @author Mark Paluch - * @since 3.0 - * @deprecated Use {@link RedisSetAsyncCommands} - */ -@Deprecated -public interface RedisSetsAsyncConnection { - - /** - * Add one or more members to a set. - * - * @param key the key - * @param members the member type: value - * @return RedisFuture<Long> integer-reply the number of elements that were added to the set, not including all the - * elements already present into the set. - */ - RedisFuture sadd(K key, V... members); - - /** - * Get the number of members in a set. - * - * @param key the key - * @return RedisFuture<Long> integer-reply the cardinality (number of elements) of the set, or {@literal false} if - * {@code key} does not exist. - */ - RedisFuture scard(K key); - - /** - * Subtract multiple sets. - * - * @param keys the key - * @return RedisFuture<Set<V>> array-reply list with members of the resulting set. - */ - RedisFuture> sdiff(K... keys); - - /** - * Subtract multiple sets. - * - * @param channel streaming channel that receives a call for every value - * @param keys the keys - * @return RedisFuture<Long> count of members of the resulting set. - */ - RedisFuture sdiff(ValueStreamingChannel channel, K... keys); - - /** - * Subtract multiple sets and store the resulting set in a key. - * - * @param destination the destination type: key - * @param keys the key - * @return RedisFuture<Long> integer-reply the number of elements in the resulting set. - */ - RedisFuture sdiffstore(K destination, K... keys); - - /** - * Intersect multiple sets. - * - * @param keys the key - * @return RedisFuture<Set<V>> array-reply list with members of the resulting set. - */ - RedisFuture> sinter(K... keys); - - /** - * Intersect multiple sets. - * - * @param channel streaming channel that receives a call for every value - * @param keys the keys - * @return RedisFuture<Long> count of members of the resulting set. - */ - RedisFuture sinter(ValueStreamingChannel channel, K... keys); - - /** - * Intersect multiple sets and store the resulting set in a key. - * - * @param destination the destination type: key - * @param keys the key - * @return RedisFuture<Long> integer-reply the number of elements in the resulting set. - */ - RedisFuture sinterstore(K destination, K... keys); - - /** - * Determine if a given value is a member of a set. - * - * @param key the key - * @param member the member type: value - * @return RedisFuture<Boolean> integer-reply specifically: - * - * {@literal true} if the element is a member of the set. {@literal false} if the element is not a member of the - * set, or if {@code key} does not exist. - */ - RedisFuture sismember(K key, V member); - - /** - * Move a member from one set to another. - * - * @param source the source key - * @param destination the destination type: key - * @param member the member type: value - * @return RedisFuture<Boolean> integer-reply specifically: - * - * {@literal true} if the element is moved. {@literal false} if the element is not a member of {@code source} and no - * operation was performed. - */ - RedisFuture smove(K source, K destination, V member); - - /** - * Get all the members in a set. - * - * @param key the key - * @return RedisFuture<Set<V>> array-reply all elements of the set. - */ - RedisFuture> smembers(K key); - - /** - * Get all the members in a set. - * - * @param channel streaming channel that receives a call for every value - * @param key the key - * @return RedisFuture<Long> count of members of the resulting set. - */ - RedisFuture smembers(ValueStreamingChannel channel, K key); - - /** - * Remove and return a random member from a set. - * - * @param key the key - * @return RedisFuture<V> bulk-string-reply the removed element, or {@literal null} when {@code key} does not exist. - */ - RedisFuture spop(K key); - - /** - * Remove and return one or multiple random members from a set. - * - * @param key the key - * @param count number of members to pop - * @return RedisFuture<Set<V>> bulk-string-reply the removed element, or {@literal null} when {@code key} does not exist. - */ - RedisFuture> spop(K key, long count); - - /** - * Get one or multiple random members from a set. - * - * @param key the key - * - * @return RedisFuture<V> bulk-string-reply without the additional {@code count} argument the command returns a Bulk - * Reply with the randomly selected element, or {@literal null} when {@code key} does not exist. - */ - RedisFuture srandmember(K key); - - /** - * Get one or multiple random members from a set. - * - * @param key the key - * @param count the count type: long - * @return RedisFuture<Set<V>> bulk-string-reply without the additional {@code count} argument the command - * returns a Bulk Reply with the randomly selected element, or {@literal null} when {@code key} does not exist. - */ - RedisFuture> srandmember(K key, long count); - - /** - * Get one or multiple random members from a set. - * - * @param channel streaming channel that receives a call for every value - * @param key the key - * @param count the count - * @return RedisFuture<Long> count of members of the resulting set. - */ - RedisFuture srandmember(ValueStreamingChannel channel, K key, long count); - - /** - * Remove one or more members from a set. - * - * @param key the key - * @param members the member type: value - * @return RedisFuture<Long> integer-reply the number of members that were removed from the set, not including non - * existing members. - */ - RedisFuture srem(K key, V... members); - - /** - * Add multiple sets. - * - * @param keys the key - * @return RedisFuture<Set<V>> array-reply list with members of the resulting set. - */ - RedisFuture> sunion(K... keys); - - /** - * Add multiple sets. - * - * @param channel streaming channel that receives a call for every value - * @param keys the key - * @return RedisFuture<Long> count of members of the resulting set. - */ - RedisFuture sunion(ValueStreamingChannel channel, K... keys); - - /** - * Add multiple sets and store the resulting set in a key. - * - * @param destination the destination type: key - * @param keys the key - * @return RedisFuture<Long> integer-reply the number of elements in the resulting set. - */ - RedisFuture sunionstore(K destination, K... keys); - - /** - * Incrementally iterate Set elements. - * - * @param key the key - * @return RedisFuture<ValueScanCursor>V<> scan cursor. - */ - RedisFuture> sscan(K key); - - /** - * Incrementally iterate Set elements. - * - * @param key the key - * @param scanArgs scan arguments - * @return RedisFuture<ValueScanCursor>V<> scan cursor. - */ - RedisFuture> sscan(K key, ScanArgs scanArgs); - - /** - * Incrementally iterate Set elements. - * - * @param key the key - * @param scanCursor cursor to resume from a previous scan, must not be {@literal null} - * @param scanArgs scan arguments - * @return RedisFuture<ValueScanCursor>V<> scan cursor. - */ - RedisFuture> sscan(K key, ScanCursor scanCursor, ScanArgs scanArgs); - - /** - * Incrementally iterate Set elements. - * - * @param key the key - * @param scanCursor cursor to resume from a previous scan, must not be {@literal null} - * @return RedisFuture<ValueScanCursor>V<> scan cursor. - */ - RedisFuture> sscan(K key, ScanCursor scanCursor); - - /** - * Incrementally iterate Set elements. - * - * @param channel streaming channel that receives a call for every value - * @param key the key - * @return RedisFuture<StreamScanCursor> scan cursor. - */ - RedisFuture sscan(ValueStreamingChannel channel, K key); - - /** - * Incrementally iterate Set elements. - * - * @param channel streaming channel that receives a call for every value - * @param key the key - * @param scanArgs scan arguments - * @return RedisFuture<StreamScanCursor> scan cursor. - */ - RedisFuture sscan(ValueStreamingChannel channel, K key, ScanArgs scanArgs); - - /** - * Incrementally iterate Set elements. - * - * @param channel streaming channel that receives a call for every value - * @param key the key - * @param scanCursor cursor to resume from a previous scan, must not be {@literal null} - * @param scanArgs scan arguments - * @return RedisFuture<StreamScanCursor> scan cursor. - */ - RedisFuture sscan(ValueStreamingChannel channel, K key, ScanCursor scanCursor, ScanArgs scanArgs); - - /** - * Incrementally iterate Set elements. - * - * @param channel streaming channel that receives a call for every value - * @param key the key - * @param scanCursor cursor to resume from a previous scan, must not be {@literal null} - * @return RedisFuture<StreamScanCursor> scan cursor. - */ - RedisFuture sscan(ValueStreamingChannel channel, K key, ScanCursor scanCursor); -} diff --git a/src/main/java/com/lambdaworks/redis/RedisSetsConnection.java b/src/main/java/com/lambdaworks/redis/RedisSetsConnection.java deleted file mode 100644 index 9104cb8d02..0000000000 --- a/src/main/java/com/lambdaworks/redis/RedisSetsConnection.java +++ /dev/null @@ -1,291 +0,0 @@ -package com.lambdaworks.redis; - -import java.util.List; -import java.util.Set; - -import com.lambdaworks.redis.api.sync.RedisSetCommands; -import com.lambdaworks.redis.output.ValueStreamingChannel; - -/** - * Synchronous executed commands for Sets. - * - * @param Key type. - * @param Value type. - * @author Mark Paluch - * @since 3.0 - * @deprecated Use {@link RedisSetCommands} - */ -@Deprecated -public interface RedisSetsConnection { - - /** - * Add one or more members to a set. - * - * @param key the key - * @param members the member type: value - * @return Long integer-reply the number of elements that were added to the set, not including all the elements already - * present into the set. - */ - Long sadd(K key, V... members); - - /** - * Get the number of members in a set. - * - * @param key the key - * @return Long integer-reply the cardinality (number of elements) of the set, or {@literal false} if {@code key} does not - * exist. - */ - Long scard(K key); - - /** - * Subtract multiple sets. - * - * @param keys the key - * @return Set<V> array-reply list with members of the resulting set. - */ - Set sdiff(K... keys); - - /** - * Subtract multiple sets. - * - * @param channel the channel - * @param keys the keys - * @return Long count of members of the resulting set. - */ - Long sdiff(ValueStreamingChannel channel, K... keys); - - /** - * Subtract multiple sets and store the resulting set in a key. - * - * @param destination the destination type: key - * @param keys the key - * @return Long integer-reply the number of elements in the resulting set. - */ - Long sdiffstore(K destination, K... keys); - - /** - * Intersect multiple sets. - * - * @param keys the key - * @return Set<V> array-reply list with members of the resulting set. - */ - Set sinter(K... keys); - - /** - * Intersect multiple sets. - * - * @param channel the channel - * @param keys the keys - * @return Long count of members of the resulting set. - */ - Long sinter(ValueStreamingChannel channel, K... keys); - - /** - * Intersect multiple sets and store the resulting set in a key. - * - * @param destination the destination type: key - * @param keys the key - * @return Long integer-reply the number of elements in the resulting set. - */ - Long sinterstore(K destination, K... keys); - - /** - * Determine if a given value is a member of a set. - * - * @param key the key - * @param member the member type: value - * @return Boolean integer-reply specifically: - * - * {@literal true} if the element is a member of the set. {@literal false} if the element is not a member of the - * set, or if {@code key} does not exist. - */ - Boolean sismember(K key, V member); - - /** - * Move a member from one set to another. - * - * @param source the source key - * @param destination the destination type: key - * @param member the member type: value - * @return Boolean integer-reply specifically: - * - * {@literal true} if the element is moved. {@literal false} if the element is not a member of {@code source} and no - * operation was performed. - */ - Boolean smove(K source, K destination, V member); - - /** - * Get all the members in a set. - * - * @param key the key - * @return Set<V> array-reply all elements of the set. - */ - Set smembers(K key); - - /** - * Get all the members in a set. - * - * @param channel the channel - * @param key the keys - * @return Long count of members of the resulting set. - */ - Long smembers(ValueStreamingChannel channel, K key); - - /** - * Remove and return a random member from a set. - * - * @param key the key - * @return V bulk-string-reply the removed element, or {@literal null} when {@code key} does not exist. - */ - V spop(K key); - - /** - * Remove and return one or multiple random members from a set. - * - * @param key the key - * @param count number of members to pop - * @return Set<V> bulk-string-reply the removed element, or {@literal null} when {@code key} does not exist. - */ - Set spop(K key, long count); - - /** - * Get one or multiple random members from a set. - * - * @param key the key - * - * @return V bulk-string-reply without the additional {@code count} argument the command returns a Bulk Reply with the - * randomly selected element, or {@literal null} when {@code key} does not exist. - */ - V srandmember(K key); - - /** - * Get one or multiple random members from a set. - * - * @param key the key - * @param count the count type: long - * @return Set<V> bulk-string-reply without the additional {@code count} argument the command returns a Bulk Reply - * with the randomly selected element, or {@literal null} when {@code key} does not exist. - */ - List srandmember(K key, long count); - - /** - * Get one or multiple random members from a set. - * - * @param channel streaming channel that receives a call for every value - * @param key the key - * @param count the count - * @return Long count of members of the resulting set. - */ - Long srandmember(ValueStreamingChannel channel, K key, long count); - - /** - * Remove one or more members from a set. - * - * @param key the key - * @param members the member type: value - * @return Long integer-reply the number of members that were removed from the set, not including non existing members. - */ - Long srem(K key, V... members); - - /** - * Add multiple sets. - * - * @param keys the key - * @return Set<V> array-reply list with members of the resulting set. - */ - Set sunion(K... keys); - - /** - * Add multiple sets. - * - * @param channel streaming channel that receives a call for every value - * @param keys the keys - * @return Long count of members of the resulting set. - */ - Long sunion(ValueStreamingChannel channel, K... keys); - - /** - * Add multiple sets and store the resulting set in a key. - * - * @param destination the destination type: key - * @param keys the key - * @return Long integer-reply the number of elements in the resulting set. - */ - Long sunionstore(K destination, K... keys); - - /** - * Incrementally iterate Set elements. - * - * @param key the key - * @return ValueScanCursor<V> scan cursor. - */ - ValueScanCursor sscan(K key); - - /** - * Incrementally iterate Set elements. - * - * @param key the key - * @param scanArgs scan arguments - * @return ValueScanCursor<V> scan cursor. - */ - ValueScanCursor sscan(K key, ScanArgs scanArgs); - - /** - * Incrementally iterate Set elements. - * - * @param key the key - * @param scanCursor cursor to resume from a previous scan, must not be {@literal null} - * @param scanArgs scan arguments - * @return ValueScanCursor<V> scan cursor. - */ - ValueScanCursor sscan(K key, ScanCursor scanCursor, ScanArgs scanArgs); - - /** - * Incrementally iterate Set elements. - * - * @param key the key - * @param scanCursor cursor to resume from a previous scan, must not be {@literal null} - * @return ValueScanCursor<V> scan cursor. - */ - ValueScanCursor sscan(K key, ScanCursor scanCursor); - - /** - * Incrementally iterate Set elements. - * - * @param channel streaming channel that receives a call for every value - * @param key the key - * @return StreamScanCursor scan cursor. - */ - StreamScanCursor sscan(ValueStreamingChannel channel, K key); - - /** - * Incrementally iterate Set elements. - * - * @param channel streaming channel that receives a call for every value - * @param key the key - * @param scanArgs scan arguments - * @return StreamScanCursor scan cursor. - */ - StreamScanCursor sscan(ValueStreamingChannel channel, K key, ScanArgs scanArgs); - - /** - * Incrementally iterate Set elements. - * - * @param channel streaming channel that receives a call for every value - * @param key the key - * @param scanCursor cursor to resume from a previous scan, must not be {@literal null} - * @param scanArgs scan arguments - * @return StreamScanCursor scan cursor. - */ - StreamScanCursor sscan(ValueStreamingChannel channel, K key, ScanCursor scanCursor, ScanArgs scanArgs); - - /** - * Incrementally iterate Set elements. - * - * @param channel streaming channel that receives a call for every value - * @param key the key - * @param scanCursor cursor to resume from a previous scan, must not be {@literal null} - * @return StreamScanCursor scan cursor. - */ - StreamScanCursor sscan(ValueStreamingChannel channel, K key, ScanCursor scanCursor); -} diff --git a/src/main/java/com/lambdaworks/redis/RedisSortedSetsAsyncConnection.java b/src/main/java/com/lambdaworks/redis/RedisSortedSetsAsyncConnection.java deleted file mode 100644 index e30e008c01..0000000000 --- a/src/main/java/com/lambdaworks/redis/RedisSortedSetsAsyncConnection.java +++ /dev/null @@ -1,812 +0,0 @@ -package com.lambdaworks.redis; - -import java.util.List; - -import com.lambdaworks.redis.api.async.RedisSortedSetAsyncCommands; -import com.lambdaworks.redis.output.ScoredValueStreamingChannel; -import com.lambdaworks.redis.output.ValueStreamingChannel; - -/** - * Asynchronous executed commands for Sorted Sets. - * - * @param Key type. - * @param Value type. - * @author Mark Paluch - * @since 3.0 - * @deprecated Use {@literal RedisSortedSetAsyncCommands} - */ -@Deprecated -public interface RedisSortedSetsAsyncConnection { - /** - * Add one or more members to a sorted set, or update its score if it already exists. - * - * @param key the key - * @param score the score - * @param member the member - * - * @return RedisFuture<Long> integer-reply specifically: - * - * The number of elements added to the sorted sets, not including elements already existing for which the score was - * updated. - */ - RedisFuture zadd(K key, double score, V member); - - /** - * Add one or more members to a sorted set, or update its score if it already exists. - * - * @param key the key - * @param scoresAndValues the scoresAndValue tuples (score,value,score,value,...) - * @return RedisFuture<Long> integer-reply specifically: - * - * The number of elements added to the sorted sets, not including elements already existing for which the score was - * updated. - */ - RedisFuture zadd(K key, Object... scoresAndValues); - - /** - * Add one or more members to a sorted set, or update its score if it already exists. - * - * @param key the key - * @param zAddArgs arguments for zadd - * @param score the score - * @param member the member - * - * @return RedisFuture<Long> integer-reply specifically: - * - * The number of elements added to the sorted sets, not including elements already existing for which the score was - * updated. - */ - RedisFuture zadd(K key, ZAddArgs zAddArgs, double score, V member); - - /** - * Add one or more members to a sorted set, or update its score if it already exists. - * - * @param key the key - * @param zAddArgs arguments for zadd - * @param scoresAndValues the scoresAndValue tuples (score,value,score,value,...) - * @return RedisFuture<Long> integer-reply specifically: - * - * The number of elements added to the sorted sets, not including elements already existing for which the score was - * updated. - */ - RedisFuture zadd(K key, ZAddArgs zAddArgs, Object... scoresAndValues); - - /** - * ZADD acts like ZINCRBY - * - * @param key the key - * @param score the score - * @param member the member - * - * @return RedisFuture<Long> integer-reply specifically: - * - * The total number of elements changed - */ - RedisFuture zaddincr(K key, double score, V member); - - /** - * Get the number of members in a sorted set. - * - * @param key the key - * @return RedisFuture<Long> integer-reply the cardinality (number of elements) of the sorted set, or {@literal false} - * if {@code key} does not exist. - */ - RedisFuture zcard(K key); - - /** - * Count the members in a sorted set with scores within the given values. - * - * @param key the key - * @param min min score - * @param max max score - * @return RedisFuture<Long> integer-reply the number of elements in the specified score range. - */ - RedisFuture zcount(K key, double min, double max); - - /** - * Count the members in a sorted set with scores within the given values. - * - * @param key the key - * @param min min score - * @param max max score - * @return RedisFuture<Long> integer-reply the number of elements in the specified score range. - */ - RedisFuture zcount(K key, String min, String max); - - /** - * Increment the score of a member in a sorted set. - * - * @param key the key - * @param amount the increment type: long - * @param member the member type: key - * @return RedisFuture<Double;> bulk-string-reply the new score of {@code member} (a double precision floating point - * number), represented as string. - */ - RedisFuture zincrby(K key, double amount, K member); - - /** - * Intersect multiple sorted sets and store the resulting sorted set in a new key. - * - * @param destination the destination - * @param keys the keys - * - * @return RedisFuture<Long> integer-reply the number of elements in the resulting sorted set at {@code destination}. - */ - RedisFuture zinterstore(K destination, K... keys); - - /** - * Intersect multiple sorted sets and store the resulting sorted set in a new key. - * - * @param destination the destination - * @param storeArgs the storeArgs - * @param keys the keys - * - * @return RedisFuture<Long> integer-reply the number of elements in the resulting sorted set at {@code destination}. - */ - RedisFuture zinterstore(K destination, ZStoreArgs storeArgs, K... keys); - - /** - * Return a range of members in a sorted set, by index. - * - * @param key the key - * @param start the start - * @param stop the stop - * @return RedisFuture<List<V>> array-reply list of elements in the specified range. - */ - RedisFuture> zrange(K key, long start, long stop); - - /** - * Return a range of members in a sorted set, by index. - * - * @param key the key - * @param start the start - * @param stop the stop - * @return RedisFuture<List<ScoredValue<V>>> array-reply list of elements in the specified range. - */ - RedisFuture>> zrangeWithScores(K key, long start, long stop); - - /** - * Return a range of members in a sorted set, by score. - * - * @param key the key - * @param min min score - * @param max max score - * @return RedisFuture<List<V>> array-reply list of elements in the specified score range. - */ - RedisFuture> zrangebyscore(K key, double min, double max); - - /** - * Return a range of members in a sorted set, by score. - * - * @param key the key - * @param min min score - * @param max max score - * @return RedisFuture<List<V>> array-reply list of elements in the specified score range. - */ - RedisFuture> zrangebyscore(K key, String min, String max); - - /** - * Return a range of members in a sorted set, by score. - * - * @param key the key - * @param min min score - * @param max max score - * @param offset the offset - * @param count the count - * @return RedisFuture<List<V>> array-reply list of elements in the specified score range. - */ - RedisFuture> zrangebyscore(K key, double min, double max, long offset, long count); - - /** - * Return a range of members in a sorted set, by score. - * - * @param key the key - * @param min min score - * @param max max score - * @param offset the offset - * @param count the count - * @return RedisFuture<List<V>> array-reply list of elements in the specified score range. - */ - RedisFuture> zrangebyscore(K key, String min, String max, long offset, long count); - - /** - * Return a range of members with score in a sorted set, by score. - * - * @param key the key - * @param min min score - * @param max max score - * @return RedisFuture<List<ScoredValue<V>>> array-reply list of elements in the specified score range. - */ - RedisFuture>> zrangebyscoreWithScores(K key, double min, double max); - - /** - * Return a range of members with score in a sorted set, by score. - * - * @param key the key - * @param min min score - * @param max max score - * @return RedisFuture<List<ScoredValue<V>>> array-reply list of elements in the specified score range. - */ - RedisFuture>> zrangebyscoreWithScores(K key, String min, String max); - - /** - * Return a range of members with score in a sorted set, by score. - * - * @param key the key - * @param min min score - * @param max max score - * @param offset the offset - * @param count the count - * @return RedisFuture<List<ScoredValue<V>>> array-reply list of elements in the specified score range. - */ - RedisFuture>> zrangebyscoreWithScores(K key, double min, double max, long offset, long count); - - /** - * Return a range of members with score in a sorted set, by score. - * - * @param key the key - * @param min min score - * @param max max score - * @param offset the offset - * @param count the count - * @return RedisFuture<List<ScoredValue<V>>> array-reply list of elements in the specified score range. - */ - RedisFuture>> zrangebyscoreWithScores(K key, String min, String max, long offset, long count); - - /** - * Stream over a range of members in a sorted set, by index. - * - * @param channel streaming channel that receives a call for every value - * @param key the key - * @param start the start - * @param stop the stop - * @return RedisFuture<Long> count of elements in the specified range. - */ - RedisFuture zrange(ValueStreamingChannel channel, K key, long start, long stop); - - /** - * Stream over a range of members with scores in a sorted set, by index. - * - * @param channel streaming channel that receives a call for every value - * @param key the key - * @param start the start - * @param stop the stop - * @return RedisFuture<Long> count of elements in the specified range. - */ - RedisFuture zrangeWithScores(ScoredValueStreamingChannel channel, K key, long start, long stop); - - /** - * Stream over a range of members in a sorted set, by score. - * - * @param channel streaming channel that receives a call for every value - * @param key the key - * @param min min score - * @param max max score - * @return RedisFuture<Long> count of elements in the specified score range. - */ - RedisFuture zrangebyscore(ValueStreamingChannel channel, K key, double min, double max); - - /** - * Stream over a range of members in a sorted set, by score. - * - * @param channel streaming channel that receives a call for every value - * @param key the key - * @param min min score - * @param max max score - * @return RedisFuture<Long> count of elements in the specified score range. - */ - RedisFuture zrangebyscore(ValueStreamingChannel channel, K key, String min, String max); - - /** - * Stream over a range of members in a sorted set, by score. - * - * @param channel streaming channel that receives a call for every value - * @param key the key - * @param min min score - * @param max max score - * @param offset the offset - * @param count the count - * @return RedisFuture<Long> count of elements in the specified score range. - */ - RedisFuture zrangebyscore(ValueStreamingChannel channel, K key, double min, double max, long offset, long count); - - /** - * Stream over a range of members in a sorted set, by score. - * - * @param channel streaming channel that receives a call for every value - * @param key the key - * @param min min score - * @param max max score - * @param offset the offset - * @param count the count - * @return RedisFuture<Long> count of elements in the specified score range. - */ - RedisFuture zrangebyscore(ValueStreamingChannel channel, K key, String min, String max, long offset, long count); - - /** - * Stream over a range of members with scores in a sorted set, by score. - * - * @param channel streaming channel that receives a call for every scored value - * @param key the key - * @param min min score - * @param max max score - * @return RedisFuture<Long> count of elements in the specified score range. - */ - RedisFuture zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, double min, double max); - - /** - * Stream over a range of members with scores in a sorted set, by score. - * - * @param channel streaming channel that receives a call for every scored value - * @param key the key - * @param min min score - * @param max max score - * @return RedisFuture<Long> count of elements in the specified score range. - */ - RedisFuture zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, String min, String max); - - /** - * Stream over a range of members with scores in a sorted set, by score. - * - * @param channel streaming channel that receives a call for every scored value - * @param key the key - * @param min min score - * @param max max score - * @param offset the offset - * @param count the count - * @return RedisFuture<Long> count of elements in the specified score range. - */ - RedisFuture zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, double min, double max, - long offset, long count); - - /** - * Stream over a range of members with scores in a sorted set, by score. - * - * @param channel streaming channel that receives a call for every scored value - * @param key the key - * @param min min score - * @param max max score - * @param offset the offset - * @param count the count - * @return RedisFuture<Long> count of elements in the specified score range. - */ - RedisFuture zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, String min, String max, - long offset, long count); - - /** - * Determine the index of a member in a sorted set. - * - * @param key the key - * @param member the member type: value - * @return RedisFuture<Long> integer-reply the rank of {@code member}. If {@code member} does not exist in the sorted - * set or {@code key} does not exist, - */ - RedisFuture zrank(K key, V member); - - /** - * Remove one or more members from a sorted set. - * - * @param key the key - * @param members the member type: value - * @return RedisFuture<Long> integer-reply specifically: - * - * The number of members removed from the sorted set, not including non existing members. - */ - RedisFuture zrem(K key, V... members); - - /** - * Remove all members in a sorted set within the given indexes. - * - * @param key the key - * @param start the start type: long - * @param stop the stop type: long - * @return RedisFuture<Long> integer-reply the number of elements removed. - */ - RedisFuture zremrangebyrank(K key, long start, long stop); - - /** - * Remove all members in a sorted set within the given scores. - * - * @param key the key - * @param min min score - * @param max max score - * @return RedisFuture<Long> integer-reply the number of elements removed. - */ - RedisFuture zremrangebyscore(K key, double min, double max); - - /** - * Remove all members in a sorted set within the given scores. - * - * @param key the key - * @param min min score - * @param max max score - * @return RedisFuture<Long> integer-reply the number of elements removed. - */ - RedisFuture zremrangebyscore(K key, String min, String max); - - /** - * Return a range of members in a sorted set, by index, with scores ordered from high to low. - * - * @param key the key - * @param start the start - * @param stop the stop - * @return RedisFuture<List<V>> array-reply list of elements in the specified range. - */ - RedisFuture> zrevrange(K key, long start, long stop); - - /** - * Return a range of members with scores in a sorted set, by index, with scores ordered from high to low. - * - * @param key the key - * @param start the start - * @param stop the stop - * @return RedisFuture<List<V>> array-reply list of elements in the specified range. - */ - RedisFuture>> zrevrangeWithScores(K key, long start, long stop); - - /** - * Return a range of members in a sorted set, by score, with scores ordered from high to low. - * - * @param key the key - * @param min min score - * @param max max score - * @return RedisFuture<List<V>> array-reply list of elements in the specified score range. - */ - RedisFuture> zrevrangebyscore(K key, double max, double min); - - /** - * Return a range of members in a sorted set, by score, with scores ordered from high to low. - * - * @param key the key - * @param min min score - * @param max max score - * @return RedisFuture<List<V>> array-reply list of elements in the specified score range. - */ - RedisFuture> zrevrangebyscore(K key, String max, String min); - - /** - * Return a range of members in a sorted set, by score, with scores ordered from high to low. - * - * @param key the key - * @param min min score - * @param max max score - * @param offset the offset - * @param count the count - * @return RedisFuture<List<V>> array-reply list of elements in the specified score range. - */ - RedisFuture> zrevrangebyscore(K key, double max, double min, long offset, long count); - - /** - * Return a range of members in a sorted set, by score, with scores ordered from high to low. - * - * @param key the key - * @param max max score - * @param min min score - * @param offset the offset - * @param count the count - * @return RedisFuture<List<V>> array-reply list of elements in the specified score range. - */ - RedisFuture> zrevrangebyscore(K key, String max, String min, long offset, long count); - - /** - * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. - * - * @param key the key - * @param max max score - * @param min min score - * @return RedisFuture<List<ScoredValue<V>>> array-reply list of elements in the specified score range. - */ - RedisFuture>> zrevrangebyscoreWithScores(K key, double max, double min); - - /** - * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. - * - * @param key the key - * @param max max score - * @param min min score - * @return RedisFuture<List<ScoredValue<V>>> array-reply list of elements in the specified score range. - */ - RedisFuture>> zrevrangebyscoreWithScores(K key, String max, String min); - - /** - * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. - * - * @param key the key - * @param max max score - * @param min min score - * @param offset the offset - * @param count the count - * @return RedisFuture<List<ScoredValue<V>>> array-reply list of elements in the specified score range. - */ - RedisFuture>> zrevrangebyscoreWithScores(K key, double max, double min, long offset, long count); - - /** - * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. - * - * @param key the key - * @param max max score - * @param min min score - * @param offset the offset - * @param count the count - * @return RedisFuture<List<ScoredValue<V>>> array-reply list of elements in the specified score range. - */ - RedisFuture>> zrevrangebyscoreWithScores(K key, String max, String min, long offset, long count); - - /** - * Stream over a range of members in a sorted set, by index, with scores ordered from high to low. - * - * @param channel streaming channel that receives a call for every scored value - * @param key the key - * @param start the start - * @param stop the stop - * @return RedisFuture<Long> count of elements in the specified range. - */ - RedisFuture zrevrange(ValueStreamingChannel channel, K key, long start, long stop); - - /** - * Stream over a range of members with scores in a sorted set, by index, with scores ordered from high to low. - * - * @param channel streaming channel that receives a call for every scored value - * @param key the key - * @param start the start - * @param stop the stop - * @return RedisFuture<Long> count of elements in the specified range. - */ - RedisFuture zrevrangeWithScores(ScoredValueStreamingChannel channel, K key, long start, long stop); - - /** - * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. - * - * @param channel streaming channel that receives a call for every value - * @param key the key - * @param max max score - * @param min min score - * @return RedisFuture<Long> count of elements in the specified range. - */ - RedisFuture zrevrangebyscore(ValueStreamingChannel channel, K key, double max, double min); - - /** - * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. - * - * @param channel streaming channel that receives a call for every value - * @param key the key - * @param min min score - * @param max max score - * @return RedisFuture<Long> count of elements in the specified range. - */ - RedisFuture zrevrangebyscore(ValueStreamingChannel channel, K key, String max, String min); - - /** - * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. - * - * @param channel streaming channel that receives a call for every value - * @param key the key - * @param min min score - * @param max max score - * @param offset the offset - * @param count the count - * @return RedisFuture<Long> count of elements in the specified range. - */ - RedisFuture zrevrangebyscore(ValueStreamingChannel channel, K key, double max, double min, long offset, long count); - - /** - * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. - * - * @param channel streaming channel that receives a call for every value - * @param key the key - * @param min min score - * @param max max score - * @param offset the offset - * @param count the count - * @return RedisFuture<Long> count of elements in the specified range. - */ - RedisFuture zrevrangebyscore(ValueStreamingChannel channel, K key, String max, String min, long offset, long count); - - /** - * Stream over a range of members with scores in a sorted set, by score, with scores ordered from high to low. - * - * @param channel streaming channel that receives a call for every scored value - * @param key the key - * @param min min score - * @param max max score - * @return RedisFuture<Long> count of elements in the specified range. - */ - RedisFuture zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, double max, double min); - - /** - * Stream over a range of members with scores in a sorted set, by score, with scores ordered from high to low. - * - * @param channel streaming channel that receives a call for every scored value - * @param key the key - * @param min min score - * @param max max score - * @return RedisFuture<Long> count of elements in the specified range. - */ - RedisFuture zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, String max, String min); - - /** - * Stream over a range of members with scores in a sorted set, by score, with scores ordered from high to low. - * - * @param channel streaming channel that receives a call for every scored value - * @param key the key - * @param min min score - * @param max max score - * @param offset the offset - * @param count the count - * @return RedisFuture<Long> count of elements in the specified range. - */ - RedisFuture zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, double max, double min, - long offset, long count); - - /** - * Stream over a range of members with scores in a sorted set, by score, with scores ordered from high to low. - * - * @param channel streaming channel that receives a call for every scored value - * @param key the key - * @param min min score - * @param max max score - * @param offset the offset - * @param count the count - * @return RedisFuture<Long> count of elements in the specified range. - */ - RedisFuture zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, String max, String min, - long offset, long count); - - /** - * Determine the index of a member in a sorted set, with scores ordered from high to low. - * - * @param key the key - * @param member the member type: value - * @return RedisFuture<Long> integer-reply the rank of {@code member}. If {@code member} does not exist in the sorted - * set or {@code key} does not exist, - */ - RedisFuture zrevrank(K key, V member); - - /** - * Get the score associated with the given member in a sorted set. - * - * @param key the key - * @param member the member type: value - * @return RedisFuture<Double;> bulk-string-reply the score of {@code member} (a double precision floating point - * number), represented as string. - */ - RedisFuture zscore(K key, V member); - - /** - * Add multiple sorted sets and store the resulting sorted set in a new key. - * - * @param destination destination key - * @param keys source keys - * - * @return RedisFuture<Long> integer-reply the number of elements in the resulting sorted set at {@code destination}. - */ - RedisFuture zunionstore(K destination, K... keys); - - /** - * Add multiple sorted sets and store the resulting sorted set in a new key. - * - * @param destination the destination - * @param storeArgs the storeArgs - * @param keys the keys - * @return RedisFuture<Long> integer-reply the number of elements in the resulting sorted set at {@code destination}. - */ - RedisFuture zunionstore(K destination, ZStoreArgs storeArgs, K... keys); - - /** - * Incrementally iterate sorted sets elements and associated scores. - * - * @param key the key - * @return RedisFuture<ScoredValueScanCursor<V>> scan cursor. - */ - RedisFuture> zscan(K key); - - /** - * Incrementally iterate sorted sets elements and associated scores. - * - * @param key the key - * @param scanArgs scan arguments - * @return RedisFuture<ScoredValueScanCursor<V>> scan cursor. - */ - RedisFuture> zscan(K key, ScanArgs scanArgs); - - /** - * Incrementally iterate sorted sets elements and associated scores. - * - * @param key the key - * @param scanCursor cursor to resume from a previous scan, must not be {@literal null} - * @param scanArgs scan arguments - * @return RedisFuture<ScoredValueScanCursor<V>> scan cursor. - */ - RedisFuture> zscan(K key, ScanCursor scanCursor, ScanArgs scanArgs); - - /** - * Incrementally iterate sorted sets elements and associated scores. - * - * @param key the key - * @param scanCursor cursor to resume from a previous scan, must not be {@literal null} - * @return RedisFuture<ScoredValueScanCursor<V>> scan cursor. - */ - RedisFuture> zscan(K key, ScanCursor scanCursor); - - /** - * Incrementally iterate sorted sets elements and associated scores. - * - * @param channel streaming channel that receives a call for every scored value - * @param key the key - * @return RedisFuture<StreamScanCursor> scan cursor. - */ - RedisFuture zscan(ScoredValueStreamingChannel channel, K key); - - /** - * Incrementally iterate sorted sets elements and associated scores. - * - * @param channel streaming channel that receives a call for every scored value - * @param key the key - * @param scanArgs scan arguments - * @return RedisFuture<StreamScanCursor> scan cursor. - */ - RedisFuture zscan(ScoredValueStreamingChannel channel, K key, ScanArgs scanArgs); - - /** - * Incrementally iterate sorted sets elements and associated scores. - * - * @param channel streaming channel that receives a call for every scored value - * @param key the key - * @param scanCursor cursor to resume from a previous scan, must not be {@literal null} - * @param scanArgs scan arguments - * @return RedisFuture<StreamScanCursor> scan cursor. - */ - RedisFuture zscan(ScoredValueStreamingChannel channel, K key, ScanCursor scanCursor, ScanArgs scanArgs); - - /** - * Incrementally iterate sorted sets elements and associated scores. - * - * @param channel streaming channel that receives a call for every scored value - * @param key the key - * @param scanCursor cursor to resume from a previous scan, must not be {@literal null} - * @return RedisFuture<StreamScanCursor> scan cursor. - */ - RedisFuture zscan(ScoredValueStreamingChannel channel, K key, ScanCursor scanCursor); - - /** - * Count the number of members in a sorted set between a given lexicographical range. - * - * @param key the key - * @param min min score - * @param max max score - * @return RedisFuture<Long> integer-reply the number of elements in the specified score range. - */ - RedisFuture zlexcount(K key, String min, String max); - - /** - * Remove all members in a sorted set between the given lexicographical range. - * - * @param key the key - * @param min min score - * @param max max score - * @return RedisFuture<Long> integer-reply the number of elements removed. - */ - RedisFuture zremrangebylex(K key, String min, String max); - - /** - * Return a range of members in a sorted set, by lexicographical range. - * - * @param key the key - * @param min min score - * @param max max score - * @return RedisFuture<List<V>> array-reply list of elements in the specified score range. - */ - RedisFuture> zrangebylex(K key, String min, String max); - - /** - * Return a range of members in a sorted set, by lexicographical range. - * - * @param key the key - * @param min min score - * @param max max score - * @param offset the offset - * @param count the count - * @return RedisFuture<List<V>> array-reply list of elements in the specified score range. - */ - RedisFuture> zrangebylex(K key, String min, String max, long offset, long count); -} diff --git a/src/main/java/com/lambdaworks/redis/RedisSortedSetsConnection.java b/src/main/java/com/lambdaworks/redis/RedisSortedSetsConnection.java deleted file mode 100644 index 97867a80e0..0000000000 --- a/src/main/java/com/lambdaworks/redis/RedisSortedSetsConnection.java +++ /dev/null @@ -1,807 +0,0 @@ -package com.lambdaworks.redis; - -import java.util.List; - -import com.lambdaworks.redis.api.sync.RedisSortedSetCommands; -import com.lambdaworks.redis.output.ScoredValueStreamingChannel; -import com.lambdaworks.redis.output.ValueStreamingChannel; - -/** - * Synchronous executed commands for Sorted Sets. - * - * @param Key type. - * @param Value type. - * @author Mark Paluch - * @since 3.0 - * @deprecated Use {@literal RedisSortedSetCommands} - */ -@Deprecated -public interface RedisSortedSetsConnection { - /** - * Add one or more members to a sorted set, or update its score if it already exists. - * - * @param key the key - * @param score the score - * @param member the member - * - * @return Long integer-reply specifically: - * - * The number of elements added to the sorted sets, not including elements already existing for which the score was - * updated. - */ - Long zadd(K key, double score, V member); - - /** - * Add one or more members to a sorted set, or update its score if it already exists. - * - * @param key the key - * @param scoresAndValues the scoresAndValue tuples (score,value,score,value,...) - * @return Long integer-reply specifically: - * - * The number of elements added to the sorted sets, not including elements already existing for which the score was - * updated. - */ - Long zadd(K key, Object... scoresAndValues); - - /** - * Add one or more members to a sorted set, or update its score if it already exists. - * - * @param key the key - * @param zAddArgs arguments for zadd - * @param score the score - * @param member the member - * - * @return Long integer-reply specifically: - * - * The number of elements added to the sorted sets, not including elements already existing for which the score was - * updated. - */ - Long zadd(K key, ZAddArgs zAddArgs, double score, V member); - - /** - * Add one or more members to a sorted set, or update its score if it already exists. - * - * @param key the key - * @param zAddArgs arguments for zadd - * @param scoresAndValues the scoresAndValue tuples (score,value,score,value,...) - * @return Long integer-reply specifically: - * - * The number of elements added to the sorted sets, not including elements already existing for which the score was - * updated. - */ - Long zadd(K key, ZAddArgs zAddArgs, Object... scoresAndValues); - - /** - * ZADD acts like ZINCRBY - * - * @param key the key - * @param score the score - * @param member the member - * - * @return Long integer-reply specifically: - * - * The total number of elements changed - */ - Double zaddincr(K key, double score, V member); - - /** - * Get the number of members in a sorted set. - * - * @param key the key - * @return Long integer-reply the cardinality (number of elements) of the sorted set, or {@literal false} if {@code key} - * does not exist. - */ - Long zcard(K key); - - /** - * Count the members in a sorted set with scores within the given values. - * - * @param key the key - * @param min min score - * @param max max score - * @return Long integer-reply the number of elements in the specified score range. - */ - Long zcount(K key, double min, double max); - - /** - * Count the members in a sorted set with scores within the given values. - * - * @param key the key - * @param min min score - * @param max max score - * @return Long integer-reply the number of elements in the specified score range. - */ - Long zcount(K key, String min, String max); - - /** - * Increment the score of a member in a sorted set. - * - * @param key the key - * @param amount the increment type: long - * @param member the member type: key - * @return Double bulk-string-reply the new score of {@code member} (a double precision floating point number), represented - * as string. - */ - Double zincrby(K key, double amount, K member); - - /** - * Intersect multiple sorted sets and store the resulting sorted set in a new key. - * - * @param destination the destination - * @param keys the keys - * @return Long integer-reply the number of elements in the resulting sorted set at {@code destination}. - */ - Long zinterstore(K destination, K... keys); - - /** - * Intersect multiple sorted sets and store the resulting sorted set in a new key. - * - * @param destination the destination - * @param storeArgs the storeArgs - * @param keys the keys - * @return Long integer-reply the number of elements in the resulting sorted set at {@code destination}. - */ - Long zinterstore(K destination, ZStoreArgs storeArgs, K... keys); - - /** - * Return a range of members in a sorted set, by index. - * - * @param key the key - * @param start the start - * @param stop the stop - * @return List<V> array-reply list of elements in the specified range. - */ - List zrange(K key, long start, long stop); - - /** - * Return a range of members with scores in a sorted set, by index. - * - * @param key the key - * @param start the start - * @param stop the stop - * @return List<V> array-reply list of elements in the specified range. - */ - List> zrangeWithScores(K key, long start, long stop); - - /** - * Return a range of members in a sorted set, by score. - * - * @param key the key - * @param min min score - * @param max max score - * @return List<V> array-reply list of elements in the specified score range. - */ - List zrangebyscore(K key, double min, double max); - - /** - * Return a range of members in a sorted set, by score. - * - * @param key the key - * @param min min score - * @param max max score - * @return List<V> array-reply list of elements in the specified score range. - */ - List zrangebyscore(K key, String min, String max); - - /** - * Return a range of members in a sorted set, by score. - * - * @param key the key - * @param min min score - * @param max max score - * @param offset the offset - * @param count the count - * @return List<V> array-reply list of elements in the specified score range. - */ - List zrangebyscore(K key, double min, double max, long offset, long count); - - /** - * Return a range of members in a sorted set, by score. - * - * @param key the key - * @param min min score - * @param max max score - * @param offset the offset - * @param count the count - * @return List<V> array-reply list of elements in the specified score range. - */ - List zrangebyscore(K key, String min, String max, long offset, long count); - - /** - * Return a range of members with score in a sorted set, by score. - * - * @param key the key - * @param min min score - * @param max max score - * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. - */ - List> zrangebyscoreWithScores(K key, double min, double max); - - /** - * Return a range of members with score in a sorted set, by score. - * - * @param key the key - * @param min min score - * @param max max score - * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. - */ - List> zrangebyscoreWithScores(K key, String min, String max); - - /** - * Return a range of members with score in a sorted set, by score. - * - * @param key the key - * @param min min score - * @param max max score - * @param offset the offset - * @param count the count - * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. - */ - List> zrangebyscoreWithScores(K key, double min, double max, long offset, long count); - - /** - * Return a range of members with score in a sorted set, by score. - * - * @param key the key - * @param min min score - * @param max max score - * @param offset the offset - * @param count the count - * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. - */ - List> zrangebyscoreWithScores(K key, String min, String max, long offset, long count); - - /** - * Return a range of members in a sorted set, by index. - * - * @param channel streaming channel that receives a call for every value - * @param key the key - * @param start the start - * @param stop the stop - * @return Long count of elements in the specified range. - */ - Long zrange(ValueStreamingChannel channel, K key, long start, long stop); - - /** - * Stream over a range of members with scores in a sorted set, by index. - * - * @param channel streaming channel that receives a call for every value - * @param key the key - * @param start the start - * @param stop the stop - * @return Long count of elements in the specified range. - */ - Long zrangeWithScores(ScoredValueStreamingChannel channel, K key, long start, long stop); - - /** - * Stream over a range of members in a sorted set, by score. - * - * @param channel streaming channel that receives a call for every value - * @param key the key - * @param min min score - * @param max max score - * @return Long count of elements in the specified score range. - */ - Long zrangebyscore(ValueStreamingChannel channel, K key, double min, double max); - - /** - * Stream over a range of members in a sorted set, by score. - * - * @param channel streaming channel that receives a call for every value - * @param key the key - * @param min min score - * @param max max score - * @return Long count of elements in the specified score range. - */ - Long zrangebyscore(ValueStreamingChannel channel, K key, String min, String max); - - /** - * Stream over range of members in a sorted set, by score. - * - * @param channel streaming channel that receives a call for every value - * @param key the key - * @param min min score - * @param max max score - * @param offset the offset - * @param count the count - * @return Long count of elements in the specified score range. - */ - Long zrangebyscore(ValueStreamingChannel channel, K key, double min, double max, long offset, long count); - - /** - * Stream over a range of members in a sorted set, by score. - * - * @param channel streaming channel that receives a call for every value - * @param key the key - * @param min min score - * @param max max score - * @param offset the offset - * @param count the count - * @return Long count of elements in the specified score range. - */ - Long zrangebyscore(ValueStreamingChannel channel, K key, String min, String max, long offset, long count); - - /** - * Stream over a range of members with scores in a sorted set, by score. - * - * @param channel streaming channel that receives a call for every scored value - * @param key the key - * @param min min score - * @param max max score - * @return Long count of elements in the specified score range. - */ - Long zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, double min, double max); - - /** - * Stream over a range of members with scores in a sorted set, by score. - * - * @param channel streaming channel that receives a call for every scored value - * @param key the key - * @param min min score - * @param max max score - * @return Long count of elements in the specified score range. - */ - Long zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, String min, String max); - - /** - * Stream over a range of members with scores in a sorted set, by score. - * - * @param channel streaming channel that receives a call for every scored value - * @param key the key - * @param min min score - * @param max max score - * @param offset the offset - * @param count the count - * @return Long count of elements in the specified score range. - */ - Long zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, double min, double max, long offset, long count); - - /** - * Stream over a range of members with scores in a sorted set, by score. - * - * @param channel streaming channel that receives a call for every scored value - * @param key the key - * @param min min score - * @param max max score - * @param offset the offset - * @param count the count - * @return Long count of elements in the specified score range. - */ - Long zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, String min, String max, long offset, long count); - - /** - * Determine the index of a member in a sorted set. - * - * @param key the key - * @param member the member type: value - * @return Long integer-reply the rank of {@code member}. If {@code member} does not exist in the sorted set or {@code key} - * does not exist, - */ - Long zrank(K key, V member); - - /** - * Remove one or more members from a sorted set. - * - * @param key the key - * @param members the member type: value - * @return Long integer-reply specifically: - * - * The number of members removed from the sorted set, not including non existing members. - */ - Long zrem(K key, V... members); - - /** - * Remove all members in a sorted set within the given indexes. - * - * @param key the key - * @param start the start type: long - * @param stop the stop type: long - * @return Long integer-reply the number of elements removed. - */ - Long zremrangebyrank(K key, long start, long stop); - - /** - * Remove all members in a sorted set within the given scores. - * - * @param key the key - * @param min min score - * @param max max score - * @return Long integer-reply the number of elements removed. - */ - Long zremrangebyscore(K key, double min, double max); - - /** - * Remove all members in a sorted set within the given scores. - * - * @param key the key - * @param min min score - * @param max max score - * @return Long integer-reply the number of elements removed. - */ - Long zremrangebyscore(K key, String min, String max); - - /** - * Return a range of members in a sorted set, by index, with scores ordered from high to low. - * - * @param key the key - * @param start the start - * @param stop the stop - * @return List<V> array-reply list of elements in the specified range. - */ - List zrevrange(K key, long start, long stop); - - /** - * Return a range of members with scores in a sorted set, by index, with scores ordered from high to low. - * - * @param key the key - * @param start the start - * @param stop the stop - * @return List<V> array-reply list of elements in the specified range. - */ - List> zrevrangeWithScores(K key, long start, long stop); - - /** - * Return a range of members in a sorted set, by score, with scores ordered from high to low. - * - * @param key the key - * @param min min score - * @param max max score - * @return List<V> array-reply list of elements in the specified score range. - */ - List zrevrangebyscore(K key, double max, double min); - - /** - * Return a range of members in a sorted set, by score, with scores ordered from high to low. - * - * @param key the key - * @param min min score - * @param max max score - * @return List<V> array-reply list of elements in the specified score range. - */ - List zrevrangebyscore(K key, String max, String min); - - /** - * Return a range of members in a sorted set, by score, with scores ordered from high to low. - * - * @param key the key - * @param max max score - * @param min min score - * @param offset the withscores - * @param count the null - * @return List<V> array-reply list of elements in the specified score range. - */ - List zrevrangebyscore(K key, double max, double min, long offset, long count); - - /** - * Return a range of members in a sorted set, by score, with scores ordered from high to low. - * - * @param key the key - * @param max max score - * @param min min score - * @param offset the offset - * @param count the count - * @return List<V> array-reply list of elements in the specified score range. - */ - List zrevrangebyscore(K key, String max, String min, long offset, long count); - - /** - * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. - * - * @param key the key - * @param max max score - * @param min min score - * @return List<V> array-reply list of elements in the specified score range. - */ - List> zrevrangebyscoreWithScores(K key, double max, double min); - - /** - * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. - * - * @param key the key - * @param max max score - * @param min min score - * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. - */ - List> zrevrangebyscoreWithScores(K key, String max, String min); - - /** - * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. - * - * @param key the key - * @param max max score - * @param min min score - * @param offset the offset - * @param count the count - * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. - */ - List> zrevrangebyscoreWithScores(K key, double max, double min, long offset, long count); - - /** - * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. - * - * @param key the key - * @param max max score - * @param min min score - * @param offset the offset - * @param count the count - * @return List<V> array-reply list of elements in the specified score range. - */ - List> zrevrangebyscoreWithScores(K key, String max, String min, long offset, long count); - - /** - * Stream over a range of members in a sorted set, by index, with scores ordered from high to low. - * - * @param channel streaming channel that receives a call for every scored value - * @param key the key - * @param start the start - * @param stop the stop - * @return Long count of elements in the specified range. - */ - Long zrevrange(ValueStreamingChannel channel, K key, long start, long stop); - - /** - * Stream over a range of members with scores in a sorted set, by index, with scores ordered from high to low. - * - * @param channel streaming channel that receives a call for every scored value - * @param key the key - * @param start the start - * @param stop the stop - * @return Long count of elements in the specified range. - */ - Long zrevrangeWithScores(ScoredValueStreamingChannel channel, K key, long start, long stop); - - /** - * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. - * - * @param channel streaming channel that receives a call for every value - * @param key the key - * @param max max score - * @param min min score - * @return Long count of elements in the specified range. - */ - Long zrevrangebyscore(ValueStreamingChannel channel, K key, double max, double min); - - /** - * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. - * - * @param channel streaming channel that receives a call for every value - * @param key the key - * @param min min score - * @param max max score - * @return Long count of elements in the specified range. - */ - Long zrevrangebyscore(ValueStreamingChannel channel, K key, String max, String min); - - /** - * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. - * - * @param channel streaming channel that receives a call for every value - * @param key the key - * @param min min score - * @param max max score - * @param offset the offset - * @param count the count - * @return Long count of elements in the specified range. - */ - Long zrevrangebyscore(ValueStreamingChannel channel, K key, double max, double min, long offset, long count); - - /** - * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. - * - * @param channel streaming channel that receives a call for every value - * @param key the key - * @param min min score - * @param max max score - * @param offset the offset - * @param count the count - * @return Long count of elements in the specified range. - */ - Long zrevrangebyscore(ValueStreamingChannel channel, K key, String max, String min, long offset, long count); - - /** - * Stream over a range of members with scores in a sorted set, by score, with scores ordered from high to low. - * - * @param channel streaming channel that receives a call for every scored value - * @param key the key - * @param min min score - * @param max max score - * @return Long count of elements in the specified range. - */ - Long zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, double max, double min); - - /** - * Stream over a range of members with scores in a sorted set, by score, with scores ordered from high to low. - * - * @param channel streaming channel that receives a call for every scored value - * @param key the key - * @param min min score - * @param max max score - * @return Long count of elements in the specified range. - */ - Long zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, String max, String min); - - /** - * Stream over a range of members with scores in a sorted set, by score, with scores ordered from high to low. - * - * @param channel streaming channel that receives a call for every scored value - * @param key the key - * @param min min score - * @param max max score - * @param offset the offset - * @param count the count - * @return Long count of elements in the specified range. - */ - Long zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, double max, double min, long offset, - long count); - - /** - * Stream over a range of members with scores in a sorted set, by score, with scores ordered from high to low. - * - * @param channel streaming channel that receives a call for every scored value - * @param key the key - * @param min min score - * @param max max score - * @param offset the offset - * @param count the count - * @return Long count of elements in the specified range. - */ - Long zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, String max, String min, long offset, - long count); - - /** - * Determine the index of a member in a sorted set, with scores ordered from high to low. - * - * @param key the key - * @param member the member type: value - * @return Long integer-reply the rank of {@code member}. If {@code member} does not exist in the sorted set or {@code key} - * does not exist, - */ - Long zrevrank(K key, V member); - - /** - * Get the score associated with the given member in a sorted set. - * - * @param key the key - * @param member the member type: value - * @return Double bulk-string-reply the score of {@code member} (a double precision floating point number), represented as - * string. - */ - Double zscore(K key, V member); - - /** - * Add multiple sorted sets and store the resulting sorted set in a new key. - * - * @param destination destination key - * @param keys source keys - * @return Long integer-reply the number of elements in the resulting sorted set at {@code destination}. - */ - Long zunionstore(K destination, K... keys); - - /** - * Add multiple sorted sets and store the resulting sorted set in a new key. - * - * @param destination the destination - * @param storeArgs the storeArgs - * @param keys the keys - * @return Long integer-reply the number of elements in the resulting sorted set at {@code destination}. - */ - Long zunionstore(K destination, ZStoreArgs storeArgs, K... keys); - - /** - * Incrementally iterate sorted sets elements and associated scores. - * - * @param key the key - * @return ScoredValueScanCursor<V> scan cursor. - */ - ScoredValueScanCursor zscan(K key); - - /** - * Incrementally iterate sorted sets elements and associated scores. - * - * @param key the key - * @param scanArgs scan arguments - * @return ScoredValueScanCursor<V> scan cursor. - */ - ScoredValueScanCursor zscan(K key, ScanArgs scanArgs); - - /** - * Incrementally iterate sorted sets elements and associated scores. - * - * @param key the key - * @param scanCursor cursor to resume from a previous scan, must not be {@literal null} - * @param scanArgs scan arguments - * @return ScoredValueScanCursor<V> scan cursor. - */ - ScoredValueScanCursor zscan(K key, ScanCursor scanCursor, ScanArgs scanArgs); - - /** - * Incrementally iterate sorted sets elements and associated scores. - * - * @param key the key - * @param scanCursor cursor to resume from a previous scan, must not be {@literal null} - * @return ScoredValueScanCursor<V> scan cursor. - */ - ScoredValueScanCursor zscan(K key, ScanCursor scanCursor); - - /** - * Incrementally iterate sorted sets elements and associated scores. - * - * @param channel streaming channel that receives a call for every scored value - * @param key the key - * @return StreamScanCursor scan cursor. - */ - StreamScanCursor zscan(ScoredValueStreamingChannel channel, K key); - - /** - * Incrementally iterate sorted sets elements and associated scores. - * - * @param channel streaming channel that receives a call for every scored value - * @param key the key - * @param scanArgs scan arguments - * @return StreamScanCursor scan cursor. - */ - StreamScanCursor zscan(ScoredValueStreamingChannel channel, K key, ScanArgs scanArgs); - - /** - * Incrementally iterate sorted sets elements and associated scores. - * - * @param channel streaming channel that receives a call for every scored value - * @param key the key - * @param scanCursor cursor to resume from a previous scan, must not be {@literal null} - * @param scanArgs scan arguments - * @return StreamScanCursor scan cursor. - */ - StreamScanCursor zscan(ScoredValueStreamingChannel channel, K key, ScanCursor scanCursor, ScanArgs scanArgs); - - /** - * Incrementally iterate sorted sets elements and associated scores. - * - * @param channel streaming channel that receives a call for every scored value - * @param key the key - * @param scanCursor cursor to resume from a previous scan, must not be {@literal null} - * @return StreamScanCursor scan cursor. - */ - StreamScanCursor zscan(ScoredValueStreamingChannel channel, K key, ScanCursor scanCursor); - - /** - * Count the number of members in a sorted set between a given lexicographical range. - * - * @param key the key - * @param min min score - * @param max max score - * @return Long integer-reply the number of elements in the specified score range. - */ - Long zlexcount(K key, String min, String max); - - /** - * Remove all members in a sorted set between the given lexicographical range. - * - * @param key the key - * @param min min score - * @param max max score - * @return Long integer-reply the number of elements removed. - */ - Long zremrangebylex(K key, String min, String max); - - /** - * Return a range of members in a sorted set, by lexicographical range. - * - * @param key the key - * @param min min score - * @param max max score - * @return List<V> array-reply list of elements in the specified score range. - */ - List zrangebylex(K key, String min, String max); - - /** - * Return a range of members in a sorted set, by lexicographical range. - * - * @param key the key - * @param min min score - * @param max max score - * @param offset the offset - * @param count the count - * @return List<V> array-reply list of elements in the specified score range. - */ - List zrangebylex(K key, String min, String max, long offset, long count); -} diff --git a/src/main/java/com/lambdaworks/redis/RedisStringsAsyncConnection.java b/src/main/java/com/lambdaworks/redis/RedisStringsAsyncConnection.java deleted file mode 100644 index df1bb95452..0000000000 --- a/src/main/java/com/lambdaworks/redis/RedisStringsAsyncConnection.java +++ /dev/null @@ -1,347 +0,0 @@ -package com.lambdaworks.redis; - -import com.lambdaworks.redis.output.ValueStreamingChannel; - -import java.util.List; -import java.util.Map; - -/** - * Asynchronous executed commands for Strings. - * - * @param Key type. - * @param Value type. - * @author Mark Paluch - * @since 3.0 - * @deprecated Use {@literal RedisStringAsyncCommands} - */ -@Deprecated -public interface RedisStringsAsyncConnection { - - /** - * Append a value to a key. - * - * @param key the key - * @param value the value - * @return RedisFuture<Long> integer-reply the length of the string after the append operation. - */ - RedisFuture append(K key, V value); - - /** - * Count set bits in a string. - * - * @param key the key - * - * @return RedisFuture<Long> integer-reply The number of bits set to 1. - */ - RedisFuture bitcount(K key); - - /** - * Count set bits in a string. - * - * @param key the key - * @param start the start - * @param end the end - * - * @return RedisFuture<Long> integer-reply The number of bits set to 1. - */ - RedisFuture bitcount(K key, long start, long end); - - /** - * Execute {@code BITFIELD} with its subcommands. - * - * @param key the key - * @param bitFieldArgs the args containing subcommands, must not be {@literal null}. - * - * @return Long bulk-reply the results from the bitfield commands. - */ - RedisFuture> bitfield(K key, BitFieldArgs bitFieldArgs); - - /** - * Find first bit set or clear in a string. - * - * @param key the key - * @param state the state - * - * @return RedisFuture<Long> integer-reply The command returns the position of the first bit set to 1 or 0 according - * to the request. - * - * If we look for set bits (the bit argument is 1) and the string is empty or composed of just zero bytes, -1 is - * returned. - * - * If we look for clear bits (the bit argument is 0) and the string only contains bit set to 1, the function returns - * the first bit not part of the string on the right. So if the string is tree bytes set to the value 0xff the - * command {@code BITPOS key 0} will return 24, since up to bit 23 all the bits are 1. - * - * Basically the function consider the right of the string as padded with zeros if you look for clear bits and - * specify no range or the start argument only. - * - * However this behavior changes if you are looking for clear bits and specify a range with both - * end and end. If no clear bit is found in the specified range, the function - * returns -1 as the user specified a clear range and there are no 0 bits in that range. - */ - RedisFuture bitpos(K key, boolean state); - - /** - * Find first bit set or clear in a string. - * - * @param key the key - * @param state the bit type: long - * @param start the start type: long - * @param end the end type: long - * @return RedisFuture<Long> integer-reply The command returns the position of the first bit set to 1 or 0 according - * to the request. - * - * If we look for set bits (the bit argument is 1) and the string is empty or composed of just zero bytes, -1 is - * returned. - * - * If we look for clear bits (the bit argument is 0) and the string only contains bit set to 1, the function returns - * the first bit not part of the string on the right. So if the string is tree bytes set to the value 0xff the - * command {@code BITPOS key 0} will return 24, since up to bit 23 all the bits are 1. - * - * Basically the function consider the right of the string as padded with zeros if you look for clear bits and - * specify no range or the start argument only. - * - * However this behavior changes if you are looking for clear bits and specify a range with both - * start and end. If no clear bit is found in the specified range, the function - * returns -1 as the user specified a clear range and there are no 0 bits in that range. - */ - RedisFuture bitpos(K key, boolean state, long start, long end); - - /** - * Perform bitwise AND between strings. - * - * @param destination result key of the operation - * @param keys operation input key names - * @return RedisFuture<Long> integer-reply The size of the string stored in the destination key, that is equal to the - * size of the longest input string. - */ - RedisFuture bitopAnd(K destination, K... keys); - - /** - * Perform bitwise NOT between strings. - * - * @param destination result key of the operation - * @param source operation input key names - * @return RedisFuture<Long> integer-reply The size of the string stored in the destination key, that is equal to the - * size of the longest input string. - */ - RedisFuture bitopNot(K destination, K source); - - /** - * Perform bitwise OR between strings. - * - * @param destination result key of the operation - * @param keys operation input key names - * @return RedisFuture<Long> integer-reply The size of the string stored in the destination key, that is equal to the - * size of the longest input string. - */ - RedisFuture bitopOr(K destination, K... keys); - - /** - * Perform bitwise XOR between strings. - * - * @param destination result key of the operation - * @param keys operation input key names - * @return RedisFuture<Long> integer-reply The size of the string stored in the destination key, that is equal to the - * size of the longest input string. - */ - RedisFuture bitopXor(K destination, K... keys); - - /** - * Decrement the integer value of a key by one. - * - * @param key the key - * @return RedisFuture<Long> integer-reply the value of {@code key} after the decrement - */ - RedisFuture decr(K key); - - /** - * Decrement the integer value of a key by the given number. - * - * @param key the key - * @param amount the decrement type: long - * @return RedisFuture<Long> integer-reply the value of {@code key} after the decrement - */ - RedisFuture decrby(K key, long amount); - - /** - * Get the value of a key. - * - * @param key the key - * @return RedisFuture<V> bulk-string-reply the value of {@code key}, or {@literal null} when {@code key} does not - * exist. - */ - RedisFuture get(K key); - - /** - * Returns the bit value at offset in the string value stored at key. - * - * @param key the key - * @param offset the offset type: long - * @return RedisFuture<Long> integer-reply the bit value stored at offset. - */ - RedisFuture getbit(K key, long offset); - - /** - * Get a substring of the string stored at a key. - * - * @param key the key - * @param start the start type: long - * @param end the end type: long - * @return RedisFuture<V> bulk-string-reply - */ - RedisFuture getrange(K key, long start, long end); - - /** - * Set the string value of a key and return its old value. - * - * @param key the key - * @param value the value - * @return RedisFuture<V> bulk-string-reply the old value stored at {@code key}, or {@literal null} when {@code key} - * did not exist. - */ - RedisFuture getset(K key, V value); - - /** - * Increment the integer value of a key by one. - * - * @param key the key - * @return RedisFuture<Long> integer-reply the value of {@code key} after the increment - */ - RedisFuture incr(K key); - - /** - * Increment the integer value of a key by the given amount. - * - * @param key the key - * @param amount the increment type: long - * @return RedisFuture<Long> integer-reply the value of {@code key} after the increment - */ - RedisFuture incrby(K key, long amount); - - /** - * Increment the float value of a key by the given amount. - * - * @param key the key - * @param amount the increment type: double - * @return RedisFuture<Double;> bulk-string-reply the value of {@code key} after the increment. - */ - RedisFuture incrbyfloat(K key, double amount); - - /** - * Get the values of all the given keys. - * - * @param keys the key - * @return RedisFuture<List<V>> array-reply list of values at the specified keys. - */ - RedisFuture> mget(K... keys); - - /** - * Stream the values of all the given keys. - * - * @param channel the channel - * @param keys the keys - * - * @return RedisFuture<Long> array-reply list of values at the specified keys. - */ - RedisFuture mget(ValueStreamingChannel channel, K... keys); - - /** - * Set multiple keys to multiple values. - * - * @param map the null - * @return RedisFuture<String> simple-string-reply always {@code OK} since {@code MSET} can't fail. - */ - RedisFuture mset(Map map); - - /** - * Set multiple keys to multiple values, only if none of the keys exist. - * - * @param map the null - * @return RedisFuture<Boolean> integer-reply specifically: - * - * {@code 1} if the all the keys were set. {@code 0} if no key was set (at least one key already existed). - */ - RedisFuture msetnx(Map map); - - /** - * Set the string value of a key. - * - * @param key the key - * @param value the value - * - * @return RedisFuture<String> simple-string-reply {@code OK} if {@code SET} was executed correctly. - */ - RedisFuture set(K key, V value); - - /** - * Set the string value of a key. - * - * @param key the key - * @param value the value - * @param setArgs the setArgs - * - * @return RedisFuture<V> simple-string-reply {@code OK} if {@code SET} was executed correctly. - */ - RedisFuture set(K key, V value, SetArgs setArgs); - - /** - * Sets or clears the bit at offset in the string value stored at key. - * - * @param key the key - * @param offset the offset type: long - * @param value the value type: string - * @return RedisFuture<Long> integer-reply the original bit value stored at offset. - */ - RedisFuture setbit(K key, long offset, int value); - - /** - * Set the value and expiration of a key. - * - * @param key the key - * @param seconds the seconds type: long - * @param value the value - * @return RedisFuture<String> simple-string-reply - */ - RedisFuture setex(K key, long seconds, V value); - - /** - * Set the value and expiration in milliseconds of a key. - * - * @param key the key - * @param milliseconds the milliseconds type: long - * @param value the value - * @return RedisFuture<String> simple-string-reply - */ - RedisFuture psetex(K key, long milliseconds, V value); - - /** - * Set the value of a key, only if the key does not exist. - * - * @param key the key - * @param value the value - * @return RedisFuture<Boolean> integer-reply specifically: - * - * {@code 1} if the key was set {@code 0} if the key was not set - */ - RedisFuture setnx(K key, V value); - - /** - * Overwrite part of a string at key starting at the specified offset. - * - * @param key the key - * @param offset the offset type: long - * @param value the value - * @return RedisFuture<Long> integer-reply the length of the string after it was modified by the command. - */ - RedisFuture setrange(K key, long offset, V value); - - /** - * Get the length of the value stored in a key. - * - * @param key the key - * @return RedisFuture<Long> integer-reply the length of the string at {@code key}, or {@code 0} when {@code key} does - * not exist. - */ - RedisFuture strlen(K key); -} diff --git a/src/main/java/com/lambdaworks/redis/RedisStringsConnection.java b/src/main/java/com/lambdaworks/redis/RedisStringsConnection.java deleted file mode 100644 index 96799fbc14..0000000000 --- a/src/main/java/com/lambdaworks/redis/RedisStringsConnection.java +++ /dev/null @@ -1,343 +0,0 @@ -package com.lambdaworks.redis; - -import com.lambdaworks.redis.api.sync.RedisStringCommands; -import com.lambdaworks.redis.output.ValueStreamingChannel; - -import java.util.List; -import java.util.Map; - -/** - * Synchronous executed commands for Strings. - * - * @param Key type. - * @param Value type. - * @author Mark Paluch - * @since 3.0 - * @deprecated Use {@link RedisStringCommands} - */ -@Deprecated -public interface RedisStringsConnection { - - /** - * Append a value to a key. - * - * @param key the key - * @param value the value - * @return Long integer-reply the length of the string after the append operation. - */ - Long append(K key, V value); - - /** - * Count set bits in a string. - * - * @param key the key - * - * @return Long integer-reply The number of bits set to 1. - */ - Long bitcount(K key); - - /** - * Count set bits in a string. - * - * @param key the key - * @param start the start - * @param end the end - * - * @return Long integer-reply The number of bits set to 1. - */ - Long bitcount(K key, long start, long end); - - /** - * Execute {@code BITFIELD} with its subcommands. - * - * @param key the key - * @param bitFieldArgs the args containing subcommands, must not be {@literal null}. - * - * @return Long bulk-reply the results from the bitfield commands. - */ - List bitfield(K key, BitFieldArgs bitFieldArgs); - - /** - * Find first bit set or clear in a string. - * - * @param key the key - * @param state the state - * - * @return Long integer-reply The command returns the position of the first bit set to 1 or 0 according to the request. - * - * If we look for set bits (the bit argument is 1) and the string is empty or composed of just zero bytes, -1 is - * returned. - * - * If we look for clear bits (the bit argument is 0) and the string only contains bit set to 1, the function returns - * the first bit not part of the string on the right. So if the string is tree bytes set to the value 0xff the - * command {@code BITPOS key 0} will return 24, since up to bit 23 all the bits are 1. - * - * Basically the function consider the right of the string as padded with zeros if you look for clear bits and - * specify no range or the start argument only. - * - * However this behavior changes if you are looking for clear bits and specify a range with both - * start and end. If no clear bit is found in the specified range, the function - * returns -1 as the user specified a clear range and there are no 0 bits in that range. - */ - Long bitpos(K key, boolean state); - - /** - * Find first bit set or clear in a string. - * - * @param key the key - * @param state the bit type: long - * @param start the start type: long - * @param end the end type: long - * @return Long integer-reply The command returns the position of the first bit set to 1 or 0 according to the request. - * - * If we look for set bits (the bit argument is 1) and the string is empty or composed of just zero bytes, -1 is - * returned. - * - * If we look for clear bits (the bit argument is 0) and the string only contains bit set to 1, the function returns - * the first bit not part of the string on the right. So if the string is tree bytes set to the value 0xff the - * command {@code BITPOS key 0} will return 24, since up to bit 23 all the bits are 1. - * - * Basically the function consider the right of the string as padded with zeros if you look for clear bits and - * specify no range or the start argument only. - * - * However this behavior changes if you are looking for clear bits and specify a range with both - * start and end. If no clear bit is found in the specified range, the function - * returns -1 as the user specified a clear range and there are no 0 bits in that range. - */ - Long bitpos(K key, boolean state, long start, long end); - - /** - * Perform bitwise AND between strings. - * - * @param destination result key of the operation - * @param keys operation input key names - * @return Long integer-reply The size of the string stored in the destination key, that is equal to the size of the longest - * input string. - */ - Long bitopAnd(K destination, K... keys); - - /** - * Perform bitwise NOT between strings. - * - * @param destination result key of the operation - * @param source operation input key names - * @return Long integer-reply The size of the string stored in the destination key, that is equal to the size of the longest - * input string. - */ - Long bitopNot(K destination, K source); - - /** - * Perform bitwise OR between strings. - * - * @param destination result key of the operation - * @param keys operation input key names - * @return Long integer-reply The size of the string stored in the destination key, that is equal to the size of the longest - * input string. - */ - Long bitopOr(K destination, K... keys); - - /** - * Perform bitwise XOR between strings. - * - * @param destination result key of the operation - * @param keys operation input key names - * @return Long integer-reply The size of the string stored in the destination key, that is equal to the size of the longest - * input string. - */ - Long bitopXor(K destination, K... keys); - - /** - * Decrement the integer value of a key by one. - * - * @param key the key - * @return Long integer-reply the value of {@code key} after the decrement - */ - Long decr(K key); - - /** - * Decrement the integer value of a key by the given number. - * - * @param key the key - * @param amount the decrement type: long - * @return Long integer-reply the value of {@code key} after the decrement - */ - Long decrby(K key, long amount); - - /** - * Get the value of a key. - * - * @param key the key - * @return V bulk-string-reply the value of {@code key}, or {@literal null} when {@code key} does not exist. - */ - V get(K key); - - /** - * Returns the bit value at offset in the string value stored at key. - * - * @param key the key - * @param offset the offset type: long - * @return Long integer-reply the bit value stored at offset. - */ - Long getbit(K key, long offset); - - /** - * Get a substring of the string stored at a key. - * - * @param key the key - * @param start the start type: long - * @param end the end type: long - * @return V bulk-string-reply - */ - V getrange(K key, long start, long end); - - /** - * Set the string value of a key and return its old value. - * - * @param key the key - * @param value the value - * @return V bulk-string-reply the old value stored at {@code key}, or {@literal null} when {@code key} did not exist. - */ - V getset(K key, V value); - - /** - * Increment the integer value of a key by one. - * - * @param key the key - * @return Long integer-reply the value of {@code key} after the increment - */ - Long incr(K key); - - /** - * Increment the integer value of a key by the given amount. - * - * @param key the key - * @param amount the increment type: long - * @return Long integer-reply the value of {@code key} after the increment - */ - Long incrby(K key, long amount); - - /** - * Increment the float value of a key by the given amount. - * - * @param key the key - * @param amount the increment type: double - * @return Double bulk-string-reply the value of {@code key} after the increment. - */ - Double incrbyfloat(K key, double amount); - - /** - * Get the values of all the given keys. - * - * @param keys the key - * @return List<V> array-reply list of values at the specified keys. - */ - List mget(K... keys); - - /** - * Stream over the values of all the given keys. - * - * @param channel the channel - * @param keys the keys - * - * @return Long array-reply list of values at the specified keys. - */ - Long mget(ValueStreamingChannel channel, K... keys); - - /** - * Set multiple keys to multiple values. - * - * @param map the null - * @return String simple-string-reply always {@code OK} since {@code MSET} can't fail. - */ - String mset(Map map); - - /** - * Set multiple keys to multiple values, only if none of the keys exist. - * - * @param map the null - * @return Boolean integer-reply specifically: - * - * {@code 1} if the all the keys were set. {@code 0} if no key was set (at least one key already existed). - */ - Boolean msetnx(Map map); - - /** - * Set the string value of a key. - * - * @param key the key - * @param value the value - * - * @return String simple-string-reply {@code OK} if {@code SET} was executed correctly. - */ - String set(K key, V value); - - /** - * Set the string value of a key. - * - * @param key the key - * @param value the value - * @param setArgs the setArgs - * - * @return String simple-string-reply {@code OK} if {@code SET} was executed correctly. - */ - String set(K key, V value, SetArgs setArgs); - - /** - * Sets or clears the bit at offset in the string value stored at key. - * - * @param key the key - * @param offset the offset type: long - * @param value the value type: string - * @return Long integer-reply the original bit value stored at offset. - */ - Long setbit(K key, long offset, int value); - - /** - * Set the value and expiration of a key. - * - * @param key the key - * @param seconds the seconds type: long - * @param value the value - * @return String simple-string-reply - */ - String setex(K key, long seconds, V value); - - /** - * Set the value and expiration in milliseconds of a key. - * - * @param key the key - * @param milliseconds the milliseconds type: long - * @param value the value - * @return String simple-string-reply - */ - String psetex(K key, long milliseconds, V value); - - /** - * Set the value of a key, only if the key does not exist. - * - * @param key the key - * @param value the value - * @return Boolean integer-reply specifically: - * - * {@code 1} if the key was set {@code 0} if the key was not set - */ - Boolean setnx(K key, V value); - - /** - * Overwrite part of a string at key starting at the specified offset. - * - * @param key the key - * @param offset the offset type: long - * @param value the value - * @return Long integer-reply the length of the string after it was modified by the command. - */ - Long setrange(K key, long offset, V value); - - /** - * Get the length of the value stored in a key. - * - * @param key the key - * @return Long integer-reply the length of the string at {@code key}, or {@code 0} when {@code key} does not exist. - */ - Long strlen(K key); -} diff --git a/src/main/java/com/lambdaworks/redis/RedisURI.java b/src/main/java/com/lambdaworks/redis/RedisURI.java index 905edfd399..68993ce9f3 100644 --- a/src/main/java/com/lambdaworks/redis/RedisURI.java +++ b/src/main/java/com/lambdaworks/redis/RedisURI.java @@ -850,11 +850,7 @@ public static class Builder { private TimeUnit unit = TimeUnit.SECONDS; private final List sentinels = new ArrayList<>(); - /** - * @deprecated Use {@link RedisURI#builder()} - */ - @Deprecated - public Builder() { + private Builder() { } /** diff --git a/src/main/java/com/lambdaworks/redis/api/async/BaseRedisAsyncCommands.java b/src/main/java/com/lambdaworks/redis/api/async/BaseRedisAsyncCommands.java index f52953b96b..fb4acd1f55 100644 --- a/src/main/java/com/lambdaworks/redis/api/async/BaseRedisAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/async/BaseRedisAsyncCommands.java @@ -148,4 +148,19 @@ public interface BaseRedisAsyncCommands extends AutoCloseable { * internal state machine gets out of sync with the connection. */ void reset(); + + /** + * Disable or enable auto-flush behavior. Default is {@literal true}. If autoFlushCommands is disabled, multiple commands + * can be issued without writing them actually to the transport. Commands are buffered until a {@link #flushCommands()} is + * issued. After calling {@link #flushCommands()} commands are sent to the transport and executed by Redis. + * + * @param autoFlush state of autoFlush. + */ + void setAutoFlushCommands(boolean autoFlush); + + /** + * Flush pending commands. This commands forces a flush on the channel and can be used to buffer ("pipeline") commands to + * achieve batching. No-op if channel is not connected. + */ + void flushCommands(); } diff --git a/src/main/java/com/lambdaworks/redis/api/async/RedisAsyncCommands.java b/src/main/java/com/lambdaworks/redis/api/async/RedisAsyncCommands.java index e3c57e540c..31adaa7a6f 100644 --- a/src/main/java/com/lambdaworks/redis/api/async/RedisAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/async/RedisAsyncCommands.java @@ -2,7 +2,6 @@ import java.util.concurrent.TimeUnit; -import com.lambdaworks.redis.RedisAsyncConnection; import com.lambdaworks.redis.api.StatefulRedisConnection; import com.lambdaworks.redis.cluster.api.async.RedisClusterAsyncCommands; @@ -18,7 +17,7 @@ public interface RedisAsyncCommands extends RedisHashAsyncCommands, RedisStringAsyncCommands, RedisListAsyncCommands, RedisSetAsyncCommands, RedisSortedSetAsyncCommands, RedisScriptingAsyncCommands, RedisServerAsyncCommands, RedisHLLAsyncCommands, BaseRedisAsyncCommands, RedisClusterAsyncCommands, - RedisTransactionalAsyncCommands, RedisGeoAsyncCommands, RedisAsyncConnection { + RedisTransactionalAsyncCommands, RedisGeoAsyncCommands { /** * Set the default timeout for operations. diff --git a/src/main/java/com/lambdaworks/redis/api/async/RedisListAsyncCommands.java b/src/main/java/com/lambdaworks/redis/api/async/RedisListAsyncCommands.java index 5627680465..7a719ffbff 100644 --- a/src/main/java/com/lambdaworks/redis/api/async/RedisListAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/async/RedisListAsyncCommands.java @@ -99,16 +99,6 @@ public interface RedisListAsyncCommands { */ RedisFuture lpush(K key, V... values); - /** - * Prepend a value to a list, only if the list exists. - * - * @param key the key - * @param value the value - * @return Long integer-reply the length of the list after the push operation. - * @deprecated Use {@link #lpushx(Object, Object[])} - */ - RedisFuture lpushx(K key, V value); - /** * Prepend values to a list, only if the list exists. * @@ -195,16 +185,6 @@ public interface RedisListAsyncCommands { */ RedisFuture rpush(K key, V... values); - /** - * Append a value to a list, only if the list exists. - * - * @param key the key - * @param value the value - * @return Long integer-reply the length of the list after the push operation. - * @deprecated Use {@link #rpushx(java.lang.Object, java.lang.Object[])} - */ - RedisFuture rpushx(K key, V value); - /** * Append values to a list, only if the list exists. * diff --git a/src/main/java/com/lambdaworks/redis/api/async/RedisServerAsyncCommands.java b/src/main/java/com/lambdaworks/redis/api/async/RedisServerAsyncCommands.java index 9cfd71cedc..3d40677882 100644 --- a/src/main/java/com/lambdaworks/redis/api/async/RedisServerAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/async/RedisServerAsyncCommands.java @@ -173,12 +173,14 @@ public interface RedisServerAsyncCommands { /** * Make the server crash: Out of memory. * + * @return nothing, because the server crashes before returning. */ void debugOom(); /** * Make the server crash: Invalid pointer access. * + * @return nothing, because the server crashes before returning. */ void debugSegfault(); @@ -313,14 +315,6 @@ public interface RedisServerAsyncCommands { */ RedisFuture slowlogReset(); - /** - * Internal command used for replication. - * - * @return String simple-string-reply - */ - @Deprecated - RedisFuture sync(); - /** * Return the current server time. * diff --git a/src/main/java/com/lambdaworks/redis/api/async/RedisStringAsyncCommands.java b/src/main/java/com/lambdaworks/redis/api/async/RedisStringAsyncCommands.java index 4ef6e72599..ed2aee7fbf 100644 --- a/src/main/java/com/lambdaworks/redis/api/async/RedisStringAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/async/RedisStringAsyncCommands.java @@ -1,16 +1,15 @@ package com.lambdaworks.redis.api.async; -import com.lambdaworks.redis.BitFieldArgs; -import com.lambdaworks.redis.RedisFuture; -import com.lambdaworks.redis.SetArgs; -import com.lambdaworks.redis.output.ValueStreamingChannel; - import java.util.List; import java.util.Map; +import com.lambdaworks.redis.output.ValueStreamingChannel; +import com.lambdaworks.redis.BitFieldArgs; +import com.lambdaworks.redis.SetArgs; +import com.lambdaworks.redis.RedisFuture; /** * Asynchronous executed commands for Strings. - * + * * @param Key type. * @param Value type. * @author Mark Paluch @@ -21,7 +20,7 @@ public interface RedisStringAsyncCommands { /** * Append a value to a key. - * + * * @param key the key * @param value the value * @return Long integer-reply the length of the string after the append operation. @@ -30,52 +29,52 @@ public interface RedisStringAsyncCommands { /** * Count set bits in a string. - * + * * @param key the key - * + * * @return Long integer-reply The number of bits set to 1. */ RedisFuture bitcount(K key); /** * Count set bits in a string. - * + * * @param key the key * @param start the start * @param end the end - * + * * @return Long integer-reply The number of bits set to 1. */ RedisFuture bitcount(K key, long start, long end); /** * Execute {@code BITFIELD} with its subcommands. - * + * * @param key the key * @param bitFieldArgs the args containing subcommands, must not be {@literal null}. - * + * * @return Long bulk-reply the results from the bitfield commands. */ RedisFuture> bitfield(K key, BitFieldArgs bitFieldArgs); /** * Find first bit set or clear in a string. - * + * * @param key the key * @param state the state - * + * * @return Long integer-reply The command returns the position of the first bit set to 1 or 0 according to the request. - * + * * If we look for set bits (the bit argument is 1) and the string is empty or composed of just zero bytes, -1 is * returned. - * + * * If we look for clear bits (the bit argument is 0) and the string only contains bit set to 1, the function returns * the first bit not part of the string on the right. So if the string is tree bytes set to the value 0xff the * command {@code BITPOS key 0} will return 24, since up to bit 23 all the bits are 1. - * + * * Basically the function consider the right of the string as padded with zeros if you look for clear bits and * specify no range or the start argument only. - * + * * However this behavior changes if you are looking for clear bits and specify a range with both * start and end. If no clear bit is found in the specified range, the function * returns -1 as the user specified a clear range and there are no 0 bits in that range. @@ -84,23 +83,23 @@ public interface RedisStringAsyncCommands { /** * Find first bit set or clear in a string. - * + * * @param key the key * @param state the bit type: long * @param start the start type: long * @param end the end type: long * @return Long integer-reply The command returns the position of the first bit set to 1 or 0 according to the request. - * + * * If we look for set bits (the bit argument is 1) and the string is empty or composed of just zero bytes, -1 is * returned. - * + * * If we look for clear bits (the bit argument is 0) and the string only contains bit set to 1, the function returns * the first bit not part of the string on the right. So if the string is tree bytes set to the value 0xff the * command {@code BITPOS key 0} will return 24, since up to bit 23 all the bits are 1. - * + * * Basically the function consider the right of the string as padded with zeros if you look for clear bits and * specify no range or the start argument only. - * + * * However this behavior changes if you are looking for clear bits and specify a range with both * start and end. If no clear bit is found in the specified range, the function * returns -1 as the user specified a clear range and there are no 0 bits in that range. @@ -109,7 +108,7 @@ public interface RedisStringAsyncCommands { /** * Perform bitwise AND between strings. - * + * * @param destination result key of the operation * @param keys operation input key names * @return Long integer-reply The size of the string stored in the destination key, that is equal to the size of the longest @@ -119,7 +118,7 @@ public interface RedisStringAsyncCommands { /** * Perform bitwise NOT between strings. - * + * * @param destination result key of the operation * @param source operation input key names * @return Long integer-reply The size of the string stored in the destination key, that is equal to the size of the longest @@ -129,7 +128,7 @@ public interface RedisStringAsyncCommands { /** * Perform bitwise OR between strings. - * + * * @param destination result key of the operation * @param keys operation input key names * @return Long integer-reply The size of the string stored in the destination key, that is equal to the size of the longest @@ -139,7 +138,7 @@ public interface RedisStringAsyncCommands { /** * Perform bitwise XOR between strings. - * + * * @param destination result key of the operation * @param keys operation input key names * @return Long integer-reply The size of the string stored in the destination key, that is equal to the size of the longest @@ -149,7 +148,7 @@ public interface RedisStringAsyncCommands { /** * Decrement the integer value of a key by one. - * + * * @param key the key * @return Long integer-reply the value of {@code key} after the decrement */ @@ -157,7 +156,7 @@ public interface RedisStringAsyncCommands { /** * Decrement the integer value of a key by the given number. - * + * * @param key the key * @param amount the decrement type: long * @return Long integer-reply the value of {@code key} after the decrement @@ -166,7 +165,7 @@ public interface RedisStringAsyncCommands { /** * Get the value of a key. - * + * * @param key the key * @return V bulk-string-reply the value of {@code key}, or {@literal null} when {@code key} does not exist. */ @@ -174,7 +173,7 @@ public interface RedisStringAsyncCommands { /** * Returns the bit value at offset in the string value stored at key. - * + * * @param key the key * @param offset the offset type: long * @return Long integer-reply the bit value stored at offset. @@ -183,7 +182,7 @@ public interface RedisStringAsyncCommands { /** * Get a substring of the string stored at a key. - * + * * @param key the key * @param start the start type: long * @param end the end type: long @@ -193,7 +192,7 @@ public interface RedisStringAsyncCommands { /** * Set the string value of a key and return its old value. - * + * * @param key the key * @param value the value * @return V bulk-string-reply the old value stored at {@code key}, or {@literal null} when {@code key} did not exist. @@ -202,7 +201,7 @@ public interface RedisStringAsyncCommands { /** * Increment the integer value of a key by one. - * + * * @param key the key * @return Long integer-reply the value of {@code key} after the increment */ @@ -210,7 +209,7 @@ public interface RedisStringAsyncCommands { /** * Increment the integer value of a key by the given amount. - * + * * @param key the key * @param amount the increment type: long * @return Long integer-reply the value of {@code key} after the increment @@ -219,7 +218,7 @@ public interface RedisStringAsyncCommands { /** * Increment the float value of a key by the given amount. - * + * * @param key the key * @param amount the increment type: double * @return Double bulk-string-reply the value of {@code key} after the increment. @@ -228,7 +227,7 @@ public interface RedisStringAsyncCommands { /** * Get the values of all the given keys. - * + * * @param keys the key * @return List<V> array-reply list of values at the specified keys. */ @@ -236,17 +235,17 @@ public interface RedisStringAsyncCommands { /** * Stream over the values of all the given keys. - * + * * @param channel the channel * @param keys the keys - * + * * @return Long array-reply list of values at the specified keys. */ RedisFuture mget(ValueStreamingChannel channel, K... keys); /** * Set multiple keys to multiple values. - * + * * @param map the null * @return String simple-string-reply always {@code OK} since {@code MSET} can't fail. */ @@ -254,38 +253,38 @@ public interface RedisStringAsyncCommands { /** * Set multiple keys to multiple values, only if none of the keys exist. - * + * * @param map the null * @return Boolean integer-reply specifically: - * + * * {@code 1} if the all the keys were set. {@code 0} if no key was set (at least one key already existed). */ RedisFuture msetnx(Map map); /** * Set the string value of a key. - * + * * @param key the key * @param value the value - * + * * @return String simple-string-reply {@code OK} if {@code SET} was executed correctly. */ RedisFuture set(K key, V value); /** * Set the string value of a key. - * + * * @param key the key * @param value the value * @param setArgs the setArgs - * + * * @return String simple-string-reply {@code OK} if {@code SET} was executed correctly. */ RedisFuture set(K key, V value, SetArgs setArgs); /** * Sets or clears the bit at offset in the string value stored at key. - * + * * @param key the key * @param offset the offset type: long * @param value the value type: string @@ -295,7 +294,7 @@ public interface RedisStringAsyncCommands { /** * Set the value and expiration of a key. - * + * * @param key the key * @param seconds the seconds type: long * @param value the value @@ -305,7 +304,7 @@ public interface RedisStringAsyncCommands { /** * Set the value and expiration in milliseconds of a key. - * + * * @param key the key * @param milliseconds the milliseconds type: long * @param value the value @@ -315,18 +314,18 @@ public interface RedisStringAsyncCommands { /** * Set the value of a key, only if the key does not exist. - * + * * @param key the key * @param value the value * @return Boolean integer-reply specifically: - * + * * {@code 1} if the key was set {@code 0} if the key was not set */ RedisFuture setnx(K key, V value); /** * Overwrite part of a string at key starting at the specified offset. - * + * * @param key the key * @param offset the offset type: long * @param value the value @@ -336,7 +335,7 @@ public interface RedisStringAsyncCommands { /** * Get the length of the value stored in a key. - * + * * @param key the key * @return Long integer-reply the length of the string at {@code key}, or {@code 0} when {@code key} does not exist. */ diff --git a/src/main/java/com/lambdaworks/redis/api/rx/BaseRedisReactiveCommands.java b/src/main/java/com/lambdaworks/redis/api/rx/BaseRedisReactiveCommands.java index e6b4312175..e257c522b8 100644 --- a/src/main/java/com/lambdaworks/redis/api/rx/BaseRedisReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/rx/BaseRedisReactiveCommands.java @@ -1,12 +1,10 @@ package com.lambdaworks.redis.api.rx; -import java.util.Collection; +import java.util.List; import java.util.Map; - -import com.lambdaworks.redis.output.CommandOutput; import com.lambdaworks.redis.protocol.CommandArgs; import com.lambdaworks.redis.protocol.ProtocolKeyword; - +import com.lambdaworks.redis.output.CommandOutput; import rx.Observable; /** @@ -71,8 +69,8 @@ public interface BaseRedisReactiveCommands extends AutoCloseable { /** * Return the role of the instance in the context of replication. * - * @return Object array-reply where the first element is one of master, slave, sentinel and the additional elements are - * role-specific. + * @return Object array-reply where the first element is one of master, slave, sentinel and the additional + * elements are role-specific. */ Observable role(); @@ -150,4 +148,19 @@ public interface BaseRedisReactiveCommands extends AutoCloseable { * internal state machine gets out of sync with the connection. */ void reset(); + + /** + * Disable or enable auto-flush behavior. Default is {@literal true}. If autoFlushCommands is disabled, multiple commands + * can be issued without writing them actually to the transport. Commands are buffered until a {@link #flushCommands()} is + * issued. After calling {@link #flushCommands()} commands are sent to the transport and executed by Redis. + * + * @param autoFlush state of autoFlush. + */ + void setAutoFlushCommands(boolean autoFlush); + + /** + * Flush pending commands. This commands forces a flush on the channel and can be used to buffer ("pipeline") commands to + * achieve batching. No-op if channel is not connected. + */ + void flushCommands(); } diff --git a/src/main/java/com/lambdaworks/redis/api/rx/RedisListReactiveCommands.java b/src/main/java/com/lambdaworks/redis/api/rx/RedisListReactiveCommands.java index 552f9de0e8..4f9b4d4832 100644 --- a/src/main/java/com/lambdaworks/redis/api/rx/RedisListReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/rx/RedisListReactiveCommands.java @@ -99,16 +99,6 @@ public interface RedisListReactiveCommands { */ Observable lpush(K key, V... values); - /** - * Prepend a value to a list, only if the list exists. - * - * @param key the key - * @param value the value - * @return Long integer-reply the length of the list after the push operation. - * @deprecated Use {@link #lpushx(Object, Object[])} - */ - Observable lpushx(K key, V value); - /** * Prepend values to a list, only if the list exists. * @@ -195,16 +185,6 @@ public interface RedisListReactiveCommands { */ Observable rpush(K key, V... values); - /** - * Append a value to a list, only if the list exists. - * - * @param key the key - * @param value the value - * @return Long integer-reply the length of the list after the push operation. - * @deprecated Use {@link #rpushx(java.lang.Object, java.lang.Object[])} - */ - Observable rpushx(K key, V value); - /** * Append values to a list, only if the list exists. * diff --git a/src/main/java/com/lambdaworks/redis/api/rx/RedisServerReactiveCommands.java b/src/main/java/com/lambdaworks/redis/api/rx/RedisServerReactiveCommands.java index 22993104f3..bcf8575949 100644 --- a/src/main/java/com/lambdaworks/redis/api/rx/RedisServerReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/rx/RedisServerReactiveCommands.java @@ -267,7 +267,6 @@ public interface RedisServerReactiveCommands { * Synchronously save the dataset to disk and then shut down the server. * * @param save {@literal true} force save operation - * @return nothing because the server shuts down before returning a value */ Observable shutdown(boolean save); @@ -316,14 +315,6 @@ public interface RedisServerReactiveCommands { */ Observable slowlogReset(); - /** - * Internal command used for replication. - * - * @return String simple-string-reply - */ - @Deprecated - Observable sync(); - /** * Return the current server time. * diff --git a/src/main/java/com/lambdaworks/redis/api/rx/RedisStringReactiveCommands.java b/src/main/java/com/lambdaworks/redis/api/rx/RedisStringReactiveCommands.java index cf522e63ac..1d26d273d9 100644 --- a/src/main/java/com/lambdaworks/redis/api/rx/RedisStringReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/rx/RedisStringReactiveCommands.java @@ -1,15 +1,15 @@ package com.lambdaworks.redis.api.rx; +import java.util.List; +import java.util.Map; +import com.lambdaworks.redis.output.ValueStreamingChannel; import com.lambdaworks.redis.BitFieldArgs; import com.lambdaworks.redis.SetArgs; -import com.lambdaworks.redis.output.ValueStreamingChannel; import rx.Observable; -import java.util.Map; - /** * Observable commands for Strings. - * + * * @param Key type. * @param Value type. * @author Mark Paluch @@ -20,7 +20,7 @@ public interface RedisStringReactiveCommands { /** * Append a value to a key. - * + * * @param key the key * @param value the value * @return Long integer-reply the length of the string after the append operation. @@ -29,52 +29,52 @@ public interface RedisStringReactiveCommands { /** * Count set bits in a string. - * + * * @param key the key - * + * * @return Long integer-reply The number of bits set to 1. */ Observable bitcount(K key); /** * Count set bits in a string. - * + * * @param key the key * @param start the start * @param end the end - * + * * @return Long integer-reply The number of bits set to 1. */ Observable bitcount(K key, long start, long end); /** * Execute {@code BITFIELD} with its subcommands. - * + * * @param key the key * @param bitFieldArgs the args containing subcommands, must not be {@literal null}. - * + * * @return Long bulk-reply the results from the bitfield commands. */ Observable bitfield(K key, BitFieldArgs bitFieldArgs); /** * Find first bit set or clear in a string. - * + * * @param key the key * @param state the state - * + * * @return Long integer-reply The command returns the position of the first bit set to 1 or 0 according to the request. - * + * * If we look for set bits (the bit argument is 1) and the string is empty or composed of just zero bytes, -1 is * returned. - * + * * If we look for clear bits (the bit argument is 0) and the string only contains bit set to 1, the function returns * the first bit not part of the string on the right. So if the string is tree bytes set to the value 0xff the * command {@code BITPOS key 0} will return 24, since up to bit 23 all the bits are 1. - * + * * Basically the function consider the right of the string as padded with zeros if you look for clear bits and * specify no range or the start argument only. - * + * * However this behavior changes if you are looking for clear bits and specify a range with both * start and end. If no clear bit is found in the specified range, the function * returns -1 as the user specified a clear range and there are no 0 bits in that range. @@ -83,23 +83,23 @@ public interface RedisStringReactiveCommands { /** * Find first bit set or clear in a string. - * + * * @param key the key * @param state the bit type: long * @param start the start type: long * @param end the end type: long * @return Long integer-reply The command returns the position of the first bit set to 1 or 0 according to the request. - * + * * If we look for set bits (the bit argument is 1) and the string is empty or composed of just zero bytes, -1 is * returned. - * + * * If we look for clear bits (the bit argument is 0) and the string only contains bit set to 1, the function returns * the first bit not part of the string on the right. So if the string is tree bytes set to the value 0xff the * command {@code BITPOS key 0} will return 24, since up to bit 23 all the bits are 1. - * + * * Basically the function consider the right of the string as padded with zeros if you look for clear bits and * specify no range or the start argument only. - * + * * However this behavior changes if you are looking for clear bits and specify a range with both * start and end. If no clear bit is found in the specified range, the function * returns -1 as the user specified a clear range and there are no 0 bits in that range. @@ -108,7 +108,7 @@ public interface RedisStringReactiveCommands { /** * Perform bitwise AND between strings. - * + * * @param destination result key of the operation * @param keys operation input key names * @return Long integer-reply The size of the string stored in the destination key, that is equal to the size of the longest @@ -118,7 +118,7 @@ public interface RedisStringReactiveCommands { /** * Perform bitwise NOT between strings. - * + * * @param destination result key of the operation * @param source operation input key names * @return Long integer-reply The size of the string stored in the destination key, that is equal to the size of the longest @@ -128,7 +128,7 @@ public interface RedisStringReactiveCommands { /** * Perform bitwise OR between strings. - * + * * @param destination result key of the operation * @param keys operation input key names * @return Long integer-reply The size of the string stored in the destination key, that is equal to the size of the longest @@ -138,7 +138,7 @@ public interface RedisStringReactiveCommands { /** * Perform bitwise XOR between strings. - * + * * @param destination result key of the operation * @param keys operation input key names * @return Long integer-reply The size of the string stored in the destination key, that is equal to the size of the longest @@ -148,7 +148,7 @@ public interface RedisStringReactiveCommands { /** * Decrement the integer value of a key by one. - * + * * @param key the key * @return Long integer-reply the value of {@code key} after the decrement */ @@ -156,7 +156,7 @@ public interface RedisStringReactiveCommands { /** * Decrement the integer value of a key by the given number. - * + * * @param key the key * @param amount the decrement type: long * @return Long integer-reply the value of {@code key} after the decrement @@ -165,7 +165,7 @@ public interface RedisStringReactiveCommands { /** * Get the value of a key. - * + * * @param key the key * @return V bulk-string-reply the value of {@code key}, or {@literal null} when {@code key} does not exist. */ @@ -173,7 +173,7 @@ public interface RedisStringReactiveCommands { /** * Returns the bit value at offset in the string value stored at key. - * + * * @param key the key * @param offset the offset type: long * @return Long integer-reply the bit value stored at offset. @@ -182,7 +182,7 @@ public interface RedisStringReactiveCommands { /** * Get a substring of the string stored at a key. - * + * * @param key the key * @param start the start type: long * @param end the end type: long @@ -192,7 +192,7 @@ public interface RedisStringReactiveCommands { /** * Set the string value of a key and return its old value. - * + * * @param key the key * @param value the value * @return V bulk-string-reply the old value stored at {@code key}, or {@literal null} when {@code key} did not exist. @@ -201,7 +201,7 @@ public interface RedisStringReactiveCommands { /** * Increment the integer value of a key by one. - * + * * @param key the key * @return Long integer-reply the value of {@code key} after the increment */ @@ -209,7 +209,7 @@ public interface RedisStringReactiveCommands { /** * Increment the integer value of a key by the given amount. - * + * * @param key the key * @param amount the increment type: long * @return Long integer-reply the value of {@code key} after the increment @@ -218,7 +218,7 @@ public interface RedisStringReactiveCommands { /** * Increment the float value of a key by the given amount. - * + * * @param key the key * @param amount the increment type: double * @return Double bulk-string-reply the value of {@code key} after the increment. @@ -227,7 +227,7 @@ public interface RedisStringReactiveCommands { /** * Get the values of all the given keys. - * + * * @param keys the key * @return V array-reply list of values at the specified keys. */ @@ -235,17 +235,17 @@ public interface RedisStringReactiveCommands { /** * Stream over the values of all the given keys. - * + * * @param channel the channel * @param keys the keys - * + * * @return Long array-reply list of values at the specified keys. */ Observable mget(ValueStreamingChannel channel, K... keys); /** * Set multiple keys to multiple values. - * + * * @param map the null * @return String simple-string-reply always {@code OK} since {@code MSET} can't fail. */ @@ -253,38 +253,38 @@ public interface RedisStringReactiveCommands { /** * Set multiple keys to multiple values, only if none of the keys exist. - * + * * @param map the null * @return Boolean integer-reply specifically: - * + * * {@code 1} if the all the keys were set. {@code 0} if no key was set (at least one key already existed). */ Observable msetnx(Map map); /** * Set the string value of a key. - * + * * @param key the key * @param value the value - * + * * @return String simple-string-reply {@code OK} if {@code SET} was executed correctly. */ Observable set(K key, V value); /** * Set the string value of a key. - * + * * @param key the key * @param value the value * @param setArgs the setArgs - * + * * @return String simple-string-reply {@code OK} if {@code SET} was executed correctly. */ Observable set(K key, V value, SetArgs setArgs); /** * Sets or clears the bit at offset in the string value stored at key. - * + * * @param key the key * @param offset the offset type: long * @param value the value type: string @@ -294,7 +294,7 @@ public interface RedisStringReactiveCommands { /** * Set the value and expiration of a key. - * + * * @param key the key * @param seconds the seconds type: long * @param value the value @@ -304,7 +304,7 @@ public interface RedisStringReactiveCommands { /** * Set the value and expiration in milliseconds of a key. - * + * * @param key the key * @param milliseconds the milliseconds type: long * @param value the value @@ -314,18 +314,18 @@ public interface RedisStringReactiveCommands { /** * Set the value of a key, only if the key does not exist. - * + * * @param key the key * @param value the value * @return Boolean integer-reply specifically: - * + * * {@code 1} if the key was set {@code 0} if the key was not set */ Observable setnx(K key, V value); /** * Overwrite part of a string at key starting at the specified offset. - * + * * @param key the key * @param offset the offset type: long * @param value the value @@ -335,7 +335,7 @@ public interface RedisStringReactiveCommands { /** * Get the length of the value stored in a key. - * + * * @param key the key * @return Long integer-reply the length of the string at {@code key}, or {@code 0} when {@code key} does not exist. */ diff --git a/src/main/java/com/lambdaworks/redis/api/sync/RedisCommands.java b/src/main/java/com/lambdaworks/redis/api/sync/RedisCommands.java index 00e40e5125..3a84e48bf8 100644 --- a/src/main/java/com/lambdaworks/redis/api/sync/RedisCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/sync/RedisCommands.java @@ -2,7 +2,6 @@ import java.util.concurrent.TimeUnit; -import com.lambdaworks.redis.RedisConnection; import com.lambdaworks.redis.api.StatefulRedisConnection; import com.lambdaworks.redis.cluster.api.sync.RedisClusterCommands; @@ -18,7 +17,7 @@ public interface RedisCommands extends RedisHashCommands, RedisKeyCommands, RedisStringCommands, RedisListCommands, RedisSetCommands, RedisSortedSetCommands, RedisScriptingCommands, RedisServerCommands, RedisHLLCommands, BaseRedisCommands, RedisClusterCommands, - RedisTransactionalCommands, RedisGeoCommands, RedisConnection { + RedisTransactionalCommands, RedisGeoCommands { /** * Set the default timeout for operations. diff --git a/src/main/java/com/lambdaworks/redis/api/sync/RedisHLLCommands.java b/src/main/java/com/lambdaworks/redis/api/sync/RedisHLLCommands.java index 3151281632..1c2f72a1f6 100644 --- a/src/main/java/com/lambdaworks/redis/api/sync/RedisHLLCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/sync/RedisHLLCommands.java @@ -1,6 +1,5 @@ package com.lambdaworks.redis.api.sync; - /** * Synchronous executed commands for HyperLogLog (PF* commands). * diff --git a/src/main/java/com/lambdaworks/redis/api/sync/RedisListCommands.java b/src/main/java/com/lambdaworks/redis/api/sync/RedisListCommands.java index db469ea64c..6baa624022 100644 --- a/src/main/java/com/lambdaworks/redis/api/sync/RedisListCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/sync/RedisListCommands.java @@ -98,16 +98,6 @@ public interface RedisListCommands { */ Long lpush(K key, V... values); - /** - * Prepend a value to a list, only if the list exists. - * - * @param key the key - * @param value the value - * @return Long integer-reply the length of the list after the push operation. - * @deprecated Use {@link #lpushx(Object, Object[])} - */ - Long lpushx(K key, V value); - /** * Prepend values to a list, only if the list exists. * @@ -194,16 +184,6 @@ public interface RedisListCommands { */ Long rpush(K key, V... values); - /** - * Append a value to a list, only if the list exists. - * - * @param key the key - * @param value the value - * @return Long integer-reply the length of the list after the push operation. - * @deprecated Use {@link #rpushx(java.lang.Object, java.lang.Object[])} - */ - Long rpushx(K key, V value); - /** * Append values to a list, only if the list exists. * diff --git a/src/main/java/com/lambdaworks/redis/api/sync/RedisServerCommands.java b/src/main/java/com/lambdaworks/redis/api/sync/RedisServerCommands.java index 7dd5ac1321..1d82353e5d 100644 --- a/src/main/java/com/lambdaworks/redis/api/sync/RedisServerCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/sync/RedisServerCommands.java @@ -171,11 +171,15 @@ public interface RedisServerCommands { /** * Make the server crash: Out of memory. + * + * @return nothing, because the server crashes before returning. */ void debugOom(); /** * Make the server crash: Invalid pointer access. + * + * @return nothing, because the server crashes before returning. */ void debugSegfault(); @@ -310,14 +314,6 @@ public interface RedisServerCommands { */ String slowlogReset(); - /** - * Internal command used for replication. - * - * @return String simple-string-reply - * - * @Deprecated/ - String sync(); - /** * Return the current server time. * diff --git a/src/main/java/com/lambdaworks/redis/api/sync/RedisStringCommands.java b/src/main/java/com/lambdaworks/redis/api/sync/RedisStringCommands.java index 4daf15764e..f23685f16f 100644 --- a/src/main/java/com/lambdaworks/redis/api/sync/RedisStringCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/sync/RedisStringCommands.java @@ -8,7 +8,7 @@ /** * Synchronous executed commands for Strings. - * + * * @param Key type. * @param Value type. * @author Mark Paluch @@ -19,7 +19,7 @@ public interface RedisStringCommands { /** * Append a value to a key. - * + * * @param key the key * @param value the value * @return Long integer-reply the length of the string after the append operation. @@ -28,52 +28,52 @@ public interface RedisStringCommands { /** * Count set bits in a string. - * + * * @param key the key - * + * * @return Long integer-reply The number of bits set to 1. */ Long bitcount(K key); /** * Count set bits in a string. - * + * * @param key the key * @param start the start * @param end the end - * + * * @return Long integer-reply The number of bits set to 1. */ Long bitcount(K key, long start, long end); /** * Execute {@code BITFIELD} with its subcommands. - * + * * @param key the key * @param bitFieldArgs the args containing subcommands, must not be {@literal null}. - * + * * @return Long bulk-reply the results from the bitfield commands. */ List bitfield(K key, BitFieldArgs bitFieldArgs); /** * Find first bit set or clear in a string. - * + * * @param key the key * @param state the state - * + * * @return Long integer-reply The command returns the position of the first bit set to 1 or 0 according to the request. - * + * * If we look for set bits (the bit argument is 1) and the string is empty or composed of just zero bytes, -1 is * returned. - * + * * If we look for clear bits (the bit argument is 0) and the string only contains bit set to 1, the function returns * the first bit not part of the string on the right. So if the string is tree bytes set to the value 0xff the * command {@code BITPOS key 0} will return 24, since up to bit 23 all the bits are 1. - * + * * Basically the function consider the right of the string as padded with zeros if you look for clear bits and * specify no range or the start argument only. - * + * * However this behavior changes if you are looking for clear bits and specify a range with both * start and end. If no clear bit is found in the specified range, the function * returns -1 as the user specified a clear range and there are no 0 bits in that range. @@ -82,23 +82,23 @@ public interface RedisStringCommands { /** * Find first bit set or clear in a string. - * + * * @param key the key * @param state the bit type: long * @param start the start type: long * @param end the end type: long * @return Long integer-reply The command returns the position of the first bit set to 1 or 0 according to the request. - * + * * If we look for set bits (the bit argument is 1) and the string is empty or composed of just zero bytes, -1 is * returned. - * + * * If we look for clear bits (the bit argument is 0) and the string only contains bit set to 1, the function returns * the first bit not part of the string on the right. So if the string is tree bytes set to the value 0xff the * command {@code BITPOS key 0} will return 24, since up to bit 23 all the bits are 1. - * + * * Basically the function consider the right of the string as padded with zeros if you look for clear bits and * specify no range or the start argument only. - * + * * However this behavior changes if you are looking for clear bits and specify a range with both * start and end. If no clear bit is found in the specified range, the function * returns -1 as the user specified a clear range and there are no 0 bits in that range. @@ -107,7 +107,7 @@ public interface RedisStringCommands { /** * Perform bitwise AND between strings. - * + * * @param destination result key of the operation * @param keys operation input key names * @return Long integer-reply The size of the string stored in the destination key, that is equal to the size of the longest @@ -117,7 +117,7 @@ public interface RedisStringCommands { /** * Perform bitwise NOT between strings. - * + * * @param destination result key of the operation * @param source operation input key names * @return Long integer-reply The size of the string stored in the destination key, that is equal to the size of the longest @@ -127,7 +127,7 @@ public interface RedisStringCommands { /** * Perform bitwise OR between strings. - * + * * @param destination result key of the operation * @param keys operation input key names * @return Long integer-reply The size of the string stored in the destination key, that is equal to the size of the longest @@ -137,7 +137,7 @@ public interface RedisStringCommands { /** * Perform bitwise XOR between strings. - * + * * @param destination result key of the operation * @param keys operation input key names * @return Long integer-reply The size of the string stored in the destination key, that is equal to the size of the longest @@ -147,7 +147,7 @@ public interface RedisStringCommands { /** * Decrement the integer value of a key by one. - * + * * @param key the key * @return Long integer-reply the value of {@code key} after the decrement */ @@ -155,7 +155,7 @@ public interface RedisStringCommands { /** * Decrement the integer value of a key by the given number. - * + * * @param key the key * @param amount the decrement type: long * @return Long integer-reply the value of {@code key} after the decrement @@ -164,7 +164,7 @@ public interface RedisStringCommands { /** * Get the value of a key. - * + * * @param key the key * @return V bulk-string-reply the value of {@code key}, or {@literal null} when {@code key} does not exist. */ @@ -172,7 +172,7 @@ public interface RedisStringCommands { /** * Returns the bit value at offset in the string value stored at key. - * + * * @param key the key * @param offset the offset type: long * @return Long integer-reply the bit value stored at offset. @@ -181,7 +181,7 @@ public interface RedisStringCommands { /** * Get a substring of the string stored at a key. - * + * * @param key the key * @param start the start type: long * @param end the end type: long @@ -191,7 +191,7 @@ public interface RedisStringCommands { /** * Set the string value of a key and return its old value. - * + * * @param key the key * @param value the value * @return V bulk-string-reply the old value stored at {@code key}, or {@literal null} when {@code key} did not exist. @@ -200,7 +200,7 @@ public interface RedisStringCommands { /** * Increment the integer value of a key by one. - * + * * @param key the key * @return Long integer-reply the value of {@code key} after the increment */ @@ -208,7 +208,7 @@ public interface RedisStringCommands { /** * Increment the integer value of a key by the given amount. - * + * * @param key the key * @param amount the increment type: long * @return Long integer-reply the value of {@code key} after the increment @@ -217,7 +217,7 @@ public interface RedisStringCommands { /** * Increment the float value of a key by the given amount. - * + * * @param key the key * @param amount the increment type: double * @return Double bulk-string-reply the value of {@code key} after the increment. @@ -226,7 +226,7 @@ public interface RedisStringCommands { /** * Get the values of all the given keys. - * + * * @param keys the key * @return List<V> array-reply list of values at the specified keys. */ @@ -234,17 +234,17 @@ public interface RedisStringCommands { /** * Stream over the values of all the given keys. - * + * * @param channel the channel * @param keys the keys - * + * * @return Long array-reply list of values at the specified keys. */ Long mget(ValueStreamingChannel channel, K... keys); /** * Set multiple keys to multiple values. - * + * * @param map the null * @return String simple-string-reply always {@code OK} since {@code MSET} can't fail. */ @@ -252,38 +252,38 @@ public interface RedisStringCommands { /** * Set multiple keys to multiple values, only if none of the keys exist. - * + * * @param map the null * @return Boolean integer-reply specifically: - * + * * {@code 1} if the all the keys were set. {@code 0} if no key was set (at least one key already existed). */ Boolean msetnx(Map map); /** * Set the string value of a key. - * + * * @param key the key * @param value the value - * + * * @return String simple-string-reply {@code OK} if {@code SET} was executed correctly. */ String set(K key, V value); /** * Set the string value of a key. - * + * * @param key the key * @param value the value * @param setArgs the setArgs - * + * * @return String simple-string-reply {@code OK} if {@code SET} was executed correctly. */ String set(K key, V value, SetArgs setArgs); /** * Sets or clears the bit at offset in the string value stored at key. - * + * * @param key the key * @param offset the offset type: long * @param value the value type: string @@ -293,7 +293,7 @@ public interface RedisStringCommands { /** * Set the value and expiration of a key. - * + * * @param key the key * @param seconds the seconds type: long * @param value the value @@ -303,7 +303,7 @@ public interface RedisStringCommands { /** * Set the value and expiration in milliseconds of a key. - * + * * @param key the key * @param milliseconds the milliseconds type: long * @param value the value @@ -313,18 +313,18 @@ public interface RedisStringCommands { /** * Set the value of a key, only if the key does not exist. - * + * * @param key the key * @param value the value * @return Boolean integer-reply specifically: - * + * * {@code 1} if the key was set {@code 0} if the key was not set */ Boolean setnx(K key, V value); /** * Overwrite part of a string at key starting at the specified offset. - * + * * @param key the key * @param offset the offset type: long * @param value the value @@ -334,7 +334,7 @@ public interface RedisStringCommands { /** * Get the length of the value stored in a key. - * + * * @param key the key * @return Long integer-reply the length of the string at {@code key}, or {@code 0} when {@code key} does not exist. */ diff --git a/src/main/java/com/lambdaworks/redis/cluster/ClusterClientOptions.java b/src/main/java/com/lambdaworks/redis/cluster/ClusterClientOptions.java index c3150c832d..9e573f5cdf 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/ClusterClientOptions.java +++ b/src/main/java/com/lambdaworks/redis/cluster/ClusterClientOptions.java @@ -33,7 +33,7 @@ protected ClusterClientOptions(Builder builder) { ClusterTopologyRefreshOptions refreshOptions = builder.topologyRefreshOptions; if (refreshOptions == null) { - refreshOptions = new ClusterTopologyRefreshOptions.Builder()// + refreshOptions = ClusterTopologyRefreshOptions.builder() // .enablePeriodicRefresh(builder.refreshClusterView)// .refreshPeriod(builder.refreshPeriod, builder.refreshPeriodUnit)// .closeStaleConnections(builder.closeStaleConnections)// @@ -93,61 +93,7 @@ public static class Builder extends ClientOptions.Builder { private int maxRedirects = DEFAULT_MAX_REDIRECTS; private ClusterTopologyRefreshOptions topologyRefreshOptions = null; - /** - * @deprecated Use {@link ClusterClientOptions#builder()} - */ - @Deprecated - public Builder() { - } - - /** - * Enable regular cluster topology updates. The client starts updating the cluster topology in the intervals of - * {@link Builder#refreshPeriod} /{@link Builder#refreshPeriodUnit}. Defaults to {@literal false}. See - * {@link #DEFAULT_REFRESH_CLUSTER_VIEW}. - * - * @param refreshClusterView {@literal true} enable regular cluster topology updates or {@literal false} to disable - * auto-updating - * @return {@code this} - * @deprecated Use {@link #topologyRefreshOptions}, see - * {@link com.lambdaworks.redis.cluster.ClusterTopologyRefreshOptions.Builder#enablePeriodicRefresh(boolean)} - */ - @Deprecated - public Builder refreshClusterView(boolean refreshClusterView) { - this.refreshClusterView = refreshClusterView; - return this; - } - - /** - * Set the refresh period. Defaults to {@literal 60 SECONDS}. See {@link #DEFAULT_REFRESH_PERIOD} and - * {@link #DEFAULT_REFRESH_PERIOD_UNIT}. - * - * @param refreshPeriod period for triggering topology updates - * @param refreshPeriodUnit unit for {@code refreshPeriod} - * @return {@code this} - * @deprecated Use {@link #topologyRefreshOptions}, see - * {@link com.lambdaworks.redis.cluster.ClusterTopologyRefreshOptions.Builder#refreshPeriod(long, TimeUnit)} - */ - @Deprecated - public Builder refreshPeriod(long refreshPeriod, TimeUnit refreshPeriodUnit) { - this.refreshPeriod = refreshPeriod; - this.refreshPeriodUnit = refreshPeriodUnit; - return this; - } - - /** - * Flag, whether to close stale connections when refreshing the cluster topology. Defaults to {@literal true}. Comes - * only into effect if {@link #isRefreshClusterView()} is {@literal true}. See - * {@link ClusterClientOptions#DEFAULT_CLOSE_STALE_CONNECTIONS}. - * - * @param closeStaleConnections {@literal true} if stale connections are cleaned up after cluster topology updates - * @return {@code this} - * @deprecated Use {@link #topologyRefreshOptions}, see - * {@link com.lambdaworks.redis.cluster.ClusterTopologyRefreshOptions.Builder#closeStaleConnections(boolean)} - */ - @Deprecated - public Builder closeStaleConnections(boolean closeStaleConnections) { - this.closeStaleConnections = closeStaleConnections; - return this; + protected Builder() { } /** diff --git a/src/main/java/com/lambdaworks/redis/cluster/ClusterTopologyRefreshOptions.java b/src/main/java/com/lambdaworks/redis/cluster/ClusterTopologyRefreshOptions.java index ccd113e3ce..25838259a8 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/ClusterTopologyRefreshOptions.java +++ b/src/main/java/com/lambdaworks/redis/cluster/ClusterTopologyRefreshOptions.java @@ -111,11 +111,7 @@ public static class Builder { private TimeUnit adaptiveRefreshTimeoutUnit = DEFAULT_ADAPTIVE_REFRESH_TIMEOUT_UNIT; private int refreshTriggersReconnectAttempts = DEFAULT_REFRESH_TRIGGERS_RECONNECT_ATTEMPTS; - /** - * @deprecated Use {@link ClusterTopologyRefreshOptions#builder()} - */ - @Deprecated - public Builder() { + private Builder() { } /** diff --git a/src/main/java/com/lambdaworks/redis/cluster/RedisAdvancedClusterAsyncCommandsImpl.java b/src/main/java/com/lambdaworks/redis/cluster/RedisAdvancedClusterAsyncCommandsImpl.java index 89a2b5fd17..e207d69155 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/RedisAdvancedClusterAsyncCommandsImpl.java +++ b/src/main/java/com/lambdaworks/redis/cluster/RedisAdvancedClusterAsyncCommandsImpl.java @@ -11,6 +11,7 @@ import java.util.function.Predicate; import com.lambdaworks.redis.*; +import com.lambdaworks.redis.api.StatefulRedisConnection; import com.lambdaworks.redis.api.async.RedisAsyncCommands; import com.lambdaworks.redis.api.async.RedisKeyAsyncCommands; import com.lambdaworks.redis.api.async.RedisScriptingAsyncCommands; @@ -40,7 +41,7 @@ */ @SuppressWarnings("unchecked") public class RedisAdvancedClusterAsyncCommandsImpl extends AbstractRedisAsyncCommands implements - RedisAdvancedClusterAsyncConnection, RedisAdvancedClusterAsyncCommands { + RedisAdvancedClusterAsyncCommands { private Random random = new Random(); @@ -239,15 +240,15 @@ public RedisFuture clientSetname(K name) { Map> executions = new HashMap<>(); for (RedisClusterNode redisClusterNode : getStatefulConnection().getPartitions()) { - RedisClusterAsyncCommands byNodeId = getConnection(redisClusterNode.getNodeId()); + StatefulRedisConnection byNodeId = getStatefulConnection().getConnection(redisClusterNode.getNodeId()); if (byNodeId.isOpen()) { - executions.put("NodeId: " + redisClusterNode.getNodeId(), byNodeId.clientSetname(name)); + executions.put("NodeId: " + redisClusterNode.getNodeId(), byNodeId.async().clientSetname(name)); } RedisURI uri = redisClusterNode.getUri(); - RedisClusterAsyncCommands byHost = getConnection(uri.getHost(), uri.getPort()); + StatefulRedisConnection byHost = getStatefulConnection().getConnection(uri.getHost(), uri.getPort()); if (byHost.isOpen()) { - executions.put("HostAndPort: " + redisClusterNode.getNodeId(), byHost.clientSetname(name)); + executions.put("HostAndPort: " + redisClusterNode.getNodeId(), byHost.async().clientSetname(name)); } } @@ -374,7 +375,7 @@ public RedisFuture touch(Iterable keys) { /** * Run a command on all available masters, - * + * * @param function function producing the command * @param result type * @return map of a key (counter) and commands. @@ -386,7 +387,7 @@ protected Map> executeOnMasters( /** * Run a command on all available nodes that match {@code filter}. - * + * * @param function function producing the command * @param filter filter function for the node selection * @param result type @@ -403,9 +404,9 @@ protected Map> executeOnNodes( } RedisURI uri = redisClusterNode.getUri(); - RedisClusterAsyncCommands connection = getConnection(uri.getHost(), uri.getPort()); + StatefulRedisConnection connection = getStatefulConnection().getConnection(uri.getHost(), uri.getPort()); if (connection.isOpen()) { - executions.put(redisClusterNode.getNodeId(), function.apply(connection)); + executions.put(redisClusterNode.getNodeId(), function.apply(connection.async())); } } return executions; diff --git a/src/main/java/com/lambdaworks/redis/cluster/RedisAdvancedClusterAsyncConnection.java b/src/main/java/com/lambdaworks/redis/cluster/RedisAdvancedClusterAsyncConnection.java deleted file mode 100644 index 4bbc480aa6..0000000000 --- a/src/main/java/com/lambdaworks/redis/cluster/RedisAdvancedClusterAsyncConnection.java +++ /dev/null @@ -1,59 +0,0 @@ -package com.lambdaworks.redis.cluster; - -import com.lambdaworks.redis.RedisClusterAsyncConnection; -import com.lambdaworks.redis.RedisException; -import com.lambdaworks.redis.cluster.api.StatefulRedisClusterConnection; - -/** - * Advanced asynchronous and thread-safe cluster API. - * - * @author Mark Paluch - * @since 3.3 - * @deprecated Use {@link com.lambdaworks.redis.cluster.api.async.RedisAdvancedClusterAsyncCommands} - */ -@Deprecated -public interface RedisAdvancedClusterAsyncConnection extends RedisClusterAsyncConnection { - - /** - * Retrieve a connection to the specified cluster node using the nodeId. Host and port are looked up in the node list. This - * connection is bound to the node id. Once the cluster topology view is updated, the connection will try to reconnect the - * to the node with the specified {@code nodeId}, that behavior can also lead to a closed connection once the node with the - * specified {@code nodeId} is no longer part of the cluster. - * - * Do not close the connections. Otherwise, unpredictable behavior will occur. The nodeId must be part of the cluster and is - * validated against the current topology view in {@link com.lambdaworks.redis.cluster.models.partitions.Partitions}. - * - * In contrast to the {@link RedisAdvancedClusterAsyncConnection}, node-connections do not route commands to other cluster - * nodes. - * - * @param nodeId the node Id - * @return a connection to the requested cluster node - * @throws RedisException if the requested node identified by {@code nodeId} is not part of the cluster - */ - RedisClusterAsyncConnection getConnection(String nodeId); - - /** - * Retrieve a connection to the specified cluster node using the nodeId. This connection is bound to a host and port. - * Updates to the cluster topology view can close the connection once the host, identified by {@code host} and {@code port}, - * are no longer part of the cluster. - * - * Do not close the connections. Otherwise, unpredictable behavior will occur. The node must be part of the cluster and - * host/port are validated (exact check) against the current topology view in - * {@link com.lambdaworks.redis.cluster.models.partitions.Partitions}. - * - * In contrast to the {@link RedisAdvancedClusterAsyncConnection}, node-connections do not route commands to other cluster - * nodes. - * - * @param host the host - * @param port the port - * @return a connection to the requested cluster node - * @throws RedisException if the requested node identified by {@code host} and {@code port} is not part of the cluster - */ - RedisClusterAsyncConnection getConnection(String host, int port); - - /** - * @return the underlying connection. - */ - StatefulRedisClusterConnection getStatefulConnection(); - -} diff --git a/src/main/java/com/lambdaworks/redis/cluster/RedisAdvancedClusterConnection.java b/src/main/java/com/lambdaworks/redis/cluster/RedisAdvancedClusterConnection.java deleted file mode 100644 index 30f30ba03a..0000000000 --- a/src/main/java/com/lambdaworks/redis/cluster/RedisAdvancedClusterConnection.java +++ /dev/null @@ -1,57 +0,0 @@ -package com.lambdaworks.redis.cluster; - -import com.lambdaworks.redis.RedisClusterConnection; -import com.lambdaworks.redis.RedisException; -import com.lambdaworks.redis.cluster.api.StatefulRedisClusterConnection; - -/** - * Advanced synchronous and thread-safe cluster API. - * - * @author Mark Paluch - * @since 3.3 - * @deprecated Use {@link com.lambdaworks.redis.cluster.api.sync.RedisAdvancedClusterCommands} - */ -@Deprecated -public interface RedisAdvancedClusterConnection extends RedisClusterConnection { - - /** - * Retrieve a connection to the specified cluster node using the nodeId. Host and port are looked up in the node list. This - * connection is bound to the node id. Once the cluster topology view is updated, the connection will try to reconnect the - * to the node with the specified {@code nodeId}, that behavior can also lead to a closed connection once the node with the - * specified {@code nodeId} is no longer part of the cluster. - * - * Do not close the connections. Otherwise, unpredictable behavior will occur. The nodeId must be part of the cluster and is - * validated against the current topology view in {@link com.lambdaworks.redis.cluster.models.partitions.Partitions}. - * - * In contrast to the {@link RedisAdvancedClusterConnection}, node-connections do not route commands to other cluster nodes. - * - * @param nodeId the node Id - * @return a connection to the requested cluster node - * @throws RedisException if the requested node identified by {@code nodeId} is not part of the cluster - */ - RedisClusterConnection getConnection(String nodeId); - - /** - * Retrieve a connection to the specified cluster node using the nodeId. This connection is bound to a host and port. - * Updates to the cluster topology view can close the connection once the host, identified by {@code host} and {@code port}, - * are no longer part of the cluster. - * - * Do not close the connections. Otherwise, unpredictable behavior will occur. The node must be part of the cluster and - * host/port are validated (exact check) against the current topology view in - * {@link com.lambdaworks.redis.cluster.models.partitions.Partitions}. - * - * In contrast to the {@link RedisAdvancedClusterConnection}, node-connections do not route commands to other cluster nodes. - * - * @param host the host - * @param port the port - * @return a connection to the requested cluster node - * @throws RedisException if the requested node identified by {@code host} and {@code port} is not part of the cluster - */ - RedisClusterConnection getConnection(String host, int port); - - /** - * @return the underlying connection. - */ - StatefulRedisClusterConnection getStatefulConnection(); - -} diff --git a/src/main/java/com/lambdaworks/redis/cluster/RedisAdvancedClusterReactiveCommandsImpl.java b/src/main/java/com/lambdaworks/redis/cluster/RedisAdvancedClusterReactiveCommandsImpl.java index ce559f0390..219487850a 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/RedisAdvancedClusterReactiveCommandsImpl.java +++ b/src/main/java/com/lambdaworks/redis/cluster/RedisAdvancedClusterReactiveCommandsImpl.java @@ -13,6 +13,7 @@ import rx.Observable; import com.lambdaworks.redis.*; +import com.lambdaworks.redis.api.StatefulRedisConnection; import com.lambdaworks.redis.api.rx.RedisKeyReactiveCommands; import com.lambdaworks.redis.api.rx.RedisScriptingReactiveCommands; import com.lambdaworks.redis.api.rx.RedisServerReactiveCommands; @@ -26,6 +27,8 @@ import com.lambdaworks.redis.output.KeyStreamingChannel; import com.lambdaworks.redis.output.ValueStreamingChannel; +import rx.Observable; + /** * An advanced reactive and thread-safe API to a Redis Cluster connection. * @@ -224,15 +227,15 @@ public Observable clientSetname(K name) { List> observables = new ArrayList<>(); for (RedisClusterNode redisClusterNode : getStatefulConnection().getPartitions()) { - RedisClusterReactiveCommands byNodeId = getConnection(redisClusterNode.getNodeId()); + StatefulRedisConnection byNodeId = getStatefulConnection().getConnection(redisClusterNode.getNodeId()); if (byNodeId.isOpen()) { - observables.add(byNodeId.clientSetname(name)); + observables.add(byNodeId.reactive().clientSetname(name)); } - RedisClusterReactiveCommands byHost = getConnection(redisClusterNode.getUri().getHost(), redisClusterNode + StatefulRedisConnection byHost = getStatefulConnection().getConnection(redisClusterNode.getUri().getHost(), redisClusterNode .getUri().getPort()); if (byHost.isOpen()) { - observables.add(byHost.clientSetname(name)); + observables.add(byHost.reactive().clientSetname(name)); } } @@ -354,9 +357,9 @@ protected Map> executeOnNodes( } RedisURI uri = redisClusterNode.getUri(); - RedisClusterReactiveCommands connection = getConnection(uri.getHost(), uri.getPort()); + StatefulRedisConnection connection = getStatefulConnection().getConnection(uri.getHost(), uri.getPort()); if (connection.isOpen()) { - executions.put(redisClusterNode.getNodeId(), function.apply(connection)); + executions.put(redisClusterNode.getNodeId(), function.apply(connection.reactive())); } } return executions; diff --git a/src/main/java/com/lambdaworks/redis/cluster/RedisClusterClient.java b/src/main/java/com/lambdaworks/redis/cluster/RedisClusterClient.java index 0dbe3163e7..824a0ade39 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/RedisClusterClient.java +++ b/src/main/java/com/lambdaworks/redis/cluster/RedisClusterClient.java @@ -125,32 +125,9 @@ public class RedisClusterClient extends AbstractRedisClient { private RedisClusterClient() { - setOptions(ClusterClientOptions.create()); - this.initialUris = Collections.emptyList(); - } - - /** - * Initialize the client with an initial cluster URI. - * - * @param initialUri initial cluster URI - * @deprecated Use {@link #create(RedisURI)} - */ - @Deprecated - public RedisClusterClient(RedisURI initialUri) { - this(Collections.singletonList(assertNotNull(initialUri))); - } + super(null); - /** - * Initialize the client with a list of cluster URI's. All uris are tried in sequence for connecting initially to the - * cluster. If any uri is successful for connection, the others are not tried anymore. The initial uri is needed to discover - * the cluster structure for distributing the requests. - * - * @param redisURIs iterable of initial {@link RedisURI cluster URIs}. Must not be {@literal null} and not empty. - * @deprecated Use {@link #create(Iterable)} - */ - @Deprecated - public RedisClusterClient(List redisURIs) { - this(null, redisURIs); + initialUris = Collections.emptyList(); } /** @@ -378,58 +355,6 @@ public StatefulRedisPubSubConnection connectPubSub(RedisCodec return connectClusterPubSubImpl(codec); } - /** - * Open a new synchronous connection to a Redis Cluster that treats keys and values as UTF-8 strings. - * - * @return A new connection - * @deprecated Use {@code connect().sync()} - */ - @Deprecated - public RedisAdvancedClusterCommands connectCluster() { - return connectCluster(newStringStringCodec()); - } - - /** - * Open a new synchronous connection to a Redis Cluster. Use the supplied {@link RedisCodec codec} to encode/decode keys and - * values. - * - * @param codec Use this codec to encode/decode keys and values, must not be {@literal null} - * @param Key type - * @param Value type - * @return A new connection - * @deprecated @deprecated Use {@code connect(codec).sync()} - */ - @SuppressWarnings("unchecked") - @Deprecated - public RedisAdvancedClusterCommands connectCluster(RedisCodec codec) { - return connectClusterImpl(codec).sync(); - } - - /** - * Open a new asynchronous connection to a Redis Cluster that treats keys and values as UTF-8 strings. - * - * @return A new connection - * @deprecated Use {@code connect().async()} - */ - @Deprecated - public RedisAdvancedClusterAsyncCommands connectClusterAsync() { - return connectClusterImpl(newStringStringCodec()).async(); - } - - /** - * Open a new asynchronous connection to a Redis Cluster. Use the supplied {@link RedisCodec codec} to encode/decode keys - * and values. - * - * @param codec Use this codec to encode/decode keys and values, must not be {@literal null} - * @param Key type - * @param Value type - * @return A new connection - * @deprecated @deprecated Use {@code connect(codec).async()} - */ - @Deprecated - public RedisAdvancedClusterAsyncCommands connectClusterAsync(RedisCodec codec) { - return connectClusterImpl(codec).async(); - } protected StatefulRedisConnection connectToNode(final SocketAddress socketAddress) { return connectToNode(newStringStringCodec(), socketAddress.toString(), null, new Supplier() { diff --git a/src/main/java/com/lambdaworks/redis/cluster/StatefulRedisClusterConnectionImpl.java b/src/main/java/com/lambdaworks/redis/cluster/StatefulRedisClusterConnectionImpl.java index e36a7f97bc..2503df6dbe 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/StatefulRedisClusterConnectionImpl.java +++ b/src/main/java/com/lambdaworks/redis/cluster/StatefulRedisClusterConnectionImpl.java @@ -1,6 +1,8 @@ package com.lambdaworks.redis.cluster; -import static com.lambdaworks.redis.protocol.CommandType.*; +import static com.lambdaworks.redis.protocol.CommandType.AUTH; +import static com.lambdaworks.redis.protocol.CommandType.READONLY; +import static com.lambdaworks.redis.protocol.CommandType.READWRITE; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; @@ -71,7 +73,7 @@ public StatefulRedisClusterConnectionImpl(RedisChannelWriter writer, Redis this.async = new RedisAdvancedClusterAsyncCommandsImpl<>(this, codec); this.sync = (RedisAdvancedClusterCommands) Proxy.newProxyInstance(AbstractRedisClient.class.getClassLoader(), - new Class[] { RedisAdvancedClusterConnection.class, RedisAdvancedClusterCommands.class }, syncInvocationHandler()); + new Class[] { RedisAdvancedClusterCommands.class }, syncInvocationHandler()); this.reactive = new RedisAdvancedClusterReactiveCommandsImpl<>(this, codec); } @@ -94,11 +96,6 @@ public RedisAdvancedClusterReactiveCommands reactive() { return reactive; } - @Deprecated - protected RedisAdvancedClusterReactiveCommandsImpl getReactiveCommands() { - return reactive; - } - private RedisURI lookup(String nodeId) { for (RedisClusterNode partition : partitions) { diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/async/BaseNodeSelectionAsyncCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/async/BaseNodeSelectionAsyncCommands.java index 70f16aa8c8..4aa308f69f 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/async/BaseNodeSelectionAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/async/BaseNodeSelectionAsyncCommands.java @@ -1,8 +1,10 @@ package com.lambdaworks.redis.cluster.api.async; -import java.lang.AutoCloseable; import java.util.List; import java.util.Map; +import com.lambdaworks.redis.protocol.CommandArgs; +import com.lambdaworks.redis.protocol.ProtocolKeyword; +import com.lambdaworks.redis.output.CommandOutput; import com.lambdaworks.redis.RedisFuture; /** @@ -94,4 +96,40 @@ public interface BaseNodeSelectionAsyncCommands extends AutoCloseable { * @return number of replicas */ AsyncExecutions waitForReplication(int replicas, long timeout); + + /** + * Dispatch a command to the Redis Server. Please note the command output type must fit to the command response. + * + * @param type the command, must not be {@literal null}. + * @param output the command output, must not be {@literal null}. + * @param response type + * @return the command response + */ + AsyncExecutions dispatch(ProtocolKeyword type, CommandOutput output); + + /** + * Dispatch a command to the Redis Server. Please note the command output type must fit to the command response. + * + * @param type the command, must not be {@literal null}. + * @param output the command output, must not be {@literal null}. + * @param args the command arguments, must not be {@literal null}. + * @param response type + * @return the command response + */ + AsyncExecutions dispatch(ProtocolKeyword type, CommandOutput output, CommandArgs args); + + /** + * Disable or enable auto-flush behavior. Default is {@literal true}. If autoFlushCommands is disabled, multiple commands + * can be issued without writing them actually to the transport. Commands are buffered until a {@link #flushCommands()} is + * issued. After calling {@link #flushCommands()} commands are sent to the transport and executed by Redis. + * + * @param autoFlush state of autoFlush. + */ + AsyncExecutions setAutoFlushCommands(boolean autoFlush); + + /** + * Flush pending commands. This commands forces a flush on the channel and can be used to buffer ("pipeline") commands to + * achieve batching. No-op if channel is not connected. + */ + AsyncExecutions flushCommands(); } diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionListAsyncCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionListAsyncCommands.java index c99450d89b..083f1b89ff 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionListAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionListAsyncCommands.java @@ -99,16 +99,6 @@ public interface NodeSelectionListAsyncCommands { */ AsyncExecutions lpush(K key, V... values); - /** - * Prepend a value to a list, only if the list exists. - * - * @param key the key - * @param value the value - * @return Long integer-reply the length of the list after the push operation. - * @deprecated Use {@link #lpushx(Object, Object[])} - */ - AsyncExecutions lpushx(K key, V value); - /** * Prepend values to a list, only if the list exists. * @@ -195,16 +185,6 @@ public interface NodeSelectionListAsyncCommands { */ AsyncExecutions rpush(K key, V... values); - /** - * Append a value to a list, only if the list exists. - * - * @param key the key - * @param value the value - * @return Long integer-reply the length of the list after the push operation. - * @deprecated Use {@link #rpushx(java.lang.Object, java.lang.Object[])} - */ - AsyncExecutions rpushx(K key, V value); - /** * Append values to a list, only if the list exists. * diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionServerAsyncCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionServerAsyncCommands.java index bf47db28d0..7dcf7fd256 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionServerAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionServerAsyncCommands.java @@ -294,14 +294,6 @@ public interface NodeSelectionServerAsyncCommands { */ AsyncExecutions slowlogReset(); - /** - * Internal command used for replication. - * - * @return String simple-string-reply - */ - @Deprecated - AsyncExecutions sync(); - /** * Return the current server time. * diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionStringAsyncCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionStringAsyncCommands.java index 21228dbf78..841a6bea7a 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionStringAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionStringAsyncCommands.java @@ -1,15 +1,15 @@ package com.lambdaworks.redis.cluster.api.async; -import com.lambdaworks.redis.BitFieldArgs; -import com.lambdaworks.redis.SetArgs; -import com.lambdaworks.redis.output.ValueStreamingChannel; - import java.util.List; import java.util.Map; +import com.lambdaworks.redis.output.ValueStreamingChannel; +import com.lambdaworks.redis.BitFieldArgs; +import com.lambdaworks.redis.SetArgs; +import com.lambdaworks.redis.RedisFuture; /** * Asynchronous executed commands on a node selection for Strings. - * + * * @param Key type. * @param Value type. * @author Mark Paluch @@ -20,7 +20,7 @@ public interface NodeSelectionStringAsyncCommands { /** * Append a value to a key. - * + * * @param key the key * @param value the value * @return Long integer-reply the length of the string after the append operation. @@ -29,52 +29,52 @@ public interface NodeSelectionStringAsyncCommands { /** * Count set bits in a string. - * + * * @param key the key - * + * * @return Long integer-reply The number of bits set to 1. */ AsyncExecutions bitcount(K key); /** * Count set bits in a string. - * + * * @param key the key * @param start the start * @param end the end - * + * * @return Long integer-reply The number of bits set to 1. */ AsyncExecutions bitcount(K key, long start, long end); /** * Execute {@code BITFIELD} with its subcommands. - * + * * @param key the key * @param bitFieldArgs the args containing subcommands, must not be {@literal null}. - * + * * @return Long bulk-reply the results from the bitfield commands. */ AsyncExecutions> bitfield(K key, BitFieldArgs bitFieldArgs); /** * Find first bit set or clear in a string. - * + * * @param key the key * @param state the state - * + * * @return Long integer-reply The command returns the position of the first bit set to 1 or 0 according to the request. - * + * * If we look for set bits (the bit argument is 1) and the string is empty or composed of just zero bytes, -1 is * returned. - * + * * If we look for clear bits (the bit argument is 0) and the string only contains bit set to 1, the function returns * the first bit not part of the string on the right. So if the string is tree bytes set to the value 0xff the * command {@code BITPOS key 0} will return 24, since up to bit 23 all the bits are 1. - * + * * Basically the function consider the right of the string as padded with zeros if you look for clear bits and * specify no range or the start argument only. - * + * * However this behavior changes if you are looking for clear bits and specify a range with both * start and end. If no clear bit is found in the specified range, the function * returns -1 as the user specified a clear range and there are no 0 bits in that range. @@ -83,23 +83,23 @@ public interface NodeSelectionStringAsyncCommands { /** * Find first bit set or clear in a string. - * + * * @param key the key * @param state the bit type: long * @param start the start type: long * @param end the end type: long * @return Long integer-reply The command returns the position of the first bit set to 1 or 0 according to the request. - * + * * If we look for set bits (the bit argument is 1) and the string is empty or composed of just zero bytes, -1 is * returned. - * + * * If we look for clear bits (the bit argument is 0) and the string only contains bit set to 1, the function returns * the first bit not part of the string on the right. So if the string is tree bytes set to the value 0xff the * command {@code BITPOS key 0} will return 24, since up to bit 23 all the bits are 1. - * + * * Basically the function consider the right of the string as padded with zeros if you look for clear bits and * specify no range or the start argument only. - * + * * However this behavior changes if you are looking for clear bits and specify a range with both * start and end. If no clear bit is found in the specified range, the function * returns -1 as the user specified a clear range and there are no 0 bits in that range. @@ -108,7 +108,7 @@ public interface NodeSelectionStringAsyncCommands { /** * Perform bitwise AND between strings. - * + * * @param destination result key of the operation * @param keys operation input key names * @return Long integer-reply The size of the string stored in the destination key, that is equal to the size of the longest @@ -118,7 +118,7 @@ public interface NodeSelectionStringAsyncCommands { /** * Perform bitwise NOT between strings. - * + * * @param destination result key of the operation * @param source operation input key names * @return Long integer-reply The size of the string stored in the destination key, that is equal to the size of the longest @@ -128,7 +128,7 @@ public interface NodeSelectionStringAsyncCommands { /** * Perform bitwise OR between strings. - * + * * @param destination result key of the operation * @param keys operation input key names * @return Long integer-reply The size of the string stored in the destination key, that is equal to the size of the longest @@ -138,7 +138,7 @@ public interface NodeSelectionStringAsyncCommands { /** * Perform bitwise XOR between strings. - * + * * @param destination result key of the operation * @param keys operation input key names * @return Long integer-reply The size of the string stored in the destination key, that is equal to the size of the longest @@ -148,7 +148,7 @@ public interface NodeSelectionStringAsyncCommands { /** * Decrement the integer value of a key by one. - * + * * @param key the key * @return Long integer-reply the value of {@code key} after the decrement */ @@ -156,7 +156,7 @@ public interface NodeSelectionStringAsyncCommands { /** * Decrement the integer value of a key by the given number. - * + * * @param key the key * @param amount the decrement type: long * @return Long integer-reply the value of {@code key} after the decrement @@ -165,7 +165,7 @@ public interface NodeSelectionStringAsyncCommands { /** * Get the value of a key. - * + * * @param key the key * @return V bulk-string-reply the value of {@code key}, or {@literal null} when {@code key} does not exist. */ @@ -173,7 +173,7 @@ public interface NodeSelectionStringAsyncCommands { /** * Returns the bit value at offset in the string value stored at key. - * + * * @param key the key * @param offset the offset type: long * @return Long integer-reply the bit value stored at offset. @@ -182,7 +182,7 @@ public interface NodeSelectionStringAsyncCommands { /** * Get a substring of the string stored at a key. - * + * * @param key the key * @param start the start type: long * @param end the end type: long @@ -192,7 +192,7 @@ public interface NodeSelectionStringAsyncCommands { /** * Set the string value of a key and return its old value. - * + * * @param key the key * @param value the value * @return V bulk-string-reply the old value stored at {@code key}, or {@literal null} when {@code key} did not exist. @@ -201,7 +201,7 @@ public interface NodeSelectionStringAsyncCommands { /** * Increment the integer value of a key by one. - * + * * @param key the key * @return Long integer-reply the value of {@code key} after the increment */ @@ -209,7 +209,7 @@ public interface NodeSelectionStringAsyncCommands { /** * Increment the integer value of a key by the given amount. - * + * * @param key the key * @param amount the increment type: long * @return Long integer-reply the value of {@code key} after the increment @@ -218,7 +218,7 @@ public interface NodeSelectionStringAsyncCommands { /** * Increment the float value of a key by the given amount. - * + * * @param key the key * @param amount the increment type: double * @return Double bulk-string-reply the value of {@code key} after the increment. @@ -227,7 +227,7 @@ public interface NodeSelectionStringAsyncCommands { /** * Get the values of all the given keys. - * + * * @param keys the key * @return List<V> array-reply list of values at the specified keys. */ @@ -235,17 +235,17 @@ public interface NodeSelectionStringAsyncCommands { /** * Stream over the values of all the given keys. - * + * * @param channel the channel * @param keys the keys - * + * * @return Long array-reply list of values at the specified keys. */ AsyncExecutions mget(ValueStreamingChannel channel, K... keys); /** * Set multiple keys to multiple values. - * + * * @param map the null * @return String simple-string-reply always {@code OK} since {@code MSET} can't fail. */ @@ -253,38 +253,38 @@ public interface NodeSelectionStringAsyncCommands { /** * Set multiple keys to multiple values, only if none of the keys exist. - * + * * @param map the null * @return Boolean integer-reply specifically: - * + * * {@code 1} if the all the keys were set. {@code 0} if no key was set (at least one key already existed). */ AsyncExecutions msetnx(Map map); /** * Set the string value of a key. - * + * * @param key the key * @param value the value - * + * * @return String simple-string-reply {@code OK} if {@code SET} was executed correctly. */ AsyncExecutions set(K key, V value); /** * Set the string value of a key. - * + * * @param key the key * @param value the value * @param setArgs the setArgs - * + * * @return String simple-string-reply {@code OK} if {@code SET} was executed correctly. */ AsyncExecutions set(K key, V value, SetArgs setArgs); /** * Sets or clears the bit at offset in the string value stored at key. - * + * * @param key the key * @param offset the offset type: long * @param value the value type: string @@ -294,7 +294,7 @@ public interface NodeSelectionStringAsyncCommands { /** * Set the value and expiration of a key. - * + * * @param key the key * @param seconds the seconds type: long * @param value the value @@ -304,7 +304,7 @@ public interface NodeSelectionStringAsyncCommands { /** * Set the value and expiration in milliseconds of a key. - * + * * @param key the key * @param milliseconds the milliseconds type: long * @param value the value @@ -314,18 +314,18 @@ public interface NodeSelectionStringAsyncCommands { /** * Set the value of a key, only if the key does not exist. - * + * * @param key the key * @param value the value * @return Boolean integer-reply specifically: - * + * * {@code 1} if the key was set {@code 0} if the key was not set */ AsyncExecutions setnx(K key, V value); /** * Overwrite part of a string at key starting at the specified offset. - * + * * @param key the key * @param offset the offset type: long * @param value the value @@ -335,7 +335,7 @@ public interface NodeSelectionStringAsyncCommands { /** * Get the length of the value stored in a key. - * + * * @param key the key * @return Long integer-reply the length of the string at {@code key}, or {@code 0} when {@code key} does not exist. */ diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/async/RedisAdvancedClusterAsyncCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/async/RedisAdvancedClusterAsyncCommands.java index 4ed24b0adf..33fe6f5432 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/async/RedisAdvancedClusterAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/async/RedisAdvancedClusterAsyncCommands.java @@ -10,7 +10,6 @@ import com.lambdaworks.redis.api.async.RedisServerAsyncCommands; import com.lambdaworks.redis.api.async.RedisStringAsyncCommands; import com.lambdaworks.redis.cluster.ClusterClientOptions; -import com.lambdaworks.redis.cluster.RedisAdvancedClusterAsyncConnection; import com.lambdaworks.redis.cluster.api.NodeSelectionSupport; import com.lambdaworks.redis.cluster.api.StatefulRedisClusterConnection; import com.lambdaworks.redis.cluster.models.partitions.RedisClusterNode; @@ -23,7 +22,7 @@ * @since 4.0 */ public interface RedisAdvancedClusterAsyncCommands - extends RedisClusterAsyncCommands, RedisAdvancedClusterAsyncConnection { + extends RedisClusterAsyncCommands { /** * Retrieve a connection to the specified cluster node using the nodeId. Host and port are looked up in the node list. diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/async/RedisClusterAsyncCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/async/RedisClusterAsyncCommands.java index afeec58229..dced1f67ce 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/async/RedisClusterAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/async/RedisClusterAsyncCommands.java @@ -4,7 +4,6 @@ import java.util.Map; import java.util.concurrent.TimeUnit; -import com.lambdaworks.redis.RedisClusterAsyncConnection; import com.lambdaworks.redis.RedisFuture; import com.lambdaworks.redis.api.async.*; @@ -20,7 +19,7 @@ public interface RedisClusterAsyncCommands extends RedisHashAsyncCommands, RedisKeyAsyncCommands, RedisStringAsyncCommands, RedisListAsyncCommands, RedisSetAsyncCommands, RedisSortedSetAsyncCommands, RedisScriptingAsyncCommands, RedisServerAsyncCommands, RedisHLLAsyncCommands, - RedisGeoAsyncCommands, BaseRedisAsyncCommands, RedisClusterAsyncConnection { + RedisGeoAsyncCommands, BaseRedisAsyncCommands { /** * Set the default timeout for operations. diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/sync/BaseNodeSelectionCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/sync/BaseNodeSelectionCommands.java index 3d38f61c10..31cbb13e8b 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/sync/BaseNodeSelectionCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/sync/BaseNodeSelectionCommands.java @@ -1,8 +1,10 @@ package com.lambdaworks.redis.cluster.api.sync; -import java.lang.AutoCloseable; import java.util.List; import java.util.Map; +import com.lambdaworks.redis.protocol.CommandArgs; +import com.lambdaworks.redis.protocol.ProtocolKeyword; +import com.lambdaworks.redis.output.CommandOutput; /** * @@ -93,4 +95,19 @@ public interface BaseNodeSelectionCommands extends AutoCloseable { * @return number of replicas */ Executions waitForReplication(int replicas, long timeout); + + /** + * Disable or enable auto-flush behavior. Default is {@literal true}. If autoFlushCommands is disabled, multiple commands + * can be issued without writing them actually to the transport. Commands are buffered until a {@link #flushCommands()} is + * issued. After calling {@link #flushCommands()} commands are sent to the transport and executed by Redis. + * + * @param autoFlush state of autoFlush. + */ + Executions setAutoFlushCommands(boolean autoFlush); + + /** + * Flush pending commands. This commands forces a flush on the channel and can be used to buffer ("pipeline") commands to + * achieve batching. No-op if channel is not connected. + */ + Executions flushCommands(); } diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionListCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionListCommands.java index a8a1dafe1d..9d4830c0ba 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionListCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionListCommands.java @@ -98,16 +98,6 @@ public interface NodeSelectionListCommands { */ Executions lpush(K key, V... values); - /** - * Prepend a value to a list, only if the list exists. - * - * @param key the key - * @param value the value - * @return Long integer-reply the length of the list after the push operation. - * @deprecated Use {@link #lpushx(Object, Object[])} - */ - Executions lpushx(K key, V value); - /** * Prepend values to a list, only if the list exists. * @@ -194,16 +184,6 @@ public interface NodeSelectionListCommands { */ Executions rpush(K key, V... values); - /** - * Append a value to a list, only if the list exists. - * - * @param key the key - * @param value the value - * @return Long integer-reply the length of the list after the push operation. - * @deprecated Use {@link #rpushx(java.lang.Object, java.lang.Object[])} - */ - Executions rpushx(K key, V value); - /** * Append values to a list, only if the list exists. * diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionServerCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionServerCommands.java index 7599ee4809..c0554cdbf9 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionServerCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionServerCommands.java @@ -293,14 +293,6 @@ public interface NodeSelectionServerCommands { */ Executions slowlogReset(); - /** - * Internal command used for replication. - * - * @return String simple-string-reply - */ - @Deprecated - Executions sync(); - /** * Return the current server time. * diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/sync/RedisAdvancedClusterCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/sync/RedisAdvancedClusterCommands.java index 5bf7a14e68..19bb507013 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/sync/RedisAdvancedClusterCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/sync/RedisAdvancedClusterCommands.java @@ -10,7 +10,6 @@ import com.lambdaworks.redis.api.sync.RedisServerCommands; import com.lambdaworks.redis.api.sync.RedisStringCommands; import com.lambdaworks.redis.cluster.ClusterClientOptions; -import com.lambdaworks.redis.cluster.RedisAdvancedClusterConnection; import com.lambdaworks.redis.cluster.api.NodeSelectionSupport; import com.lambdaworks.redis.cluster.api.StatefulRedisClusterConnection; import com.lambdaworks.redis.cluster.models.partitions.RedisClusterNode; @@ -22,7 +21,7 @@ * @author Mark Paluch * @since 4.0 */ -public interface RedisAdvancedClusterCommands extends RedisClusterCommands, RedisAdvancedClusterConnection { +public interface RedisAdvancedClusterCommands extends RedisClusterCommands { /** * Retrieve a connection to the specified cluster node using the nodeId. Host and port are looked up in the node list. In diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/sync/RedisClusterCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/sync/RedisClusterCommands.java index 611c9e1a1a..4d9dcf08d3 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/sync/RedisClusterCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/sync/RedisClusterCommands.java @@ -3,7 +3,6 @@ import java.util.List; import java.util.concurrent.TimeUnit; -import com.lambdaworks.redis.RedisClusterConnection; import com.lambdaworks.redis.api.sync.*; /** @@ -16,8 +15,7 @@ */ public interface RedisClusterCommands extends RedisHashCommands, RedisKeyCommands, RedisStringCommands, RedisListCommands, RedisSetCommands, RedisSortedSetCommands, RedisScriptingCommands, - RedisServerCommands, RedisHLLCommands, RedisGeoCommands, BaseRedisCommands, AutoCloseable, - RedisClusterConnection { + RedisServerCommands, RedisHLLCommands, RedisGeoCommands, BaseRedisCommands { /** * Set the default timeout for operations. @@ -34,7 +32,7 @@ public interface RedisClusterCommands extends RedisHashCommands, Red * @return String simple-string-reply */ String auth(String password); - + /** * Generate a new config epoch, incrementing the current epoch, assign the new epoch to this node, WITHOUT any consensus and * persist the configuration on disk before sending packets with the new configuration. @@ -272,11 +270,4 @@ public interface RedisClusterCommands extends RedisHashCommands, Red * @return String simple-string-reply */ String readWrite(); - - /** - * Close the connection. The connection will become not usable anymore as soon as this method was called. - */ - @Override - void close(); - } diff --git a/src/main/java/com/lambdaworks/redis/cluster/models/slots/ClusterSlotRange.java b/src/main/java/com/lambdaworks/redis/cluster/models/slots/ClusterSlotRange.java index 750287f6b7..eed08503f0 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/models/slots/ClusterSlotRange.java +++ b/src/main/java/com/lambdaworks/redis/cluster/models/slots/ClusterSlotRange.java @@ -22,41 +22,10 @@ public class ClusterSlotRange implements Serializable { private int from; private int to; - @Deprecated - private HostAndPort master; - private RedisClusterNode masterNode; - - @Deprecated - private List slaves = Collections.emptyList(); - private List slaveNodes = Collections.emptyList(); public ClusterSlotRange() { - - } - - /** - * Constructs a {@link ClusterSlotRange} - * - * @param from from slot - * @param to to slot - * @param master master for the slots, may be {@literal null} - * @param slaves list of slaves must not be {@literal null} but may be empty - * @deprecated Use {@link #ClusterSlotRange(int, int, RedisClusterNode, List)} - */ - @Deprecated - public ClusterSlotRange(int from, int to, HostAndPort master, List slaves) { - - LettuceAssert.notNull(master, "Master must not be null"); - LettuceAssert.notNull(slaves, "Slaves must not be null"); - - this.from = from; - this.to = to; - this.masterNode = toRedisClusterNode(master, null, Collections.singleton(RedisClusterNode.NodeFlag.MASTER)); - this.slaveNodes = toRedisClusterNodes(slaves, null, Collections.singleton(RedisClusterNode.NodeFlag.SLAVE)); - this.master = master; - this.slaves = slaves; } /** @@ -74,35 +43,21 @@ public ClusterSlotRange(int from, int to, RedisClusterNode masterNode, List toHostAndPorts(List nodes) { - List result = new ArrayList<>(); - for (RedisClusterNode node : nodes) { - result.add(toHostAndPort(node)); - } - return result; - } - private RedisClusterNode toRedisClusterNode(HostAndPort hostAndPort, String slaveOf, Set flags) { RedisClusterNode redisClusterNode = new RedisClusterNode(); - redisClusterNode.setUri(RedisURI - .create(hostAndPort.getHostText(), hostAndPort.getPortOrDefault(RedisURI.DEFAULT_REDIS_PORT))); + redisClusterNode + .setUri(RedisURI.create(hostAndPort.getHostText(), hostAndPort.getPortOrDefault(RedisURI.DEFAULT_REDIS_PORT))); redisClusterNode.setSlaveOf(slaveOf); redisClusterNode.setFlags(flags); return redisClusterNode; } - private List toRedisClusterNodes(List hostAndPorts, String slaveOf, Set flags) { + private List toRedisClusterNodes(List hostAndPorts, String slaveOf, + Set flags) { List result = new ArrayList<>(); for (HostAndPort hostAndPort : hostAndPorts) { result.add(toRedisClusterNode(hostAndPort, slaveOf, flags)); @@ -118,24 +73,6 @@ public int getTo() { return to; } - /** - * @deprecated Use {@link #getMasterNode()} to retrieve the {@code nodeId} and the {@code slaveOf} details. - * @return the master host and port - */ - @Deprecated - public HostAndPort getMaster() { - return master; - } - - /** - * @deprecated Use {@link #getSlaveNodes()} to retrieve the {@code nodeId} and the {@code slaveOf} details. - * @return the master host and port - */ - @Deprecated - public List getSlaves() { - return slaves; - } - public RedisClusterNode getMasterNode() { return masterNode; } @@ -160,17 +97,6 @@ public void setTo(int to) { this.to = to; } - public void setMaster(HostAndPort master) { - LettuceAssert.notNull(master, "Master must not be null"); - this.master = master; - } - - public void setSlaves(List slaves) { - - LettuceAssert.notNull(slaves, "Slaves must not be null"); - this.slaves = slaves; - } - @Override public String toString() { final StringBuilder sb = new StringBuilder(); diff --git a/src/main/java/com/lambdaworks/redis/masterslave/MasterSlaveConnectionProvider.java b/src/main/java/com/lambdaworks/redis/masterslave/MasterSlaveConnectionProvider.java index 3350621229..cf181b96de 100644 --- a/src/main/java/com/lambdaworks/redis/masterslave/MasterSlaveConnectionProvider.java +++ b/src/main/java/com/lambdaworks/redis/masterslave/MasterSlaveConnectionProvider.java @@ -43,15 +43,6 @@ public class MasterSlaveConnectionProvider { private Object stateLock = new Object(); private ReadFrom readFrom; - @Deprecated - public MasterSlaveConnectionProvider(RedisClient redisClient, RedisCodec redisCodec, - StatefulRedisConnection masterConnection, RedisURI initialRedisUri) { - this.initialRedisUri = initialRedisUri; - this.debugEnabled = logger.isDebugEnabled(); - this.connectionFactory = new ConnectionFactory<>(redisClient, redisCodec); - connections.put(toConnectionKey(initialRedisUri), masterConnection); - } - MasterSlaveConnectionProvider(RedisClient redisClient, RedisCodec redisCodec, RedisURI initialRedisUri, Map> initialConnections) { diff --git a/src/main/java/com/lambdaworks/redis/metrics/DefaultCommandLatencyCollectorOptions.java b/src/main/java/com/lambdaworks/redis/metrics/DefaultCommandLatencyCollectorOptions.java index eb4fa60ac9..6723979266 100644 --- a/src/main/java/com/lambdaworks/redis/metrics/DefaultCommandLatencyCollectorOptions.java +++ b/src/main/java/com/lambdaworks/redis/metrics/DefaultCommandLatencyCollectorOptions.java @@ -2,7 +2,6 @@ import java.util.concurrent.TimeUnit; -import com.lambdaworks.redis.ClientOptions; import com.lambdaworks.redis.internal.LettuceAssert; /** @@ -74,11 +73,7 @@ public static class Builder { private boolean localDistinction = DEFAULT_LOCAL_DISTINCTION; private boolean enabled = DEFAULT_ENABLED; - /** - * @deprecated Use {@link ClientOptions#builder()} - */ - @Deprecated - public Builder() { + private Builder() { } /** diff --git a/src/main/java/com/lambdaworks/redis/pubsub/RedisPubSubAsyncCommandsImpl.java b/src/main/java/com/lambdaworks/redis/pubsub/RedisPubSubAsyncCommandsImpl.java index a22398e1ed..7a74854617 100644 --- a/src/main/java/com/lambdaworks/redis/pubsub/RedisPubSubAsyncCommandsImpl.java +++ b/src/main/java/com/lambdaworks/redis/pubsub/RedisPubSubAsyncCommandsImpl.java @@ -2,20 +2,13 @@ package com.lambdaworks.redis.pubsub; -import static com.lambdaworks.redis.protocol.CommandType.PSUBSCRIBE; -import static com.lambdaworks.redis.protocol.CommandType.PUNSUBSCRIBE; -import static com.lambdaworks.redis.protocol.CommandType.SUBSCRIBE; -import static com.lambdaworks.redis.protocol.CommandType.UNSUBSCRIBE; +import java.util.List; +import java.util.Map; import com.lambdaworks.redis.RedisAsyncCommandsImpl; import com.lambdaworks.redis.RedisFuture; import com.lambdaworks.redis.codec.RedisCodec; -import com.lambdaworks.redis.protocol.CommandArgs; import com.lambdaworks.redis.pubsub.api.async.RedisPubSubAsyncCommands; -import rx.Observable; - -import java.util.List; -import java.util.Map; /** * An asynchronous and thread-safe API for a Redis pub/sub connection. @@ -24,8 +17,7 @@ * @param Value type. * @author Will Glozer */ -public class RedisPubSubAsyncCommandsImpl extends RedisAsyncCommandsImpl implements RedisPubSubConnection, - RedisPubSubAsyncCommands { +public class RedisPubSubAsyncCommandsImpl extends RedisAsyncCommandsImpl implements RedisPubSubAsyncCommands { private PubSubCommandBuilder commandBuilder; diff --git a/src/main/java/com/lambdaworks/redis/pubsub/RedisPubSubConnection.java b/src/main/java/com/lambdaworks/redis/pubsub/RedisPubSubConnection.java deleted file mode 100644 index ed47ea1d1d..0000000000 --- a/src/main/java/com/lambdaworks/redis/pubsub/RedisPubSubConnection.java +++ /dev/null @@ -1,62 +0,0 @@ -package com.lambdaworks.redis.pubsub; - -import com.lambdaworks.redis.RedisAsyncConnection; -import com.lambdaworks.redis.RedisFuture; -import com.lambdaworks.redis.pubsub.api.async.RedisPubSubAsyncCommands; - -/** - * @param Key type. - * @param Value type. - * @author Mark Paluch - * @since 3.0 - * @deprecated Use {@link RedisPubSubAsyncCommands} - */ -@Deprecated -public interface RedisPubSubConnection extends RedisAsyncConnection { - - /** - * Add a new listener. - * - * @param listener Listener. - */ - void addListener(RedisPubSubListener listener); - - /** - * Remove an existing listener. - * - * @param listener Listener. - */ - void removeListener(RedisPubSubListener listener); - - /** - * Listen for messages published to channels matching the given patterns. - * - * @param patterns the patterns - * @return RedisFuture<Void> Future to synchronize {@code psubscribe} completion - */ - RedisFuture psubscribe(K... patterns); - - /** - * Stop listening for messages posted to channels matching the given patterns. - * - * @param patterns the patterns - * @return RedisFuture<Void> Future to synchronize {@code punsubscribe} completion - */ - RedisFuture punsubscribe(K... patterns); - - /** - * Listen for messages published to the given channels. - * - * @param channels the channels - * @return RedisFuture<Void> Future to synchronize {@code subscribe} completion - */ - RedisFuture subscribe(K... channels); - - /** - * Stop listening for messages posted to the given channels. - * - * @param channels the channels - * @return RedisFuture<Void> Future to synchronize {@code unsubscribe} completion. - */ - RedisFuture unsubscribe(K... channels); -} diff --git a/src/main/java/com/lambdaworks/redis/pubsub/StatefulRedisPubSubConnectionImpl.java b/src/main/java/com/lambdaworks/redis/pubsub/StatefulRedisPubSubConnectionImpl.java index 8916cef152..6652c69577 100644 --- a/src/main/java/com/lambdaworks/redis/pubsub/StatefulRedisPubSubConnectionImpl.java +++ b/src/main/java/com/lambdaworks/redis/pubsub/StatefulRedisPubSubConnectionImpl.java @@ -8,14 +8,15 @@ import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.TimeUnit; -import com.lambdaworks.redis.*; -import com.lambdaworks.redis.api.sync.RedisCommands; -import com.lambdaworks.redis.cluster.api.sync.RedisClusterCommands; +import com.lambdaworks.redis.RedisChannelWriter; +import com.lambdaworks.redis.RedisFuture; +import com.lambdaworks.redis.StatefulRedisConnectionImpl; import com.lambdaworks.redis.codec.RedisCodec; import com.lambdaworks.redis.protocol.ConnectionWatchdog; import com.lambdaworks.redis.pubsub.api.async.RedisPubSubAsyncCommands; import com.lambdaworks.redis.pubsub.api.rx.RedisPubSubReactiveCommands; import com.lambdaworks.redis.pubsub.api.sync.RedisPubSubCommands; + import io.netty.channel.ChannelHandler; import io.netty.util.internal.ConcurrentSet; @@ -91,7 +92,7 @@ public RedisPubSubCommands sync() { @Override protected RedisPubSubCommands newRedisSyncCommandsImpl() { - return syncHandler(async(), RedisConnection.class, RedisClusterConnection.class, RedisPubSubCommands.class); + return syncHandler(async(), RedisPubSubCommands.class); } @Override diff --git a/src/main/java/com/lambdaworks/redis/pubsub/api/async/RedisPubSubAsyncCommands.java b/src/main/java/com/lambdaworks/redis/pubsub/api/async/RedisPubSubAsyncCommands.java index 3e2f94a696..68a7f2d2a4 100644 --- a/src/main/java/com/lambdaworks/redis/pubsub/api/async/RedisPubSubAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/pubsub/api/async/RedisPubSubAsyncCommands.java @@ -1,9 +1,7 @@ package com.lambdaworks.redis.pubsub.api.async; -import com.lambdaworks.redis.RedisAsyncConnection; import com.lambdaworks.redis.RedisFuture; import com.lambdaworks.redis.api.async.RedisAsyncCommands; -import com.lambdaworks.redis.pubsub.RedisPubSubConnection; import com.lambdaworks.redis.pubsub.RedisPubSubListener; import com.lambdaworks.redis.pubsub.StatefulRedisPubSubConnection; @@ -15,7 +13,7 @@ * @author Mark Paluch * @since 3.0 */ -public interface RedisPubSubAsyncCommands extends RedisAsyncCommands, RedisPubSubConnection { +public interface RedisPubSubAsyncCommands extends RedisAsyncCommands { /** * Add a new listener. diff --git a/src/main/java/com/lambdaworks/redis/pubsub/api/sync/RedisPubSubCommands.java b/src/main/java/com/lambdaworks/redis/pubsub/api/sync/RedisPubSubCommands.java index 7b19319903..f124325d46 100644 --- a/src/main/java/com/lambdaworks/redis/pubsub/api/sync/RedisPubSubCommands.java +++ b/src/main/java/com/lambdaworks/redis/pubsub/api/sync/RedisPubSubCommands.java @@ -1,6 +1,5 @@ package com.lambdaworks.redis.pubsub.api.sync; -import com.lambdaworks.redis.RedisConnection; import com.lambdaworks.redis.api.sync.RedisCommands; import com.lambdaworks.redis.pubsub.RedisPubSubListener; import com.lambdaworks.redis.pubsub.StatefulRedisPubSubConnection; diff --git a/src/main/java/com/lambdaworks/redis/resource/DefaultClientResources.java b/src/main/java/com/lambdaworks/redis/resource/DefaultClientResources.java index 8589bfa0c5..b39290f882 100644 --- a/src/main/java/com/lambdaworks/redis/resource/DefaultClientResources.java +++ b/src/main/java/com/lambdaworks/redis/resource/DefaultClientResources.java @@ -195,11 +195,7 @@ public static class Builder { private DnsResolver dnsResolver = DnsResolvers.JVM_DEFAULT; private Delay reconnectDelay = DEFAULT_RECONNECT_DELAY; - /** - * @deprecated Use {@link DefaultClientResources#builder()} - */ - @Deprecated - public Builder() { + private Builder() { } /** diff --git a/src/main/java/com/lambdaworks/redis/sentinel/RedisSentinelAsyncCommandsImpl.java b/src/main/java/com/lambdaworks/redis/sentinel/RedisSentinelAsyncCommandsImpl.java index c97abe7f29..5c3aeeb1e9 100644 --- a/src/main/java/com/lambdaworks/redis/sentinel/RedisSentinelAsyncCommandsImpl.java +++ b/src/main/java/com/lambdaworks/redis/sentinel/RedisSentinelAsyncCommandsImpl.java @@ -8,7 +8,6 @@ import java.util.concurrent.atomic.AtomicReference; import com.lambdaworks.redis.RedisFuture; -import com.lambdaworks.redis.RedisSentinelAsyncConnection; import com.lambdaworks.redis.api.StatefulConnection; import com.lambdaworks.redis.codec.RedisCodec; import com.lambdaworks.redis.internal.LettuceAssert; @@ -26,8 +25,7 @@ * @author Mark Paluch * @since 3.0 */ -public class RedisSentinelAsyncCommandsImpl implements RedisSentinelAsyncCommands, - RedisSentinelAsyncConnection { +public class RedisSentinelAsyncCommandsImpl implements RedisSentinelAsyncCommands { private final SentinelCommandBuilder commandBuilder; private final StatefulConnection connection; diff --git a/src/main/java/com/lambdaworks/redis/sentinel/RedisSentinelReactiveCommandsImpl.java b/src/main/java/com/lambdaworks/redis/sentinel/RedisSentinelReactiveCommandsImpl.java index a9bd5400d7..6f70f3de72 100644 --- a/src/main/java/com/lambdaworks/redis/sentinel/RedisSentinelReactiveCommandsImpl.java +++ b/src/main/java/com/lambdaworks/redis/sentinel/RedisSentinelReactiveCommandsImpl.java @@ -94,12 +94,12 @@ public Observable ping() { return createObservable(() -> commandBuilder.ping()); } - @Override + //@Override public void close() { connection.close(); } - @Override + //@Override public boolean isOpen() { return connection.isOpen(); } diff --git a/src/main/java/com/lambdaworks/redis/sentinel/api/async/RedisSentinelAsyncCommands.java b/src/main/java/com/lambdaworks/redis/sentinel/api/async/RedisSentinelAsyncCommands.java index 1204d29648..677012500d 100644 --- a/src/main/java/com/lambdaworks/redis/sentinel/api/async/RedisSentinelAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/sentinel/api/async/RedisSentinelAsyncCommands.java @@ -1,12 +1,10 @@ package com.lambdaworks.redis.sentinel.api.async; -import java.io.Closeable; import java.net.SocketAddress; import java.util.List; import java.util.Map; import com.lambdaworks.redis.sentinel.api.StatefulRedisSentinelConnection; import com.lambdaworks.redis.RedisFuture; -import com.lambdaworks.redis.RedisSentinelAsyncConnection; /** * Asynchronous executed commands for Redis Sentinel. @@ -17,7 +15,7 @@ * @since 4.0 * @generated by com.lambdaworks.apigenerator.CreateAsyncApi */ -public interface RedisSentinelAsyncCommands extends Closeable, RedisSentinelAsyncConnection { +public interface RedisSentinelAsyncCommands { /** * Return the ip and port number of the master with that name. diff --git a/src/main/java/com/lambdaworks/redis/sentinel/api/rx/RedisSentinelReactiveCommands.java b/src/main/java/com/lambdaworks/redis/sentinel/api/rx/RedisSentinelReactiveCommands.java index be0217cfe2..74add9e9ef 100644 --- a/src/main/java/com/lambdaworks/redis/sentinel/api/rx/RedisSentinelReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/sentinel/api/rx/RedisSentinelReactiveCommands.java @@ -1,6 +1,5 @@ package com.lambdaworks.redis.sentinel.api.rx; -import java.io.Closeable; import java.net.SocketAddress; import java.util.List; import java.util.Map; @@ -16,7 +15,7 @@ * @since 4.0 * @generated by com.lambdaworks.apigenerator.CreateReactiveApi */ -public interface RedisSentinelReactiveCommands extends Closeable { +public interface RedisSentinelReactiveCommands { /** * Return the ip and port number of the master with that name. diff --git a/src/main/java/com/lambdaworks/redis/sentinel/api/sync/RedisSentinelCommands.java b/src/main/java/com/lambdaworks/redis/sentinel/api/sync/RedisSentinelCommands.java index aacb8a89b0..918bf1f92b 100644 --- a/src/main/java/com/lambdaworks/redis/sentinel/api/sync/RedisSentinelCommands.java +++ b/src/main/java/com/lambdaworks/redis/sentinel/api/sync/RedisSentinelCommands.java @@ -1,6 +1,5 @@ package com.lambdaworks.redis.sentinel.api.sync; -import java.io.Closeable; import java.net.SocketAddress; import java.util.List; import java.util.Map; @@ -15,7 +14,7 @@ * @since 4.0 * @generated by com.lambdaworks.apigenerator.CreateSyncApi */ -public interface RedisSentinelCommands extends Closeable { +public interface RedisSentinelCommands { /** * Return the ip and port number of the master with that name. diff --git a/src/main/java/com/lambdaworks/redis/support/ClientResourcesFactoryBean.java b/src/main/java/com/lambdaworks/redis/support/ClientResourcesFactoryBean.java index c48ae6a619..dfa01b6d71 100644 --- a/src/main/java/com/lambdaworks/redis/support/ClientResourcesFactoryBean.java +++ b/src/main/java/com/lambdaworks/redis/support/ClientResourcesFactoryBean.java @@ -50,7 +50,7 @@ public Class getObjectType() { @Override protected ClientResources createInstance() throws Exception { - return new DefaultClientResources.Builder().computationThreadPoolSize(computationThreadPoolSize) + return DefaultClientResources.builder().computationThreadPoolSize(computationThreadPoolSize) .ioThreadPoolSize(ioThreadPoolSize).build(); } diff --git a/src/main/java/com/lambdaworks/redis/support/PoolingProxyFactory.java b/src/main/java/com/lambdaworks/redis/support/PoolingProxyFactory.java deleted file mode 100644 index 237085bf59..0000000000 --- a/src/main/java/com/lambdaworks/redis/support/PoolingProxyFactory.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.lambdaworks.redis.support; - -import java.lang.reflect.Proxy; - -import com.lambdaworks.redis.RedisConnectionPool; - -/** - * Pooling proxy factory to create transparent pooling proxies. These proxies will allocate internally connections and use - * always valid connections. You don't need to allocate/free the connections anymore. - * - * @author Mark Paluch - * @since 3.0 - */ -public class PoolingProxyFactory { - - /** - * Utility constructor. - */ - private PoolingProxyFactory() { - - } - - /** - * Creates a transparent connection pooling proxy. Will re-check the connection every 5 secs. - * - * @param connectionPool The Redis connection pool - * @param Type of the connection. - * @return Transparent pooling proxy. - */ - @SuppressWarnings("unchecked") - public static T create(RedisConnectionPool connectionPool) { - Class componentType = connectionPool.getComponentType(); - - TransparentPoolingInvocationHandler h = new TransparentPoolingInvocationHandler(connectionPool); - - Object o = Proxy.newProxyInstance(PoolingProxyFactory.class.getClassLoader(), new Class[] { componentType }, h); - - return (T) o; - } - -} diff --git a/src/main/java/com/lambdaworks/redis/support/TransparentPoolingInvocationHandler.java b/src/main/java/com/lambdaworks/redis/support/TransparentPoolingInvocationHandler.java deleted file mode 100644 index 5234c45ccd..0000000000 --- a/src/main/java/com/lambdaworks/redis/support/TransparentPoolingInvocationHandler.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.lambdaworks.redis.support; - -import java.lang.reflect.Method; - -import com.lambdaworks.redis.RedisConnectionPool; -import com.lambdaworks.redis.RedisException; -import com.lambdaworks.redis.internal.AbstractInvocationHandler; - -/** - * Invocation Handler with transparent pooling. This handler is thread-safe. - * - * @author Mark Paluch - * @since 3.0 - */ -public class TransparentPoolingInvocationHandler extends AbstractInvocationHandler { - - private RedisConnectionPool pool; - - public TransparentPoolingInvocationHandler(RedisConnectionPool pool) { - this.pool = pool; - } - - @Override - protected Object handleInvocation(Object proxy, Method method, Object[] args) throws Throwable { - - if (pool == null) { - throw new RedisException("Connection pool is closed"); - } - - if (method.getName().equals("close")) { - pool.close(); - pool = null; - return null; - } - - T connection = pool.allocateConnection(); - try { - return method.invoke(connection, args); - } finally { - pool.freeConnection(connection); - } - } - - public RedisConnectionPool getPool() { - return pool; - } - -} diff --git a/src/main/java/com/lambdaworks/redis/support/WithConnection.java b/src/main/java/com/lambdaworks/redis/support/WithConnection.java deleted file mode 100644 index 70c0a2f58b..0000000000 --- a/src/main/java/com/lambdaworks/redis/support/WithConnection.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.lambdaworks.redis.support; - -import com.lambdaworks.redis.RedisConnectionPool; - -/** - * Execution-Template which allocates a connection around the run()-call. Use this class as adapter template and implement your - * redis calls within the run-method. - * - * @param Connection type. - * @author Mark Paluch - * @since 3.0 - */ -public abstract class WithConnection { - - /** - * Performs connection handling and invokes the run-method with a valid Redis connection. - * - * @param pool the connection pool. - */ - public WithConnection(RedisConnectionPool pool) { - T connection = pool.allocateConnection(); - try { - run(connection); - } finally { - pool.freeConnection(connection); - } - } - - /** - * Execution method. Will be called with a valid redis connection. - * - * @param connection the connection - */ - protected abstract void run(T connection); -} diff --git a/src/main/templates/com/lambdaworks/redis/api/BaseRedisCommands.java b/src/main/templates/com/lambdaworks/redis/api/BaseRedisCommands.java index d6b280fa16..8242dfaf0d 100644 --- a/src/main/templates/com/lambdaworks/redis/api/BaseRedisCommands.java +++ b/src/main/templates/com/lambdaworks/redis/api/BaseRedisCommands.java @@ -149,4 +149,18 @@ public interface BaseRedisCommands extends AutoCloseable { */ void reset(); + /** + * Disable or enable auto-flush behavior. Default is {@literal true}. If autoFlushCommands is disabled, multiple commands + * can be issued without writing them actually to the transport. Commands are buffered until a {@link #flushCommands()} is + * issued. After calling {@link #flushCommands()} commands are sent to the transport and executed by Redis. + * + * @param autoFlush state of autoFlush. + */ + void setAutoFlushCommands(boolean autoFlush); + + /** + * Flush pending commands. This commands forces a flush on the channel and can be used to buffer ("pipeline") commands to + * achieve batching. No-op if channel is not connected. + */ + void flushCommands(); } diff --git a/src/main/templates/com/lambdaworks/redis/api/RedisListCommands.java b/src/main/templates/com/lambdaworks/redis/api/RedisListCommands.java index ec2b74f3e5..d1dbee8ac2 100644 --- a/src/main/templates/com/lambdaworks/redis/api/RedisListCommands.java +++ b/src/main/templates/com/lambdaworks/redis/api/RedisListCommands.java @@ -98,17 +98,6 @@ public interface RedisListCommands { */ Long lpush(K key, V... values); - /** - * Prepend a value to a list, only if the list exists. - * - * @param key the key - * @param value the value - * @return Long integer-reply the length of the list after the push operation. - * @deprecated Use {@link #lpushx(Object, Object[])} - */ - @Deprecated - Long lpushx(K key, V value); - /** * Prepend values to a list, only if the list exists. * @@ -195,17 +184,6 @@ public interface RedisListCommands { */ Long rpush(K key, V... values); - /** - * Append a value to a list, only if the list exists. - * - * @param key the key - * @param value the value - * @return Long integer-reply the length of the list after the push operation. - * @deprecated Use {@link #rpushx(java.lang.Object, java.lang.Object[])} - */ - @Deprecated - Long rpushx(K key, V value); - /** * Append values to a list, only if the list exists. * diff --git a/src/main/templates/com/lambdaworks/redis/api/RedisSentinelCommands.java b/src/main/templates/com/lambdaworks/redis/api/RedisSentinelCommands.java index 8020e24a0f..ac71032723 100644 --- a/src/main/templates/com/lambdaworks/redis/api/RedisSentinelCommands.java +++ b/src/main/templates/com/lambdaworks/redis/api/RedisSentinelCommands.java @@ -1,9 +1,9 @@ package com.lambdaworks.redis; -import java.io.Closeable; import java.net.SocketAddress; import java.util.List; import java.util.Map; + import com.lambdaworks.redis.sentinel.api.StatefulRedisSentinelConnection; /** @@ -14,7 +14,7 @@ * @author Mark Paluch * @since 4.0 */ -public interface RedisSentinelCommands extends Closeable{ +public interface RedisSentinelCommands { /** * Return the ip and port number of the master with that name. @@ -103,7 +103,6 @@ public interface RedisSentinelCommands extends Closeable{ /** * close the underlying connection. */ - @Override void close(); /** diff --git a/src/main/templates/com/lambdaworks/redis/api/RedisServerCommands.java b/src/main/templates/com/lambdaworks/redis/api/RedisServerCommands.java index 2c33a0b905..790e7a0087 100644 --- a/src/main/templates/com/lambdaworks/redis/api/RedisServerCommands.java +++ b/src/main/templates/com/lambdaworks/redis/api/RedisServerCommands.java @@ -314,14 +314,6 @@ public interface RedisServerCommands { */ String slowlogReset(); - /** - * Internal command used for replication. - * - * @return String simple-string-reply - */ - @Deprecated - String sync(); - /** * Return the current server time. * @@ -332,5 +324,4 @@ public interface RedisServerCommands { * unix time in seconds. microseconds. */ List time(); - } diff --git a/src/test/java/biz/paluch/redis/extensibility/LettuceGeoDemo.java b/src/test/java/biz/paluch/redis/extensibility/LettuceGeoDemo.java index 6e7f515d0b..fad1917949 100644 --- a/src/test/java/biz/paluch/redis/extensibility/LettuceGeoDemo.java +++ b/src/test/java/biz/paluch/redis/extensibility/LettuceGeoDemo.java @@ -1,14 +1,17 @@ package biz.paluch.redis.extensibility; -import java.util.*; +import java.util.List; +import java.util.Set; + import com.lambdaworks.redis.*; +import com.lambdaworks.redis.api.sync.RedisCommands; public class LettuceGeoDemo { public static void main(String[] args) { RedisClient redisClient = RedisClient.create(RedisURI.Builder.redis("localhost", 6379).build()); - RedisConnection redis = (RedisConnection) redisClient.connect(); + RedisCommands redis = redisClient.connect().sync(); String key = "my-geo-set"; redis.geoadd(key, 8.6638775, 49.5282537, "Weinheim", 8.3796281, 48.9978127, "Office tower", 8.665351, 49.553302, diff --git a/src/test/java/biz/paluch/redis/extensibility/MyExtendedRedisClient.java b/src/test/java/biz/paluch/redis/extensibility/MyExtendedRedisClient.java index f1c2014db6..42be2f7f2f 100644 --- a/src/test/java/biz/paluch/redis/extensibility/MyExtendedRedisClient.java +++ b/src/test/java/biz/paluch/redis/extensibility/MyExtendedRedisClient.java @@ -1,13 +1,15 @@ package biz.paluch.redis.extensibility; +import java.util.concurrent.TimeUnit; + +import javax.enterprise.inject.Alternative; + import com.lambdaworks.redis.RedisClient; import com.lambdaworks.redis.RedisURI; import com.lambdaworks.redis.codec.RedisCodec; import com.lambdaworks.redis.pubsub.PubSubCommandHandler; import com.lambdaworks.redis.pubsub.StatefulRedisPubSubConnectionImpl; - -import javax.enterprise.inject.Alternative; -import java.util.concurrent.TimeUnit; +import com.lambdaworks.redis.resource.ClientResources; /** * Demo code for extending a RedisClient. @@ -16,19 +18,12 @@ */ @Alternative public class MyExtendedRedisClient extends RedisClient { - public MyExtendedRedisClient() { - } - public MyExtendedRedisClient(String host) { - super(host); + public MyExtendedRedisClient(ClientResources clientResources, RedisURI redisURI) { + super(clientResources, redisURI); } - public MyExtendedRedisClient(String host, int port) { - super(host, port); - } - - public MyExtendedRedisClient(RedisURI redisURI) { - super(redisURI); + public MyExtendedRedisClient() { } @Override diff --git a/src/test/java/biz/paluch/redis/extensibility/MyExtendedRedisClientTest.java b/src/test/java/biz/paluch/redis/extensibility/MyExtendedRedisClientTest.java index a2d1db7ae7..a28f804d20 100644 --- a/src/test/java/biz/paluch/redis/extensibility/MyExtendedRedisClientTest.java +++ b/src/test/java/biz/paluch/redis/extensibility/MyExtendedRedisClientTest.java @@ -1,15 +1,17 @@ package biz.paluch.redis.extensibility; -import static org.assertj.core.api.Assertions.*; +import static org.assertj.core.api.Assertions.assertThat; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; import com.lambdaworks.redis.FastShutdown; -import com.lambdaworks.redis.RedisConnection; +import com.lambdaworks.redis.RedisURI; import com.lambdaworks.redis.TestSettings; +import com.lambdaworks.redis.api.sync.RedisCommands; import com.lambdaworks.redis.pubsub.RedisPubSubAsyncCommandsImpl; +import com.lambdaworks.redis.pubsub.StatefulRedisPubSubConnection; import com.lambdaworks.redis.pubsub.api.async.RedisPubSubAsyncCommands; /** @@ -20,7 +22,7 @@ public class MyExtendedRedisClientTest { public static final int port = TestSettings.port(); protected static MyExtendedRedisClient client; - protected RedisConnection redis; + protected RedisCommands redis; protected String key = "key"; protected String value = "value"; @@ -30,7 +32,7 @@ public static void setupClient() { } protected static MyExtendedRedisClient getRedisClient() { - return new MyExtendedRedisClient(host, port); + return new MyExtendedRedisClient(null, RedisURI.create(host, port)); } @AfterClass @@ -40,11 +42,12 @@ public static void shutdownClient() { @Test public void testPubsub() throws Exception { - RedisPubSubAsyncCommands connection = client.connectPubSub().async(); - assertThat(connection).isInstanceOf(RedisPubSubAsyncCommandsImpl.class); - assertThat(connection.getStatefulConnection()).isInstanceOf(MyPubSubConnection.class); - connection.set("key", "value").get(); + StatefulRedisPubSubConnection connection = client + .connectPubSub(); + RedisPubSubAsyncCommands commands = connection.async(); + assertThat(commands).isInstanceOf(RedisPubSubAsyncCommandsImpl.class); + assertThat(commands.getStatefulConnection()).isInstanceOf(MyPubSubConnection.class); + commands.set("key", "value").get(); connection.close(); - } } diff --git a/src/test/java/com/lambdaworks/Connections.java b/src/test/java/com/lambdaworks/Connections.java index ea11e61cf7..f54947a246 100644 --- a/src/test/java/com/lambdaworks/Connections.java +++ b/src/test/java/com/lambdaworks/Connections.java @@ -1,8 +1,11 @@ package com.lambdaworks; +import java.util.Queue; + import org.springframework.test.util.ReflectionTestUtils; import com.lambdaworks.redis.RedisChannelHandler; +import com.lambdaworks.redis.RedisChannelWriter; import com.lambdaworks.redis.StatefulRedisConnectionImpl; import com.lambdaworks.redis.api.StatefulConnection; import com.lambdaworks.redis.api.async.RedisAsyncCommands; @@ -31,4 +34,21 @@ public static ConnectionWatchdog getConnectionWatchdog(StatefulConnection public static StatefulRedisConnectionImpl getStatefulConnection(RedisAsyncCommands connection) { return (StatefulRedisConnectionImpl) connection.getStatefulConnection(); } + + public static RedisChannelWriter getChannelWriter(StatefulConnection connection) { + return ((RedisChannelHandler) connection).getChannelWriter(); + } + + + public static Queue getQueue(StatefulConnection connection) { + return (Queue) ReflectionTestUtils.getField(Connections.getChannelWriter(connection), "queue"); + } + + public static Queue getCommandBuffer(StatefulConnection connection) { + return (Queue) ReflectionTestUtils.getField(Connections.getChannelWriter(connection), "commandBuffer"); + } + + public static String getConnectionState(StatefulConnection connection) { + return ReflectionTestUtils.getField(Connections.getChannelWriter(connection), "lifecycleState").toString(); + } } diff --git a/src/test/java/com/lambdaworks/TestClientResources.java b/src/test/java/com/lambdaworks/TestClientResources.java index 89478cc9a1..165adec08b 100644 --- a/src/test/java/com/lambdaworks/TestClientResources.java +++ b/src/test/java/com/lambdaworks/TestClientResources.java @@ -16,7 +16,7 @@ public class TestClientResources { public static ClientResources create() { - final DefaultClientResources resources = new DefaultClientResources.Builder().eventLoopGroupProvider( + final DefaultClientResources resources = DefaultClientResources.builder().eventLoopGroupProvider( new TestEventLoopGroupProvider()).build(); Runtime.getRuntime().addShutdownHook(new Thread() { diff --git a/src/test/java/com/lambdaworks/apigenerator/CreateAsyncApi.java b/src/test/java/com/lambdaworks/apigenerator/CreateAsyncApi.java index e2f784b4cd..914aac2530 100644 --- a/src/test/java/com/lambdaworks/apigenerator/CreateAsyncApi.java +++ b/src/test/java/com/lambdaworks/apigenerator/CreateAsyncApi.java @@ -61,24 +61,7 @@ public CreateAsyncApi(String templateName) { } factory = new CompilationUnitFactory(templateFile, Constants.SOURCES, targetPackage, targetName, commentMutator(), - methodTypeMutator(), methodDeclaration -> true, importSupplier(), typeMutator(), null); - } - - private Consumer typeMutator() { - return type -> { - - if (type.getName().contains("SentinelAsyncCommands")) { - type.getExtends().add(new ClassOrInterfaceType("RedisSentinelAsyncConnection")); - CompilationUnit compilationUnit = (CompilationUnit) type.getParentNode(); - if (compilationUnit.getImports() == null) { - compilationUnit.setImports(new ArrayList<>()); - } - compilationUnit.getImports() - .add(new ImportDeclaration(new NameExpr("com.lambdaworks.redis.RedisSentinelAsyncConnection"), false, - false)); - } - - }; + methodTypeMutator(), methodDeclaration -> true, importSupplier(), null, null); } /** diff --git a/src/test/java/com/lambdaworks/apigenerator/CreateAsyncNodeSelectionClusterApi.java b/src/test/java/com/lambdaworks/apigenerator/CreateAsyncNodeSelectionClusterApi.java index 0f83a7d863..5ee043a9fe 100644 --- a/src/test/java/com/lambdaworks/apigenerator/CreateAsyncNodeSelectionClusterApi.java +++ b/src/test/java/com/lambdaworks/apigenerator/CreateAsyncNodeSelectionClusterApi.java @@ -69,7 +69,7 @@ protected Function commentMutator() { } /** - * Mutate type to async result. + * Method filter * * @return */ diff --git a/src/test/java/com/lambdaworks/apigenerator/CreateReactiveApi.java b/src/test/java/com/lambdaworks/apigenerator/CreateReactiveApi.java index 832ae8c9a9..d128097853 100644 --- a/src/test/java/com/lambdaworks/apigenerator/CreateReactiveApi.java +++ b/src/test/java/com/lambdaworks/apigenerator/CreateReactiveApi.java @@ -27,7 +27,7 @@ public class CreateReactiveApi { private Set KEEP_METHOD_RESULT_TYPE = LettuceSets.unmodifiableSet( "digest", "close", "isOpen", "BaseRedisCommands.reset", - "getStatefulConnection"); + "getStatefulConnection", "setAutoFlushCommands", "flushCommands"); private CompilationUnitFactory factory; diff --git a/src/test/java/com/lambdaworks/apigenerator/CreateSyncApi.java b/src/test/java/com/lambdaworks/apigenerator/CreateSyncApi.java index ab04430a5c..9ac6075046 100644 --- a/src/test/java/com/lambdaworks/apigenerator/CreateSyncApi.java +++ b/src/test/java/com/lambdaworks/apigenerator/CreateSyncApi.java @@ -4,9 +4,13 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Set; import java.util.function.Function; +import java.util.function.Predicate; import java.util.function.Supplier; +import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration; +import com.lambdaworks.redis.internal.LettuceSets; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -22,6 +26,8 @@ @RunWith(Parameterized.class) public class CreateSyncApi { + private Set FILTER_METHODS = LettuceSets.unmodifiableSet("setAutoFlushCommands", "flushCommands"); + private CompilationUnitFactory factory; @Parameterized.Parameters(name = "Create {0}") @@ -52,7 +58,7 @@ public CreateSyncApi(String templateName) { } factory = new CompilationUnitFactory(templateFile, Constants.SOURCES, targetPackage, targetName, commentMutator(), - methodTypeMutator(), methodDeclaration -> true, importSupplier(), null, null); + methodTypeMutator(), methodFilter(), importSupplier(), null, null); } /** @@ -65,6 +71,23 @@ protected Function commentMutator() { + getClass().getName() + "\r\n "; } + /** + * Method filter + * + * @return + */ + protected Predicate methodFilter() { + return method -> { + ClassOrInterfaceDeclaration classOfMethod = (ClassOrInterfaceDeclaration) method.getParentNode(); + if (FILTER_METHODS.contains(method.getName()) + || FILTER_METHODS.contains(classOfMethod.getName() + "." + method.getName())) { + return false; + } + + return true; + }; + } + /** * Mutate type to async result. * diff --git a/src/test/java/com/lambdaworks/examples/ConnectToRedis.java b/src/test/java/com/lambdaworks/examples/ConnectToRedis.java index a7448257f8..b8b3d66237 100644 --- a/src/test/java/com/lambdaworks/examples/ConnectToRedis.java +++ b/src/test/java/com/lambdaworks/examples/ConnectToRedis.java @@ -1,8 +1,6 @@ package com.lambdaworks.examples; import com.lambdaworks.redis.RedisClient; -import com.lambdaworks.redis.RedisConnection; -import com.lambdaworks.redis.RedisURI; import com.lambdaworks.redis.api.StatefulRedisConnection; /** diff --git a/src/test/java/com/lambdaworks/examples/ConnectToRedisCluster.java b/src/test/java/com/lambdaworks/examples/ConnectToRedisCluster.java index 9e57c28fa6..2eb5701ad7 100644 --- a/src/test/java/com/lambdaworks/examples/ConnectToRedisCluster.java +++ b/src/test/java/com/lambdaworks/examples/ConnectToRedisCluster.java @@ -1,8 +1,5 @@ package com.lambdaworks.examples; -import com.lambdaworks.redis.RedisURI; -import com.lambdaworks.redis.api.StatefulRedisConnection; -import com.lambdaworks.redis.cluster.RedisAdvancedClusterConnection; import com.lambdaworks.redis.cluster.RedisClusterClient; import com.lambdaworks.redis.cluster.api.StatefulRedisClusterConnection; diff --git a/src/test/java/com/lambdaworks/examples/SpringExample.java b/src/test/java/com/lambdaworks/examples/SpringExample.java index 5eedd2c601..9ac1c334c8 100644 --- a/src/test/java/com/lambdaworks/examples/SpringExample.java +++ b/src/test/java/com/lambdaworks/examples/SpringExample.java @@ -1,11 +1,10 @@ package com.lambdaworks.examples; -import com.lambdaworks.redis.api.StatefulRedisConnection; -import com.lambdaworks.redis.api.sync.RedisCommands; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.lambdaworks.redis.RedisClient; -import com.lambdaworks.redis.RedisConnection; +import com.lambdaworks.redis.api.StatefulRedisConnection; +import com.lambdaworks.redis.api.sync.RedisCommands; /** * @author Mark Paluch diff --git a/src/test/java/com/lambdaworks/redis/AllTheAPIsTest.java b/src/test/java/com/lambdaworks/redis/AllTheAPIsTest.java index 05df78814d..e7ed946c03 100644 --- a/src/test/java/com/lambdaworks/redis/AllTheAPIsTest.java +++ b/src/test/java/com/lambdaworks/redis/AllTheAPIsTest.java @@ -37,12 +37,12 @@ public void standaloneSync() throws Exception { @Test public void standaloneAsync() throws Exception { - redisClient.connect().async().close(); + redisClient.connect().async().getStatefulConnection().close(); } @Test public void standaloneReactive() throws Exception { - redisClient.connect().reactive().close(); + redisClient.connect().reactive().getStatefulConnection().close(); } @Test @@ -50,21 +50,6 @@ public void standaloneStateful() throws Exception { redisClient.connect().close(); } - @Test - public void deprecatedStandaloneAsync() throws Exception { - redisClient.connectAsync().close(); - } - - @Test - public void deprecatedStandaloneReactive() throws Exception { - redisClient.connectAsync().getStatefulConnection().reactive().close(); - } - - @Test - public void deprecatedStandaloneStateful() throws Exception { - redisClient.connectAsync().getStatefulConnection().close(); - } - // PubSub @Test public void pubsubSync() throws Exception { @@ -94,12 +79,12 @@ public void sentinelSync() throws Exception { @Test public void sentinelAsync() throws Exception { - redisClient.connectSentinel().async().close(); + redisClient.connectSentinel().async().getStatefulConnection().close(); } @Test public void sentinelReactive() throws Exception { - redisClient.connectSentinel().reactive().close(); + redisClient.connectSentinel().reactive().getStatefulConnection().close(); } @Test @@ -107,51 +92,20 @@ public void sentinelStateful() throws Exception { redisClient.connectSentinel().close(); } - @Test - public void deprecatedSentinelSync() throws Exception { - redisClient.connectSentinelAsync().getStatefulConnection().sync().close(); - } - - @Test - public void deprecatedSentinelAsync() throws Exception { - redisClient.connectSentinelAsync().getStatefulConnection().async().close(); - } - - @Test - public void deprecatedSentinelReactive() throws Exception { - redisClient.connectSentinelAsync().getStatefulConnection().reactive().close(); - } - - @Test - public void deprecatedSentinelStateful() throws Exception { - redisClient.connectSentinelAsync().getStatefulConnection().close(); - } - - // Pool - @Test - public void poolSync() throws Exception { - redisClient.pool().close(); - } - - @Test - public void poolAsync() throws Exception { - redisClient.asyncPool().close(); - } - // Cluster @Test public void clusterSync() throws Exception { - clusterClient.connect().sync().close(); + clusterClient.connect().sync().getStatefulConnection().close(); } @Test public void clusterAsync() throws Exception { - clusterClient.connect().async().close(); + clusterClient.connect().async().getStatefulConnection().close(); } @Test public void clusterReactive() throws Exception { - clusterClient.connect().reactive().close(); + clusterClient.connect().reactive().getStatefulConnection().close(); } @Test @@ -161,17 +115,17 @@ public void clusterStateful() throws Exception { @Test public void clusterPubSubSync() throws Exception { - clusterClient.connectPubSub().sync().close(); + clusterClient.connectPubSub().sync().getStatefulConnection().close(); } @Test public void clusterPubSubAsync() throws Exception { - clusterClient.connectPubSub().async().close(); + clusterClient.connectPubSub().async().getStatefulConnection().close(); } @Test public void clusterPubSubReactive() throws Exception { - clusterClient.connectPubSub().reactive().close(); + clusterClient.connectPubSub().reactive().getStatefulConnection().close(); } @Test @@ -179,31 +133,10 @@ public void clusterPubSubStateful() throws Exception { clusterClient.connectPubSub().close(); } - @Test - public void deprecatedClusterSync() throws Exception { - clusterClient.connectCluster().getStatefulConnection().sync().close(); - } - - @Test - public void deprecatedClusterAsync() throws Exception { - clusterClient.connectCluster().getStatefulConnection().async().close(); - } - - @Test - public void deprecatedClusterReactive() throws Exception { - clusterClient.connectCluster().getStatefulConnection().reactive().close(); - } - - @Test - public void deprecatedClusterStateful() throws Exception { - clusterClient.connectCluster().getStatefulConnection().close(); - } - // Advanced Cluster @Test public void advancedClusterSync() throws Exception { - StatefulRedisClusterConnection statefulConnection = clusterClient.connectCluster() - .getStatefulConnection(); + StatefulRedisClusterConnection statefulConnection = clusterClient.connect(); RedisURI uri = clusterClient.getPartitions().getPartition(0).getUri(); statefulConnection.getConnection(uri.getHost(), uri.getPort()).sync(); statefulConnection.close(); @@ -211,8 +144,7 @@ public void advancedClusterSync() throws Exception { @Test public void advancedClusterAsync() throws Exception { - StatefulRedisClusterConnection statefulConnection = clusterClient.connectCluster() - .getStatefulConnection(); + StatefulRedisClusterConnection statefulConnection = clusterClient.connect(); RedisURI uri = clusterClient.getPartitions().getPartition(0).getUri(); statefulConnection.getConnection(uri.getHost(), uri.getPort()).sync(); statefulConnection.close(); @@ -220,8 +152,7 @@ public void advancedClusterAsync() throws Exception { @Test public void advancedClusterReactive() throws Exception { - StatefulRedisClusterConnection statefulConnection = clusterClient.connectCluster() - .getStatefulConnection(); + StatefulRedisClusterConnection statefulConnection = clusterClient.connect(); RedisURI uri = clusterClient.getPartitions().getPartition(0).getUri(); statefulConnection.getConnection(uri.getHost(), uri.getPort()).reactive(); statefulConnection.close(); @@ -232,11 +163,6 @@ public void advancedClusterStateful() throws Exception { clusterClient.connect().close(); } - @Test - public void deprecatedAvancedClusterStateful() throws Exception { - clusterClient.connectCluster().getStatefulConnection().close(); - } - // Cluster node selection @Test public void nodeSelectionClusterAsync() throws Exception { diff --git a/src/test/java/com/lambdaworks/redis/AsyncConnectionTest.java b/src/test/java/com/lambdaworks/redis/AsyncConnectionTest.java index 6ea4e377ef..00bd094582 100644 --- a/src/test/java/com/lambdaworks/redis/AsyncConnectionTest.java +++ b/src/test/java/com/lambdaworks/redis/AsyncConnectionTest.java @@ -15,20 +15,22 @@ import org.junit.Test; import org.junit.rules.ExpectedException; +import com.lambdaworks.redis.api.async.RedisAsyncCommands; + public class AsyncConnectionTest extends AbstractRedisClientTest { - private RedisAsyncConnection async; + private RedisAsyncCommands async; @Rule public ExpectedException exception = ExpectedException.none(); @Before public void openAsyncConnection() throws Exception { - async = client.connectAsync(); + async = client.connect().async(); } @After public void closeAsyncConnection() throws Exception { - async.close(); + async.getStatefulConnection().close(); } @Test(timeout = 10000) @@ -76,7 +78,7 @@ public void run() { redis.lpush(key, "" + i); } - RedisAsyncConnection connection = client.connectAsync(); + RedisAsyncCommands connection = client.connect().async(); Long len = connection.llen(key).get(); assertThat(len.intValue()).isEqualTo(1000); @@ -91,7 +93,7 @@ public void run() { assertThat(run).hasSize(1); - connection.close(); + connection.getStatefulConnection().close(); } @@ -107,7 +109,7 @@ public void run() { } }; - RedisAsyncConnection connection = client.connectAsync(); + RedisAsyncCommands connection = client.connect().async(); RedisFuture set = connection.set(key, value); set.get(); @@ -116,7 +118,7 @@ public void run() { assertThat(run).hasSize(1); - connection.close(); + connection.getStatefulConnection().close(); } @Test(timeout = 500) diff --git a/src/test/java/com/lambdaworks/redis/ClientOptionsTest.java b/src/test/java/com/lambdaworks/redis/ClientOptionsTest.java index b81efa0e22..785090adae 100644 --- a/src/test/java/com/lambdaworks/redis/ClientOptionsTest.java +++ b/src/test/java/com/lambdaworks/redis/ClientOptionsTest.java @@ -61,8 +61,8 @@ public void variousClientOptions() throws Exception { assertThat(getStatefulConnection(plain).getOptions().isAutoReconnect()).isTrue(); - plain.close(); - connection.close(); + plain.getStatefulConnection().close(); + connection.getStatefulConnection().close(); } @Test @@ -75,7 +75,7 @@ public void requestQueueSize() throws Exception { connection.quit(); - Wait.untilTrue(() -> !connection.isOpen()).waitOrTimeout(); + Wait.untilTrue(() -> !connection.getStatefulConnection().isOpen()).waitOrTimeout(); for (int i = 0; i < 10; i++) { connection.ping(); @@ -88,7 +88,7 @@ public void requestQueueSize() throws Exception { assertThat(e).hasMessageContaining("Request queue size exceeded"); } - connection.close(); + connection.getStatefulConnection().close(); } @Test @@ -99,13 +99,13 @@ public void disconnectedWithoutReconnect() throws Exception { RedisAsyncCommands connection = client.connect().async(); connection.quit(); - Wait.untilTrue(() -> !connection.isOpen()).waitOrTimeout(); + Wait.untilTrue(() -> !connection.getStatefulConnection().isOpen()).waitOrTimeout(); try { connection.get(key); } catch (Exception e) { assertThat(e).isInstanceOf(RedisException.class).hasMessageContaining("not connected"); } finally { - connection.close(); + connection.getStatefulConnection().close(); } } @@ -119,13 +119,13 @@ public void disconnectedRejectCommands() throws Exception { getConnectionWatchdog(connection.getStatefulConnection()).setListenOnChannelInactive(false); connection.quit(); - Wait.untilTrue(() -> !connection.isOpen()).waitOrTimeout(); + Wait.untilTrue(() -> !connection.getStatefulConnection().isOpen()).waitOrTimeout(); try { connection.get(key); } catch (Exception e) { assertThat(e).isInstanceOf(RedisException.class).hasMessageContaining("not connected"); } finally { - connection.close(); + connection.getStatefulConnection().close(); } } @@ -138,9 +138,9 @@ public void disconnectedAcceptCommands() throws Exception { RedisAsyncCommands connection = client.connect().async(); connection.quit(); - Wait.untilTrue(() -> !connection.isOpen()).waitOrTimeout(); + Wait.untilTrue(() -> !connection.getStatefulConnection().isOpen()).waitOrTimeout(); connection.get(key); - connection.close(); + connection.getStatefulConnection().close(); } @Test(timeout = 10000) @@ -154,7 +154,7 @@ public void pingBeforeConnect() throws Exception { String result = connection.get(key); assertThat(result).isEqualTo(value); } finally { - connection.close(); + connection.getStatefulConnection().close(); } } @@ -174,7 +174,7 @@ protected void run(RedisClient client) throws Exception { String result = connection.info(); assertThat(result).contains("memory"); } finally { - connection.close(); + connection.getStatefulConnection().close(); } } @@ -198,7 +198,7 @@ protected void run(RedisClient client) throws Exception { String result = connection.info(); assertThat(result).contains("memory"); } finally { - connection.close(); + connection.getStatefulConnection().close(); } } @@ -241,7 +241,6 @@ protected void run(RedisClient client) throws Exception { } catch (RedisConnectionException e) { assertThat(e).hasRootCauseInstanceOf(RedisCommandExecutionException.class); } - } }; } @@ -251,7 +250,7 @@ public void pingBeforeConnectWithQueuedCommandsAndReconnect() throws Exception { StatefulRedisConnection controlConnection = client.connect(); - client.setOptions(new ClientOptions.Builder().pingBeforeActivateConnection(true).build()); + client.setOptions(ClientOptions.builder().pingBeforeActivateConnection(true).build()); Utf8StringCodec codec = new Utf8StringCodec(); @@ -298,7 +297,7 @@ protected void run(RedisClient client) throws Exception { RedisURI redisURI = RedisURI.Builder.redis(host, port).withPassword(passwd).withDatabase(5).build(); StatefulRedisConnection controlConnection = client.connect(redisURI); - client.setOptions(new ClientOptions.Builder().pingBeforeActivateConnection(true).build()); + client.setOptions(ClientOptions.builder().pingBeforeActivateConnection(true).build()); Utf8StringCodec codec = new Utf8StringCodec(); diff --git a/src/test/java/com/lambdaworks/redis/ClientTest.java b/src/test/java/com/lambdaworks/redis/ClientTest.java index 470d332d39..8e8b8a4ac7 100644 --- a/src/test/java/com/lambdaworks/redis/ClientTest.java +++ b/src/test/java/com/lambdaworks/redis/ClientTest.java @@ -4,13 +4,9 @@ import static com.google.code.tempusfugit.temporal.Duration.seconds; import static com.google.code.tempusfugit.temporal.WaitFor.waitOrTimeout; -import static com.lambdaworks.Connections.getConnectionWatchdog; import static com.lambdaworks.Connections.getStatefulConnection; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.fail; -import java.util.concurrent.CancellationException; -import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import org.junit.FixMethodOrder; @@ -18,17 +14,11 @@ import org.junit.Test; import org.junit.rules.ExpectedException; import org.junit.runners.MethodSorters; -import org.springframework.test.util.ReflectionTestUtils; import com.google.code.tempusfugit.temporal.Condition; import com.google.code.tempusfugit.temporal.Timeout; -import com.lambdaworks.Wait; -import com.lambdaworks.redis.ClientOptions.DisconnectedBehavior; import com.lambdaworks.redis.api.StatefulRedisConnection; import com.lambdaworks.redis.api.async.RedisAsyncCommands; -import com.lambdaworks.redis.protocol.ConnectionWatchdog; -import com.lambdaworks.redis.server.RandomResponseServer; -import io.netty.channel.Channel; @FixMethodOrder(MethodSorters.NAME_ASCENDING) public class ClientTest extends AbstractRedisClientTest { @@ -165,18 +155,20 @@ public void interrupt() throws Exception { @Test public void connectFailure() throws Exception { - RedisClient client = new RedisClient("invalid"); + RedisClient client = RedisClient.create("redis://invalid"); exception.expect(RedisException.class); exception.expectMessage("Unable to connect"); client.connect(); + FastShutdown.shutdown(client); } @Test public void connectPubSubFailure() throws Exception { - RedisClient client = new RedisClient("invalid"); + RedisClient client = RedisClient.create("redis://invalid"); exception.expect(RedisException.class); exception.expectMessage("Unable to connect"); client.connectPubSub(); + FastShutdown.shutdown(client); } private class TestConnectionListener implements RedisConnectionStateListener { @@ -205,7 +197,7 @@ public void onRedisExceptionCaught(RedisChannelHandler connection, Throwab @Test public void emptyClient() throws Exception { - RedisClient client = new RedisClient(); + RedisClient client = RedisClient.create(); try { client.connect(); } catch (IllegalStateException e) { @@ -224,11 +216,6 @@ public void emptyClient() throws Exception { assertThat(e).hasMessageContaining("RedisURI"); } - try { - client.connectAsync((RedisURI) null); - } catch (IllegalArgumentException e) { - assertThat(e).hasMessageContaining("RedisURI"); - } FastShutdown.shutdown(client); } diff --git a/src/test/java/com/lambdaworks/redis/ConnectionCommandTest.java b/src/test/java/com/lambdaworks/redis/ConnectionCommandTest.java index ccc3893d4f..964f603320 100644 --- a/src/test/java/com/lambdaworks/redis/ConnectionCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/ConnectionCommandTest.java @@ -4,11 +4,6 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.fail; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import java.util.concurrent.ExecutionException; import org.assertj.core.api.Assertions; import org.junit.FixMethodOrder; @@ -17,8 +12,8 @@ import org.springframework.test.util.ReflectionTestUtils; import com.lambdaworks.redis.api.StatefulRedisConnection; -import com.lambdaworks.redis.protocol.BaseRedisCommandBuilder; -import com.lambdaworks.redis.protocol.CommandHandler; +import com.lambdaworks.redis.api.async.RedisAsyncCommands; +import com.lambdaworks.redis.api.sync.RedisCommands; @FixMethodOrder(MethodSorters.NAME_ASCENDING) public class ConnectionCommandTest extends AbstractRedisClientTest { @@ -27,7 +22,7 @@ public void auth() throws Exception { new WithPasswordRequired() { @Override public void run(RedisClient client) { - RedisConnection connection = client.connect().sync(); + RedisCommands connection = client.connect().sync(); try { connection.ping(); fail("Server doesn't require authentication"); @@ -38,10 +33,10 @@ public void run(RedisClient client) { } RedisURI redisURI = RedisURI.Builder.redis(host, port).withDatabase(2).withPassword(passwd).build(); - RedisClient redisClient = new RedisClient(redisURI); - RedisConnection authConnection = redisClient.connect().sync(); + RedisClient redisClient = RedisClient.create(redisURI); + RedisCommands authConnection = redisClient.connect().sync(); authConnection.ping(); - authConnection.close(); + authConnection.getStatefulConnection().close(); FastShutdown.shutdown(redisClient); } }; @@ -79,7 +74,7 @@ public void authReconnect() throws Exception { new WithPasswordRequired() { @Override public void run(RedisClient client) { - RedisConnection connection = client.connect().sync(); + RedisCommands connection = client.connect().sync(); assertThat(connection.auth(passwd)).isEqualTo("OK"); assertThat(connection.set(key, value)).isEqualTo("OK"); connection.quit(); @@ -96,78 +91,6 @@ public void selectReconnect() throws Exception { assertThat(redis.get(key)).isEqualTo(value); } - @Test - public void isValid() throws Exception { - - assertThat(Connections.isValid(redis)).isTrue(); - RedisAsyncCommandsImpl asyncConnection = (RedisAsyncCommandsImpl) client.connectAsync(); - RedisChannelHandler channelHandler = (RedisChannelHandler) asyncConnection - .getStatefulConnection(); - - assertThat(Connections.isValid(asyncConnection)).isTrue(); - assertThat(Connections.isOpen(asyncConnection)).isTrue(); - assertThat(asyncConnection.isOpen()).isTrue(); - assertThat(channelHandler.isClosed()).isFalse(); - - CommandHandler channelWriter = (CommandHandler) channelHandler.getChannelWriter(); - assertThat(channelWriter.isClosed()).isFalse(); - assertThat(channelWriter.isSharable()).isTrue(); - - Connections.close(asyncConnection); - assertThat(Connections.isOpen(asyncConnection)).isFalse(); - assertThat(Connections.isValid(asyncConnection)).isFalse(); - - assertThat(asyncConnection.isOpen()).isFalse(); - assertThat(channelHandler.isClosed()).isTrue(); - - assertThat(channelWriter.isClosed()).isTrue(); - } - - @Test - @SuppressWarnings("unchecked") - public void isValidAsyncExceptions() throws Exception { - - RedisAsyncConnection connection = mock(RedisAsyncConnection.class); - RedisFuture future = mock(RedisFuture.class); - when(connection.ping()).thenReturn(future); - - when(future.get()).thenThrow(new ExecutionException(new RuntimeException())); - assertThat(Connections.isValid(connection)).isFalse(); - - } - - @Test - public void isValidSyncExceptions() throws Exception { - - RedisConnection connection = mock(RedisConnection.class); - - when(connection.ping()).thenThrow(new RuntimeException()); - assertThat(Connections.isValid(connection)).isFalse(); - } - - @Test - public void closeExceptions() throws Exception { - - RedisConnection connection = mock(RedisConnection.class); - doThrow(new RuntimeException()).when(connection).close(); - Connections.close(connection); - } - - @Test(expected = IllegalArgumentException.class) - public void isValidWrongObject() throws Exception { - Connections.isValid(new Object()); - } - - @Test(expected = IllegalArgumentException.class) - public void isOpenWrongObject() throws Exception { - Connections.isOpen(new Object()); - } - - @Test(expected = IllegalArgumentException.class) - public void closeWrongObject() throws Exception { - Connections.close(new Object()); - } - @Test public void getSetReconnect() throws Exception { redis.set(key, value); @@ -178,34 +101,32 @@ public void getSetReconnect() throws Exception { @Test @SuppressWarnings("unchecked") public void authInvalidPassword() throws Exception { - RedisAsyncConnection async = client.connectAsync(); + RedisAsyncCommands async = client.connect().async(); try { async.auth("invalid"); fail("Authenticated with invalid password"); } catch (RedisException e) { assertThat(e.getMessage()).isEqualTo("ERR Client sent AUTH, but no password is set"); - StatefulRedisConnection statefulRedisConnection = (StatefulRedisConnection) ReflectionTestUtils - .getField(async, "connection"); - assertThat(ReflectionTestUtils.getField(statefulRedisConnection, "password")).isNull(); + StatefulRedisConnection statefulRedisCommands = async.getStatefulConnection(); + assertThat(ReflectionTestUtils.getField(statefulRedisCommands, "password")).isNull(); } finally { - async.close(); + async.getStatefulConnection().close(); } } @Test @SuppressWarnings("unchecked") public void selectInvalid() throws Exception { - RedisAsyncConnection async = client.connectAsync(); + RedisAsyncCommands async = client.connect().async(); try { async.select(1024); fail("Selected invalid db index"); } catch (RedisException e) { assertThat(e.getMessage()).isEqualTo("ERR invalid DB index"); - StatefulRedisConnection statefulRedisConnection = (StatefulRedisConnection) ReflectionTestUtils - .getField(async, "connection"); - assertThat(ReflectionTestUtils.getField(statefulRedisConnection, "db")).isEqualTo(0); + StatefulRedisConnection statefulRedisCommands = async.getStatefulConnection(); + assertThat(ReflectionTestUtils.getField(statefulRedisCommands, "db")).isEqualTo(0); } finally { - async.close(); + async.getStatefulConnection().close(); } } diff --git a/src/test/java/com/lambdaworks/redis/LettucePerformanceTest.java b/src/test/java/com/lambdaworks/redis/LettucePerformanceTest.java index fa7069eb3f..17f994f4ba 100644 --- a/src/test/java/com/lambdaworks/redis/LettucePerformanceTest.java +++ b/src/test/java/com/lambdaworks/redis/LettucePerformanceTest.java @@ -11,6 +11,7 @@ import org.junit.*; import com.lambdaworks.redis.api.StatefulRedisConnection; +import com.lambdaworks.redis.api.async.RedisAsyncCommands; import com.lambdaworks.redis.api.rx.RedisReactiveCommands; import rx.Observable; @@ -21,7 +22,7 @@ @Ignore public class LettucePerformanceTest { - private static RedisClient redisClient = new RedisClient(TestSettings.host(), TestSettings.port()); + private static RedisClient redisClient = RedisClient.create(RedisURI.create(TestSettings.host(), TestSettings.port())); private ExecutorService executor; private CountDownLatch latch = new CountDownLatch(1); @@ -107,9 +108,9 @@ public void testSyncAsyncPerformance() throws Exception { protected void submitExecutionTasks(int threads, List>>> futurama, final int callsPerThread, final boolean connectionPerThread) { - final RedisAsyncConnection sharedConnection; + final RedisAsyncCommands sharedConnection; if (!connectionPerThread) { - sharedConnection = redisClient.connectAsync(); + sharedConnection = redisClient.connect().async(); } else { sharedConnection = null; } @@ -117,9 +118,9 @@ protected void submitExecutionTasks(int threads, List>> submit = executor.submit(() -> { - RedisAsyncConnection connection = sharedConnection; + RedisAsyncCommands connection = sharedConnection; if (connectionPerThread) { - connection = redisClient.connectAsync(); + connection = redisClient.connect().async(); } connection.ping().get(); @@ -193,7 +194,7 @@ protected void submitObservableTasks(int threads, List sharedConnection; if (!connectionPerThread) { - sharedConnection = redisClient.connectAsync().getStatefulConnection(); + sharedConnection = redisClient.connect(); } else { sharedConnection = null; } @@ -203,7 +204,7 @@ protected void submitObservableTasks(int threads, List connection = sharedConnection; if (connectionPerThread) { - connection = redisClient.connectAsync().getStatefulConnection(); + connection = redisClient.connect(); } RedisReactiveCommands reactive = connection.reactive(); diff --git a/src/test/java/com/lambdaworks/redis/MultiConnectionTest.java b/src/test/java/com/lambdaworks/redis/MultiConnectionTest.java deleted file mode 100644 index 4d50c0b3ba..0000000000 --- a/src/test/java/com/lambdaworks/redis/MultiConnectionTest.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.lambdaworks.redis; - -import static org.assertj.core.api.Assertions.assertThat; - -import java.util.Set; -import java.util.concurrent.Future; - -import org.junit.Test; - -public class MultiConnectionTest extends AbstractRedisClientTest { - - @Test - public void twoConnections() throws Exception { - - RedisAsyncConnection connection1 = client.connectAsync(); - - RedisAsyncConnection connection2 = client.connectAsync(); - - connection1.sadd("key", "member1", "member2").get(); - - Future> members = connection2.smembers("key"); - - assertThat(members.get()).hasSize(2); - - connection1.close(); - connection2.close(); - } -} diff --git a/src/test/java/com/lambdaworks/redis/PoolConnectionTest.java b/src/test/java/com/lambdaworks/redis/PoolConnectionTest.java deleted file mode 100644 index fc374c10f6..0000000000 --- a/src/test/java/com/lambdaworks/redis/PoolConnectionTest.java +++ /dev/null @@ -1,224 +0,0 @@ -package com.lambdaworks.redis; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.fail; - -import java.lang.reflect.Proxy; -import java.util.concurrent.TimeUnit; - -import org.junit.Test; - -import com.google.common.base.Stopwatch; -import com.lambdaworks.redis.api.async.RedisAsyncCommands; -import com.lambdaworks.redis.api.sync.RedisCommands; - -public class PoolConnectionTest extends AbstractRedisClientTest { - - @Test - public void twoConnections() throws Exception { - - RedisConnectionPool> pool = client.pool(); - RedisCommands c1 = pool.allocateConnection(); - RedisConnection c2 = pool.allocateConnection(); - - String result1 = c1.ping(); - String result2 = c2.ping(); - assertThat(result1).isEqualTo("PONG"); - assertThat(result2).isEqualTo("PONG"); - - c1.close(); - c2.close(); - pool.close(); - } - - @Test(expected = UnsupportedOperationException.class) - public void getStatefulConnection() throws Exception { - - RedisConnectionPool> pool = client.pool(); - RedisCommands c1 = pool.allocateConnection(); - - try { - c1.getStatefulConnection(); - } finally { - c1.close(); - pool.close(); - } - } - - @Test - public void sameConnectionAfterFree() throws Exception { - RedisConnectionPool> pool = client.pool(); - RedisCommands c1 = pool.allocateConnection(); - pool.freeConnection(c1); - assertConnectionStillThere(c1); - - RedisConnection c2 = pool.allocateConnection(); - assertThat(c2).isSameAs(c1); - - c2.close(); - pool.close(); - } - - @Test - public void connectionCloseDoesNotClose() throws Exception { - RedisConnectionPool> pool = client.pool(); - RedisConnection c1 = pool.allocateConnection(); - c1.close(); - RedisConnection actualConnection1 = assertConnectionStillThere(c1); - - RedisConnection c2 = pool.allocateConnection(); - assertThat(c2).isSameAs(c1); - - RedisConnection actualConnection2 = assertConnectionStillThere(c2); - assertThat(actualConnection1).isSameAs(actualConnection2); - - c2.close(); - pool.close(); - } - - @SuppressWarnings("unchecked") - private RedisConnection assertConnectionStillThere(RedisConnection c1) { - // unwrap code from RedisConnectionPool destroyObject - if (Proxy.isProxyClass(c1.getClass())) { - RedisConnectionPool.PooledConnectionInvocationHandler> invocationHandler; - invocationHandler = (RedisConnectionPool.PooledConnectionInvocationHandler>) Proxy - .getInvocationHandler(c1); - - RedisConnection connection = invocationHandler.getConnection(); - assertThat(connection).isNotNull(); - return connection; - } - return null; - } - - @Test - public void releaseConnectionWithClose() throws Exception { - - RedisConnectionPool> pool = client.pool(); - RedisConnection c1 = pool.allocateConnection(); - assertThat(pool.getNumActive()).isEqualTo(1); - c1.close(); - assertThat(pool.getNumActive()).isEqualTo(0); - - pool.allocateConnection(); - assertThat(pool.getNumActive()).isEqualTo(1); - } - - @Test - public void connectionsClosedAfterPoolClose() throws Exception { - - RedisConnectionPool> pool = client.pool(); - RedisCommands c1 = pool.allocateConnection(); - pool.freeConnection(c1); - pool.close(); - - try { - c1.ping(); - fail("Missing Exception: Connection closed"); - } catch (Exception e) { - } - } - - @Test - public void connectionNotClosedWhenBorrowed() throws Exception { - - RedisConnectionPool> pool = client.pool(); - RedisConnection c1 = pool.allocateConnection(); - pool.close(); - - c1.ping(); - c1.close(); - } - - @Test - public void connectionNotClosedWhenBorrowed2() throws Exception { - - RedisConnectionPool> pool = client.pool(); - RedisCommands c1 = pool.allocateConnection(); - pool.freeConnection(c1); - c1 = pool.allocateConnection(); - pool.close(); - - c1.ping(); - c1.close(); - } - - @Test - public void testResourceCleaning() throws Exception { - - RedisClient redisClient = newRedisClient(); - - assertThat(redisClient.getChannelCount()).isEqualTo(0); - assertThat(redisClient.getResourceCount()).isEqualTo(0); - - RedisConnectionPool> pool1 = redisClient.asyncPool(); - - assertThat(redisClient.getChannelCount()).isEqualTo(0); - assertThat(redisClient.getResourceCount()).isEqualTo(1); - - pool1.allocateConnection(); - - assertThat(redisClient.getChannelCount()).isEqualTo(1); - assertThat(redisClient.getResourceCount()).isEqualTo(2); - - RedisConnectionPool> pool2 = redisClient.pool(); - - assertThat(redisClient.getResourceCount()).isEqualTo(3); - - pool2.allocateConnection(); - - assertThat(redisClient.getResourceCount()).isEqualTo(4); - - redisClient.pool().close(); - assertThat(redisClient.getResourceCount()).isEqualTo(4); - - FastShutdown.shutdown(redisClient); - - assertThat(redisClient.getChannelCount()).isEqualTo(0); - assertThat(redisClient.getResourceCount()).isEqualTo(0); - - } - - @Test - public void syncPoolPerformanceTest() throws Exception { - - RedisConnectionPool> pool = client.pool(); - RedisConnection c1 = pool.allocateConnection(); - - c1.ping(); - Stopwatch stopwatch = Stopwatch.createStarted(); - - for (int i = 0; i < 1000; i++) { - c1.ping(); - } - - long elapsed = stopwatch.stop().elapsed(TimeUnit.MILLISECONDS); - - log.info("syncPoolPerformanceTest Duration: " + elapsed + "ms"); - - c1.close(); - pool.close(); - - } - - @Test - public void asyncPoolPerformanceTest() throws Exception { - - RedisConnectionPool> pool = client.asyncPool(); - RedisAsyncConnection c1 = pool.allocateConnection(); - - c1.ping(); - Stopwatch stopwatch = Stopwatch.createStarted(); - - for (int i = 0; i < 1000; i++) { - c1.ping(); - } - - long elapsed = stopwatch.stop().elapsed(TimeUnit.MILLISECONDS); - - log.info("asyncPoolPerformanceTest Duration: " + elapsed + "ms"); - - c1.close(); - pool.close(); - } -} diff --git a/src/test/java/com/lambdaworks/redis/RedisClientConnectionTest.java b/src/test/java/com/lambdaworks/redis/RedisClientConnectionTest.java index 0a0c935496..81b713dd5b 100644 --- a/src/test/java/com/lambdaworks/redis/RedisClientConnectionTest.java +++ b/src/test/java/com/lambdaworks/redis/RedisClientConnectionTest.java @@ -29,42 +29,6 @@ public void before() throws Exception { client.setDefaultTimeout(EXPECTED_TIMEOUT, EXPECTED_TIME_UNIT); } - /* - * Pool/Sync - */ - @Test - public void poolClientUri() throws Exception { - client.pool().close(); - } - - @Test - public void poolClientUriConfig() throws Exception { - client.pool(1, 1).close(); - } - - @Test - public void poolCodecClientUriConfig() throws Exception { - client.pool(CODEC, 1, 1).close(); - } - - /* - * Pool/Async - */ - @Test - public void asyncPoolClientUri() throws Exception { - client.asyncPool().close(); - } - - @Test - public void asyncPoolClientUriConfig() throws Exception { - client.asyncPool(1, 1).close(); - } - - @Test - public void asyncPoolCodecClientUriConfig() throws Exception { - client.asyncPool(CODEC, 1, 1).close(); - } - /* * Standalone/Stateful */ @@ -119,29 +83,6 @@ public void connectcodecSentinelMissingHostAndSocketUri() throws Exception { client.connect(CODEC, invalidSentinel()); } - /* - * Deprecated: Standalone/Async - */ - @Test - public void connectAsyncClientUri() throws Exception { - client.connectAsync().close(); - } - - @Test - public void connectAsyncCodecClientUri() throws Exception { - client.connectAsync(CODEC).close(); - } - - @Test - public void connectAsyncOwnUri() throws Exception { - client.connectAsync(redis(host, port).build()).close(); - } - - @Test - public void connectAsyncCodecOwnUri() throws Exception { - client.connectAsync(CODEC, redis(host, port).build()).close(); - } - /* * Standalone/PubSub Stateful */ @@ -248,29 +189,6 @@ public void connectSentinelCodecSentinelMissingHostAndSocketUri() throws Excepti client.connectSentinel(CODEC, invalidSentinel()); } - /* - * Deprecated: Sentinel/Async - */ - @Test - public void connectSentinelAsyncClientUri() throws Exception { - client.connectSentinelAsync().close(); - } - - @Test - public void connectSentinelAsyncCodecClientUri() throws Exception { - client.connectSentinelAsync(CODEC).close(); - } - - @Test - public void connectSentineAsynclOwnUri() throws Exception { - client.connectSentinelAsync(redis(host, port).build()).close(); - } - - @Test - public void connectSentinelAsyncCodecOwnUri() throws Exception { - client.connectSentinelAsync(CODEC, redis(host, port).build()).close(); - } - private RedisURI invalidSentinel() { RedisURI redisURI = new RedisURI(); redisURI.getSentinels().add(new RedisURI()); diff --git a/src/test/java/com/lambdaworks/redis/TimeTest.java b/src/test/java/com/lambdaworks/redis/TimeTest.java deleted file mode 100644 index cdba0183bd..0000000000 --- a/src/test/java/com/lambdaworks/redis/TimeTest.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.lambdaworks.redis; - -import java.util.concurrent.TimeUnit; - -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -import static org.assertj.core.api.Assertions.assertThat; - -public class TimeTest { - RedisClient client = RedisClient.create(); - - @Before - public void setUp() throws Exception { - client.setDefaultTimeout(15, TimeUnit.SECONDS); - } - - @After - public void after() throws Exception { - FastShutdown.shutdown(client); - } - - @Test - public void testTime() throws Exception { - assertThat(client.makeTimeout()).isEqualTo(15000); - } -} diff --git a/src/test/java/com/lambdaworks/redis/UnixDomainSocketTest.java b/src/test/java/com/lambdaworks/redis/UnixDomainSocketTest.java index ad1555467d..a7aeb5f8ef 100644 --- a/src/test/java/com/lambdaworks/redis/UnixDomainSocketTest.java +++ b/src/test/java/com/lambdaworks/redis/UnixDomainSocketTest.java @@ -16,7 +16,10 @@ import org.junit.Test; import com.lambdaworks.redis.api.StatefulRedisConnection; +import com.lambdaworks.redis.api.sync.RedisCommands; import com.lambdaworks.redis.sentinel.SentinelRule; +import com.lambdaworks.redis.sentinel.api.StatefulRedisSentinelConnection; + import io.netty.util.internal.SystemPropertyUtil; /** @@ -112,9 +115,9 @@ public void sentinel_Linux_x86_64_RedisClientWithSocket() throws Exception { connection.close(); - RedisSentinelAsyncConnection sentinelConnection = redisClient.connectSentinelAsync(); + StatefulRedisSentinelConnection sentinelConnection = redisClient.connectSentinel(); - assertThat(sentinelConnection.ping().get()).isEqualTo("PONG"); + assertThat(sentinelConnection.sync().ping()).isEqualTo("PONG"); sentinelConnection.close(); FastShutdown.shutdown(redisClient); @@ -137,9 +140,9 @@ public void sentinel_Linux_x86_64_ConnectToSocket() throws Exception { connection.close(); - RedisSentinelAsyncConnection sentinelConnection = redisClient.connectSentinelAsync(uri); + StatefulRedisSentinelConnection sentinelConnection = redisClient.connectSentinel(uri); - assertThat(sentinelConnection.ping().get()).isEqualTo("PONG"); + assertThat(sentinelConnection.sync().ping()).isEqualTo("PONG"); sentinelConnection.close(); FastShutdown.shutdown(redisClient); @@ -156,11 +159,11 @@ public void sentinel_Linux_x86_64_socket_and_inet() throws Exception { uri.getSentinels().add(RedisURI.create(RedisURI.URI_SCHEME_REDIS + "://" + TestSettings.host() + ":26379")); uri.setSentinelMasterId(MASTER_ID); - RedisClient redisClient = new RedisClient(uri); + RedisClient redisClient = RedisClient.create(uri); - RedisSentinelAsyncConnection sentinelConnection = redisClient - .connectSentinelAsync(getSentinelSocketRedisUri()); - log.info("Masters: " + sentinelConnection.masters().get()); + StatefulRedisSentinelConnection sentinelConnection = redisClient + .connectSentinel(getSentinelSocketRedisUri()); + log.info("Masters: " + sentinelConnection.sync().masters()); try { redisClient.connect(); @@ -173,7 +176,7 @@ public void sentinel_Linux_x86_64_socket_and_inet() throws Exception { } - private void someRedisAction(RedisConnection connection) { + private void someRedisAction(RedisCommands connection) { connection.set(key, value); String result = connection.get(key); @@ -181,6 +184,6 @@ private void someRedisAction(RedisConnection connection) { } protected static RedisClient getRedisSentinelClient() { - return new RedisClient(RedisURI.Builder.sentinel(TestSettings.host(), MASTER_ID).build()); + return RedisClient.create(RedisURI.Builder.sentinel(TestSettings.host(), MASTER_ID).build()); } } diff --git a/src/test/java/com/lambdaworks/redis/cluster/AbstractClusterTest.java b/src/test/java/com/lambdaworks/redis/cluster/AbstractClusterTest.java index 5d31ed5a29..a18a73cbc8 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/AbstractClusterTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/AbstractClusterTest.java @@ -1,16 +1,14 @@ package com.lambdaworks.redis.cluster; -import java.util.concurrent.TimeUnit; - -import com.lambdaworks.redis.FastShutdown; -import com.lambdaworks.redis.internal.LettuceLists; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Rule; import com.lambdaworks.redis.AbstractTest; +import com.lambdaworks.redis.FastShutdown; import com.lambdaworks.redis.RedisURI; import com.lambdaworks.redis.TestSettings; +import com.lambdaworks.redis.internal.LettuceLists; /** * @author Mark Paluch @@ -37,6 +35,7 @@ public class AbstractClusterTest extends AbstractTest { public static final int port7 = port1 + 6; public static final String KEY_A = "a"; public static final String KEY_B = "b"; + public static final String KEY_D = "d"; protected static RedisClusterClient clusterClient; diff --git a/src/test/java/com/lambdaworks/redis/cluster/AdvancedClusterClientTest.java b/src/test/java/com/lambdaworks/redis/cluster/AdvancedClusterClientTest.java index deb08b9808..3a1b7ff77f 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/AdvancedClusterClientTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/AdvancedClusterClientTest.java @@ -16,6 +16,7 @@ import com.lambdaworks.redis.api.StatefulRedisConnection; import com.lambdaworks.redis.cluster.api.StatefulRedisClusterConnection; import com.lambdaworks.redis.cluster.api.async.RedisAdvancedClusterAsyncCommands; +import com.lambdaworks.redis.cluster.api.async.RedisClusterAsyncCommands; import com.lambdaworks.redis.cluster.api.rx.RedisAdvancedClusterReactiveCommands; import com.lambdaworks.redis.cluster.api.rx.RedisClusterReactiveCommands; import com.lambdaworks.redis.cluster.api.sync.RedisAdvancedClusterCommands; @@ -55,7 +56,7 @@ public void nodeConnections() throws Exception { assertThat(clusterClient.getPartitions()).hasSize(4); for (RedisClusterNode redisClusterNode : clusterClient.getPartitions()) { - RedisClusterAsyncConnection nodeConnection = commands.getConnection(redisClusterNode.getNodeId()); + RedisClusterAsyncCommands nodeConnection = commands.getConnection(redisClusterNode.getNodeId()); String myid = nodeConnection.clusterMyId().get(); assertThat(myid).isEqualTo(redisClusterNode.getNodeId()); @@ -86,11 +87,11 @@ public void doWeirdThingsWithClusterconnections() throws Exception { assertThat(clusterClient.getPartitions()).hasSize(4); for (RedisClusterNode redisClusterNode : clusterClient.getPartitions()) { - RedisClusterAsyncConnection nodeConnection = commands.getConnection(redisClusterNode.getNodeId()); + RedisClusterAsyncCommands nodeConnection = commands.getConnection(redisClusterNode.getNodeId()); nodeConnection.close(); - RedisClusterAsyncConnection nextConnection = commands.getConnection(redisClusterNode.getNodeId()); + RedisClusterAsyncCommands nextConnection = commands.getConnection(redisClusterNode.getNodeId()); assertThat(commands).isNotSameAs(nextConnection); } } @@ -99,8 +100,8 @@ public void doWeirdThingsWithClusterconnections() throws Exception { public void differentConnections() throws Exception { for (RedisClusterNode redisClusterNode : clusterClient.getPartitions()) { - RedisClusterAsyncConnection nodeId = commands.getConnection(redisClusterNode.getNodeId()); - RedisClusterAsyncConnection hostAndPort = commands + RedisClusterAsyncCommands nodeId = commands.getConnection(redisClusterNode.getNodeId()); + RedisClusterAsyncCommands hostAndPort = commands .getConnection(redisClusterNode.getUri().getHost(), redisClusterNode.getUri().getPort()); assertThat(nodeId).isNotSameAs(hostAndPort); @@ -439,7 +440,7 @@ public void routeCommandToForbiddenHostOnRedirect() throws Exception { @Test public void getConnectionToNotAClusterMemberForbidden() throws Exception { - RedisAdvancedClusterConnection sync = clusterClient.connectCluster(); + StatefulRedisClusterConnection sync = clusterClient.connect(); try { sync.getConnection(TestSettings.host(), TestSettings.port()); } catch (RedisException e) { @@ -485,19 +486,6 @@ public void pipelining() throws Exception { } verificationConnection.close(); - - } - - @Test - public void transactions() throws Exception { - - commands.multi(); - commands.set(key, value); - commands.discard(); - - commands.multi(); - commands.set(key, value); - commands.exec(); } @Test diff --git a/src/test/java/com/lambdaworks/redis/cluster/AdvancedClusterReactiveTest.java b/src/test/java/com/lambdaworks/redis/cluster/AdvancedClusterReactiveTest.java index 760a08e030..7b6059cdc4 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/AdvancedClusterReactiveTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/AdvancedClusterReactiveTest.java @@ -15,8 +15,6 @@ import org.junit.Ignore; import org.junit.Test; -import rx.Observable; - import com.lambdaworks.RandomKeys; import com.lambdaworks.redis.*; import com.lambdaworks.redis.api.sync.RedisCommands; @@ -29,6 +27,8 @@ import com.lambdaworks.redis.commands.rx.RxSyncInvocationHandler; import com.lambdaworks.redis.internal.LettuceLists; +import rx.Observable; + /** * @author Mark Paluch */ @@ -42,7 +42,7 @@ public class AdvancedClusterReactiveTest extends AbstractClusterTest { @Before public void before() throws Exception { - commands = clusterClient.connectClusterAsync().getStatefulConnection().reactive(); + commands = clusterClient.connect().reactive(); syncCommands = RxSyncInvocationHandler.sync(commands.getStatefulConnection()); } diff --git a/src/test/java/com/lambdaworks/redis/cluster/ByteCodecClusterTest.java b/src/test/java/com/lambdaworks/redis/cluster/ByteCodecClusterTest.java index 448d4f623c..c7ba6665fa 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/ByteCodecClusterTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/ByteCodecClusterTest.java @@ -5,8 +5,6 @@ import org.junit.Test; import com.lambdaworks.redis.cluster.api.StatefulRedisClusterConnection; -import com.lambdaworks.redis.cluster.api.async.RedisAdvancedClusterAsyncCommands; -import com.lambdaworks.redis.cluster.api.sync.RedisAdvancedClusterCommands; import com.lambdaworks.redis.codec.ByteArrayCodec; /** @@ -22,22 +20,4 @@ public void testByteCodec() throws Exception { connection.sync().set(key.getBytes(), value.getBytes()); assertThat(connection.sync().get(key.getBytes())).isEqualTo(value.getBytes()); } - - @Test - public void deprecatedTestByteCodec() throws Exception { - - RedisAdvancedClusterCommands commands = clusterClient.connectCluster(new ByteArrayCodec()); - - commands.set(key.getBytes(), value.getBytes()); - assertThat(commands.get(key.getBytes())).isEqualTo(value.getBytes()); - } - - @Test - public void deprecatedTestAsyncByteCodec() throws Exception { - - RedisAdvancedClusterAsyncCommands commands = clusterClient.connectClusterAsync(new ByteArrayCodec()); - - commands.set(key.getBytes(), value.getBytes()).get(); - assertThat(commands.get(key.getBytes()).get()).isEqualTo(value.getBytes()); - } } diff --git a/src/test/java/com/lambdaworks/redis/cluster/ClusterClientOptionsTest.java b/src/test/java/com/lambdaworks/redis/cluster/ClusterClientOptionsTest.java index 7697c4b78a..79e0e893e8 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/ClusterClientOptionsTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/ClusterClientOptionsTest.java @@ -2,8 +2,6 @@ import static org.assertj.core.api.Assertions.assertThat; -import java.util.concurrent.TimeUnit; - import org.junit.Test; /** @@ -14,7 +12,7 @@ public class ClusterClientOptionsTest { @Test public void testCopy() throws Exception { - ClusterClientOptions options = ClusterClientOptions.builder().closeStaleConnections(true).refreshClusterView(true) + ClusterClientOptions options = ClusterClientOptions.builder() .autoReconnect(false).requestQueueSize(100).suspendReconnectOnProtocolFailure(true).maxRedirects(1234) .validateClusterNodeMembership(false).build(); @@ -31,15 +29,4 @@ public void testCopy() throws Exception { assertThat(copy.isSuspendReconnectOnProtocolFailure()).isEqualTo(options.isSuspendReconnectOnProtocolFailure()); assertThat(copy.getMaxRedirects()).isEqualTo(options.getMaxRedirects()); } - - @Test - public void enablesRefreshUsingDeprecatedMethods() throws Exception { - - ClusterClientOptions options = ClusterClientOptions.builder().refreshClusterView(true) - .refreshPeriod(10, TimeUnit.MINUTES).build(); - - assertThat(options.getRefreshPeriod()).isEqualTo(10); - assertThat(options.getRefreshPeriodUnit()).isEqualTo(TimeUnit.MINUTES); - assertThat(options.isRefreshClusterView()).isEqualTo(true); - } } diff --git a/src/test/java/com/lambdaworks/redis/cluster/ClusterCommandTest.java b/src/test/java/com/lambdaworks/redis/cluster/ClusterCommandTest.java index 3cdce47aa1..81694bea2b 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/ClusterCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/ClusterCommandTest.java @@ -13,10 +13,14 @@ import org.junit.runners.MethodSorters; import com.google.code.tempusfugit.temporal.WaitFor; -import com.lambdaworks.redis.*; +import com.lambdaworks.redis.FastShutdown; +import com.lambdaworks.redis.RedisClient; +import com.lambdaworks.redis.RedisFuture; +import com.lambdaworks.redis.RedisURI; import com.lambdaworks.redis.api.StatefulRedisConnection; +import com.lambdaworks.redis.api.sync.RedisCommands; +import com.lambdaworks.redis.cluster.api.StatefulRedisClusterConnection; import com.lambdaworks.redis.cluster.api.async.RedisClusterAsyncCommands; -import com.lambdaworks.redis.cluster.api.sync.RedisAdvancedClusterCommands; import com.lambdaworks.redis.cluster.api.sync.RedisClusterCommands; import com.lambdaworks.redis.cluster.models.slots.ClusterSlotRange; import com.lambdaworks.redis.cluster.models.slots.ClusterSlotsParser; @@ -61,18 +65,6 @@ public void after() throws Exception { connection.close(); } - @Test - public void statefulConnectionFromSync() throws Exception { - RedisAdvancedClusterConnection sync = clusterClient.connectCluster(); - assertThat(sync.getStatefulConnection().sync()).isSameAs(sync); - } - - @Test - public void statefulConnectionFromAsync() throws Exception { - RedisAsyncConnection async = client.connectAsync(); - assertThat(async.getStatefulConnection().async()).isSameAs(async); - } - @Test public void testClusterBumpEpoch() throws Exception { @@ -108,9 +100,9 @@ public void testClusterNodes() throws Exception { @Test public void testClusterNodesSync() throws Exception { - RedisClusterConnection connection = clusterClient.connectCluster(); + StatefulRedisClusterConnection connection = clusterClient.connect(); - String string = connection.clusterNodes(); + String string = connection.sync().clusterNodes(); connection.close(); assertThat(string).contains("connected"); @@ -135,15 +127,16 @@ public void testAsking() throws Exception { public void testReset() throws Exception { clusterClient.reloadPartitions(); - RedisAdvancedClusterAsyncCommandsImpl connection = (RedisAdvancedClusterAsyncCommandsImpl) clusterClient - .connectClusterAsync(); - RedisFuture setA = connection.set("a", "myValue1"); + StatefulRedisClusterConnection clusterConnection = clusterClient + .connect(); + + RedisFuture setA = clusterConnection.async().set("a", "myValue1"); setA.get(); - connection.reset(); + clusterConnection.reset(); - setA = connection.set("a", "myValue1"); + setA = clusterConnection.async().set("a", "myValue1"); assertThat(setA.getError()).isNull(); assertThat(setA.get()).isEqualTo("OK"); @@ -165,10 +158,7 @@ public void testClusterSlots() throws Exception { assertThat(clusterSlotRange.getFrom()).isEqualTo(0); assertThat(clusterSlotRange.getTo()).isEqualTo(11999); - assertThat(clusterSlotRange.getMaster()).isNotNull(); - assertThat(clusterSlotRange.getSlaves()).isNotNull(); assertThat(clusterSlotRange.toString()).contains(ClusterSlotRange.class.getSimpleName()); - } @Test @@ -180,7 +170,7 @@ public void readOnly() throws Exception { prepareReadonlyTest(key); // assume cluster node 3 is a slave for the master 1 - RedisConnection connect3 = client.connect(RedisURI.Builder.redis(host, port3).build()).sync(); + RedisCommands connect3 = client.connect(RedisURI.Builder.redis(host, port3).build()).sync(); assertThat(connect3.readOnly()).isEqualTo("OK"); waitUntilValueIsVisible(key, connect3); @@ -203,7 +193,7 @@ public void readOnlyWithReconnect() throws Exception { prepareReadonlyTest(key); // assume cluster node 3 is a slave for the master 1 - RedisConnection connect3 = client.connect(RedisURI.Builder.redis(host, port3).build()).sync(); + RedisCommands connect3 = client.connect(RedisURI.Builder.redis(host, port3).build()).sync(); assertThat(connect3.readOnly()).isEqualTo("OK"); connect3.quit(); @@ -214,9 +204,9 @@ public void readOnlyWithReconnect() throws Exception { } - protected void waitUntilValueIsVisible(String key, RedisConnection connection) throws InterruptedException, + protected void waitUntilValueIsVisible(String key, RedisCommands commands) throws InterruptedException, TimeoutException { - WaitFor.waitOrTimeout(() -> connection.get(key) != null, timeout(seconds(5))); + WaitFor.waitOrTimeout(() -> commands.get(key) != null, timeout(seconds(5))); } protected void prepareReadonlyTest(String key) throws InterruptedException, TimeoutException, @@ -238,7 +228,7 @@ public void readOnlyReadWrite() throws Exception { prepareReadonlyTest(key); // assume cluster node 3 is a slave for the master 1 - final RedisConnection connect3 = client.connect(RedisURI.Builder.redis(host, port3).build()).sync(); + final RedisCommands connect3 = client.connect(RedisURI.Builder.redis(host, port3).build()).sync(); try { connect3.get("b"); diff --git a/src/test/java/com/lambdaworks/redis/cluster/ClusterReactiveCommandTest.java b/src/test/java/com/lambdaworks/redis/cluster/ClusterReactiveCommandTest.java index cd37113a31..6479c85278 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/ClusterReactiveCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/ClusterReactiveCommandTest.java @@ -5,17 +5,9 @@ import java.util.List; -import com.lambdaworks.redis.internal.LettuceLists; -import org.junit.After; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.FixMethodOrder; -import org.junit.Test; +import org.junit.*; import org.junit.runners.MethodSorters; -import rx.Observable; - import com.lambdaworks.redis.FastShutdown; import com.lambdaworks.redis.RedisClient; import com.lambdaworks.redis.RedisURI; @@ -23,6 +15,9 @@ import com.lambdaworks.redis.cluster.api.rx.RedisClusterReactiveCommands; import com.lambdaworks.redis.cluster.models.slots.ClusterSlotRange; import com.lambdaworks.redis.cluster.models.slots.ClusterSlotsParser; +import com.lambdaworks.redis.internal.LettuceLists; + +import rx.Observable; @FixMethodOrder(MethodSorters.NAME_ASCENDING) @SuppressWarnings("unchecked") @@ -53,7 +48,7 @@ public void before() throws Exception { clusterRule.getClusterClient().reloadPartitions(); - async = client.connectAsync(RedisURI.Builder.redis(host, port1).build()); + async = client.connect(RedisURI.Builder.redis(host, port1).build()).async(); reactive = async.getStatefulConnection().reactive(); } @@ -125,8 +120,6 @@ public void testClusterSlots() throws Exception { assertThat(clusterSlotRange.getFrom()).isEqualTo(0); assertThat(clusterSlotRange.getTo()).isEqualTo(11999); - assertThat(clusterSlotRange.getMaster()).isNotNull(); - assertThat(clusterSlotRange.getSlaves()).isNotNull(); assertThat(clusterSlotRange.toString()).contains(ClusterSlotRange.class.getSimpleName()); } diff --git a/src/test/java/com/lambdaworks/redis/cluster/ClusterSetup.java b/src/test/java/com/lambdaworks/redis/cluster/ClusterSetup.java index 6ed809d13d..e2c9b93964 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/ClusterSetup.java +++ b/src/test/java/com/lambdaworks/redis/cluster/ClusterSetup.java @@ -33,7 +33,7 @@ public static void setup2Masters(ClusterRule clusterRule) throws InterruptedExce clusterRule.meet(AbstractClusterTest.host, AbstractClusterTest.port5); clusterRule.meet(AbstractClusterTest.host, AbstractClusterTest.port6); - RedisAdvancedClusterAsyncCommands connection = clusterRule.getClusterClient().connectClusterAsync(); + RedisAdvancedClusterAsyncCommands connection = clusterRule.getClusterClient().connect().async(); Wait.untilTrue(() -> { clusterRule.getClusterClient().reloadPartitions(); @@ -96,7 +96,7 @@ public static void setupMasterWithSlave(ClusterRule clusterRule) throws Interrup clusterRule.meet(AbstractClusterTest.host, AbstractClusterTest.port5); clusterRule.meet(AbstractClusterTest.host, AbstractClusterTest.port6); - RedisAdvancedClusterAsyncCommands connection = clusterRule.getClusterClient().connectClusterAsync(); + RedisAdvancedClusterAsyncCommands connection = clusterRule.getClusterClient().connect().async(); StatefulRedisClusterConnection statefulConnection = connection.getStatefulConnection(); Wait.untilEquals(2, () -> { diff --git a/src/test/java/com/lambdaworks/redis/cluster/ClusterTestUtil.java b/src/test/java/com/lambdaworks/redis/cluster/ClusterTestUtil.java index 4803a39788..fd12451b4e 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/ClusterTestUtil.java +++ b/src/test/java/com/lambdaworks/redis/cluster/ClusterTestUtil.java @@ -3,7 +3,6 @@ import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; -import com.lambdaworks.redis.RedisClusterConnection; import com.lambdaworks.redis.api.sync.RedisCommands; import com.lambdaworks.redis.cluster.api.StatefulRedisClusterConnection; import com.lambdaworks.redis.cluster.api.sync.RedisClusterCommands; diff --git a/src/test/java/com/lambdaworks/redis/cluster/NodeSelectionAsyncTest.java b/src/test/java/com/lambdaworks/redis/cluster/NodeSelectionAsyncTest.java index 1544c755dc..c6c38a2bbe 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/NodeSelectionAsyncTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/NodeSelectionAsyncTest.java @@ -7,8 +7,6 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; -import com.google.code.tempusfugit.temporal.WaitFor; -import com.lambdaworks.redis.internal.LettuceSets; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -23,6 +21,7 @@ import com.lambdaworks.redis.cluster.api.sync.RedisAdvancedClusterCommands; import com.lambdaworks.redis.cluster.models.partitions.Partitions; import com.lambdaworks.redis.cluster.models.partitions.RedisClusterNode; +import com.lambdaworks.redis.internal.LettuceSets; /** * @author Mark Paluch @@ -148,7 +147,7 @@ public void testStaticNodeSelection() throws Exception { @Test public void testAsynchronicityOfMultiNodeExecution() throws Exception { - RedisAdvancedClusterAsyncCommands connection2 = clusterClient.connectClusterAsync(); + RedisAdvancedClusterAsyncCommands connection2 = clusterClient.connect().async(); AsyncNodeSelection masters = connection2.masters(); CompletableFuture.allOf(masters.commands().configSet("lua-time-limit", "10").futures()).get(); diff --git a/src/test/java/com/lambdaworks/redis/cluster/RedisClusterClientTest.java b/src/test/java/com/lambdaworks/redis/cluster/RedisClusterClientTest.java index 8d1a9fc6b9..5a6f91fb4e 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/RedisClusterClientTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/RedisClusterClientTest.java @@ -33,15 +33,15 @@ public class RedisClusterClientTest extends AbstractClusterTest { protected static RedisClient client; - protected StatefulRedisConnection redis1; - protected StatefulRedisConnection redis2; - protected StatefulRedisConnection redis3; - protected StatefulRedisConnection redis4; + private StatefulRedisConnection redis1; + private StatefulRedisConnection redis2; + private StatefulRedisConnection redis3; + private StatefulRedisConnection redis4; - protected RedisClusterCommands redissync1; - protected RedisClusterCommands redissync2; - protected RedisClusterCommands redissync3; - protected RedisClusterCommands redissync4; + private RedisClusterCommands redissync1; + private RedisClusterCommands redissync2; + private RedisClusterCommands redissync3; + private RedisClusterCommands redissync4; protected RedisAdvancedClusterCommands sync; @@ -76,7 +76,7 @@ public void before() throws Exception { redissync4 = redis4.sync(); clusterClient.reloadPartitions(); - sync = clusterClient.connectCluster(); + sync = clusterClient.connect().sync(); } @After @@ -92,14 +92,14 @@ public void after() throws Exception { @Test public void statefulConnectionFromSync() throws Exception { - RedisAdvancedClusterConnection sync = clusterClient.connectCluster(); + RedisAdvancedClusterCommands sync = clusterClient.connect().sync(); assertThat(sync.getStatefulConnection().sync()).isSameAs(sync); sync.close(); } @Test public void statefulConnectionFromAsync() throws Exception { - RedisAsyncConnection async = client.connectAsync(); + RedisAdvancedClusterAsyncCommands async = clusterClient.connect().async(); assertThat(async.getStatefulConnection().async()).isSameAs(async); async.close(); } @@ -187,19 +187,12 @@ public void testClusteredOperations() throws Exception { } clusterClient.reloadPartitions(); - RedisClusterAsyncConnection connection = clusterClient.connectClusterAsync(); + RedisClusterCommands connection = clusterClient.connect().sync(); - RedisFuture setA = connection.set(KEY_A, value); - setA.get(); - - assertThat(setA.getError()).isNull(); - assertThat(setA.get()).isEqualTo("OK"); - RedisFuture setB = connection.set(KEY_B, "myValue2"); - assertThat(setB.get()).isEqualTo("OK"); - - RedisFuture setD = connection.set("d", "myValue2"); - assertThat(setD.get()).isEqualTo("OK"); + assertThat(connection.set(KEY_A, value)).isEqualTo("OK"); + assertThat(connection.set(KEY_B, "myValue2")).isEqualTo("OK"); + assertThat(connection.set(KEY_D, "myValue2")).isEqualTo("OK"); connection.close(); @@ -209,21 +202,13 @@ public void testClusteredOperations() throws Exception { public void testReset() throws Exception { clusterClient.reloadPartitions(); - RedisAdvancedClusterAsyncCommandsImpl connection = (RedisAdvancedClusterAsyncCommandsImpl) clusterClient - .connectClusterAsync(); - - RedisFuture setA = connection.set(KEY_A, value); - setA.get(); + StatefulRedisClusterConnection connection = clusterClient.connect(); + connection.sync().set(KEY_A, value); connection.reset(); - setA = connection.set(KEY_A, "myValue1"); - - assertThat(setA.getError()).isNull(); - assertThat(setA.get()).isEqualTo("OK"); - + assertThat(connection.sync().set(KEY_A, value)).isEqualTo("OK"); connection.close(); - } @Test @@ -327,37 +312,40 @@ public void closeConnection() throws Exception { @Test public void clusterAuth() throws Exception { - RedisClusterClient clusterClient = new RedisClusterClient( - RedisURI.Builder.redis(TestSettings.host(), port7).withPassword("foobared").build()); + RedisClusterClient clusterClient = RedisClusterClient + .create(RedisURI.Builder.redis(TestSettings.host(), port7).withPassword("foobared").build()); - try (RedisAdvancedClusterConnection connection = clusterClient.connectCluster()) { + StatefulRedisClusterConnection connection = clusterClient.connect(); + RedisAdvancedClusterCommands sync = connection.sync(); - List time = connection.time(); - assertThat(time).hasSize(2); + List time = sync.time(); + assertThat(time).hasSize(2); - connection.getStatefulConnection().async().quit().get(); + connection.async().quit().get(); - time = connection.time(); - assertThat(time).hasSize(2); + time = sync.time(); + assertThat(time).hasSize(2); - char[] password = (char[]) ReflectionTestUtils.getField(connection.getStatefulConnection(), "password"); - assertThat(new String(password)).isEqualTo("foobared"); - } finally { - FastShutdown.shutdown(clusterClient); + char[] password = (char[]) ReflectionTestUtils.getField(connection, "password"); + assertThat(new String(password)).isEqualTo("foobared"); - } + connection.close(); + FastShutdown.shutdown(clusterClient); } @Test(expected = RedisException.class) public void clusterNeedsAuthButNotSupplied() throws Exception { - RedisClusterClient clusterClient = new RedisClusterClient(RedisURI.Builder.redis(TestSettings.host(), port7).build()); + RedisClusterClient clusterClient = RedisClusterClient + .create(RedisURI.Builder.redis(TestSettings.host(), port7).build()); - try (RedisClusterCommands connection = clusterClient.connectCluster()) { + StatefulRedisClusterConnection connection = clusterClient.connect(); - List time = connection.time(); + try { + List time = connection.sync().time(); assertThat(time).hasSize(2); } finally { + connection.close(); FastShutdown.shutdown(clusterClient); } } @@ -365,12 +353,14 @@ public void clusterNeedsAuthButNotSupplied() throws Exception { @Test public void noClusterNodeAvailable() throws Exception { - RedisClusterClient clusterClient = new RedisClusterClient(RedisURI.Builder.redis(host, 40400).build()); + RedisClusterClient clusterClient = RedisClusterClient.create(RedisURI.Builder.redis(host, 40400).build()); try { - clusterClient.connectCluster(); + clusterClient.connect(); fail("Missing RedisException"); } catch (RedisException e) { assertThat(e).isInstanceOf(RedisException.class); + }finally { + FastShutdown.shutdown(clusterClient); } } @@ -442,12 +432,14 @@ public void readOnlyOnCluster() throws Exception { sync.readWrite(); assertThat(ReflectionTestUtils.getField(sync.getStatefulConnection(), "readOnly")).isEqualTo(Boolean.FALSE); - RedisClusterClient clusterClient = new RedisClusterClient(RedisURI.Builder.redis(host, 40400).build()); + RedisClusterClient clusterClient = RedisClusterClient.create(RedisURI.Builder.redis(host, 40400).build()); try { - clusterClient.connectCluster(); + clusterClient.connect(); fail("Missing RedisException"); } catch (RedisException e) { assertThat(e).isInstanceOf(RedisException.class); + }finally { + FastShutdown.shutdown(clusterClient); } } @@ -526,7 +518,8 @@ public void testReadFromNull() throws Exception { @Test public void testPfmerge() throws Exception { - RedisAdvancedClusterConnection connection = clusterClient.connectCluster(); + + RedisAdvancedClusterCommands connection = clusterClient.connect().sync(); assertThat(SlotHash.getSlot("key2660")).isEqualTo(SlotHash.getSlot("key7112")).isEqualTo(SlotHash.getSlot("key8885")); diff --git a/src/test/java/com/lambdaworks/redis/cluster/RedisClusterReadFromTest.java b/src/test/java/com/lambdaworks/redis/cluster/RedisClusterReadFromTest.java index e5898beef5..bd7b01293a 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/RedisClusterReadFromTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/RedisClusterReadFromTest.java @@ -2,22 +2,17 @@ import static org.assertj.core.api.Assertions.assertThat; -import com.lambdaworks.redis.ReadFrom; -import org.junit.After; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.FixMethodOrder; -import org.junit.Test; +import java.util.Collections; + +import org.junit.*; import org.junit.runners.MethodSorters; import com.lambdaworks.redis.FastShutdown; +import com.lambdaworks.redis.ReadFrom; import com.lambdaworks.redis.RedisURI; import com.lambdaworks.redis.cluster.api.StatefulRedisClusterConnection; import com.lambdaworks.redis.cluster.api.sync.RedisAdvancedClusterCommands; -import java.util.Collections; - @FixMethodOrder(MethodSorters.NAME_ASCENDING) @SuppressWarnings("unchecked") public class RedisClusterReadFromTest extends AbstractClusterTest { @@ -28,7 +23,7 @@ public class RedisClusterReadFromTest extends AbstractClusterTest { @BeforeClass public static void setupClient() throws Exception { setupClusterClient(); - clusterClient = new RedisClusterClient(Collections.singletonList(RedisURI.Builder.redis(host, port1).build())); + clusterClient = RedisClusterClient.create(Collections.singletonList(RedisURI.Builder.redis(host, port1).build())); } @AfterClass diff --git a/src/test/java/com/lambdaworks/redis/cluster/RedisClusterSetupTest.java b/src/test/java/com/lambdaworks/redis/cluster/RedisClusterSetupTest.java index c69617085b..90a323b3d3 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/RedisClusterSetupTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/RedisClusterSetupTest.java @@ -42,7 +42,10 @@ @SlowTests public class RedisClusterSetupTest extends AbstractTest { - public static final String host = TestSettings.hostAddr(); + private static final String host = TestSettings.hostAddr(); + + private static final ClusterTopologyRefreshOptions PERIODIC_REFRESH_ENABLED = ClusterTopologyRefreshOptions.builder() + .enablePeriodicRefresh(1, TimeUnit.SECONDS).build(); private static RedisClusterClient clusterClient; private static RedisClient client = DefaultRedisClient.get(); @@ -166,8 +169,7 @@ public void clusterSlotMigrationImport() throws Exception { @Test public void clusterTopologyRefresh() throws Exception { - clusterClient.setOptions( - ClusterClientOptions.builder().refreshClusterView(true).refreshPeriod(5, TimeUnit.SECONDS).build()); + clusterClient.setOptions(ClusterClientOptions.builder().topologyRefreshOptions(PERIODIC_REFRESH_ENABLED).build()); clusterClient.reloadPartitions(); RedisAdvancedClusterAsyncCommands clusterConnection = clusterClient.connect().async(); @@ -187,8 +189,7 @@ public void changeTopologyWhileOperations() throws Exception { ClusterTopologyRefreshOptions clusterTopologyRefreshOptions = ClusterTopologyRefreshOptions.builder() .enableAllAdaptiveRefreshTriggers().build(); - clusterClient - .setOptions(ClusterClientOptions.builder().topologyRefreshOptions(clusterTopologyRefreshOptions).build()); + clusterClient.setOptions(ClusterClientOptions.builder().topologyRefreshOptions(clusterTopologyRefreshOptions).build()); StatefulRedisClusterConnection connection = clusterClient.connect(); RedisAdvancedClusterCommands sync = connection.sync(); RedisAdvancedClusterAsyncCommands async = connection.async(); @@ -251,11 +252,11 @@ public void slotMigrationShouldUseAsking() throws Exception { @Test public void disconnectedConnectionRejectTest() throws Exception { - clusterClient.setOptions(ClusterClientOptions.builder().refreshClusterView(true).refreshPeriod(1, TimeUnit.SECONDS) + clusterClient.setOptions(ClusterClientOptions.builder().topologyRefreshOptions(PERIODIC_REFRESH_ENABLED) .disconnectedBehavior(ClientOptions.DisconnectedBehavior.REJECT_COMMANDS).build()); RedisAdvancedClusterAsyncCommands clusterConnection = clusterClient.connect().async(); clusterClient.setOptions(ClusterClientOptions.builder() - .disconnectedBehavior(ClientOptions.DisconnectedBehavior.REJECT_COMMANDS).refreshClusterView(false).build()); + .disconnectedBehavior(ClientOptions.DisconnectedBehavior.REJECT_COMMANDS).build()); ClusterSetup.setup2Masters(clusterRule); assertRoutedExecution(clusterConnection); @@ -284,10 +285,9 @@ public void disconnectedConnectionRejectTest() throws Exception { @Test public void atLeastOnceForgetNodeFailover() throws Exception { - clusterClient.setOptions( - ClusterClientOptions.builder().refreshClusterView(true).refreshPeriod(1, TimeUnit.SECONDS).build()); - RedisAdvancedClusterAsyncCommands clusterConnection = clusterClient.connectClusterAsync(); - clusterClient.setOptions(ClusterClientOptions.builder().refreshClusterView(false).build()); + clusterClient.setOptions(ClusterClientOptions.builder().topologyRefreshOptions(PERIODIC_REFRESH_ENABLED).build()); + RedisAdvancedClusterAsyncCommands clusterConnection = clusterClient.connect().async(); + clusterClient.setOptions(ClusterClientOptions.create()); ClusterSetup.setup2Masters(clusterRule); assertRoutedExecution(clusterConnection); @@ -315,7 +315,7 @@ public void atLeastOnceForgetNodeFailover() throws Exception { redis1.clusterForget(partition2.getNodeId()); redis2.clusterForget(partition1.getNodeId()); - clusterClient.setOptions(ClusterClientOptions.builder().refreshClusterView(true).build()); + clusterClient.setOptions(ClusterClientOptions.builder().topologyRefreshOptions(PERIODIC_REFRESH_ENABLED).build()); waitUntilOnlyOnePartition(); Wait.untilTrue(() -> Futures.areAllCompleted(futures)).waitOrTimeout(); @@ -329,9 +329,8 @@ public void atLeastOnceForgetNodeFailover() throws Exception { @Test public void expireStaleNodeIdConnections() throws Exception { - clusterClient.setOptions( - ClusterClientOptions.builder().refreshClusterView(true).refreshPeriod(1, TimeUnit.SECONDS).build()); - RedisAdvancedClusterAsyncCommands clusterConnection = clusterClient.connectClusterAsync(); + clusterClient.setOptions(ClusterClientOptions.builder().topologyRefreshOptions(PERIODIC_REFRESH_ENABLED).build()); + RedisAdvancedClusterAsyncCommands clusterConnection = clusterClient.connect().async(); ClusterSetup.setup2Masters(clusterRule); @@ -374,7 +373,8 @@ private void assertRoutedExecution(RedisClusterAsyncCommands clu @Test public void doNotExpireStaleNodeIdConnections() throws Exception { - clusterClient.setOptions(ClusterClientOptions.builder().closeStaleConnections(false).build()); + clusterClient.setOptions(ClusterClientOptions.builder() + .topologyRefreshOptions(ClusterTopologyRefreshOptions.builder().closeStaleConnections(false).build()).build()); RedisAdvancedClusterAsyncCommands clusterConnection = clusterClient.connect().async(); ClusterSetup.setup2Masters(clusterRule); @@ -414,7 +414,7 @@ public void doNotExpireStaleNodeIdConnections() throws Exception { public void expireStaleHostAndPortConnections() throws Exception { clusterClient.setOptions(ClusterClientOptions.builder().build()); - RedisAdvancedClusterAsyncCommands clusterConnection = clusterClient.connectClusterAsync(); + RedisAdvancedClusterAsyncCommands clusterConnection = clusterClient.connect().async(); ClusterSetup.setup2Masters(clusterRule); diff --git a/src/test/java/com/lambdaworks/redis/cluster/RedisClusterStressScenariosTest.java b/src/test/java/com/lambdaworks/redis/cluster/RedisClusterStressScenariosTest.java index 11a946771b..286d7deac6 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/RedisClusterStressScenariosTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/RedisClusterStressScenariosTest.java @@ -21,6 +21,8 @@ import com.lambdaworks.category.SlowTests; import com.lambdaworks.redis.*; import com.lambdaworks.redis.api.StatefulRedisConnection; +import com.lambdaworks.redis.api.async.RedisAsyncCommands; +import com.lambdaworks.redis.cluster.api.async.RedisClusterAsyncCommands; import com.lambdaworks.redis.cluster.api.sync.RedisClusterCommands; import com.lambdaworks.redis.cluster.models.partitions.RedisClusterNode; @@ -118,7 +120,7 @@ public void testClusterFailover() throws Exception { public void testClusterConnectionStability() throws Exception { RedisAdvancedClusterAsyncCommandsImpl connection = (RedisAdvancedClusterAsyncCommandsImpl) clusterClient - .connectClusterAsync(); + .connect().async(); RedisChannelHandler statefulConnection = (RedisChannelHandler) connection.getStatefulConnection(); @@ -129,7 +131,7 @@ public void testClusterConnectionStability() throws Exception { StatefulRedisConnectionImpl statefulSlotConnection = (StatefulRedisConnectionImpl) writer .getClusterConnectionProvider().getConnection(ClusterConnectionProvider.Intent.WRITE, 3300); - final RedisAsyncConnection slotConnection = statefulSlotConnection.async(); + final RedisAsyncCommands slotConnection = statefulSlotConnection.async(); slotConnection.set("a", "b"); slotConnection.close(); @@ -156,7 +158,7 @@ public void testClusterConnectionStability() throws Exception { @Test(timeout = 20000) public void distributedClusteredAccessAsync() throws Exception { - RedisClusterAsyncConnection connection = clusterClient.connectClusterAsync(); + RedisClusterAsyncCommands connection = clusterClient.connect().async(); List> futures = new ArrayList<>(); for (int i = 0; i < 100; i++) { @@ -193,7 +195,7 @@ public void distributedClusteredAccessAsync() throws Exception { @Test public void distributedClusteredAccessSync() throws Exception { - RedisClusterConnection connection = clusterClient.connectCluster(); + RedisClusterCommands connection = clusterClient.connect().sync(); for (int i = 0; i < 100; i++) { connection.set("a" + i, "myValue1" + i); diff --git a/src/test/java/com/lambdaworks/redis/cluster/commands/CustomClusterCommandTest.java b/src/test/java/com/lambdaworks/redis/cluster/commands/CustomClusterCommandTest.java index aa4ce06e5f..23abe9b280 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/commands/CustomClusterCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/commands/CustomClusterCommandTest.java @@ -32,7 +32,7 @@ public class CustomClusterCommandTest extends AbstractClusterTest { @BeforeClass public static void setupClient() { - redisClusterClient = new RedisClusterClient( + redisClusterClient = RedisClusterClient.create( RedisURI.Builder.redis(TestSettings.host(), TestSettings.port(900)).build()); } diff --git a/src/test/java/com/lambdaworks/redis/cluster/commands/GeoClusterCommandTest.java b/src/test/java/com/lambdaworks/redis/cluster/commands/GeoClusterCommandTest.java index a5db0e2d21..281edb8c21 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/commands/GeoClusterCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/commands/GeoClusterCommandTest.java @@ -25,7 +25,7 @@ public class GeoClusterCommandTest extends GeoCommandTest { @BeforeClass public static void setupClient() { - redisClusterClient = new RedisClusterClient( + redisClusterClient = RedisClusterClient.create( RedisURI.Builder.redis(TestSettings.host(), TestSettings.port(900)).build()); } @@ -43,7 +43,7 @@ public void openConnection() throws Exception { @Override @SuppressWarnings("unchecked") protected RedisCommands connect() { - clusterConnection = redisClusterClient.connectCluster().getStatefulConnection(); + clusterConnection = redisClusterClient.connect(); return ClusterTestUtil.redisCommandsOverCluster(clusterConnection); } diff --git a/src/test/java/com/lambdaworks/redis/cluster/commands/HashClusterCommandTest.java b/src/test/java/com/lambdaworks/redis/cluster/commands/HashClusterCommandTest.java index 0e51560adf..50dce303c7 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/commands/HashClusterCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/commands/HashClusterCommandTest.java @@ -1,10 +1,10 @@ package com.lambdaworks.redis.cluster.commands; -import com.lambdaworks.redis.FastShutdown; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; +import com.lambdaworks.redis.FastShutdown; import com.lambdaworks.redis.RedisURI; import com.lambdaworks.redis.TestSettings; import com.lambdaworks.redis.api.sync.RedisCommands; @@ -23,7 +23,7 @@ public class HashClusterCommandTest extends HashCommandTest { @BeforeClass public static void setupClient() { - redisClusterClient = new RedisClusterClient(RedisURI.Builder.redis(TestSettings.host(), TestSettings.port(900)).build()); + redisClusterClient = RedisClusterClient.create(RedisURI.Builder.redis(TestSettings.host(), TestSettings.port(900)).build()); } @AfterClass @@ -40,7 +40,7 @@ public void openConnection() throws Exception { @Override @SuppressWarnings("unchecked") protected RedisCommands connect() { - clusterConnection = redisClusterClient.connectCluster().getStatefulConnection(); + clusterConnection = redisClusterClient.connect(); return ClusterTestUtil.redisCommandsOverCluster(clusterConnection); } } diff --git a/src/test/java/com/lambdaworks/redis/cluster/commands/ListClusterCommandTest.java b/src/test/java/com/lambdaworks/redis/cluster/commands/ListClusterCommandTest.java index 7fafa83c66..7457bf7da6 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/commands/ListClusterCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/commands/ListClusterCommandTest.java @@ -1,12 +1,12 @@ package com.lambdaworks.redis.cluster.commands; -import com.lambdaworks.redis.FastShutdown; import org.assertj.core.api.Assertions; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; +import com.lambdaworks.redis.FastShutdown; import com.lambdaworks.redis.RedisURI; import com.lambdaworks.redis.TestSettings; import com.lambdaworks.redis.api.sync.RedisCommands; @@ -26,7 +26,7 @@ public class ListClusterCommandTest extends ListCommandTest { @BeforeClass public static void setupClient() { - redisClusterClient = new RedisClusterClient(RedisURI.Builder.redis(TestSettings.host(), TestSettings.port(900)).build()); + redisClusterClient = RedisClusterClient.create(RedisURI.Builder.redis(TestSettings.host(), TestSettings.port(900)).build()); } @AfterClass @@ -43,7 +43,7 @@ public void openConnection() throws Exception { @Override @SuppressWarnings("unchecked") protected RedisCommands connect() { - clusterConnection = redisClusterClient.connectCluster().getStatefulConnection(); + clusterConnection = redisClusterClient.connect(); return ClusterTestUtil.redisCommandsOverCluster(clusterConnection); } diff --git a/src/test/java/com/lambdaworks/redis/cluster/commands/StringClusterCommandTest.java b/src/test/java/com/lambdaworks/redis/cluster/commands/StringClusterCommandTest.java index 9d4691090c..a97e2a5305 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/commands/StringClusterCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/commands/StringClusterCommandTest.java @@ -30,7 +30,7 @@ public class StringClusterCommandTest extends StringCommandTest { @BeforeClass public static void setupClient() { - redisClusterClient = new RedisClusterClient(RedisURI.Builder.redis(TestSettings.host(), TestSettings.port(900)).build()); + redisClusterClient = RedisClusterClient.create(RedisURI.Builder.redis(TestSettings.host(), TestSettings.port(900)).build()); } @AfterClass @@ -47,7 +47,7 @@ public void openConnection() throws Exception { @Override @SuppressWarnings("unchecked") protected RedisCommands connect() { - clusterConnection = redisClusterClient.connectCluster().getStatefulConnection(); + clusterConnection = redisClusterClient.connect(); return ClusterTestUtil.redisCommandsOverCluster(clusterConnection); } diff --git a/src/test/java/com/lambdaworks/redis/cluster/commands/rx/HashClusterRxCommandTest.java b/src/test/java/com/lambdaworks/redis/cluster/commands/rx/HashClusterRxCommandTest.java index b597b9ebaa..0c63ba0d2a 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/commands/rx/HashClusterRxCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/commands/rx/HashClusterRxCommandTest.java @@ -1,14 +1,14 @@ package com.lambdaworks.redis.cluster.commands.rx; -import com.lambdaworks.redis.FastShutdown; -import com.lambdaworks.redis.cluster.ClusterTestUtil; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; +import com.lambdaworks.redis.FastShutdown; import com.lambdaworks.redis.RedisURI; import com.lambdaworks.redis.TestSettings; import com.lambdaworks.redis.api.sync.RedisCommands; +import com.lambdaworks.redis.cluster.ClusterTestUtil; import com.lambdaworks.redis.cluster.RedisClusterClient; import com.lambdaworks.redis.cluster.api.StatefulRedisClusterConnection; import com.lambdaworks.redis.commands.HashCommandTest; @@ -24,7 +24,7 @@ public class HashClusterRxCommandTest extends HashCommandTest { @BeforeClass public static void setupClient() { - redisClusterClient = new RedisClusterClient(RedisURI.Builder.redis(TestSettings.host(), TestSettings.port(900)).build()); + redisClusterClient = RedisClusterClient.create(RedisURI.Builder.redis(TestSettings.host(), TestSettings.port(900)).build()); } @AfterClass @@ -40,7 +40,7 @@ public void openConnection() throws Exception { @Override protected RedisCommands connect() { - clusterConnection = redisClusterClient.connectCluster().getStatefulConnection(); - return RxSyncInvocationHandler.sync(redisClusterClient.connectCluster().getStatefulConnection()); + clusterConnection = redisClusterClient.connect(); + return RxSyncInvocationHandler.sync(redisClusterClient.connect()); } } diff --git a/src/test/java/com/lambdaworks/redis/cluster/commands/rx/ListClusterRxCommandTest.java b/src/test/java/com/lambdaworks/redis/cluster/commands/rx/ListClusterRxCommandTest.java index 24c76669a3..228314d201 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/commands/rx/ListClusterRxCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/commands/rx/ListClusterRxCommandTest.java @@ -1,12 +1,12 @@ package com.lambdaworks.redis.cluster.commands.rx; -import com.lambdaworks.redis.FastShutdown; import org.assertj.core.api.Assertions; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; +import com.lambdaworks.redis.FastShutdown; import com.lambdaworks.redis.RedisURI; import com.lambdaworks.redis.TestSettings; import com.lambdaworks.redis.api.sync.RedisCommands; @@ -27,7 +27,7 @@ public class ListClusterRxCommandTest extends ListCommandTest { @BeforeClass public static void setupClient() { - redisClusterClient = new RedisClusterClient(RedisURI.Builder.redis(TestSettings.host(), TestSettings.port(900)).build()); + redisClusterClient = RedisClusterClient.create(RedisURI.Builder.redis(TestSettings.host(), TestSettings.port(900)).build()); } @AfterClass @@ -43,8 +43,8 @@ public void openConnection() throws Exception { @Override protected RedisCommands connect() { - clusterConnection = redisClusterClient.connectCluster().getStatefulConnection(); - return RxSyncInvocationHandler.sync(redisClusterClient.connectCluster().getStatefulConnection()); + clusterConnection = redisClusterClient.connect(); + return RxSyncInvocationHandler.sync(redisClusterClient.connect()); } // re-implementation because keys have to be on the same slot diff --git a/src/test/java/com/lambdaworks/redis/cluster/commands/rx/StringClusterRxCommandTest.java b/src/test/java/com/lambdaworks/redis/cluster/commands/rx/StringClusterRxCommandTest.java index f9fcff9f30..38bb7b794d 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/commands/rx/StringClusterRxCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/commands/rx/StringClusterRxCommandTest.java @@ -10,8 +10,6 @@ import org.junit.BeforeClass; import org.junit.Test; -import rx.Observable; - import com.lambdaworks.redis.FastShutdown; import com.lambdaworks.redis.RedisURI; import com.lambdaworks.redis.TestSettings; @@ -23,6 +21,8 @@ import com.lambdaworks.redis.commands.StringCommandTest; import com.lambdaworks.redis.commands.rx.RxSyncInvocationHandler; +import rx.Observable; + /** * @author Mark Paluch */ @@ -32,7 +32,7 @@ public class StringClusterRxCommandTest extends StringCommandTest { @BeforeClass public static void setupClient() { - redisClusterClient = new RedisClusterClient(RedisURI.Builder.redis(TestSettings.host(), TestSettings.port(900)).build()); + redisClusterClient = RedisClusterClient.create(RedisURI.Builder.redis(TestSettings.host(), TestSettings.port(900)).build()); } @AfterClass @@ -48,8 +48,8 @@ public void openConnection() throws Exception { @Override protected RedisCommands connect() { - clusterConnection = redisClusterClient.connectCluster().getStatefulConnection(); - return RxSyncInvocationHandler.sync(redisClusterClient.connectCluster().getStatefulConnection()); + clusterConnection = redisClusterClient.connect(); + return RxSyncInvocationHandler.sync(redisClusterClient.connect()); } @Test diff --git a/src/test/java/com/lambdaworks/redis/cluster/models/slots/ClusterSlotsParserTest.java b/src/test/java/com/lambdaworks/redis/cluster/models/slots/ClusterSlotsParserTest.java index 7a27c29b40..2766f5e80f 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/models/slots/ClusterSlotsParserTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/models/slots/ClusterSlotsParserTest.java @@ -8,7 +8,6 @@ import org.junit.Test; -import com.google.common.net.HostAndPort; import com.lambdaworks.redis.cluster.models.partitions.RedisClusterNode; import com.lambdaworks.redis.internal.LettuceLists; @@ -40,7 +39,6 @@ public void testParse() throws Exception { List result = ClusterSlotsParser.parse(list); assertThat(result).hasSize(1); - assertThat(result.get(0).getMaster()).isNotNull(); assertThat(result.get(0).getMasterNode()).isNotNull(); } @@ -52,10 +50,6 @@ public void testParseWithSlave() throws Exception { assertThat(result).hasSize(1); ClusterSlotRange clusterSlotRange = result.get(0); - assertThat(clusterSlotRange.getMaster()).isNotNull(); - assertThat(clusterSlotRange.getMaster().getHostText()).isEqualTo("1"); - assertThat(clusterSlotRange.getMaster().getPort()).isEqualTo(2); - RedisClusterNode masterNode = clusterSlotRange.getMasterNode(); assertThat(masterNode).isNotNull(); assertThat(masterNode.getNodeId()).isEqualTo("nodeId1"); @@ -66,14 +60,8 @@ public void testParseWithSlave() throws Exception { assertThat(masterNode.getSlots()).doesNotContain(99, 201); assertThat(masterNode.getSlots()).hasSize(101); - - assertThat(clusterSlotRange.getSlaves()).hasSize(1); assertThat(clusterSlotRange.getSlaveNodes()).hasSize(1); - HostAndPort slave = clusterSlotRange.getSlaves().get(0); - assertThat(slave.getHostText()).isEqualTo("1"); - assertThat(slave.getPort()).isEqualTo(2); - RedisClusterNode slaveNode = clusterSlotRange.getSlaveNodes().get(0); assertThat(slaveNode.getNodeId()).isEqualTo("nodeId2"); @@ -105,43 +93,6 @@ public void testSameNode() throws Exception { assertThat(masterNode.getSlots()).hasSize(201); } - @Test - public void testHostAndPortConstructor() throws Exception { - - ClusterSlotRange clusterSlotRange = new ClusterSlotRange(100, 200, HostAndPort.fromParts("1", 2), LettuceLists.newList( - HostAndPort.fromParts("1", 2))); - - RedisClusterNode masterNode = clusterSlotRange.getMasterNode(); - assertThat(masterNode).isNotNull(); - assertThat(masterNode.getNodeId()).isNull(); - assertThat(masterNode.getUri().getHost()).isEqualTo("1"); - assertThat(masterNode.getUri().getPort()).isEqualTo(2); - assertThat(masterNode.getFlags()).contains(RedisClusterNode.NodeFlag.MASTER); - - assertThat(clusterSlotRange.getSlaves()).hasSize(1); - assertThat(clusterSlotRange.getSlaveNodes()).hasSize(1); - - HostAndPort slave = clusterSlotRange.getSlaves().get(0); - assertThat(slave.getHostText()).isEqualTo("1"); - assertThat(slave.getPort()).isEqualTo(2); - - RedisClusterNode slaveNode = clusterSlotRange.getSlaveNodes().get(0); - - assertThat(slaveNode.getNodeId()).isNull(); - assertThat(slaveNode.getSlaveOf()).isNull(); - assertThat(slaveNode.getFlags()).contains(RedisClusterNode.NodeFlag.SLAVE); - - } - - @Test - public void testParseWithSlaveAndNodeIds() throws Exception { - List list = Arrays.asList(LettuceLists.newList("0", "1", LettuceLists.newList("1", "2"), LettuceLists.newList("1", 2))); - List result = ClusterSlotsParser.parse(list); - assertThat(result).hasSize(1); - assertThat(result.get(0).getMaster()).isNotNull(); - assertThat(result.get(0).getSlaves()).hasSize(1); - } - @Test(expected = IllegalArgumentException.class) public void testParseInvalidMaster() throws Exception { List list = Arrays.asList(LettuceLists.newList("0", "1", LettuceLists.newList("1"))); @@ -160,8 +111,6 @@ public void testModel() throws Exception { ClusterSlotRange range = new ClusterSlotRange(); range.setFrom(1); range.setTo(2); - range.setSlaves(new ArrayList<>()); - range.setMaster(HostAndPort.fromHost("localhost")); assertThat(range.toString()).contains(ClusterSlotRange.class.getSimpleName()); } diff --git a/src/test/java/com/lambdaworks/redis/commands/BitCommandPoolTest.java b/src/test/java/com/lambdaworks/redis/commands/BitCommandPoolTest.java deleted file mode 100644 index 879ef88349..0000000000 --- a/src/test/java/com/lambdaworks/redis/commands/BitCommandPoolTest.java +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (C) 2012 - Will Glozer. All rights reserved. - -package com.lambdaworks.redis.commands; - -import com.lambdaworks.redis.RedisConnection; -import com.lambdaworks.redis.RedisConnectionPool; -import com.lambdaworks.redis.api.sync.RedisCommands; - -public class BitCommandPoolTest extends BitCommandTest { - RedisConnectionPool> pool; - RedisConnectionPool> bitpool; - - @Override - protected RedisCommands connect() { - pool = client.pool(new BitStringCodec(), 1, 5); - bitpool = client.pool(new BitStringCodec(), 1, 5); - bitstring = bitpool.allocateConnection(); - return pool.allocateConnection(); - } - - @Override - public void closeConnection() throws Exception { - pool.freeConnection(redis); - bitpool.freeConnection(bitstring); - - pool.close(); - bitpool.close(); - } -} diff --git a/src/test/java/com/lambdaworks/redis/commands/BitCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/BitCommandTest.java index 2365c6597d..6369343a6e 100644 --- a/src/test/java/com/lambdaworks/redis/commands/BitCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/BitCommandTest.java @@ -2,9 +2,9 @@ package com.lambdaworks.redis.commands; -import static com.lambdaworks.redis.BitFieldArgs.OverflowType.WRAP; import static com.lambdaworks.redis.BitFieldArgs.signed; import static com.lambdaworks.redis.BitFieldArgs.unsigned; +import static com.lambdaworks.redis.BitFieldArgs.OverflowType.WRAP; import static org.assertj.core.api.Assertions.assertThat; import java.nio.ByteBuffer; @@ -34,7 +34,7 @@ protected void connectBitString() { @Override public void closeConnection() throws Exception { - bitstring.close(); + bitstring.getStatefulConnection().close(); super.closeConnection(); } diff --git a/src/test/java/com/lambdaworks/redis/commands/HLLCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/HLLCommandTest.java index 5213d51cf6..ca64bf3ba5 100644 --- a/src/test/java/com/lambdaworks/redis/commands/HLLCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/HLLCommandTest.java @@ -8,7 +8,6 @@ import org.junit.rules.ExpectedException; import com.lambdaworks.redis.AbstractRedisClientTest; -import com.lambdaworks.redis.RedisHLLConnection; import com.lambdaworks.redis.api.sync.RedisHLLCommands; public class HLLCommandTest extends AbstractRedisClientTest { @@ -19,10 +18,6 @@ private RedisHLLCommands commands() { return redis; } - private RedisHLLConnection connection() { - return redis; - } - @Test public void pfadd() throws Exception { @@ -31,13 +26,6 @@ public void pfadd() throws Exception { assertThat(commands().pfadd(key, value)).isEqualTo(0); } - @Test - public void pfaddDeprecated() throws Exception { - assertThat(connection().pfadd(key, value, value)).isEqualTo(1); - assertThat(connection().pfadd(key, value, value)).isEqualTo(0); - assertThat(connection().pfadd(key, value)).isEqualTo(0); - } - @Test(expected = IllegalArgumentException.class) public void pfaddNoValues() throws Exception { commands().pfadd(key); @@ -74,15 +62,6 @@ public void pfmerge() throws Exception { assertThat(commands().pfcount("key8885")).isEqualTo(3); } - @Test - public void pfmergeDeprecated() throws Exception { - connection().pfadd(key, value); - connection().pfadd("key2", "value2"); - connection().pfadd("key3", "value3"); - - assertThat(connection().pfmerge(key, "key2", "key3")).isEqualTo("OK"); - } - @Test(expected = IllegalArgumentException.class) public void pfmergeNoKeys() throws Exception { commands().pfmerge(key); @@ -96,14 +75,6 @@ public void pfcount() throws Exception { assertThat(commands().pfcount(key, "key2")).isEqualTo(2); } - @Test - public void pfcountDeprecated() throws Exception { - connection().pfadd(key, value); - connection().pfadd("key2", "value2"); - assertThat(connection().pfcount(key)).isEqualTo(1); - assertThat(connection().pfcount(key, "key2")).isEqualTo(2); - } - @Test(expected = IllegalArgumentException.class) public void pfcountNoKeys() throws Exception { commands().pfcount(); diff --git a/src/test/java/com/lambdaworks/redis/commands/HashCommandPoolTest.java b/src/test/java/com/lambdaworks/redis/commands/HashCommandPoolTest.java deleted file mode 100644 index 7c72df3061..0000000000 --- a/src/test/java/com/lambdaworks/redis/commands/HashCommandPoolTest.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.lambdaworks.redis.commands; - -import com.lambdaworks.redis.RedisConnection; -import com.lambdaworks.redis.RedisConnectionPool; -import com.lambdaworks.redis.api.sync.RedisCommands; - -/** - * @author Mark Paluch - */ -public class HashCommandPoolTest extends HashCommandTest { - - RedisConnectionPool> pool; - - @Override - protected RedisCommands connect() { - pool = client.pool(); - return pool.allocateConnection(); - } - - @Override - public void closeConnection() throws Exception { - pool.freeConnection(redis); - pool.close(); - } -} diff --git a/src/test/java/com/lambdaworks/redis/commands/KeyCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/KeyCommandTest.java index 993b5f5e37..5920de93a9 100644 --- a/src/test/java/com/lambdaworks/redis/commands/KeyCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/KeyCommandTest.java @@ -46,9 +46,9 @@ public void dump() throws Exception { @Test public void exists() throws Exception { - assertThat(redis.exists(key)).isFalse(); + assertThat(redis.exists(key)).isEqualTo(0); redis.set(key, value); - assertThat(redis.exists(key)).isTrue(); + assertThat(redis.exists(key)).isEqualTo(1); } @Test diff --git a/src/test/java/com/lambdaworks/redis/commands/RunOnlyOnceServerCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/RunOnlyOnceServerCommandTest.java index d7264296bb..650e182609 100644 --- a/src/test/java/com/lambdaworks/redis/commands/RunOnlyOnceServerCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/RunOnlyOnceServerCommandTest.java @@ -9,18 +9,19 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assume.assumeTrue; -import com.lambdaworks.CanConnect; -import com.lambdaworks.redis.*; +import java.util.Arrays; + import org.junit.FixMethodOrder; -import org.junit.Ignore; import org.junit.Test; import org.junit.runners.MethodSorters; -import com.google.code.tempusfugit.temporal.Condition; import com.google.code.tempusfugit.temporal.WaitFor; -import org.springframework.util.SocketUtils; - -import java.util.Arrays; +import com.lambdaworks.CanConnect; +import com.lambdaworks.redis.AbstractRedisClientTest; +import com.lambdaworks.redis.MigrateArgs; +import com.lambdaworks.redis.RedisURI; +import com.lambdaworks.redis.TestSettings; +import com.lambdaworks.redis.api.async.RedisAsyncCommands; @FixMethodOrder(MethodSorters.NAME_ASCENDING) public class RunOnlyOnceServerCommandTest extends AbstractRedisClientTest { @@ -36,15 +37,15 @@ public void debugSegfault() throws Exception { assumeTrue(CanConnect.to(host(), port(1))); - final RedisAsyncConnection connection = client.connectAsync(RedisURI.Builder.redis(host(), port(1)) - .build()); + final RedisAsyncCommands commands = client.connect(RedisURI.Builder.redis(host(), port(1)) + .build()).async(); try { - connection.debugSegfault(); + commands.debugSegfault(); - WaitFor.waitOrTimeout(() -> !connection.isOpen(), timeout(seconds(5))); - assertThat(connection.isOpen()).isFalse(); + WaitFor.waitOrTimeout(() -> !commands.getStatefulConnection().isOpen(), timeout(seconds(5))); + assertThat(commands.getStatefulConnection().isOpen()).isFalse(); } finally { - connection.close(); + commands.getStatefulConnection().close(); } } @@ -96,18 +97,18 @@ public void shutdown() throws Exception { assumeTrue(CanConnect.to(host(), port(2))); - final RedisAsyncConnection connection = client.connectAsync(RedisURI.Builder.redis(host(), port(2)) - .build()); + final RedisAsyncCommands commands = client.connect(RedisURI.Builder.redis(host(), port(2)) + .build()).async(); try { - connection.shutdown(true); - connection.shutdown(false); - WaitFor.waitOrTimeout(() -> !connection.isOpen(), timeout(seconds(5))); + commands.shutdown(true); + commands.shutdown(false); + WaitFor.waitOrTimeout(() -> !commands.getStatefulConnection().isOpen(), timeout(seconds(5))); - assertThat(connection.isOpen()).isFalse(); + assertThat(commands.getStatefulConnection().isOpen()).isFalse(); } finally { - connection.close(); + commands.getStatefulConnection().close(); } } } diff --git a/src/test/java/com/lambdaworks/redis/commands/ScriptingCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/ScriptingCommandTest.java index 4cb1ffdbd9..ffbd5cc800 100644 --- a/src/test/java/com/lambdaworks/redis/commands/ScriptingCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/ScriptingCommandTest.java @@ -16,8 +16,8 @@ import com.lambdaworks.Wait; import com.lambdaworks.redis.AbstractRedisClientTest; -import com.lambdaworks.redis.RedisAsyncConnection; import com.lambdaworks.redis.RedisException; +import com.lambdaworks.redis.api.StatefulRedisConnection; @FixMethodOrder(MethodSorters.NAME_ASCENDING) public class ScriptingCommandTest extends AbstractRedisClientTest { @@ -112,13 +112,13 @@ public void script() throws Exception { assertThat(redis.scriptExists(digest1, digest2)).isEqualTo(list(false, false)); redis.configSet("lua-time-limit", "10"); - RedisAsyncConnection async = client.connectAsync(); + StatefulRedisConnection connection = client.connect(); try { - async.eval("while true do end", STATUS, new String[0]); + connection.async().eval("while true do end", STATUS, new String[0]); Thread.sleep(100); assertThat(redis.scriptKill()).isEqualTo("OK"); } finally { - async.close(); + connection.close(); } } } diff --git a/src/test/java/com/lambdaworks/redis/commands/ServerCommandPoolTest.java b/src/test/java/com/lambdaworks/redis/commands/ServerCommandPoolTest.java deleted file mode 100644 index 494fd43a5b..0000000000 --- a/src/test/java/com/lambdaworks/redis/commands/ServerCommandPoolTest.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.lambdaworks.redis.commands; - -import com.lambdaworks.redis.api.sync.RedisCommands; -import org.junit.Test; - -import com.lambdaworks.redis.RedisConnection; -import com.lambdaworks.redis.RedisConnectionPool; - -/** - * @author Mark Paluch - */ -public class ServerCommandPoolTest extends ServerCommandTest { - - RedisConnectionPool> pool; - - @Override - protected RedisCommands connect() { - pool = client.pool(); - return pool.allocateConnection(); - } - - @Override - public void closeConnection() throws Exception { - pool.freeConnection(redis); - pool.close(); - } -} diff --git a/src/test/java/com/lambdaworks/redis/commands/ServerCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/ServerCommandTest.java index 641f6b8a24..07a95815d9 100644 --- a/src/test/java/com/lambdaworks/redis/commands/ServerCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/ServerCommandTest.java @@ -3,7 +3,7 @@ package com.lambdaworks.redis.commands; import static org.assertj.core.api.Assertions.assertThat; -import static org.hamcrest.CoreMatchers.*; +import static org.hamcrest.CoreMatchers.containsString; import static org.junit.Assert.assertThat; import java.util.Date; @@ -18,8 +18,8 @@ import com.lambdaworks.redis.AbstractRedisClientTest; import com.lambdaworks.redis.KillArgs; -import com.lambdaworks.redis.RedisConnection; import com.lambdaworks.redis.TestSettings; +import com.lambdaworks.redis.api.sync.RedisCommands; import com.lambdaworks.redis.models.command.CommandDetail; import com.lambdaworks.redis.models.command.CommandDetailParser; import com.lambdaworks.redis.models.role.RedisInstance; @@ -70,7 +70,7 @@ public void clientKill() throws Exception { @Test public void clientKillExtended() throws Exception { - RedisConnection connection2 = client.connect().sync(); + RedisCommands connection2 = client.connect().sync(); connection2.clientSetname("killme"); Pattern p = Pattern.compile("^.*addr=([^ ]+).*name=killme.*$", Pattern.MULTILINE | Pattern.DOTALL); @@ -86,7 +86,7 @@ public void clientKillExtended() throws Exception { assertThat(redis.clientKill(KillArgs.Builder.typeNormal().id(4234))).isEqualTo(0); assertThat(redis.clientKill(KillArgs.Builder.typePubsub().id(4234))).isEqualTo(0); - connection2.close(); + connection2.getStatefulConnection().close(); } @Test diff --git a/src/test/java/com/lambdaworks/redis/commands/TransactionCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/TransactionCommandTest.java index aca7ad5316..f041c5f8f8 100644 --- a/src/test/java/com/lambdaworks/redis/commands/TransactionCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/TransactionCommandTest.java @@ -2,7 +2,7 @@ package com.lambdaworks.redis.commands; -import static org.assertj.core.api.Assertions.*; +import static org.assertj.core.api.Assertions.assertThat; import java.util.List; @@ -13,8 +13,8 @@ import com.lambdaworks.redis.AbstractRedisClientTest; import com.lambdaworks.redis.RedisCommandExecutionException; -import com.lambdaworks.redis.RedisConnection; import com.lambdaworks.redis.RedisException; +import com.lambdaworks.redis.api.sync.RedisCommands; public class TransactionCommandTest extends AbstractRedisClientTest { @Rule @@ -40,9 +40,9 @@ public void exec() throws Exception { public void watch() throws Exception { assertThat(redis.watch(key)).isEqualTo("OK"); - RedisConnection redis2 = client.connect().sync(); + RedisCommands redis2 = client.connect().sync(); redis2.set(key, value + "X"); - redis2.close(); + redis2.getStatefulConnection().close(); redis.multi(); redis.append(key, "foo"); diff --git a/src/test/java/com/lambdaworks/redis/commands/rx/BitRxCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/rx/BitRxCommandTest.java index 89dcfca12a..97c3e35199 100644 --- a/src/test/java/com/lambdaworks/redis/commands/rx/BitRxCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/rx/BitRxCommandTest.java @@ -9,8 +9,8 @@ public class BitRxCommandTest extends BitCommandTest { @Override protected RedisCommands connect() { - bitstring = RxSyncInvocationHandler.sync(client.connectAsync(new BitStringCodec()).getStatefulConnection()); - return RxSyncInvocationHandler.sync(client.connectAsync().getStatefulConnection()); + bitstring = RxSyncInvocationHandler.sync(client.connect(new BitStringCodec())); + return RxSyncInvocationHandler.sync(client.connect()); } } diff --git a/src/test/java/com/lambdaworks/redis/commands/rx/CustomRxCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/rx/CustomRxCommandTest.java index 62db9f778e..45e08589bc 100644 --- a/src/test/java/com/lambdaworks/redis/commands/rx/CustomRxCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/rx/CustomRxCommandTest.java @@ -20,7 +20,7 @@ public class CustomRxCommandTest extends CustomCommandTest { @Override protected RedisCommands connect() { - return RxSyncInvocationHandler.sync(client.connectAsync().getStatefulConnection()); + return RxSyncInvocationHandler.sync(client.connect()); } @Test diff --git a/src/test/java/com/lambdaworks/redis/commands/rx/GeoRxCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/rx/GeoRxCommandTest.java index 605bcae85e..d90ec8abdf 100644 --- a/src/test/java/com/lambdaworks/redis/commands/rx/GeoRxCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/rx/GeoRxCommandTest.java @@ -1,12 +1,12 @@ package com.lambdaworks.redis.commands.rx; -import com.lambdaworks.redis.commands.GeoCommandTest; import com.lambdaworks.redis.api.sync.RedisCommands; +import com.lambdaworks.redis.commands.GeoCommandTest; public class GeoRxCommandTest extends GeoCommandTest { @Override protected RedisCommands connect() { - return RxSyncInvocationHandler.sync(client.connectAsync().getStatefulConnection()); + return RxSyncInvocationHandler.sync(client.connect()); } } diff --git a/src/test/java/com/lambdaworks/redis/commands/rx/HLLRxCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/rx/HLLRxCommandTest.java index 7d122d6f29..5ed77472e4 100644 --- a/src/test/java/com/lambdaworks/redis/commands/rx/HLLRxCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/rx/HLLRxCommandTest.java @@ -7,21 +7,6 @@ public class HLLRxCommandTest extends HLLCommandTest { @Override protected RedisCommands connect() { - return RxSyncInvocationHandler.sync(client.connectAsync().getStatefulConnection()); - } - - @Override - public void pfaddDeprecated() throws Exception { - // Not available on reactive connection - } - - @Override - public void pfmergeDeprecated() throws Exception { - // Not available on reactive connection - } - - @Override - public void pfcountDeprecated() throws Exception { - // Not available on reactive connection + return RxSyncInvocationHandler.sync(client.connect()); } } diff --git a/src/test/java/com/lambdaworks/redis/commands/rx/HashRxCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/rx/HashRxCommandTest.java index cc97c4c67e..4b93ca8a1f 100644 --- a/src/test/java/com/lambdaworks/redis/commands/rx/HashRxCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/rx/HashRxCommandTest.java @@ -7,7 +7,7 @@ public class HashRxCommandTest extends HashCommandTest { @Override protected RedisCommands connect() { - return RxSyncInvocationHandler.sync(client.connectAsync().getStatefulConnection()); + return RxSyncInvocationHandler.sync(client.connect()); } } diff --git a/src/test/java/com/lambdaworks/redis/commands/rx/KeyRxCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/rx/KeyRxCommandTest.java index 668d687a84..679a259b3b 100644 --- a/src/test/java/com/lambdaworks/redis/commands/rx/KeyRxCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/rx/KeyRxCommandTest.java @@ -6,6 +6,6 @@ public class KeyRxCommandTest extends KeyCommandTest { @Override protected RedisCommands connect() { - return RxSyncInvocationHandler.sync(client.connectAsync().getStatefulConnection()); + return RxSyncInvocationHandler.sync(client.connect()); } } diff --git a/src/test/java/com/lambdaworks/redis/commands/rx/ListRxCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/rx/ListRxCommandTest.java index 9b702b7bc7..034ae0f54f 100644 --- a/src/test/java/com/lambdaworks/redis/commands/rx/ListRxCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/rx/ListRxCommandTest.java @@ -6,6 +6,6 @@ public class ListRxCommandTest extends ListCommandTest { @Override protected RedisCommands connect() { - return RxSyncInvocationHandler.sync(client.connectAsync().getStatefulConnection()); + return RxSyncInvocationHandler.sync(client.connect()); } } diff --git a/src/test/java/com/lambdaworks/redis/commands/rx/NumericRxCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/rx/NumericRxCommandTest.java index 5c29c38bc0..04bf948fc8 100644 --- a/src/test/java/com/lambdaworks/redis/commands/rx/NumericRxCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/rx/NumericRxCommandTest.java @@ -6,6 +6,6 @@ public class NumericRxCommandTest extends NumericCommandTest { @Override protected RedisCommands connect() { - return RxSyncInvocationHandler.sync(client.connectAsync().getStatefulConnection()); + return RxSyncInvocationHandler.sync(client.connect()); } } diff --git a/src/test/java/com/lambdaworks/redis/commands/rx/ScriptingRxCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/rx/ScriptingRxCommandTest.java index e38f75ff99..0674bc083e 100644 --- a/src/test/java/com/lambdaworks/redis/commands/rx/ScriptingRxCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/rx/ScriptingRxCommandTest.java @@ -1,6 +1,5 @@ package com.lambdaworks.redis.commands.rx; -import com.lambdaworks.redis.api.rx.RedisReactiveCommands; import com.lambdaworks.redis.api.sync.RedisCommands; import com.lambdaworks.redis.commands.ScriptingCommandTest; @@ -9,6 +8,6 @@ public class ScriptingRxCommandTest extends ScriptingCommandTest { @Override protected RedisCommands connect() { - return RxSyncInvocationHandler.sync(client.connectAsync().getStatefulConnection()); + return RxSyncInvocationHandler.sync(client.connect()); } } diff --git a/src/test/java/com/lambdaworks/redis/commands/rx/ServerRxCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/rx/ServerRxCommandTest.java index f5e011f6da..c1cf9f3bf3 100644 --- a/src/test/java/com/lambdaworks/redis/commands/rx/ServerRxCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/rx/ServerRxCommandTest.java @@ -1,6 +1,6 @@ package com.lambdaworks.redis.commands.rx; -import static org.assertj.core.api.Assertions.*; +import static org.assertj.core.api.Assertions.assertThat; import org.junit.Before; import org.junit.Test; @@ -21,7 +21,7 @@ public void openConnection() throws Exception { @Override protected RedisCommands connect() { - return RxSyncInvocationHandler.sync(client.connectAsync().getStatefulConnection()); + return RxSyncInvocationHandler.sync(client.connect()); } /** @@ -30,30 +30,30 @@ protected RedisCommands connect() { @Test public void shutdown() throws Exception { reactive.shutdown(true); - assertThat(reactive.isOpen()).isTrue(); + assertThat(reactive.getStatefulConnection().isOpen()).isTrue(); } @Test public void debugOom() throws Exception { reactive.debugOom(); - assertThat(reactive.isOpen()).isTrue(); + assertThat(reactive.getStatefulConnection().isOpen()).isTrue(); } @Test public void debugSegfault() throws Exception { reactive.debugSegfault(); - assertThat(reactive.isOpen()).isTrue(); + assertThat(reactive.getStatefulConnection().isOpen()).isTrue(); } @Test public void debugRestart() throws Exception { reactive.debugRestart(1L); - assertThat(reactive.isOpen()).isTrue(); + assertThat(reactive.getStatefulConnection().isOpen()).isTrue(); } @Test public void migrate() throws Exception { reactive.migrate("host", 1234, "key", 1, 10); - assertThat(reactive.isOpen()).isTrue(); + assertThat(reactive.getStatefulConnection().isOpen()).isTrue(); } } diff --git a/src/test/java/com/lambdaworks/redis/commands/rx/SetRxCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/rx/SetRxCommandTest.java index 6d585e2b8c..d69b345aa6 100644 --- a/src/test/java/com/lambdaworks/redis/commands/rx/SetRxCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/rx/SetRxCommandTest.java @@ -7,7 +7,7 @@ public class SetRxCommandTest extends SetCommandTest { @Override protected RedisCommands connect() { - return RxSyncInvocationHandler.sync(client.connectAsync().getStatefulConnection()); + return RxSyncInvocationHandler.sync(client.connect()); } } diff --git a/src/test/java/com/lambdaworks/redis/commands/rx/SortRxCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/rx/SortRxCommandTest.java index 78aee42251..166522560a 100644 --- a/src/test/java/com/lambdaworks/redis/commands/rx/SortRxCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/rx/SortRxCommandTest.java @@ -6,6 +6,6 @@ public class SortRxCommandTest extends SortCommandTest { @Override protected RedisCommands connect() { - return RxSyncInvocationHandler.sync(client.connectAsync().getStatefulConnection()); + return RxSyncInvocationHandler.sync(client.connect()); } } diff --git a/src/test/java/com/lambdaworks/redis/commands/rx/SortedSetRxCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/rx/SortedSetRxCommandTest.java index ff5acd805f..4c10f21f18 100644 --- a/src/test/java/com/lambdaworks/redis/commands/rx/SortedSetRxCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/rx/SortedSetRxCommandTest.java @@ -6,6 +6,6 @@ public class SortedSetRxCommandTest extends SortedSetCommandTest { @Override protected RedisCommands connect() { - return RxSyncInvocationHandler.sync(client.connectAsync().getStatefulConnection()); + return RxSyncInvocationHandler.sync(client.connect()); } } diff --git a/src/test/java/com/lambdaworks/redis/commands/rx/StringRxCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/rx/StringRxCommandTest.java index ce2552f0ee..f18481bd99 100644 --- a/src/test/java/com/lambdaworks/redis/commands/rx/StringRxCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/rx/StringRxCommandTest.java @@ -1,17 +1,19 @@ package com.lambdaworks.redis.commands.rx; +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.Test; + import com.lambdaworks.redis.api.StatefulRedisConnection; import com.lambdaworks.redis.api.sync.RedisCommands; import com.lambdaworks.redis.commands.StringCommandTest; -import org.junit.Test; -import rx.Observable; -import static org.assertj.core.api.Assertions.assertThat; +import rx.Observable; public class StringRxCommandTest extends StringCommandTest { @Override protected RedisCommands connect() { - return RxSyncInvocationHandler.sync(client.connectAsync().getStatefulConnection()); + return RxSyncInvocationHandler.sync(client.connect()); } @Test diff --git a/src/test/java/com/lambdaworks/redis/commands/rx/TransactionRxCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/rx/TransactionRxCommandTest.java index 0649a67602..b269fae367 100644 --- a/src/test/java/com/lambdaworks/redis/commands/rx/TransactionRxCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/rx/TransactionRxCommandTest.java @@ -9,10 +9,6 @@ import org.junit.Before; import org.junit.Test; -import rx.Observable; -import rx.observables.BlockingObservable; -import rx.observers.TestSubscriber; - import com.lambdaworks.redis.ClientOptions; import com.lambdaworks.redis.RedisException; import com.lambdaworks.redis.api.rx.RedisReactiveCommands; @@ -20,13 +16,17 @@ import com.lambdaworks.redis.commands.TransactionCommandTest; import com.lambdaworks.redis.internal.LettuceLists; +import rx.Observable; +import rx.observables.BlockingObservable; +import rx.observers.TestSubscriber; + public class TransactionRxCommandTest extends TransactionCommandTest { private RedisReactiveCommands commands; @Override protected RedisCommands connect() { - return RxSyncInvocationHandler.sync(client.connectAsync().getStatefulConnection()); + return RxSyncInvocationHandler.sync(client.connect()); } @Before diff --git a/src/test/java/com/lambdaworks/redis/issue42/BreakClientBase.java b/src/test/java/com/lambdaworks/redis/issue42/BreakClientBase.java deleted file mode 100644 index 8baa2f0597..0000000000 --- a/src/test/java/com/lambdaworks/redis/issue42/BreakClientBase.java +++ /dev/null @@ -1,99 +0,0 @@ -package com.lambdaworks.redis.issue42; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.fail; - -import java.nio.ByteBuffer; -import java.util.concurrent.TimeUnit; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import com.lambdaworks.redis.RedisCommandTimeoutException; -import com.lambdaworks.redis.api.sync.RedisHashCommands; -import com.lambdaworks.redis.codec.Utf8StringCodec; - -/** - * Base for simulating slow connections/commands running into timeouts. - */ -public abstract class BreakClientBase { - - public static int TIMEOUT = 1; - - public static final String TEST_KEY = "taco"; - public volatile boolean sleep = false; - - protected Logger log = LogManager.getLogger(getClass()); - - public void testSingle(RedisHashCommands client) throws InterruptedException { - populateTest(0, client); - - assertThat(client.hvals(TEST_KEY)).hasSize(16385); - - breakClient(client); - - assertThat(client.hvals(TEST_KEY)).hasSize(16385); - } - - public void testLoop(RedisHashCommands client) throws InterruptedException { - populateTest(100, client); - - assertThat(client.hvals(TEST_KEY)).hasSize(16485); - - breakClient(client); - - assertExtraKeys(100, client); - } - - public void assertExtraKeys(int howmany, RedisHashCommands target) { - for (int x = 0; x < howmany; x++) { - int i = Integer.parseInt(target.hget(TEST_KEY, "GET-" + x)); - assertThat(x).isEqualTo(i); - } - } - - protected void breakClient(RedisHashCommands target) throws InterruptedException { - try { - this.sleep = true; - log.info("This should timeout"); - target.hgetall(TEST_KEY); - fail(); - } catch (RedisCommandTimeoutException expected) { - log.info("got expected timeout"); - } - } - - protected void populateTest(int loopFor, RedisHashCommands target) { - log.info("populating hash"); - target.hset(TEST_KEY, TEST_KEY, TEST_KEY); - - for (int x = 0; x < loopFor; x++) { - target.hset(TEST_KEY, "GET-" + x, Integer.toString(x)); - } - - for (int i = 0; i < 16384; i++) { - target.hset(TEST_KEY, Integer.toString(i), TEST_KEY); - } - assertThat(target.hvals(TEST_KEY)).hasSize(16385 + loopFor); - log.info("done"); - - } - - public Utf8StringCodec slowCodec = new Utf8StringCodec() { - public String decodeValue(ByteBuffer bytes) { - - if (sleep) { - log.info("Sleeping for " + (TIMEOUT + 2) + " seconds in slowCodec"); - sleep = false; - try { - TimeUnit.SECONDS.sleep(TIMEOUT + 2); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - log.info("Done sleeping in slowCodec"); - } - - return super.decodeValue(bytes); - } - }; -} diff --git a/src/test/java/com/lambdaworks/redis/issue42/BreakClientTest.java b/src/test/java/com/lambdaworks/redis/issue42/BreakClientTest.java deleted file mode 100644 index 70c85c7da0..0000000000 --- a/src/test/java/com/lambdaworks/redis/issue42/BreakClientTest.java +++ /dev/null @@ -1,45 +0,0 @@ -package com.lambdaworks.redis.issue42; - -import java.util.concurrent.TimeUnit; - -import com.lambdaworks.category.SlowTests; -import com.lambdaworks.redis.DefaultRedisClient; -import com.lambdaworks.redis.RedisClient; -import com.lambdaworks.redis.api.sync.RedisCommands; -import org.junit.After; -import org.junit.Before; -import org.junit.Ignore; -import org.junit.Test; - -@SlowTests -@Ignore("Run me manually") -public class BreakClientTest extends BreakClientBase { - - protected static RedisClient client = DefaultRedisClient.get(); - - protected RedisCommands redis; - - @Before - public void setUp() throws Exception { - client.setDefaultTimeout(TIMEOUT, TimeUnit.SECONDS); - redis = client.connect(this.slowCodec).sync(); - redis.flushall(); - redis.flushdb(); - } - - @After - public void tearDown() throws Exception { - redis.close(); - } - - @Test - public void testStandAlone() throws Exception { - testSingle(redis); - } - - @Test - public void testLooping() throws Exception { - testLoop(redis); - } - -} diff --git a/src/test/java/com/lambdaworks/redis/issue42/BreakClusterClientTest.java b/src/test/java/com/lambdaworks/redis/issue42/BreakClusterClientTest.java deleted file mode 100644 index d1685cb2a7..0000000000 --- a/src/test/java/com/lambdaworks/redis/issue42/BreakClusterClientTest.java +++ /dev/null @@ -1,76 +0,0 @@ -package com.lambdaworks.redis.issue42; - -import static com.google.code.tempusfugit.temporal.Duration.*; -import static com.google.code.tempusfugit.temporal.Timeout.*; - -import java.util.concurrent.TimeUnit; - -import com.lambdaworks.category.SlowTests; -import com.lambdaworks.redis.FastShutdown; -import org.junit.*; - -import com.google.code.tempusfugit.temporal.Condition; -import com.google.code.tempusfugit.temporal.Duration; -import com.google.code.tempusfugit.temporal.ThreadSleep; -import com.google.code.tempusfugit.temporal.WaitFor; -import com.lambdaworks.redis.RedisURI; -import com.lambdaworks.redis.TestSettings; -import com.lambdaworks.redis.cluster.ClusterRule; -import com.lambdaworks.redis.cluster.RedisClusterClient; -import com.lambdaworks.redis.cluster.api.sync.RedisClusterCommands; - -@SlowTests -@Ignore("Run me manually") -public class BreakClusterClientTest extends BreakClientBase { - public static final String host = TestSettings.hostAddr(); - public static final int port1 = 7379; - public static final int port2 = 7380; - public static final int port3 = 7381; - public static final int port4 = 7382; - - private static RedisClusterClient clusterClient; - private RedisClusterCommands clusterConnection; - - @Rule - public ClusterRule clusterRule = new ClusterRule(clusterClient, port1, port2, port3, port4); - - @BeforeClass - public static void setupClient() { - clusterClient = new RedisClusterClient(RedisURI.Builder.redis(host, port1).withTimeout(TIMEOUT, TimeUnit.SECONDS) - .build()); - } - - @AfterClass - public static void shutdownClient() { - FastShutdown.shutdown(clusterClient); - } - - @Before - public void setUp() throws Exception { - WaitFor.waitOrTimeout(new Condition() { - @Override - public boolean isSatisfied() { - return clusterRule.isStable(); - } - }, timeout(seconds(5)), new ThreadSleep(Duration.millis(500))); - - clusterConnection = clusterClient.connectCluster(this.slowCodec); - - } - - @After - public void tearDown() throws Exception { - clusterConnection.close(); - } - - @Test - public void testStandAlone() throws Exception { - testSingle(clusterConnection); - } - - @Test - public void testLooping() throws Exception { - testLoop(clusterConnection); - } - -} diff --git a/src/test/java/com/lambdaworks/redis/masterslave/MasterSlaveTest.java b/src/test/java/com/lambdaworks/redis/masterslave/MasterSlaveTest.java index 5b072f18fc..f5229e7f16 100644 --- a/src/test/java/com/lambdaworks/redis/masterslave/MasterSlaveTest.java +++ b/src/test/java/com/lambdaworks/redis/masterslave/MasterSlaveTest.java @@ -77,13 +77,13 @@ public void after() throws Exception { if (connectionToNode1 != null) { connectionToNode1.configSet("requirepass", ""); connectionToNode1.configSet("masterauth", "").get(1, TimeUnit.SECONDS); - connectionToNode1.close(); + connectionToNode1.getStatefulConnection().close(); } if (connectionToNode2 != null) { connectionToNode2.configSet("requirepass", ""); connectionToNode2.configSet("masterauth", "").get(1, TimeUnit.SECONDS); - connectionToNode2.close(); + connectionToNode2.getStatefulConnection().close(); } if (connection != null) { diff --git a/src/test/java/com/lambdaworks/redis/protocol/ConnectionFailureTest.java b/src/test/java/com/lambdaworks/redis/protocol/ConnectionFailureTest.java index e611f35fe6..db3266d137 100644 --- a/src/test/java/com/lambdaworks/redis/protocol/ConnectionFailureTest.java +++ b/src/test/java/com/lambdaworks/redis/protocol/ConnectionFailureTest.java @@ -4,13 +4,13 @@ import java.util.concurrent.*; -import com.lambdaworks.redis.*; -import com.lambdaworks.redis.api.StatefulRedisConnection; import org.junit.Test; import org.springframework.test.util.ReflectionTestUtils; import com.lambdaworks.Connections; import com.lambdaworks.Wait; +import com.lambdaworks.redis.*; +import com.lambdaworks.redis.api.StatefulRedisConnection; import com.lambdaworks.redis.api.async.RedisAsyncCommands; import com.lambdaworks.redis.server.RandomResponseServer; @@ -68,7 +68,7 @@ public void pingBeforeConnectFailOnReconnect() throws Exception { redisUri.setUnit(TimeUnit.SECONDS); try { - RedisAsyncCommands connection = client.connectAsync(redisUri); + RedisAsyncCommands connection = client.connect(redisUri).async(); ConnectionWatchdog connectionWatchdog = Connections.getConnectionWatchdog(connection.getStatefulConnection()); assertThat(connectionWatchdog.isListenOnChannelInactive()).isTrue(); @@ -89,7 +89,7 @@ public void pingBeforeConnectFailOnReconnect() throws Exception { assertThat(e).hasRootCauseExactlyInstanceOf(RedisException.class); assertThat(e.getCause()).hasMessageStartingWith("Invalid first byte"); } - connection.close(); + connection.getStatefulConnection().close(); } finally { ts.shutdown(); } @@ -117,7 +117,7 @@ public void pingBeforeConnectFailOnReconnectShouldSendEvents() throws Exception try { final BlockingQueue events = new LinkedBlockingDeque<>(); - RedisAsyncCommands connection = client.connectAsync(redisUri); + RedisAsyncCommands connection = client.connect(redisUri).async(); ConnectionWatchdog connectionWatchdog = Connections.getConnectionWatchdog(connection.getStatefulConnection()); ReconnectionListener reconnectionListener = new ReconnectionListener() { @@ -133,7 +133,7 @@ public void onReconnect(ConnectionEvents.Reconnect reconnect) { connection.quit(); Wait.untilTrue(() -> events.size() > 1).waitOrTimeout(); - connection.close(); + connection.getStatefulConnection().close(); ConnectionEvents.Reconnect event1 = events.take(); assertThat(event1.getAttempt()).isEqualTo(1); @@ -166,7 +166,7 @@ public void cancelCommandsOnReconnectFailure() throws Exception { try { RedisAsyncCommandsImpl connection = (RedisAsyncCommandsImpl) client - .connectAsync(redisUri); + .connect(redisUri).async(); ConnectionWatchdog connectionWatchdog = Connections.getConnectionWatchdog(connection.getStatefulConnection()); assertThat(connectionWatchdog.isListenOnChannelInactive()).isTrue(); @@ -175,7 +175,7 @@ public void cancelCommandsOnReconnectFailure() throws Exception { redisUri.setPort(TestSettings.nonexistentPort()); connection.quit(); - Wait.untilTrue(() -> !connection.isOpen()).waitOrTimeout(); + Wait.untilTrue(() -> !connection.getStatefulConnection().isOpen()).waitOrTimeout(); RedisFuture set1 = connection.set(key, value); RedisFuture set2 = connection.set(key, value); @@ -183,11 +183,11 @@ public void cancelCommandsOnReconnectFailure() throws Exception { assertThat(set1.isDone()).isFalse(); assertThat(set1.isCancelled()).isFalse(); - assertThat(connection.isOpen()).isFalse(); + assertThat(connection.getStatefulConnection().isOpen()).isFalse(); connectionWatchdog.setReconnectSuspended(false); connectionWatchdog.run(null); Thread.sleep(500); - assertThat(connection.isOpen()).isFalse(); + assertThat(connection.getStatefulConnection().isOpen()).isFalse(); try { set1.get(); @@ -208,7 +208,7 @@ public void cancelCommandsOnReconnectFailure() throws Exception { assertThat(e.getCause()).hasMessageStartingWith("Invalid first byte"); } - connection.close(); + connection.getStatefulConnection().close(); } finally { ts.shutdown(); } diff --git a/src/test/java/com/lambdaworks/redis/pubsub/PubSubCommandTest.java b/src/test/java/com/lambdaworks/redis/pubsub/PubSubCommandTest.java index 2dc501bd9c..57b38b8a5f 100644 --- a/src/test/java/com/lambdaworks/redis/pubsub/PubSubCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/pubsub/PubSubCommandTest.java @@ -98,7 +98,7 @@ public void message() throws Exception { public void pipelinedMessage() throws Exception { pubsub.subscribe(channel); assertThat(channels.take()).isEqualTo(channel); - RedisAsyncCommands connection = client.connectAsync(); + RedisAsyncCommands connection = client.connect().async(); connection.setAutoFlushCommands(false); connection.publish(channel, message); diff --git a/src/test/java/com/lambdaworks/redis/reliability/AtLeastOnceTest.java b/src/test/java/com/lambdaworks/redis/reliability/AtLeastOnceTest.java index fe3818e2d3..4c5808da73 100644 --- a/src/test/java/com/lambdaworks/redis/reliability/AtLeastOnceTest.java +++ b/src/test/java/com/lambdaworks/redis/reliability/AtLeastOnceTest.java @@ -3,42 +3,27 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assume.assumeTrue; -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Proxy; -import java.util.Queue; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; -import com.lambdaworks.Connections; -import io.netty.handler.codec.EncoderException; -import io.netty.util.Version; import org.junit.Before; import org.junit.Test; -import org.springframework.test.util.ReflectionTestUtils; +import com.lambdaworks.Connections; import com.lambdaworks.Wait; -import com.lambdaworks.redis.AbstractRedisClientTest; -import com.lambdaworks.redis.ClientOptions; -import com.lambdaworks.redis.RedisAsyncConnection; -import com.lambdaworks.redis.RedisChannelHandler; -import com.lambdaworks.redis.RedisChannelWriter; -import com.lambdaworks.redis.RedisCommandTimeoutException; -import com.lambdaworks.redis.RedisConnection; -import com.lambdaworks.redis.RedisException; -import com.lambdaworks.redis.RedisFuture; +import com.lambdaworks.redis.*; +import com.lambdaworks.redis.api.StatefulRedisConnection; import com.lambdaworks.redis.api.sync.RedisCommands; import com.lambdaworks.redis.codec.Utf8StringCodec; import com.lambdaworks.redis.output.IntegerOutput; import com.lambdaworks.redis.output.StatusOutput; -import com.lambdaworks.redis.protocol.AsyncCommand; -import com.lambdaworks.redis.protocol.Command; -import com.lambdaworks.redis.protocol.CommandArgs; -import com.lambdaworks.redis.protocol.CommandType; -import com.lambdaworks.redis.protocol.ConnectionWatchdog; +import com.lambdaworks.redis.protocol.*; import io.netty.buffer.ByteBuf; import io.netty.channel.Channel; +import io.netty.handler.codec.EncoderException; +import io.netty.util.Version; /** * @author Mark Paluch @@ -58,15 +43,15 @@ public void before() throws Exception { RedisCommands connection = client.connect().sync(); connection.flushall(); connection.flushdb(); - connection.close(); + connection.getStatefulConnection().close(); } @Test public void connectionIsConnectedAfterConnect() throws Exception { - RedisCommands connection = client.connect().sync(); + StatefulRedisConnection connection = client.connect(); - assertThat(getConnectionState(getRedisChannelHandler(connection))); + assertThat(Connections.getConnectionState(connection)); connection.close(); } @@ -81,7 +66,7 @@ public void reconnectIsActiveHandler() throws Exception { assertThat(connectionWatchdog.isListenOnChannelInactive()).isTrue(); assertThat(connectionWatchdog.isReconnectSuspended()).isFalse(); - connection.close(); + connection.getStatefulConnection().close(); } @Test @@ -92,7 +77,7 @@ public void basicOperations() throws Exception { connection.set(key, "1"); assertThat(connection.get("key")).isEqualTo("1"); - connection.close(); + connection.getStatefulConnection().close(); } @Test @@ -102,10 +87,10 @@ public void noBufferedCommandsAfterExecute() throws Exception { connection.set(key, "1"); - assertThat(getQueue(getRedisChannelHandler(connection))).isEmpty(); - assertThat(getCommandBuffer(getRedisChannelHandler(connection))).isEmpty(); + assertThat(Connections.getQueue(connection.getStatefulConnection())).isEmpty(); + assertThat(Connections.getCommandBuffer(connection.getStatefulConnection())).isEmpty(); - connection.close(); + connection.getStatefulConnection().close(); } @Test @@ -123,25 +108,26 @@ public void commandIsExecutedOnce() throws Exception { connection.incr(key); assertThat(connection.get(key)).isEqualTo("4"); - connection.close(); + connection.getStatefulConnection().close(); } @Test public void commandFailsWhenFailOnEncode() throws Exception { - RedisCommands connection = client.connect().sync(); - RedisChannelWriter channelWriter = getRedisChannelHandler(connection).getChannelWriter(); + StatefulRedisConnection connection = client.connect(); + RedisCommands sync = connection.sync(); + RedisChannelWriter channelWriter = Connections.getChannelWriter(connection); RedisCommands verificationConnection = client.connect().sync(); - connection.set(key, "1"); - AsyncCommand working = new AsyncCommand<>(new Command<>(CommandType.INCR, new IntegerOutput( - CODEC), new CommandArgs<>(CODEC).addKey(key))); + sync.set(key, "1"); + AsyncCommand working = new AsyncCommand<>( + new Command<>(CommandType.INCR, new IntegerOutput(CODEC), new CommandArgs<>(CODEC).addKey(key))); channelWriter.write(working); assertThat(working.await(2, TimeUnit.SECONDS)).isTrue(); - assertThat(connection.get(key)).isEqualTo("2"); + assertThat(sync.get(key)).isEqualTo("2"); - AsyncCommand command = new AsyncCommand(new Command<>(CommandType.INCR, - new IntegerOutput(CODEC), new CommandArgs<>(CODEC).addKey(key))) { + AsyncCommand command = new AsyncCommand( + new Command<>(CommandType.INCR, new IntegerOutput(CODEC), new CommandArgs<>(CODEC).addKey(key))) { @Override public void encode(ByteBuf buf) { @@ -157,9 +143,9 @@ public void encode(ByteBuf buf) { assertThat(verificationConnection.get(key)).isEqualTo("2"); - assertThat(getQueue(getRedisChannelHandler(connection))).isNotEmpty(); + assertThat(Connections.getQueue(connection)).isNotEmpty(); - connection.close(); + sync.getStatefulConnection().close(); } @Test @@ -167,16 +153,17 @@ public void commandNotFailedChannelClosesWhileFlush() throws Exception { assumeTrue(Version.identify().get("netty-transport").artifactVersion().startsWith("4.0.2")); - RedisCommands connection = client.connect().sync(); + StatefulRedisConnection connection = client.connect(); RedisCommands verificationConnection = client.connect().sync(); - RedisChannelWriter channelWriter = getRedisChannelHandler(connection).getChannelWriter(); + RedisChannelWriter channelWriter = Connections.getChannelWriter(connection); - connection.set(key, "1"); + RedisCommands sync = connection.sync(); + sync.set(key, "1"); assertThat(verificationConnection.get(key)).isEqualTo("1"); final CountDownLatch block = new CountDownLatch(1); - ConnectionWatchdog connectionWatchdog = Connections.getConnectionWatchdog(connection.getStatefulConnection()); + ConnectionWatchdog connectionWatchdog = Connections.getConnectionWatchdog(connection); AsyncCommand command = getBlockOnEncodeCommand(block); @@ -184,7 +171,7 @@ public void commandNotFailedChannelClosesWhileFlush() throws Exception { connectionWatchdog.setReconnectSuspended(true); - Channel channel = getChannel(getRedisChannelHandler(connection)); + Channel channel = Connections.getChannel(connection); channel.unsafe().disconnect(channel.newPromise()); assertThat(channel.isOpen()).isFalse(); @@ -197,8 +184,8 @@ public void commandNotFailedChannelClosesWhileFlush() throws Exception { assertThat(verificationConnection.get(key)).isEqualTo("1"); - assertThat(getQueue(getRedisChannelHandler(connection))).isEmpty(); - assertThat(getCommandBuffer(getRedisChannelHandler(connection))).isNotEmpty().contains(command); + assertThat(Connections.getQueue(connection)).isEmpty(); + assertThat(Connections.getCommandBuffer(connection)).isNotEmpty().contains(command); connection.close(); } @@ -208,16 +195,17 @@ public void commandRetriedChannelClosesWhileFlush() throws Exception { assumeTrue(Version.identify().get("netty-transport").artifactVersion().startsWith("4.0.2")); - RedisCommands connection = client.connect().sync(); + StatefulRedisConnection connection = client.connect(); + RedisCommands sync = connection.sync(); RedisCommands verificationConnection = client.connect().sync(); - RedisChannelWriter channelWriter = getRedisChannelHandler(connection).getChannelWriter(); + RedisChannelWriter channelWriter = Connections.getChannelWriter(connection); - connection.set(key, "1"); + sync.set(key, "1"); assertThat(verificationConnection.get(key)).isEqualTo("1"); final CountDownLatch block = new CountDownLatch(1); - ConnectionWatchdog connectionWatchdog = Connections.getConnectionWatchdog(connection.getStatefulConnection()); + ConnectionWatchdog connectionWatchdog = Connections.getConnectionWatchdog(sync.getStatefulConnection()); AsyncCommand command = getBlockOnEncodeCommand(block); @@ -225,7 +213,7 @@ public void commandRetriedChannelClosesWhileFlush() throws Exception { connectionWatchdog.setReconnectSuspended(true); - Channel channel = getChannel(getRedisChannelHandler(connection)); + Channel channel = Connections.getChannel(sync.getStatefulConnection()); channel.unsafe().disconnect(channel.newPromise()); assertThat(channel.isOpen()).isFalse(); @@ -243,16 +231,16 @@ public void commandRetriedChannelClosesWhileFlush() throws Exception { assertThat(verificationConnection.get(key)).isEqualTo("2"); - assertThat(getQueue(getRedisChannelHandler(connection))).isEmpty(); - assertThat(getCommandBuffer(getRedisChannelHandler(connection))).isEmpty(); + assertThat(Connections.getQueue(sync.getStatefulConnection())).isEmpty(); + assertThat(Connections.getCommandBuffer(sync.getStatefulConnection())).isEmpty(); - connection.close(); - verificationConnection.close(); + sync.getStatefulConnection().close(); + verificationConnection.getStatefulConnection().close(); } protected AsyncCommand getBlockOnEncodeCommand(final CountDownLatch block) { - return new AsyncCommand(new Command<>(CommandType.INCR, new IntegerOutput(CODEC), - new CommandArgs<>(CODEC).addKey(key))) { + return new AsyncCommand( + new Command<>(CommandType.INCR, new IntegerOutput(CODEC), new CommandArgs<>(CODEC).addKey(key))) { @Override public void encode(ByteBuf buf) { @@ -268,14 +256,15 @@ public void encode(ByteBuf buf) { @Test public void commandFailsDuringDecode() throws Exception { - RedisCommands connection = client.connect().sync(); - RedisChannelWriter channelWriter = getRedisChannelHandler(connection).getChannelWriter(); + StatefulRedisConnection connection = client.connect(); + RedisCommands sync = connection.sync(); + RedisChannelWriter channelWriter = Connections.getChannelWriter(connection); RedisCommands verificationConnection = client.connect().sync(); - connection.set(key, "1"); + sync.set(key, "1"); - AsyncCommand command = new AsyncCommand(new Command<>(CommandType.INCR, new StatusOutput<>( - CODEC), new CommandArgs<>(CODEC).addKey(key))); + AsyncCommand command = new AsyncCommand( + new Command<>(CommandType.INCR, new StatusOutput<>(CODEC), new CommandArgs<>(CODEC).addKey(key))); channelWriter.write(command); @@ -285,87 +274,86 @@ public void commandFailsDuringDecode() throws Exception { assertThat(getException(command)).isInstanceOf(IllegalStateException.class); assertThat(verificationConnection.get(key)).isEqualTo("2"); - assertThat(connection.get(key)).isEqualTo("2"); + assertThat(sync.get(key)).isEqualTo("2"); - connection.close(); - verificationConnection.close(); + sync.getStatefulConnection().close(); + verificationConnection.getStatefulConnection().close(); } @Test public void commandCancelledOverSyncAPIAfterConnectionIsDisconnected() throws Exception { - RedisCommands connection = client.connect().sync(); + StatefulRedisConnection connection = client.connect(); + RedisCommands sync = connection.sync(); RedisCommands verificationConnection = client.connect().sync(); - connection.set(key, "1"); + sync.set(key, "1"); - ConnectionWatchdog connectionWatchdog = Connections.getConnectionWatchdog(connection.getStatefulConnection()); + ConnectionWatchdog connectionWatchdog = Connections.getConnectionWatchdog(sync.getStatefulConnection()); connectionWatchdog.setListenOnChannelInactive(false); - connection.quit(); - Wait.untilTrue(() -> !connection.isOpen()).waitOrTimeout(); + sync.quit(); + Wait.untilTrue(() -> !sync.getStatefulConnection().isOpen()).waitOrTimeout(); try { - connection.incr(key); + sync.incr(key); } catch (RedisException e) { assertThat(e).isExactlyInstanceOf(RedisCommandTimeoutException.class); } assertThat(verificationConnection.get("key")).isEqualTo("1"); - assertThat(getQueue(getRedisChannelHandler(connection))).isEmpty(); - assertThat(getCommandBuffer(getRedisChannelHandler(connection)).size()).isGreaterThan(0); + assertThat(Connections.getQueue(connection)).isEmpty(); + assertThat(Connections.getCommandBuffer(connection).size()).isGreaterThan(0); connectionWatchdog.setListenOnChannelInactive(true); connectionWatchdog.scheduleReconnect(); - while (!getCommandBuffer(getRedisChannelHandler(connection)).isEmpty() - || !getQueue(getRedisChannelHandler(connection)).isEmpty()) { + while (!Connections.getCommandBuffer(connection).isEmpty() || !Connections.getQueue(connection).isEmpty()) { Thread.sleep(10); } - assertThat(connection.get(key)).isEqualTo("1"); + assertThat(sync.get(key)).isEqualTo("1"); - connection.close(); - verificationConnection.close(); + sync.getStatefulConnection().close(); + verificationConnection.getStatefulConnection().close(); } @Test public void retryAfterConnectionIsDisconnected() throws Exception { - RedisAsyncConnection connection = client.connectAsync(); - RedisChannelHandler redisChannelHandler = (RedisChannelHandler) connection.getStatefulConnection(); + StatefulRedisConnection connection = client.connect(); RedisCommands verificationConnection = client.connect().sync(); - connection.set(key, "1").get(); + connection.sync().set(key, "1"); - ConnectionWatchdog connectionWatchdog = Connections.getConnectionWatchdog(connection.getStatefulConnection()); + ConnectionWatchdog connectionWatchdog = Connections.getConnectionWatchdog(connection); connectionWatchdog.setListenOnChannelInactive(false); - connection.quit(); + connection.async().quit(); while (connection.isOpen()) { Thread.sleep(100); } - assertThat(connection.incr(key).await(1, TimeUnit.SECONDS)).isFalse(); + assertThat(connection.async().incr(key).await(1, TimeUnit.SECONDS)).isFalse(); assertThat(verificationConnection.get("key")).isEqualTo("1"); - assertThat(getQueue(redisChannelHandler)).isEmpty(); - assertThat(getCommandBuffer(redisChannelHandler).size()).isGreaterThan(0); + assertThat(Connections.getQueue(connection)).isEmpty(); + assertThat(Connections.getCommandBuffer(connection).size()).isGreaterThan(0); connectionWatchdog.setListenOnChannelInactive(true); connectionWatchdog.scheduleReconnect(); - while (!getCommandBuffer(redisChannelHandler).isEmpty() || !getQueue(redisChannelHandler).isEmpty()) { + while (!Connections.getCommandBuffer(connection).isEmpty() || !Connections.getQueue(connection).isEmpty()) { Thread.sleep(10); } - assertThat(connection.get(key).get()).isEqualTo("2"); + assertThat(connection.sync().get(key)).isEqualTo("2"); assertThat(verificationConnection.get(key)).isEqualTo("2"); connection.close(); - verificationConnection.close(); + verificationConnection.getStatefulConnection().close(); } private Throwable getException(RedisFuture command) { @@ -379,30 +367,4 @@ private Throwable getException(RedisFuture command) { return null; } - private RedisChannelHandler getRedisChannelHandler(RedisConnection sync) { - - InvocationHandler invocationHandler = Proxy.getInvocationHandler(sync); - return (RedisChannelHandler) ReflectionTestUtils.getField(invocationHandler, "connection"); - } - - private T getHandler(Class handlerType, RedisChannelHandler channelHandler) { - Channel channel = getChannel(channelHandler); - return (T) channel.pipeline().get((Class) handlerType); - } - - private Channel getChannel(RedisChannelHandler channelHandler) { - return (Channel) ReflectionTestUtils.getField(channelHandler.getChannelWriter(), "channel"); - } - - private Queue getQueue(RedisChannelHandler channelHandler) { - return (Queue) ReflectionTestUtils.getField(channelHandler.getChannelWriter(), "queue"); - } - - private Queue getCommandBuffer(RedisChannelHandler channelHandler) { - return (Queue) ReflectionTestUtils.getField(channelHandler.getChannelWriter(), "commandBuffer"); - } - - private String getConnectionState(RedisChannelHandler channelHandler) { - return ReflectionTestUtils.getField(channelHandler.getChannelWriter(), "lifecycleState").toString(); - } } diff --git a/src/test/java/com/lambdaworks/redis/reliability/AtMostOnceTest.java b/src/test/java/com/lambdaworks/redis/reliability/AtMostOnceTest.java index b3e738f930..9efe88b3df 100644 --- a/src/test/java/com/lambdaworks/redis/reliability/AtMostOnceTest.java +++ b/src/test/java/com/lambdaworks/redis/reliability/AtMostOnceTest.java @@ -1,42 +1,31 @@ package com.lambdaworks.redis.reliability; +import static com.lambdaworks.Connections.getCommandBuffer; +import static com.lambdaworks.Connections.getQueue; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assume.assumeTrue; -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Proxy; -import java.util.Queue; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicLong; -import io.netty.handler.codec.EncoderException; -import io.netty.util.Version; import org.junit.Before; import org.junit.Test; -import org.springframework.test.util.ReflectionTestUtils; +import com.lambdaworks.Connections; import com.lambdaworks.Wait; -import com.lambdaworks.redis.AbstractRedisClientTest; -import com.lambdaworks.redis.ClientOptions; -import com.lambdaworks.redis.RedisChannelHandler; -import com.lambdaworks.redis.RedisChannelWriter; -import com.lambdaworks.redis.RedisConnection; -import com.lambdaworks.redis.RedisException; -import com.lambdaworks.redis.RedisFuture; +import com.lambdaworks.redis.*; +import com.lambdaworks.redis.api.StatefulRedisConnection; import com.lambdaworks.redis.api.sync.RedisCommands; import com.lambdaworks.redis.codec.Utf8StringCodec; import com.lambdaworks.redis.output.IntegerOutput; import com.lambdaworks.redis.output.StatusOutput; -import com.lambdaworks.redis.protocol.AsyncCommand; -import com.lambdaworks.redis.protocol.Command; -import com.lambdaworks.redis.protocol.CommandArgs; -import com.lambdaworks.redis.protocol.CommandType; -import com.lambdaworks.redis.protocol.ConnectionWatchdog; +import com.lambdaworks.redis.protocol.*; import io.netty.buffer.ByteBuf; import io.netty.channel.Channel; +import io.netty.handler.codec.EncoderException; +import io.netty.util.Version; /** * @author Mark Paluch @@ -57,15 +46,15 @@ public void before() throws Exception { RedisCommands connection = client.connect().sync(); connection.flushall(); connection.flushdb(); - connection.close(); + connection.getStatefulConnection().close(); } @Test public void connectionIsConnectedAfterConnect() throws Exception { - RedisCommands connection = client.connect().sync(); + StatefulRedisConnection connection = client.connect(); - assertThat(getConnectionState(getRedisChannelHandler(connection))); + assertThat(Connections.getConnectionState(connection)); connection.close(); } @@ -75,10 +64,10 @@ public void noReconnectHandler() throws Exception { RedisCommands connection = client.connect().sync(); - assertThat(getHandler(RedisChannelWriter.class, getRedisChannelHandler(connection))).isNotNull(); - assertThat(getHandler(ConnectionWatchdog.class, getRedisChannelHandler(connection))).isNull(); + ConnectionWatchdog connectionWatchdog = Connections.getConnectionWatchdog(connection.getStatefulConnection()); + assertThat(connectionWatchdog).isNull(); - connection.close(); + connection.getStatefulConnection().close(); } @Test @@ -89,18 +78,19 @@ public void basicOperations() throws Exception { connection.set(key, "1"); assertThat(connection.get("key")).isEqualTo("1"); - connection.close(); + connection.getStatefulConnection().close(); } @Test public void noBufferedCommandsAfterExecute() throws Exception { - RedisCommands connection = client.connect().sync(); + StatefulRedisConnection connection = client.connect(); + RedisCommands sync = connection.sync(); - connection.set(key, "1"); + sync.set(key, "1"); - assertThat(getQueue(getRedisChannelHandler(connection))).isEmpty(); - assertThat(getCommandBuffer(getRedisChannelHandler(connection))).isEmpty(); + assertThat(getQueue(connection)).isEmpty(); + assertThat(getCommandBuffer(connection)).isEmpty(); connection.close(); } @@ -108,17 +98,18 @@ public void noBufferedCommandsAfterExecute() throws Exception { @Test public void commandIsExecutedOnce() throws Exception { - RedisCommands connection = client.connect().sync(); + StatefulRedisConnection connection = client.connect(); + RedisCommands sync = connection.sync(); - connection.set(key, "1"); - connection.incr(key); - assertThat(connection.get(key)).isEqualTo("2"); + sync.set(key, "1"); + sync.incr(key); + assertThat(sync.get(key)).isEqualTo("2"); - connection.incr(key); - assertThat(connection.get(key)).isEqualTo("3"); + sync.incr(key); + assertThat(sync.get(key)).isEqualTo("3"); - connection.incr(key); - assertThat(connection.get(key)).isEqualTo("4"); + sync.incr(key); + assertThat(sync.get(key)).isEqualTo("4"); connection.close(); } @@ -126,15 +117,16 @@ public void commandIsExecutedOnce() throws Exception { @Test public void commandNotExecutedFailsOnEncode() throws Exception { - RedisCommands connection = client.connect().sync(); - RedisChannelWriter channelWriter = getRedisChannelHandler(connection).getChannelWriter(); + StatefulRedisConnection connection = client.connect(); + RedisCommands sync = connection.sync(); + RedisChannelWriter channelWriter = Connections.getChannelWriter(connection); - connection.set(key, "1"); + sync.set(key, "1"); AsyncCommand working = new AsyncCommand<>(new Command(CommandType.INCR, new IntegerOutput(CODEC), new CommandArgs(CODEC).addKey(key))); channelWriter.write(working); assertThat(working.await(2, TimeUnit.SECONDS)).isTrue(); - assertThat(connection.get(key)).isEqualTo("2"); + assertThat(sync.get(key)).isEqualTo("2"); AsyncCommand command = new AsyncCommand( new Command(CommandType.INCR, new IntegerOutput(CODEC), @@ -151,13 +143,13 @@ public void encode(ByteBuf buf) { assertThat(command.await(2, TimeUnit.SECONDS)).isTrue(); assertThat(command.isCancelled()).isFalse(); assertThat(getException(command)).isInstanceOf(EncoderException.class); - assertThat(getQueue(getRedisChannelHandler(connection))).isNotEmpty(); - getQueue(getRedisChannelHandler(connection)).clear(); + assertThat(getQueue(connection)).isNotEmpty(); + getQueue(connection).clear(); - assertThat(connection.get(key)).isEqualTo("2"); + assertThat(sync.get(key)).isEqualTo("2"); - assertThat(getQueue(getRedisChannelHandler(connection))).isEmpty(); - assertThat(getCommandBuffer(getRedisChannelHandler(connection))).isEmpty(); + assertThat(getQueue(connection)).isEmpty(); + assertThat(getCommandBuffer(connection)).isEmpty(); connection.close(); } @@ -167,11 +159,12 @@ public void commandNotExecutedChannelClosesWhileFlush() throws Exception { assumeTrue(Version.identify().get("netty-transport").artifactVersion().startsWith("4.0.2")); - RedisCommands connection = client.connect().sync(); + StatefulRedisConnection connection = client.connect(); + RedisCommands sync = connection.sync(); RedisCommands verificationConnection = client.connect().sync(); - RedisChannelWriter channelWriter = getRedisChannelHandler(connection).getChannelWriter(); + RedisChannelWriter channelWriter = Connections.getChannelWriter(connection); - connection.set(key, "1"); + sync.set(key, "1"); assertThat(verificationConnection.get(key)).isEqualTo("1"); final CountDownLatch block = new CountDownLatch(1); @@ -191,7 +184,7 @@ public void encode(ByteBuf buf) { channelWriter.write(command); - Channel channel = getChannel(getRedisChannelHandler(connection)); + Channel channel = Connections.getChannel(connection); channel.unsafe().disconnect(channel.newPromise()); assertThat(channel.isOpen()).isFalse(); @@ -204,8 +197,8 @@ public void encode(ByteBuf buf) { assertThat(verificationConnection.get(key)).isEqualTo("1"); - assertThat(getQueue(getRedisChannelHandler(connection))).isEmpty(); - assertThat(getCommandBuffer(getRedisChannelHandler(connection))).isEmpty(); + assertThat(getQueue(connection)).isEmpty(); + assertThat(getCommandBuffer(connection)).isEmpty(); connection.close(); } @@ -213,11 +206,12 @@ public void encode(ByteBuf buf) { @Test public void commandFailsDuringDecode() throws Exception { - RedisCommands connection = client.connect().sync(); - RedisChannelWriter channelWriter = getRedisChannelHandler(connection).getChannelWriter(); + StatefulRedisConnection connection = client.connect(); + RedisCommands sync = connection.sync(); + RedisChannelWriter channelWriter = Connections.getChannelWriter(connection); RedisCommands verificationConnection = client.connect().sync(); - connection.set(key, "1"); + sync.set(key, "1"); AsyncCommand command = new AsyncCommand<>(new Command<>(CommandType.INCR, new StatusOutput<>( CODEC), new CommandArgs<>(CODEC).addKey(key))); @@ -229,7 +223,7 @@ public void commandFailsDuringDecode() throws Exception { assertThat(getException(command)).isInstanceOf(IllegalStateException.class); assertThat(verificationConnection.get(key)).isEqualTo("2"); - assertThat(connection.get(key)).isEqualTo("2"); + assertThat(sync.get(key)).isEqualTo("2"); connection.close(); } @@ -237,27 +231,27 @@ public void commandFailsDuringDecode() throws Exception { @Test public void noCommandsExecutedAfterConnectionIsDisconnected() throws Exception { - RedisCommands connection = client.connect().sync(); - connection.quit(); + StatefulRedisConnection connection = client.connect(); + connection.sync().quit(); Wait.untilTrue(() -> !connection.isOpen()).waitOrTimeout(); try { - connection.incr(key); + connection.sync().incr(key); } catch (RedisException e) { assertThat(e).isInstanceOf(RedisException.class); } connection.close(); - RedisCommands connection2 = client.connect().sync(); - connection2.quit(); + StatefulRedisConnection connection2 = client.connect(); + connection2.async().quit(); try { Wait.untilTrue(() -> !connection.isOpen()).waitOrTimeout(); - connection2.incr(key); + connection2.sync().incr(key); } catch (Exception e) { assertThat(e).isExactlyInstanceOf(RedisException.class).hasMessageContaining("not connected"); } @@ -275,31 +269,4 @@ private Throwable getException(RedisFuture command) { } return null; } - - private RedisChannelHandler getRedisChannelHandler(RedisConnection sync) { - - InvocationHandler invocationHandler = Proxy.getInvocationHandler(sync); - return (RedisChannelHandler) ReflectionTestUtils.getField(invocationHandler, "connection"); - } - - private T getHandler(Class handlerType, RedisChannelHandler channelHandler) { - Channel channel = getChannel(channelHandler); - return (T) channel.pipeline().get((Class) handlerType); - } - - private Channel getChannel(RedisChannelHandler channelHandler) { - return (Channel) ReflectionTestUtils.getField(channelHandler.getChannelWriter(), "channel"); - } - - private Queue getQueue(RedisChannelHandler channelHandler) { - return (Queue) ReflectionTestUtils.getField(channelHandler.getChannelWriter(), "queue"); - } - - private Queue getCommandBuffer(RedisChannelHandler channelHandler) { - return (Queue) ReflectionTestUtils.getField(channelHandler.getChannelWriter(), "commandBuffer"); - } - - private String getConnectionState(RedisChannelHandler channelHandler) { - return ReflectionTestUtils.getField(channelHandler.getChannelWriter(), "lifecycleState").toString(); - } } diff --git a/src/test/java/com/lambdaworks/redis/resource/DefaultClientResourcesTest.java b/src/test/java/com/lambdaworks/redis/resource/DefaultClientResourcesTest.java index f52cda10e7..3a3035226c 100644 --- a/src/test/java/com/lambdaworks/redis/resource/DefaultClientResourcesTest.java +++ b/src/test/java/com/lambdaworks/redis/resource/DefaultClientResourcesTest.java @@ -57,7 +57,7 @@ public void testDefaults() throws Exception { @Test public void testBuilder() throws Exception { - DefaultClientResources sut = new DefaultClientResources.Builder().ioThreadPoolSize(4).computationThreadPoolSize(4) + DefaultClientResources sut = DefaultClientResources.builder().ioThreadPoolSize(4).computationThreadPoolSize(4) .commandLatencyCollectorOptions(DefaultCommandLatencyCollectorOptions.disabled()).build(); EventExecutorGroup eventExecutors = sut.eventExecutorGroup(); @@ -77,7 +77,7 @@ public void testDnsResolver() throws Exception { DirContextDnsResolver dirContextDnsResolver = new DirContextDnsResolver("8.8.8.8"); - DefaultClientResources sut = new DefaultClientResources.Builder().dnsResolver(dirContextDnsResolver).build(); + DefaultClientResources sut = DefaultClientResources.builder().dnsResolver(dirContextDnsResolver).build(); assertThat(sut.dnsResolver()).isEqualTo(dirContextDnsResolver); } @@ -90,7 +90,7 @@ public void testProvidedResources() throws Exception { EventBus eventBusMock = mock(EventBus.class); CommandLatencyCollector latencyCollectorMock = mock(CommandLatencyCollector.class); - DefaultClientResources sut = new DefaultClientResources.Builder().eventExecutorGroup(executorMock) + DefaultClientResources sut = DefaultClientResources.builder().eventExecutorGroup(executorMock) .eventLoopGroupProvider(groupProviderMock).eventBus(eventBusMock).commandLatencyCollector(latencyCollectorMock) .build(); @@ -109,8 +109,7 @@ public void testProvidedResources() throws Exception { @Test public void testSmallPoolSize() throws Exception { - DefaultClientResources sut = new DefaultClientResources.Builder().ioThreadPoolSize(1).computationThreadPoolSize(1) - .build(); + DefaultClientResources sut = DefaultClientResources.builder().ioThreadPoolSize(1).computationThreadPoolSize(1).build(); EventExecutorGroup eventExecutors = sut.eventExecutorGroup(); NioEventLoopGroup eventLoopGroup = sut.eventLoopGroupProvider().allocate(NioEventLoopGroup.class); diff --git a/src/test/java/com/lambdaworks/redis/sentinel/SentinelCommandTest.java b/src/test/java/com/lambdaworks/redis/sentinel/SentinelCommandTest.java index f60fa730e4..853f46f378 100644 --- a/src/test/java/com/lambdaworks/redis/sentinel/SentinelCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/sentinel/SentinelCommandTest.java @@ -17,7 +17,8 @@ import com.lambdaworks.Wait; import com.lambdaworks.redis.*; import com.lambdaworks.redis.api.async.RedisAsyncCommands; -import com.lambdaworks.redis.sentinel.api.async.RedisSentinelAsyncCommands; +import com.lambdaworks.redis.api.sync.RedisCommands; +import com.lambdaworks.redis.sentinel.api.sync.RedisSentinelCommands; public class SentinelCommandTest extends AbstractSentinelTest { @@ -26,7 +27,7 @@ public class SentinelCommandTest extends AbstractSentinelTest { @BeforeClass public static void setupClient() { - sentinelClient = new RedisClient(RedisURI.Builder.sentinel(TestSettings.host(), MASTER_ID).build()); + sentinelClient = RedisClient.create(RedisURI.Builder.sentinel(TestSettings.host(), MASTER_ID).build()); } @Before @@ -75,29 +76,29 @@ public void masters() throws Exception { @Test public void sentinelConnectWith() throws Exception { - RedisClient client = new RedisClient( + RedisClient client = RedisClient.create( RedisURI.Builder.sentinel(TestSettings.host(), 1234, MASTER_ID).withSentinel(TestSettings.host()).build()); - RedisSentinelAsyncCommands sentinelConnection = client.connectSentinelAsync(); - assertThat(sentinelConnection.ping().get()).isEqualTo("PONG"); + RedisSentinelCommands sentinelConnection = client.connectSentinel().sync(); + assertThat(sentinelConnection.ping()).isEqualTo("PONG"); sentinelConnection.close(); - RedisConnection connection2 = client.connect().sync(); + RedisCommands connection2 = client.connect().sync(); assertThat(connection2.ping()).isEqualTo("PONG"); connection2.quit(); - Wait.untilTrue(connection2::isOpen).waitOrTimeout(); + Wait.untilTrue(() -> connection2.getStatefulConnection().isOpen()).waitOrTimeout(); assertThat(connection2.ping()).isEqualTo("PONG"); - connection2.close(); + connection2.getStatefulConnection().close(); FastShutdown.shutdown(client); } @Test public void sentinelConnectWrongMaster() throws Exception { - RedisClient client = new RedisClient( + RedisClient client = RedisClient.create( RedisURI.Builder.sentinel(TestSettings.host(), 1234, "nonexistent").withSentinel(TestSettings.host()).build()); try { client.connect(); @@ -111,12 +112,12 @@ public void sentinelConnectWrongMaster() throws Exception { @Test public void sentinelConnect() throws Exception { - RedisClient client = new RedisClient(RedisURI.Builder.redis(TestSettings.host(), TestSettings.port()).build()); + RedisClient client = RedisClient.create(RedisURI.Builder.redis(TestSettings.host(), TestSettings.port()).build()); - RedisSentinelAsyncCommands connection = client.connectSentinelAsync(); - assertThat(connection.ping().get()).isEqualTo("PONG"); + RedisSentinelCommands connection = client.connectSentinel().sync(); + assertThat(connection.ping()).isEqualTo("PONG"); - connection.close(); + connection.getStatefulConnection().close(); FastShutdown.shutdown(client); } @@ -143,7 +144,7 @@ public void role() throws Exception { assertThat(objects.get(0)).isEqualTo("sentinel"); assertThat(objects.get(1).toString()).isEqualTo("[" + MASTER_ID + "]"); } finally { - connection.close(); + connection.getStatefulConnection().close(); } } @@ -200,17 +201,17 @@ public void set() throws Exception { @Test public void connectToRedisUsingSentinel() throws Exception { - RedisConnection connect = sentinelClient.connect().sync(); + RedisCommands connect = sentinelClient.connect().sync(); connect.ping(); - connect.close(); + connect.getStatefulConnection().close(); } @Test public void connectToRedisUsingSentinelWithReconnect() throws Exception { - RedisConnection connect = sentinelClient.connect().sync(); + RedisCommands connect = sentinelClient.connect().sync(); connect.ping(); connect.quit(); connect.ping(); - connect.close(); + connect.getStatefulConnection().close(); } } diff --git a/src/test/java/com/lambdaworks/redis/sentinel/SentinelConnectionTest.java b/src/test/java/com/lambdaworks/redis/sentinel/SentinelConnectionTest.java index 7b76e46d59..2fabac5a1d 100644 --- a/src/test/java/com/lambdaworks/redis/sentinel/SentinelConnectionTest.java +++ b/src/test/java/com/lambdaworks/redis/sentinel/SentinelConnectionTest.java @@ -28,7 +28,7 @@ public class SentinelConnectionTest extends AbstractSentinelTest { @BeforeClass public static void setupClient() { - sentinelClient = new RedisClient(RedisURI.Builder.sentinel(TestSettings.host(), MASTER_ID).build()); + sentinelClient = RedisClient.create(RedisURI.Builder.sentinel(TestSettings.host(), MASTER_ID).build()); } @Before @@ -121,26 +121,10 @@ public void connectToOneNode() throws Exception { assertThat(connection.ping()).isEqualTo("PONG"); connection.close(); } - - @Test - public void deprecatedConnectToOneNode() throws Exception { - RedisSentinelAsyncCommands connection = sentinelClient - .connectSentinelAsync(RedisURI.Builder.sentinel(TestSettings.host(), MASTER_ID).build()); - assertThat(connection.ping().get()).isEqualTo("PONG"); - connection.close(); - } - @Test public void connectWithByteCodec() throws Exception { RedisSentinelCommands connection = sentinelClient.connectSentinel(new ByteArrayCodec()).sync(); assertThat(connection.master(MASTER_ID.getBytes())).isNotNull(); connection.close(); } - - @Test - public void deprecatedConnectWithByteCodec() throws Exception { - RedisSentinelAsyncCommands connection = sentinelClient.connectSentinelAsync(new ByteArrayCodec()); - assertThat(connection.master(MASTER_ID.getBytes())).isNotNull(); - connection.close(); - } } diff --git a/src/test/java/com/lambdaworks/redis/sentinel/SentinelFailoverTest.java b/src/test/java/com/lambdaworks/redis/sentinel/SentinelFailoverTest.java deleted file mode 100644 index b5f1f10c27..0000000000 --- a/src/test/java/com/lambdaworks/redis/sentinel/SentinelFailoverTest.java +++ /dev/null @@ -1,85 +0,0 @@ -package com.lambdaworks.redis.sentinel; - -import static com.google.code.tempusfugit.temporal.Duration.seconds; -import static com.lambdaworks.Delay.delay; -import static com.lambdaworks.redis.TestSettings.port; -import static org.assertj.core.api.Assertions.assertThat; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import com.lambdaworks.redis.FastShutdown; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Ignore; -import org.junit.Rule; -import org.junit.Test; - -import com.lambdaworks.redis.RedisClient; -import com.lambdaworks.redis.RedisURI; -import com.lambdaworks.redis.TestSettings; -import com.lambdaworks.redis.api.sync.RedisCommands; - -@Ignore("For manual runs only. Fails too often due to slow sentinel sync") -public class SentinelFailoverTest extends AbstractSentinelTest { - - @Rule - public SentinelRule sentinelRule = new SentinelRule(sentinelClient, false, 26379, 26380); - - @BeforeClass - public static void setupClient() { - sentinelClient = new RedisClient(RedisURI.Builder.sentinel(TestSettings.host(), 26380, MASTER_ID).build()); - } - - @Before - public void openConnection() throws Exception { - sentinel = sentinelClient.connectSentinelAsync().getStatefulConnection().sync(); - sentinelRule.needMasterWithSlave(MASTER_ID, port(3), port(4)); - } - - @Test - public void connectToRedisUsingSentinel() throws Exception { - - RedisCommands connect = sentinelClient.connect().sync(); - assertThat(connect.ping()).isEqualToIgnoringCase("PONG"); - - connect.close(); - } - - @Test - public void failover() throws Exception { - - RedisClient redisClient = new RedisClient(RedisURI.Builder.redis(TestSettings.host(), port(3)).build()); - - String tcpPort1 = connectUsingSentinelAndGetPort(); - - sentinelRule.waitForConnectedSlaves(MASTER_ID); - sentinel.failover(MASTER_ID); - - delay(seconds(5)); - - sentinelRule.waitForConnectedSlaves(MASTER_ID); - - String tcpPort2 = connectUsingSentinelAndGetPort(); - assertThat(tcpPort1).isNotEqualTo(tcpPort2); - FastShutdown.shutdown(redisClient); - } - - protected String connectUsingSentinelAndGetPort() { - RedisCommands connectAfterFailover = sentinelClient.connect().sync(); - String tcpPort2 = getTcpPort(connectAfterFailover); - connectAfterFailover.close(); - return tcpPort2; - } - - protected String getTcpPort(RedisCommands commands) { - Pattern pattern = Pattern.compile(".*tcp_port\\:(\\d+).*", Pattern.DOTALL); - - Matcher matcher = pattern.matcher(commands.info("server")); - if (matcher.lookingAt()) { - return matcher.group(1); - } - return null; - } - -} diff --git a/src/test/java/com/lambdaworks/redis/sentinel/SentinelRule.java b/src/test/java/com/lambdaworks/redis/sentinel/SentinelRule.java index da16d629be..ebc42698da 100644 --- a/src/test/java/com/lambdaworks/redis/sentinel/SentinelRule.java +++ b/src/test/java/com/lambdaworks/redis/sentinel/SentinelRule.java @@ -58,7 +58,7 @@ public SentinelRule(RedisClient redisClient, boolean flushBeforeTest, int... sen log.info("[Sentinel] Connecting to sentinels: " + Arrays.toString(sentinelPorts)); for (int port : sentinelPorts) { RedisSentinelAsyncCommands connection = redisClient - .connectSentinelAsync(RedisURI.Builder.redis(TestSettings.host(), port).build()); + .connectSentinel(RedisURI.Builder.redis(TestSettings.host(), port).build()).async(); sentinelConnections.put(port, connection.getStatefulConnection().sync()); } } diff --git a/src/test/java/com/lambdaworks/redis/sentinel/rx/SentinelRxCommandTest.java b/src/test/java/com/lambdaworks/redis/sentinel/rx/SentinelRxCommandTest.java index 1d796863b2..cf6e5ed6a5 100644 --- a/src/test/java/com/lambdaworks/redis/sentinel/rx/SentinelRxCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/sentinel/rx/SentinelRxCommandTest.java @@ -17,7 +17,7 @@ public class SentinelRxCommandTest extends SentinelCommandTest { @Override public void openConnection() throws Exception { - RedisSentinelAsyncCommands async = sentinelClient.connectSentinelAsync(); + RedisSentinelAsyncCommands async = sentinelClient.connectSentinel().async(); RedisSentinelReactiveCommands reactive = async.getStatefulConnection().reactive(); sentinel = RxSyncInvocationHandler.sync(async.getStatefulConnection()); diff --git a/src/test/java/com/lambdaworks/redis/support/PoolingProxyFactoryTest.java b/src/test/java/com/lambdaworks/redis/support/PoolingProxyFactoryTest.java deleted file mode 100644 index ab64a9868c..0000000000 --- a/src/test/java/com/lambdaworks/redis/support/PoolingProxyFactoryTest.java +++ /dev/null @@ -1,55 +0,0 @@ -package com.lambdaworks.redis.support; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.fail; - -import com.lambdaworks.redis.api.sync.RedisCommands; -import org.junit.Test; - -import com.lambdaworks.redis.AbstractRedisClientTest; -import com.lambdaworks.redis.RedisConnection; -import com.lambdaworks.redis.RedisConnectionPool; -import com.lambdaworks.redis.RedisException; - -public class PoolingProxyFactoryTest extends AbstractRedisClientTest { - - @Test - public void testCreateDefault() throws Exception { - - RedisConnectionPool> pool = client.pool(); - RedisConnection connection = PoolingProxyFactory.create(pool); - - connection.set("a", "b"); - connection.set("x", "y"); - - pool.close(); - } - - @Test - public void testCloseReturnsConnection() throws Exception { - - RedisConnectionPool> pool = client.pool(); - assertThat(pool.getNumActive()).isEqualTo(0); - RedisConnection connection = pool.allocateConnection(); - assertThat(pool.getNumActive()).isEqualTo(1); - connection.close(); - assertThat(pool.getNumActive()).isEqualTo(0); - } - - @Test - public void testCreate() throws Exception { - - RedisConnection connection = PoolingProxyFactory.create(client.pool()); - - connection.set("a", "b"); - connection.close(); - - try { - connection.set("x", "y"); - fail("missing exception"); - } catch (RedisException e) { - assertThat(e.getMessage()).isEqualTo("Connection pool is closed"); - - } - } -} diff --git a/src/test/java/com/lambdaworks/redis/support/WithConnectionTest.java b/src/test/java/com/lambdaworks/redis/support/WithConnectionTest.java deleted file mode 100644 index 74ef53584f..0000000000 --- a/src/test/java/com/lambdaworks/redis/support/WithConnectionTest.java +++ /dev/null @@ -1,65 +0,0 @@ -package com.lambdaworks.redis.support; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.fail; - -import com.lambdaworks.redis.api.sync.RedisCommands; -import org.junit.Test; - -import com.lambdaworks.redis.AbstractRedisClientTest; -import com.lambdaworks.redis.RedisConnection; -import com.lambdaworks.redis.RedisConnectionPool; - -public class WithConnectionTest extends AbstractRedisClientTest { - - @Test - public void testPooling() throws Exception { - final RedisConnectionPool> pool = client.pool(); - - assertThat(pool.getNumActive()).isEqualTo(0); - assertThat(pool.getNumIdle()).isEqualTo(0); - - new WithConnection>(pool) { - - @Override - protected void run(RedisCommands connection) { - connection.set("key", "value"); - String result = connection.get("key"); - assertThat(result).isEqualTo("value"); - - assertThat(pool.getNumActive()).isEqualTo(1); - assertThat(pool.getNumIdle()).isEqualTo(0); - } - }; - - assertThat(pool.getNumActive()).isEqualTo(0); - assertThat(pool.getNumIdle()).isEqualTo(1); - - } - - @Test - public void testPoolingWithException() throws Exception { - final RedisConnectionPool> pool = client.pool(); - - assertThat(pool.getNumActive()).isEqualTo(0); - assertThat(pool.getNumIdle()).isEqualTo(0); - - try { - new WithConnection>(pool) { - - @Override - protected void run(RedisCommands connection) { - connection.set("key", "value"); - throw new IllegalStateException("test"); - } - }; - - fail("Missing Exception"); - } catch (Exception e) { - } - - assertThat(pool.getNumActive()).isEqualTo(0); - assertThat(pool.getNumIdle()).isEqualTo(1); - - } -} diff --git a/src/test/jmh/com/lambdaworks/redis/cluster/EmptyRedisClusterClient.java b/src/test/jmh/com/lambdaworks/redis/cluster/EmptyRedisClusterClient.java index cd08ee3a3b..dfa02c93ee 100644 --- a/src/test/jmh/com/lambdaworks/redis/cluster/EmptyRedisClusterClient.java +++ b/src/test/jmh/com/lambdaworks/redis/cluster/EmptyRedisClusterClient.java @@ -1,6 +1,7 @@ package com.lambdaworks.redis.cluster; import java.net.SocketAddress; +import java.util.Collections; import java.util.function.Supplier; import com.lambdaworks.redis.RedisChannelWriter; @@ -15,7 +16,7 @@ public class EmptyRedisClusterClient extends RedisClusterClient { private final static EmptyStatefulRedisConnection CONNECTION = new EmptyStatefulRedisConnection(); public EmptyRedisClusterClient(RedisURI initialUri) { - super(initialUri); + super(null, Collections.singleton(initialUri)); } StatefulRedisConnection connectToNode(RedisCodec codec, String nodeId, From c12e39c2912c79ed2ae9445ebacd1ec45b55f71c Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Mon, 25 Jul 2016 22:21:06 +0200 Subject: [PATCH 003/808] Remove Google Guava usage #217 --- pom.xml | 6 - .../models/slots/ClusterSlotRange.java | 7 +- .../redis/models/role/ReplicationPartner.java | 2 +- .../redis/models/role/RoleParser.java | 6 +- .../redis/resource/DirContextDnsResolver.java | 152 +++++++++++++++++- .../lambdaworks/redis/LettuceFuturesTest.java | 10 +- .../redis/LettucePerformanceTest.java | 2 + .../redis/models/role/RoleParserTest.java | 4 +- 8 files changed, 166 insertions(+), 23 deletions(-) diff --git a/pom.xml b/pom.xml index d1d67ebb44..c02e5cbc7b 100644 --- a/pom.xml +++ b/pom.xml @@ -117,12 +117,6 @@ true - - com.google.guava - guava - 18.0 - - org.apache.commons commons-pool2 diff --git a/src/main/java/com/lambdaworks/redis/cluster/models/slots/ClusterSlotRange.java b/src/main/java/com/lambdaworks/redis/cluster/models/slots/ClusterSlotRange.java index eed08503f0..a0fdb55191 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/models/slots/ClusterSlotRange.java +++ b/src/main/java/com/lambdaworks/redis/cluster/models/slots/ClusterSlotRange.java @@ -6,9 +6,9 @@ import java.util.List; import java.util.Set; -import com.google.common.net.HostAndPort; import com.lambdaworks.redis.RedisURI; import com.lambdaworks.redis.cluster.models.partitions.RedisClusterNode; +import com.lambdaworks.redis.internal.HostAndPort; import com.lambdaworks.redis.internal.LettuceAssert; /** @@ -48,9 +48,10 @@ public ClusterSlotRange(int from, int to, RedisClusterNode masterNode, List flags) { + + int port = hostAndPort.hasPort() ? hostAndPort.getPort() : RedisURI.DEFAULT_REDIS_PORT; RedisClusterNode redisClusterNode = new RedisClusterNode(); - redisClusterNode - .setUri(RedisURI.create(hostAndPort.getHostText(), hostAndPort.getPortOrDefault(RedisURI.DEFAULT_REDIS_PORT))); + redisClusterNode.setUri(RedisURI.create(hostAndPort.getHostText(), port)); redisClusterNode.setSlaveOf(slaveOf); redisClusterNode.setFlags(flags); return redisClusterNode; diff --git a/src/main/java/com/lambdaworks/redis/models/role/ReplicationPartner.java b/src/main/java/com/lambdaworks/redis/models/role/ReplicationPartner.java index dd0c85f46f..aa7f7cad76 100644 --- a/src/main/java/com/lambdaworks/redis/models/role/ReplicationPartner.java +++ b/src/main/java/com/lambdaworks/redis/models/role/ReplicationPartner.java @@ -2,7 +2,7 @@ import java.io.Serializable; -import com.google.common.net.HostAndPort; +import com.lambdaworks.redis.internal.HostAndPort; import com.lambdaworks.redis.internal.LettuceAssert; /** diff --git a/src/main/java/com/lambdaworks/redis/models/role/RoleParser.java b/src/main/java/com/lambdaworks/redis/models/role/RoleParser.java index 3a9f2c0f7d..0f14b00a8a 100644 --- a/src/main/java/com/lambdaworks/redis/models/role/RoleParser.java +++ b/src/main/java/com/lambdaworks/redis/models/role/RoleParser.java @@ -2,7 +2,7 @@ import java.util.*; -import com.google.common.net.HostAndPort; +import com.lambdaworks.redis.internal.HostAndPort; import com.lambdaworks.redis.internal.LettuceAssert; /** @@ -90,7 +90,7 @@ private static RedisInstance parseSlave(List roleOutput) { String stateString = getStringFromIterator(iterator, null); long replicationOffset = getLongFromIterator(iterator, 0); - ReplicationPartner master = new ReplicationPartner(HostAndPort.fromParts(ip, Math.toIntExact(port)), replicationOffset); + ReplicationPartner master = new ReplicationPartner(HostAndPort.of(ip, Math.toIntExact(port)), replicationOffset); RedisSlaveInstance.State state = SLAVE_STATE_MAPPING.get(stateString); @@ -155,7 +155,7 @@ private static ReplicationPartner getMasterSlaveReplicationPartner(Collection long port = getLongFromIterator(iterator, 0); long replicationOffset = getLongFromIterator(iterator, 0); - return new ReplicationPartner(HostAndPort.fromParts(ip, Math.toIntExact(port)), replicationOffset); + return new ReplicationPartner(HostAndPort.of(ip, Math.toIntExact(port)), replicationOffset); } private static long getLongFromIterator(Iterator iterator, long defaultValue) { diff --git a/src/main/java/com/lambdaworks/redis/resource/DirContextDnsResolver.java b/src/main/java/com/lambdaworks/redis/resource/DirContextDnsResolver.java index 2dfb3d7deb..6bb81e7110 100644 --- a/src/main/java/com/lambdaworks/redis/resource/DirContextDnsResolver.java +++ b/src/main/java/com/lambdaworks/redis/resource/DirContextDnsResolver.java @@ -4,6 +4,7 @@ import java.io.IOException; import java.net.InetAddress; import java.net.UnknownHostException; +import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -17,7 +18,6 @@ import javax.naming.directory.Attributes; import javax.naming.directory.InitialDirContext; -import com.google.common.net.InetAddresses; import com.lambdaworks.redis.LettuceStrings; import com.lambdaworks.redis.internal.LettuceAssert; @@ -39,6 +39,9 @@ public class DirContextDnsResolver implements DnsResolver, Closeable { final static String PREFER_IPV4_KEY = "java.net.preferIPv4Stack"; final static String PREFER_IPV6_KEY = "java.net.preferIPv6Stack"; + private static final int IPV4_PART_COUNT = 4; + private static final int IPV6_PART_COUNT = 8; + private static final String CTX_FACTORY_NAME = "com.sun.jndi.dns.DnsContextFactory"; private static final String INITIAL_TIMEOUT = "com.sun.jndi.dns.timeout.initial"; private static final String LOOKUP_RETRIES = "com.sun.jndi.dns.timeout.retries"; @@ -140,8 +143,8 @@ public void close() throws IOException { @Override public InetAddress[] resolve(String host) throws UnknownHostException { - if (InetAddresses.isInetAddress(host)) { - return new InetAddress[] { InetAddresses.forString(host) }; + if (ipStringToBytes(host) != null) { + return new InetAddress[] { InetAddress.getByAddress(ipStringToBytes(host)) }; } List inetAddresses = new ArrayList<>(); @@ -318,4 +321,147 @@ public StackPreference() { this.preferIpv6 = preferIpv6; } } + + private static byte[] ipStringToBytes(String ipString) { + // Make a first pass to categorize the characters in this string. + boolean hasColon = false; + boolean hasDot = false; + for (int i = 0; i < ipString.length(); i++) { + char c = ipString.charAt(i); + if (c == '.') { + hasDot = true; + } else if (c == ':') { + if (hasDot) { + return null; // Colons must not appear after dots. + } + hasColon = true; + } else if (Character.digit(c, 16) == -1) { + return null; // Everything else must be a decimal or hex digit. + } + } + + // Now decide which address family to parse. + if (hasColon) { + if (hasDot) { + ipString = convertDottedQuadToHex(ipString); + if (ipString == null) { + return null; + } + } + return textToNumericFormatV6(ipString); + } else if (hasDot) { + return textToNumericFormatV4(ipString); + } + return null; + } + + private static byte[] textToNumericFormatV4(String ipString) { + byte[] bytes = new byte[IPV4_PART_COUNT]; + int i = 0; + try { + for (String octet : ipString.split("\\.", IPV4_PART_COUNT)) { + bytes[i++] = parseOctet(octet); + } + } catch (NumberFormatException ex) { + return null; + } + + return i == IPV4_PART_COUNT ? bytes : null; + } + + private static byte[] textToNumericFormatV6(String ipString) { + // An address can have [2..8] colons, and N colons make N+1 parts. + String[] parts = ipString.split(":", IPV6_PART_COUNT + 2); + if (parts.length < 3 || parts.length > IPV6_PART_COUNT + 1) { + return null; + } + + // Disregarding the endpoints, find "::" with nothing in between. + // This indicates that a run of zeroes has been skipped. + int skipIndex = -1; + for (int i = 1; i < parts.length - 1; i++) { + if (parts[i].length() == 0) { + if (skipIndex >= 0) { + return null; // Can't have more than one :: + } + skipIndex = i; + } + } + + int partsHi; // Number of parts to copy from above/before the "::" + int partsLo; // Number of parts to copy from below/after the "::" + if (skipIndex >= 0) { + // If we found a "::", then check if it also covers the endpoints. + partsHi = skipIndex; + partsLo = parts.length - skipIndex - 1; + if (parts[0].length() == 0 && --partsHi != 0) { + return null; // ^: requires ^:: + } + if (parts[parts.length - 1].length() == 0 && --partsLo != 0) { + return null; // :$ requires ::$ + } + } else { + // Otherwise, allocate the entire address to partsHi. The endpoints + // could still be empty, but parseHextet() will check for that. + partsHi = parts.length; + partsLo = 0; + } + + // If we found a ::, then we must have skipped at least one part. + // Otherwise, we must have exactly the right number of parts. + int partsSkipped = IPV6_PART_COUNT - (partsHi + partsLo); + if (!(skipIndex >= 0 ? partsSkipped >= 1 : partsSkipped == 0)) { + return null; + } + + // Now parse the hextets into a byte array. + ByteBuffer rawBytes = ByteBuffer.allocate(2 * IPV6_PART_COUNT); + try { + for (int i = 0; i < partsHi; i++) { + rawBytes.putShort(parseHextet(parts[i])); + } + for (int i = 0; i < partsSkipped; i++) { + rawBytes.putShort((short) 0); + } + for (int i = partsLo; i > 0; i--) { + rawBytes.putShort(parseHextet(parts[parts.length - i])); + } + } catch (NumberFormatException ex) { + return null; + } + return rawBytes.array(); + } + + private static String convertDottedQuadToHex(String ipString) { + int lastColon = ipString.lastIndexOf(':'); + String initialPart = ipString.substring(0, lastColon + 1); + String dottedQuad = ipString.substring(lastColon + 1); + byte[] quad = textToNumericFormatV4(dottedQuad); + if (quad == null) { + return null; + } + String penultimate = Integer.toHexString(((quad[0] & 0xff) << 8) | (quad[1] & 0xff)); + String ultimate = Integer.toHexString(((quad[2] & 0xff) << 8) | (quad[3] & 0xff)); + return initialPart + penultimate + ":" + ultimate; + } + + private static byte parseOctet(String ipPart) { + // Note: we already verified that this string contains only hex digits. + int octet = Integer.parseInt(ipPart); + // Disallow leading zeroes, because no clear standard exists on + // whether these should be interpreted as decimal or octal. + if (octet > 255 || (ipPart.startsWith("0") && ipPart.length() > 1)) { + throw new NumberFormatException(); + } + return (byte) octet; + } + + private static short parseHextet(String ipPart) { + // Note: we already verified that this string contains only hex digits. + int hextet = Integer.parseInt(ipPart, 16); + if (hextet > 0xffff) { + throw new NumberFormatException(); + } + return (short) hextet; + } } diff --git a/src/test/java/com/lambdaworks/redis/LettuceFuturesTest.java b/src/test/java/com/lambdaworks/redis/LettuceFuturesTest.java index e553957c0c..7e833be163 100644 --- a/src/test/java/com/lambdaworks/redis/LettuceFuturesTest.java +++ b/src/test/java/com/lambdaworks/redis/LettuceFuturesTest.java @@ -1,9 +1,9 @@ package com.lambdaworks.redis; -import com.google.common.util.concurrent.SettableFuture; import org.junit.Before; import org.junit.Test; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; import static org.assertj.core.api.Assertions.assertThat; @@ -21,8 +21,8 @@ public void setUp() throws Exception { @Test(expected = RedisCommandExecutionException.class) public void awaitAllShouldThrowRedisCommandExecutionException() throws Exception { - SettableFuture f = SettableFuture.create(); - f.setException(new RedisCommandExecutionException("error")); + CompletableFuture f = new CompletableFuture<>(); + f.completeExceptionally(new RedisCommandExecutionException("error")); LettuceFutures.awaitAll(1, TimeUnit.SECONDS, f); } @@ -30,7 +30,7 @@ public void awaitAllShouldThrowRedisCommandExecutionException() throws Exception @Test(expected = RedisCommandInterruptedException.class) public void awaitAllShouldThrowRedisCommandInterruptedException() throws Exception { - SettableFuture f = SettableFuture.create(); + CompletableFuture f = new CompletableFuture<>(); Thread.currentThread().interrupt(); LettuceFutures.awaitAll(1, TimeUnit.SECONDS, f); @@ -39,7 +39,7 @@ public void awaitAllShouldThrowRedisCommandInterruptedException() throws Excepti @Test public void awaitAllShouldSetInterruptedBit() throws Exception { - SettableFuture f = SettableFuture.create(); + CompletableFuture f = new CompletableFuture<>(); Thread.currentThread().interrupt(); try { diff --git a/src/test/java/com/lambdaworks/redis/LettucePerformanceTest.java b/src/test/java/com/lambdaworks/redis/LettucePerformanceTest.java index 17f994f4ba..39190be0c7 100644 --- a/src/test/java/com/lambdaworks/redis/LettucePerformanceTest.java +++ b/src/test/java/com/lambdaworks/redis/LettucePerformanceTest.java @@ -16,6 +16,8 @@ import rx.Observable; +import javax.annotation.Resources; + /** * @author Mark Paluch */ diff --git a/src/test/java/com/lambdaworks/redis/models/role/RoleParserTest.java b/src/test/java/com/lambdaworks/redis/models/role/RoleParserTest.java index 436cef5b57..2a70cc9ad2 100644 --- a/src/test/java/com/lambdaworks/redis/models/role/RoleParserTest.java +++ b/src/test/java/com/lambdaworks/redis/models/role/RoleParserTest.java @@ -5,9 +5,9 @@ import java.util.ArrayList; import java.util.List; +import com.lambdaworks.redis.internal.HostAndPort; import org.junit.Test; -import com.google.common.net.HostAndPort; import com.lambdaworks.redis.internal.LettuceLists; public class RoleParserTest { @@ -146,7 +146,7 @@ public void testModelTest() throws Exception { assertThat(sentinel.toString()).contains(RedisSentinelInstance.class.getSimpleName()); ReplicationPartner partner = new ReplicationPartner(); - partner.setHost(HostAndPort.fromHost("localhost")); + partner.setHost(HostAndPort.parse("localhost")); partner.setReplicationOffset(12); assertThat(partner.toString()).contains(ReplicationPartner.class.getSimpleName()); From 6cb3fc0211fdebabca70cd9eb5ed09b2156967ad Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Mon, 25 Jul 2016 22:48:37 +0200 Subject: [PATCH 004/808] Consolidate ClientResources usage in tests --- .../redis/AbstractRedisClient.java | 5 +++ src/test/java/com/lambdaworks/SslTest.java | 7 +--- .../com/lambdaworks/TestClientResources.java | 7 ++++ .../redis/AbstractRedisClientTest.java | 3 +- .../com/lambdaworks/redis/AllTheAPIsTest.java | 4 +- .../lambdaworks/redis/ClientMetricsTest.java | 3 +- .../com/lambdaworks/redis/ClientTest.java | 9 ++--- .../redis/ConnectionCommandTest.java | 5 +-- .../redis/RedisClientFactoryTest.java | 21 +++-------- .../redis/UnixDomainSocketTest.java | 13 ++++--- .../redis/cluster/AbstractClusterTest.java | 4 +- .../redis/cluster/ClusterCommandTest.java | 6 ++- .../cluster/ClusterReactiveCommandTest.java | 5 ++- .../RedisClusterClientFactoryTest.java | 37 ++++++------------- .../redis/cluster/RedisClusterClientTest.java | 9 +++-- .../RedisClusterPasswordSecuredSslTest.java | 7 ++-- .../cluster/RedisClusterReadFromTest.java | 4 +- .../redis/cluster/RedisClusterSetupTest.java | 4 +- .../RedisClusterStressScenariosTest.java | 5 ++- .../cluster/RedisRxClusterClientTest.java | 5 ++- .../commands/CustomClusterCommandTest.java | 3 +- .../commands/GeoClusterCommandTest.java | 3 +- .../commands/HashClusterCommandTest.java | 4 +- .../commands/KeyClusterCommandTest.java | 8 ++-- .../commands/ListClusterCommandTest.java | 4 +- .../commands/StringClusterCommandTest.java | 4 +- .../commands/rx/KeyClusterRxCommandTest.java | 3 +- .../masterslave/MasterSlaveSentinelTest.java | 2 +- .../redis/pubsub/PubSubCommandTest.java | 3 +- .../redis/pubsub/PubSubRxTest.java | 4 +- .../redis/sentinel/SentinelCommandTest.java | 12 +++--- .../sentinel/SentinelConnectionTest.java | 3 +- 32 files changed, 114 insertions(+), 102 deletions(-) diff --git a/src/main/java/com/lambdaworks/redis/AbstractRedisClient.java b/src/main/java/com/lambdaworks/redis/AbstractRedisClient.java index aae45992ba..5e98512311 100644 --- a/src/main/java/com/lambdaworks/redis/AbstractRedisClient.java +++ b/src/main/java/com/lambdaworks/redis/AbstractRedisClient.java @@ -201,6 +201,11 @@ protected > T initializeChannel(Connec RedisChannelHandler connection = connectionBuilder.connection(); SocketAddress redisAddress = connectionBuilder.socketAddress(); + + if(connectionBuilder.workerPool().isShuttingDown()){ + throw new IllegalStateException("Cannot connect. Worker pool not running"); + } + try { logger.debug("Connecting to Redis at {}", redisAddress); diff --git a/src/test/java/com/lambdaworks/SslTest.java b/src/test/java/com/lambdaworks/SslTest.java index 2b3fb2e288..95969ce31f 100644 --- a/src/test/java/com/lambdaworks/SslTest.java +++ b/src/test/java/com/lambdaworks/SslTest.java @@ -31,7 +31,7 @@ public class SslTest extends AbstractTest { private static final String KEYSTORE = "work/keystore.jks"; private static final String LOCALHOST_KEYSTORE = "work/keystore-localhost.jks"; - private static final RedisClient redisClient = RedisClient.create(); + private static final RedisClient redisClient = DefaultRedisClient.get(); private static final RedisURI URI_NO_VERIFY = RedisURI.Builder.redis(host(), sslPort()) // .withSsl(true) // @@ -53,11 +53,6 @@ public void before() throws Exception { redisClient.setOptions(ClientOptions.create()); } - @AfterClass - public static void afterClass() { - FastShutdown.shutdown(redisClient); - } - @Test public void standaloneWithSsl() throws Exception { diff --git a/src/test/java/com/lambdaworks/TestClientResources.java b/src/test/java/com/lambdaworks/TestClientResources.java index 165adec08b..8820292dfc 100644 --- a/src/test/java/com/lambdaworks/TestClientResources.java +++ b/src/test/java/com/lambdaworks/TestClientResources.java @@ -15,6 +15,9 @@ */ public class TestClientResources { + private final static TestClientResources instance = new TestClientResources(); + private ClientResources clientResources = create(); + public static ClientResources create() { final DefaultClientResources resources = DefaultClientResources.builder().eventLoopGroupProvider( new TestEventLoopGroupProvider()).build(); @@ -32,4 +35,8 @@ public void run() { return resources; } + + public static ClientResources get() { + return instance.clientResources; + } } diff --git a/src/test/java/com/lambdaworks/redis/AbstractRedisClientTest.java b/src/test/java/com/lambdaworks/redis/AbstractRedisClientTest.java index 6a65140f46..f64084f7a0 100644 --- a/src/test/java/com/lambdaworks/redis/AbstractRedisClientTest.java +++ b/src/test/java/com/lambdaworks/redis/AbstractRedisClientTest.java @@ -2,6 +2,7 @@ package com.lambdaworks.redis; +import com.lambdaworks.TestClientResources; import org.junit.After; import org.junit.Before; import org.junit.BeforeClass; @@ -20,7 +21,7 @@ public static void setupClient() { } protected static RedisClient newRedisClient() { - return RedisClient.create(RedisURI.Builder.redis(host, port).build()); + return RedisClient.create(TestClientResources.get(), RedisURI.Builder.redis(host, port).build()); } protected RedisCommands connect() { diff --git a/src/test/java/com/lambdaworks/redis/AllTheAPIsTest.java b/src/test/java/com/lambdaworks/redis/AllTheAPIsTest.java index e7ed946c03..f71741a34b 100644 --- a/src/test/java/com/lambdaworks/redis/AllTheAPIsTest.java +++ b/src/test/java/com/lambdaworks/redis/AllTheAPIsTest.java @@ -1,5 +1,6 @@ package com.lambdaworks.redis; +import com.lambdaworks.TestClientResources; import org.junit.BeforeClass; import org.junit.Test; @@ -19,7 +20,8 @@ public class AllTheAPIsTest { @BeforeClass public static void beforeClass() throws Exception { clusterPort = TestSettings.port(900); - clusterClient = RedisClusterClient.create(RedisURI.Builder.redis(TestSettings.host(), clusterPort).build()); + clusterClient = RedisClusterClient.create( + TestClientResources.get(), RedisURI.Builder.redis(TestSettings.host(), clusterPort).build()); } @BeforeClass diff --git a/src/test/java/com/lambdaworks/redis/ClientMetricsTest.java b/src/test/java/com/lambdaworks/redis/ClientMetricsTest.java index 30fa45d35f..ca3a9443ad 100644 --- a/src/test/java/com/lambdaworks/redis/ClientMetricsTest.java +++ b/src/test/java/com/lambdaworks/redis/ClientMetricsTest.java @@ -5,6 +5,7 @@ import static com.lambdaworks.redis.AbstractRedisClientTest.client; import static org.assertj.core.api.Assertions.assertThat; +import com.lambdaworks.TestClientResources; import com.lambdaworks.redis.api.sync.RedisCommands; import com.lambdaworks.redis.metrics.CommandLatencyId; import com.lambdaworks.redis.metrics.CommandMetrics; @@ -35,7 +36,7 @@ public class ClientMetricsTest extends AbstractTest { @BeforeClass public static void setupClient() { - client = RedisClient.create(RedisURI.Builder.redis(host, port).build()); + client = RedisClient.create(TestClientResources.get(), RedisURI.Builder.redis(host, port).build()); } @Before diff --git a/src/test/java/com/lambdaworks/redis/ClientTest.java b/src/test/java/com/lambdaworks/redis/ClientTest.java index 8e8b8a4ac7..ea10cdfd9c 100644 --- a/src/test/java/com/lambdaworks/redis/ClientTest.java +++ b/src/test/java/com/lambdaworks/redis/ClientTest.java @@ -9,6 +9,7 @@ import java.util.concurrent.TimeUnit; +import com.lambdaworks.TestClientResources; import org.junit.FixMethodOrder; import org.junit.Rule; import org.junit.Test; @@ -155,7 +156,7 @@ public void interrupt() throws Exception { @Test public void connectFailure() throws Exception { - RedisClient client = RedisClient.create("redis://invalid"); + RedisClient client = RedisClient.create(TestClientResources.get(), "redis://invalid"); exception.expect(RedisException.class); exception.expectMessage("Unable to connect"); client.connect(); @@ -164,7 +165,7 @@ public void connectFailure() throws Exception { @Test public void connectPubSubFailure() throws Exception { - RedisClient client = RedisClient.create("redis://invalid"); + RedisClient client = RedisClient.create(TestClientResources.get(), "redis://invalid"); exception.expect(RedisException.class); exception.expectMessage("Unable to connect"); client.connectPubSub(); @@ -197,7 +198,7 @@ public void onRedisExceptionCaught(RedisChannelHandler connection, Throwab @Test public void emptyClient() throws Exception { - RedisClient client = RedisClient.create(); + RedisClient client = DefaultRedisClient.get(); try { client.connect(); } catch (IllegalStateException e) { @@ -215,8 +216,6 @@ public void emptyClient() throws Exception { } catch (IllegalArgumentException e) { assertThat(e).hasMessageContaining("RedisURI"); } - - FastShutdown.shutdown(client); } @Test diff --git a/src/test/java/com/lambdaworks/redis/ConnectionCommandTest.java b/src/test/java/com/lambdaworks/redis/ConnectionCommandTest.java index 964f603320..53d821d79a 100644 --- a/src/test/java/com/lambdaworks/redis/ConnectionCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/ConnectionCommandTest.java @@ -33,11 +33,10 @@ public void run(RedisClient client) { } RedisURI redisURI = RedisURI.Builder.redis(host, port).withDatabase(2).withPassword(passwd).build(); - RedisClient redisClient = RedisClient.create(redisURI); - RedisCommands authConnection = redisClient.connect().sync(); + RedisClient redisClient = DefaultRedisClient.get(); + RedisCommands authConnection = redisClient.connect(redisURI).sync(); authConnection.ping(); authConnection.getStatefulConnection().close(); - FastShutdown.shutdown(redisClient); } }; } diff --git a/src/test/java/com/lambdaworks/redis/RedisClientFactoryTest.java b/src/test/java/com/lambdaworks/redis/RedisClientFactoryTest.java index ecb6f4d786..6a1e0a9a10 100644 --- a/src/test/java/com/lambdaworks/redis/RedisClientFactoryTest.java +++ b/src/test/java/com/lambdaworks/redis/RedisClientFactoryTest.java @@ -15,17 +15,6 @@ public class RedisClientFactoryTest { private final static String URI = "redis://" + TestSettings.host() + ":" + TestSettings.port(); private final static RedisURI REDIS_URI = RedisURI.create(URI); - private static ClientResources DEFAULT_RESOURCES; - - @BeforeClass - public static void beforeClass() throws Exception { - DEFAULT_RESOURCES = TestClientResources.create(); - } - - @AfterClass - public static void afterClass() throws Exception { - FastShutdown.shutdown(DEFAULT_RESOURCES); - } @Test public void plain() throws Exception { @@ -54,7 +43,7 @@ public void withUriNull() throws Exception { @Test public void clientResources() throws Exception { - FastShutdown.shutdown(RedisClient.create(DEFAULT_RESOURCES)); + FastShutdown.shutdown(RedisClient.create(TestClientResources.get())); } @Test(expected = IllegalArgumentException.class) @@ -64,12 +53,12 @@ public void clientResourcesNull() throws Exception { @Test public void clientResourcesWithStringUri() throws Exception { - FastShutdown.shutdown(RedisClient.create(DEFAULT_RESOURCES, URI)); + FastShutdown.shutdown(RedisClient.create(TestClientResources.get(), URI)); } @Test(expected = IllegalArgumentException.class) public void clientResourcesWithStringUriNull() throws Exception { - RedisClient.create(DEFAULT_RESOURCES, (String) null); + RedisClient.create(TestClientResources.get(), (String) null); } @Test(expected = IllegalArgumentException.class) @@ -79,12 +68,12 @@ public void clientResourcesNullWithStringUri() throws Exception { @Test public void clientResourcesWithUri() throws Exception { - FastShutdown.shutdown(RedisClient.create(DEFAULT_RESOURCES, REDIS_URI)); + FastShutdown.shutdown(RedisClient.create(TestClientResources.get(), REDIS_URI)); } @Test(expected = IllegalArgumentException.class) public void clientResourcesWithUriNull() throws Exception { - RedisClient.create(DEFAULT_RESOURCES, (RedisURI) null); + RedisClient.create(TestClientResources.get(), (RedisURI) null); } @Test(expected = IllegalArgumentException.class) diff --git a/src/test/java/com/lambdaworks/redis/UnixDomainSocketTest.java b/src/test/java/com/lambdaworks/redis/UnixDomainSocketTest.java index a7aeb5f8ef..91bf46432e 100644 --- a/src/test/java/com/lambdaworks/redis/UnixDomainSocketTest.java +++ b/src/test/java/com/lambdaworks/redis/UnixDomainSocketTest.java @@ -8,6 +8,7 @@ import java.io.IOException; import java.util.Locale; +import com.lambdaworks.TestClientResources; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.junit.AfterClass; @@ -56,7 +57,7 @@ public void standalone_Linux_x86_64_RedisClientWithSocket() throws Exception { RedisURI redisURI = getSocketRedisUri(); - RedisClient redisClient = RedisClient.create(redisURI); + RedisClient redisClient = RedisClient.create(TestClientResources.get(), redisURI); StatefulRedisConnection connection = redisClient.connect(); @@ -73,7 +74,7 @@ public void standalone_Linux_x86_64_ConnectToSocket() throws Exception { RedisURI redisURI = getSocketRedisUri(); - RedisClient redisClient = RedisClient.create(); + RedisClient redisClient = RedisClient.create(TestClientResources.get()); StatefulRedisConnection connection = redisClient.connect(redisURI); @@ -107,7 +108,7 @@ public void sentinel_Linux_x86_64_RedisClientWithSocket() throws Exception { uri.getSentinels().add(getSentinelSocketRedisUri()); uri.setSentinelMasterId("mymaster"); - RedisClient redisClient = RedisClient.create(uri); + RedisClient redisClient = RedisClient.create(TestClientResources.get(), uri); StatefulRedisConnection connection = redisClient.connect(); @@ -132,7 +133,7 @@ public void sentinel_Linux_x86_64_ConnectToSocket() throws Exception { uri.getSentinels().add(getSentinelSocketRedisUri()); uri.setSentinelMasterId("mymaster"); - RedisClient redisClient = RedisClient.create(); + RedisClient redisClient = RedisClient.create(TestClientResources.get()); StatefulRedisConnection connection = redisClient.connect(uri); @@ -159,7 +160,7 @@ public void sentinel_Linux_x86_64_socket_and_inet() throws Exception { uri.getSentinels().add(RedisURI.create(RedisURI.URI_SCHEME_REDIS + "://" + TestSettings.host() + ":26379")); uri.setSentinelMasterId(MASTER_ID); - RedisClient redisClient = RedisClient.create(uri); + RedisClient redisClient = RedisClient.create(TestClientResources.get(), uri); StatefulRedisSentinelConnection sentinelConnection = redisClient .connectSentinel(getSentinelSocketRedisUri()); @@ -184,6 +185,6 @@ private void someRedisAction(RedisCommands connection) { } protected static RedisClient getRedisSentinelClient() { - return RedisClient.create(RedisURI.Builder.sentinel(TestSettings.host(), MASTER_ID).build()); + return RedisClient.create(TestClientResources.get(), RedisURI.Builder.sentinel(TestSettings.host(), MASTER_ID).build()); } } diff --git a/src/test/java/com/lambdaworks/redis/cluster/AbstractClusterTest.java b/src/test/java/com/lambdaworks/redis/cluster/AbstractClusterTest.java index a18a73cbc8..ca2f927d9f 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/AbstractClusterTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/AbstractClusterTest.java @@ -1,5 +1,6 @@ package com.lambdaworks.redis.cluster; +import com.lambdaworks.TestClientResources; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Rule; @@ -44,7 +45,8 @@ public class AbstractClusterTest extends AbstractTest { @BeforeClass public static void setupClusterClient() throws Exception { - clusterClient = RedisClusterClient.create(LettuceLists.unmodifiableList(RedisURI.Builder.redis(host, port1).build())); + clusterClient = RedisClusterClient.create( + TestClientResources.get(), LettuceLists.unmodifiableList(RedisURI.Builder.redis(host, port1).build())); } @AfterClass diff --git a/src/test/java/com/lambdaworks/redis/cluster/ClusterCommandTest.java b/src/test/java/com/lambdaworks/redis/cluster/ClusterCommandTest.java index 81694bea2b..61c29e1a75 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/ClusterCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/ClusterCommandTest.java @@ -9,6 +9,7 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import com.lambdaworks.TestClientResources; import org.junit.*; import org.junit.runners.MethodSorters; @@ -39,8 +40,9 @@ public class ClusterCommandTest extends AbstractClusterTest { @BeforeClass public static void setupClient() throws Exception { - client = RedisClient.create(RedisURI.Builder.redis(host, port1).build()); - clusterClient = RedisClusterClient.create(LettuceLists.newList(RedisURI.Builder.redis(host, port1).build())); + client = RedisClient.create(TestClientResources.get(), RedisURI.Builder.redis(host, port1).build()); + clusterClient = RedisClusterClient.create(TestClientResources.get(), LettuceLists.newList(RedisURI.Builder.redis(host, port1).build())); + } @AfterClass diff --git a/src/test/java/com/lambdaworks/redis/cluster/ClusterReactiveCommandTest.java b/src/test/java/com/lambdaworks/redis/cluster/ClusterReactiveCommandTest.java index 6479c85278..044025b522 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/ClusterReactiveCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/ClusterReactiveCommandTest.java @@ -5,6 +5,7 @@ import java.util.List; +import com.lambdaworks.TestClientResources; import org.junit.*; import org.junit.runners.MethodSorters; @@ -31,8 +32,8 @@ public class ClusterReactiveCommandTest extends AbstractClusterTest { @BeforeClass public static void setupClient() throws Exception { setupClusterClient(); - client = RedisClient.create(RedisURI.Builder.redis(host, port1).build()); - clusterClient = RedisClusterClient.create(LettuceLists.unmodifiableList(RedisURI.Builder.redis(host, port1).build())); + client = RedisClient.create(TestClientResources.get(), RedisURI.Builder.redis(host, port1).build()); + clusterClient = RedisClusterClient.create(TestClientResources.get(), LettuceLists.unmodifiableList(RedisURI.Builder.redis(host, port1).build())); } diff --git a/src/test/java/com/lambdaworks/redis/cluster/RedisClusterClientFactoryTest.java b/src/test/java/com/lambdaworks/redis/cluster/RedisClusterClientFactoryTest.java index 7dafc83502..271f0120a0 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/RedisClusterClientFactoryTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/RedisClusterClientFactoryTest.java @@ -2,10 +2,7 @@ import java.util.Arrays; import java.util.List; -import java.util.concurrent.TimeUnit; -import org.junit.AfterClass; -import org.junit.BeforeClass; import org.junit.Test; import com.lambdaworks.TestClientResources; @@ -13,7 +10,6 @@ import com.lambdaworks.redis.RedisURI; import com.lambdaworks.redis.TestSettings; import com.lambdaworks.redis.internal.LettuceLists; -import com.lambdaworks.redis.resource.ClientResources; /** * @author Mark Paluch @@ -23,21 +19,10 @@ public class RedisClusterClientFactoryTest { private final static String URI = "redis://" + TestSettings.host() + ":" + TestSettings.port(); private final static RedisURI REDIS_URI = RedisURI.create(URI); private static final List REDIS_URIS = LettuceLists.newList(REDIS_URI); - private static ClientResources DEFAULT_RESOURCES; - - @BeforeClass - public static void beforeClass() throws Exception { - DEFAULT_RESOURCES = TestClientResources.create(); - } - - @AfterClass - public static void afterClass() throws Exception { - DEFAULT_RESOURCES.shutdown(100, 100, TimeUnit.MILLISECONDS).get(); - } @Test public void withStringUri() throws Exception { - FastShutdown.shutdown(RedisClusterClient.create(URI)); + FastShutdown.shutdown(RedisClusterClient.create(TestClientResources.get(), URI)); } @Test(expected = IllegalArgumentException.class) @@ -67,12 +52,12 @@ public void withUriIterableNull() throws Exception { @Test public void clientResourcesWithStringUri() throws Exception { - FastShutdown.shutdown(RedisClusterClient.create(DEFAULT_RESOURCES, URI)); + FastShutdown.shutdown(RedisClusterClient.create(TestClientResources.get(), URI)); } @Test(expected = IllegalArgumentException.class) public void clientResourcesWithStringUriNull() throws Exception { - RedisClusterClient.create(DEFAULT_RESOURCES, (String) null); + RedisClusterClient.create(TestClientResources.get(), (String) null); } @Test(expected = IllegalArgumentException.class) @@ -82,12 +67,12 @@ public void clientResourcesNullWithStringUri() throws Exception { @Test public void clientResourcesWithUri() throws Exception { - FastShutdown.shutdown(RedisClusterClient.create(DEFAULT_RESOURCES, REDIS_URI)); + FastShutdown.shutdown(RedisClusterClient.create(TestClientResources.get(), REDIS_URI)); } @Test(expected = IllegalArgumentException.class) public void clientResourcesWithUriNull() throws Exception { - RedisClusterClient.create(DEFAULT_RESOURCES, (RedisURI) null); + RedisClusterClient.create(TestClientResources.get(), (RedisURI) null); } @Test(expected = IllegalArgumentException.class) @@ -97,34 +82,34 @@ public void clientResourcesWithUriUri() throws Exception { @Test public void clientResourcesWithUriIterable() throws Exception { - FastShutdown.shutdown(RedisClusterClient.create(DEFAULT_RESOURCES, LettuceLists.newList(REDIS_URI))); + FastShutdown.shutdown(RedisClusterClient.create(TestClientResources.get(), LettuceLists.newList(REDIS_URI))); } @Test(expected = IllegalArgumentException.class) public void clientResourcesWithUriIterableNull() throws Exception { - RedisClusterClient.create(DEFAULT_RESOURCES, (Iterable) null); + RedisClusterClient.create(TestClientResources.get(), (Iterable) null); } @Test(expected = IllegalArgumentException.class) public void clientResourcesNullWithUriIterable() throws Exception { RedisClusterClient.create(null, REDIS_URIS); } - + @Test(expected = IllegalArgumentException.class) public void clientWithDifferentSslSettings() throws Exception { RedisClusterClient.create(Arrays.asList(RedisURI.create("redis://host1"), RedisURI.create("redis+ssl://host1"))); } - + @Test(expected = IllegalArgumentException.class) public void clientWithDifferentTlsSettings() throws Exception { RedisClusterClient.create(Arrays.asList(RedisURI.create("rediss://host1"), RedisURI.create("redis+tls://host1"))); } - + @Test(expected = IllegalArgumentException.class) public void clientWithDifferentVerifyPeerSettings() throws Exception { RedisURI redisURI = RedisURI.create("rediss://host1"); redisURI.setVerifyPeer(false); - + RedisClusterClient.create(Arrays.asList(redisURI, RedisURI.create("rediss://host1"))); } } diff --git a/src/test/java/com/lambdaworks/redis/cluster/RedisClusterClientTest.java b/src/test/java/com/lambdaworks/redis/cluster/RedisClusterClientTest.java index 5a6f91fb4e..a9d6519b4c 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/RedisClusterClientTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/RedisClusterClientTest.java @@ -10,6 +10,7 @@ import java.util.List; import java.util.concurrent.TimeUnit; +import com.lambdaworks.TestClientResources; import org.assertj.core.api.AssertionsForClassTypes; import org.junit.*; import org.junit.runners.MethodSorters; @@ -48,8 +49,8 @@ public class RedisClusterClientTest extends AbstractClusterTest { @BeforeClass public static void setupClient() throws Exception { setupClusterClient(); - client = RedisClient.create(RedisURI.Builder.redis(host, port1).build()); - clusterClient = RedisClusterClient.create(Collections.singletonList(RedisURI.Builder.redis(host, port1).build())); + client = RedisClient.create(TestClientResources.get(), RedisURI.Builder.redis(host, port1).build()); + clusterClient = RedisClusterClient.create(TestClientResources.get(), Collections.singletonList(RedisURI.Builder.redis(host, port1).build())); } @AfterClass @@ -353,7 +354,7 @@ public void clusterNeedsAuthButNotSupplied() throws Exception { @Test public void noClusterNodeAvailable() throws Exception { - RedisClusterClient clusterClient = RedisClusterClient.create(RedisURI.Builder.redis(host, 40400).build()); + RedisClusterClient clusterClient = RedisClusterClient.create(TestClientResources.get(), RedisURI.Builder.redis(host, 40400).build()); try { clusterClient.connect(); fail("Missing RedisException"); @@ -432,7 +433,7 @@ public void readOnlyOnCluster() throws Exception { sync.readWrite(); assertThat(ReflectionTestUtils.getField(sync.getStatefulConnection(), "readOnly")).isEqualTo(Boolean.FALSE); - RedisClusterClient clusterClient = RedisClusterClient.create(RedisURI.Builder.redis(host, 40400).build()); + RedisClusterClient clusterClient = RedisClusterClient.create(TestClientResources.get(), RedisURI.Builder.redis(host, 40400).build()); try { clusterClient.connect(); fail("Missing RedisException"); diff --git a/src/test/java/com/lambdaworks/redis/cluster/RedisClusterPasswordSecuredSslTest.java b/src/test/java/com/lambdaworks/redis/cluster/RedisClusterPasswordSecuredSslTest.java index 111b1b0304..3fff656970 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/RedisClusterPasswordSecuredSslTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/RedisClusterPasswordSecuredSslTest.java @@ -8,6 +8,7 @@ import java.util.List; import java.util.stream.Collectors; +import com.lambdaworks.TestClientResources; import org.junit.AfterClass; import org.junit.Before; import org.junit.Test; @@ -39,7 +40,7 @@ public class RedisClusterPasswordSecuredSslTest extends AbstractTest { public static RedisURI redisURI = RedisURI.builder().redis(host(), CLUSTER_PORT_SSL_1).withPassword("foobared") .withSsl(true).withVerifyPeer(false).build(); - public static RedisClusterClient redisClient = RedisClusterClient.create(redisURI); + public static RedisClusterClient redisClient = RedisClusterClient.create(TestClientResources.get(), redisURI); @Before public void before() throws Exception { @@ -123,7 +124,7 @@ public void connectionWithoutPasswordShouldFail() throws Exception { RedisURI redisURI = RedisURI.builder().redis(host(), CLUSTER_PORT_SSL_1).withSsl(true).withVerifyPeer(false) .build(); - RedisClusterClient redisClusterClient = RedisClusterClient.create(redisURI); + RedisClusterClient redisClusterClient = RedisClusterClient.create(TestClientResources.get(), redisURI); try { redisClusterClient.reloadPartitions(); @@ -139,7 +140,7 @@ public void connectionWithoutPasswordShouldFail2() throws Exception { RedisURI redisURI = RedisURI.builder().redis(host(), CLUSTER_PORT_SSL_1).withSsl(true).withVerifyPeer(false) .build(); - RedisClusterClient redisClusterClient = RedisClusterClient.create(redisURI); + RedisClusterClient redisClusterClient = RedisClusterClient.create(TestClientResources.get(), redisURI); try { redisClusterClient.connect(); diff --git a/src/test/java/com/lambdaworks/redis/cluster/RedisClusterReadFromTest.java b/src/test/java/com/lambdaworks/redis/cluster/RedisClusterReadFromTest.java index bd7b01293a..0f9aef7397 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/RedisClusterReadFromTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/RedisClusterReadFromTest.java @@ -4,6 +4,7 @@ import java.util.Collections; +import com.lambdaworks.TestClientResources; import org.junit.*; import org.junit.runners.MethodSorters; @@ -23,7 +24,8 @@ public class RedisClusterReadFromTest extends AbstractClusterTest { @BeforeClass public static void setupClient() throws Exception { setupClusterClient(); - clusterClient = RedisClusterClient.create(Collections.singletonList(RedisURI.Builder.redis(host, port1).build())); + clusterClient = RedisClusterClient.create( + TestClientResources.get(), Collections.singletonList(RedisURI.Builder.redis(host, port1).build())); } @AfterClass diff --git a/src/test/java/com/lambdaworks/redis/cluster/RedisClusterSetupTest.java b/src/test/java/com/lambdaworks/redis/cluster/RedisClusterSetupTest.java index 90a323b3d3..dfe8a71cc5 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/RedisClusterSetupTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/RedisClusterSetupTest.java @@ -13,6 +13,7 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import com.lambdaworks.TestClientResources; import org.junit.*; import com.google.code.tempusfugit.temporal.Condition; @@ -58,7 +59,8 @@ public class RedisClusterSetupTest extends AbstractTest { @BeforeClass public static void setupClient() { - clusterClient = RedisClusterClient.create(RedisURI.Builder.redis(host, AbstractClusterTest.port5).build()); + clusterClient = RedisClusterClient.create( + TestClientResources.get(), RedisURI.Builder.redis(host, AbstractClusterTest.port5).build()); } @AfterClass diff --git a/src/test/java/com/lambdaworks/redis/cluster/RedisClusterStressScenariosTest.java b/src/test/java/com/lambdaworks/redis/cluster/RedisClusterStressScenariosTest.java index 286d7deac6..abafa964be 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/RedisClusterStressScenariosTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/RedisClusterStressScenariosTest.java @@ -11,6 +11,7 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import com.lambdaworks.TestClientResources; import org.junit.*; import org.junit.runners.MethodSorters; @@ -52,8 +53,8 @@ public class RedisClusterStressScenariosTest extends AbstractTest { @BeforeClass public static void setupClient() throws Exception { - client = RedisClient.create(RedisURI.Builder.redis(host, AbstractClusterTest.port5).build()); - clusterClient = RedisClusterClient.create( + client = RedisClient.create(TestClientResources.get(), RedisURI.Builder.redis(host, AbstractClusterTest.port5).build()); + clusterClient = RedisClusterClient.create(TestClientResources.get(), Collections.singletonList(RedisURI.Builder.redis(host, AbstractClusterTest.port5) .build())); } diff --git a/src/test/java/com/lambdaworks/redis/cluster/RedisRxClusterClientTest.java b/src/test/java/com/lambdaworks/redis/cluster/RedisRxClusterClientTest.java index 626dac4ef7..5200e8188a 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/RedisRxClusterClientTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/RedisRxClusterClientTest.java @@ -6,6 +6,7 @@ import java.util.Collections; import java.util.List; +import com.lambdaworks.TestClientResources; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; @@ -38,8 +39,8 @@ public class RedisRxClusterClientTest extends AbstractClusterTest { @BeforeClass public static void setupClient() throws Exception { setupClusterClient(); - client = RedisClient.create(RedisURI.Builder.redis(host, port1).build()); - clusterClient = RedisClusterClient.create(Collections.singletonList(RedisURI.Builder.redis(host, port1).build())); + client = RedisClient.create(TestClientResources.get(), RedisURI.Builder.redis(host, port1).build()); + clusterClient = RedisClusterClient.create(TestClientResources.get(), Collections.singletonList(RedisURI.Builder.redis(host, port1).build())); } @AfterClass diff --git a/src/test/java/com/lambdaworks/redis/cluster/commands/CustomClusterCommandTest.java b/src/test/java/com/lambdaworks/redis/cluster/commands/CustomClusterCommandTest.java index 23abe9b280..34c3b98a3a 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/commands/CustomClusterCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/commands/CustomClusterCommandTest.java @@ -2,6 +2,7 @@ import static org.assertj.core.api.Assertions.assertThat; +import com.lambdaworks.TestClientResources; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; @@ -32,7 +33,7 @@ public class CustomClusterCommandTest extends AbstractClusterTest { @BeforeClass public static void setupClient() { - redisClusterClient = RedisClusterClient.create( + redisClusterClient = RedisClusterClient.create(TestClientResources.get(), RedisURI.Builder.redis(TestSettings.host(), TestSettings.port(900)).build()); } diff --git a/src/test/java/com/lambdaworks/redis/cluster/commands/GeoClusterCommandTest.java b/src/test/java/com/lambdaworks/redis/cluster/commands/GeoClusterCommandTest.java index 281edb8c21..5d4f01c8a5 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/commands/GeoClusterCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/commands/GeoClusterCommandTest.java @@ -2,6 +2,7 @@ import static com.lambdaworks.redis.cluster.ClusterTestUtil.flushDatabaseOfAllNodes; +import com.lambdaworks.TestClientResources; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; @@ -25,7 +26,7 @@ public class GeoClusterCommandTest extends GeoCommandTest { @BeforeClass public static void setupClient() { - redisClusterClient = RedisClusterClient.create( + redisClusterClient = RedisClusterClient.create(TestClientResources.get(), RedisURI.Builder.redis(TestSettings.host(), TestSettings.port(900)).build()); } diff --git a/src/test/java/com/lambdaworks/redis/cluster/commands/HashClusterCommandTest.java b/src/test/java/com/lambdaworks/redis/cluster/commands/HashClusterCommandTest.java index 50dce303c7..31c4a576fd 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/commands/HashClusterCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/commands/HashClusterCommandTest.java @@ -1,5 +1,6 @@ package com.lambdaworks.redis.cluster.commands; +import com.lambdaworks.TestClientResources; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; @@ -23,7 +24,8 @@ public class HashClusterCommandTest extends HashCommandTest { @BeforeClass public static void setupClient() { - redisClusterClient = RedisClusterClient.create(RedisURI.Builder.redis(TestSettings.host(), TestSettings.port(900)).build()); + redisClusterClient = RedisClusterClient.create( + TestClientResources.get(), RedisURI.Builder.redis(TestSettings.host(), TestSettings.port(900)).build()); } @AfterClass diff --git a/src/test/java/com/lambdaworks/redis/cluster/commands/KeyClusterCommandTest.java b/src/test/java/com/lambdaworks/redis/cluster/commands/KeyClusterCommandTest.java index 0539530639..2b4bfb3bed 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/commands/KeyClusterCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/commands/KeyClusterCommandTest.java @@ -56,9 +56,9 @@ public void del() throws Exception { redis.set("b", "value"); assertThat(redis.del(key, "a", "b")).isEqualTo(3); - assertThat(redis.exists(key)).isFalse(); - assertThat(redis.exists("a")).isFalse(); - assertThat(redis.exists("b")).isFalse(); + assertThat(redis.exists(key)).isEqualTo(0); + assertThat(redis.exists("a")).isEqualTo(0); + assertThat(redis.exists("b")).isEqualTo(0); } @Test @@ -92,7 +92,7 @@ public void unlink() throws Exception { redis.set("b", "value"); assertThat(redis.unlink(key, "a", "b")).isEqualTo(3); - assertThat(redis.exists(key)).isFalse(); + assertThat(redis.exists(key)).isEqualTo(0); } } diff --git a/src/test/java/com/lambdaworks/redis/cluster/commands/ListClusterCommandTest.java b/src/test/java/com/lambdaworks/redis/cluster/commands/ListClusterCommandTest.java index 7457bf7da6..8be0f120a0 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/commands/ListClusterCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/commands/ListClusterCommandTest.java @@ -1,5 +1,6 @@ package com.lambdaworks.redis.cluster.commands; +import com.lambdaworks.TestClientResources; import org.assertj.core.api.Assertions; import org.junit.AfterClass; import org.junit.Before; @@ -26,7 +27,8 @@ public class ListClusterCommandTest extends ListCommandTest { @BeforeClass public static void setupClient() { - redisClusterClient = RedisClusterClient.create(RedisURI.Builder.redis(TestSettings.host(), TestSettings.port(900)).build()); + redisClusterClient = RedisClusterClient.create( + TestClientResources.get(), RedisURI.Builder.redis(TestSettings.host(), TestSettings.port(900)).build()); } @AfterClass diff --git a/src/test/java/com/lambdaworks/redis/cluster/commands/StringClusterCommandTest.java b/src/test/java/com/lambdaworks/redis/cluster/commands/StringClusterCommandTest.java index a97e2a5305..b791f47b26 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/commands/StringClusterCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/commands/StringClusterCommandTest.java @@ -5,6 +5,7 @@ import java.util.LinkedHashMap; import java.util.Map; +import com.lambdaworks.TestClientResources; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; @@ -30,7 +31,8 @@ public class StringClusterCommandTest extends StringCommandTest { @BeforeClass public static void setupClient() { - redisClusterClient = RedisClusterClient.create(RedisURI.Builder.redis(TestSettings.host(), TestSettings.port(900)).build()); + redisClusterClient = RedisClusterClient.create( + TestClientResources.get(), RedisURI.Builder.redis(TestSettings.host(), TestSettings.port(900)).build()); } @AfterClass diff --git a/src/test/java/com/lambdaworks/redis/cluster/commands/rx/KeyClusterRxCommandTest.java b/src/test/java/com/lambdaworks/redis/cluster/commands/rx/KeyClusterRxCommandTest.java index 7b79a2baf6..d7f93062a6 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/commands/rx/KeyClusterRxCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/commands/rx/KeyClusterRxCommandTest.java @@ -1,5 +1,6 @@ package com.lambdaworks.redis.cluster.commands.rx; +import com.lambdaworks.TestClientResources; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; @@ -23,7 +24,7 @@ public class KeyClusterRxCommandTest extends KeyClusterCommandTest { @BeforeClass public static void setupClient() { - redisClusterClient = new RedisClusterClient( + redisClusterClient = RedisClusterClient.create(TestClientResources.get(), RedisURI.Builder.redis(TestSettings.host(), TestSettings.port(900)).build()); } diff --git a/src/test/java/com/lambdaworks/redis/masterslave/MasterSlaveSentinelTest.java b/src/test/java/com/lambdaworks/redis/masterslave/MasterSlaveSentinelTest.java index 523f3adcf8..55aac7e02c 100644 --- a/src/test/java/com/lambdaworks/redis/masterslave/MasterSlaveSentinelTest.java +++ b/src/test/java/com/lambdaworks/redis/masterslave/MasterSlaveSentinelTest.java @@ -28,7 +28,7 @@ public class MasterSlaveSentinelTest extends AbstractSentinelTest { static { - sentinelClient = RedisClient.create(TestClientResources.create(), + sentinelClient = RedisClient.create(TestClientResources.get(), RedisURI.Builder.sentinel(TestSettings.host(), MASTER_ID).build()); } diff --git a/src/test/java/com/lambdaworks/redis/pubsub/PubSubCommandTest.java b/src/test/java/com/lambdaworks/redis/pubsub/PubSubCommandTest.java index 57b38b8a5f..471d0463b7 100644 --- a/src/test/java/com/lambdaworks/redis/pubsub/PubSubCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/pubsub/PubSubCommandTest.java @@ -13,6 +13,7 @@ import java.util.concurrent.BlockingQueue; import java.util.concurrent.TimeUnit; +import com.lambdaworks.TestClientResources; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -257,7 +258,7 @@ public void unsubscribe() throws Exception { @Test public void pubsubCloseOnClientShutdown() throws Exception { - RedisClient redisClient = RedisClient.create(RedisURI.Builder.redis(host, port).build()); + RedisClient redisClient = RedisClient.create(TestClientResources.get(), RedisURI.Builder.redis(host, port).build()); RedisPubSubAsyncCommands connection = redisClient.connectPubSub().async(); diff --git a/src/test/java/com/lambdaworks/redis/pubsub/PubSubRxTest.java b/src/test/java/com/lambdaworks/redis/pubsub/PubSubRxTest.java index 135ce84ec9..3f5da62c6c 100644 --- a/src/test/java/com/lambdaworks/redis/pubsub/PubSubRxTest.java +++ b/src/test/java/com/lambdaworks/redis/pubsub/PubSubRxTest.java @@ -10,6 +10,7 @@ import java.util.concurrent.BlockingQueue; import java.util.concurrent.TimeUnit; +import com.lambdaworks.TestClientResources; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -286,7 +287,8 @@ public void unsubscribe() throws Exception { @Test public void pubsubCloseOnClientShutdown() throws Exception { - RedisClient redisClient = RedisClient.create(RedisURI.Builder.redis(host, port).build()); + RedisClient redisClient = RedisClient.create(TestClientResources.get(), RedisURI.Builder.redis(host, port).build()); + RedisPubSubCommands connection = redisClient.connectPubSub().sync(); FastShutdown.shutdown(redisClient); diff --git a/src/test/java/com/lambdaworks/redis/sentinel/SentinelCommandTest.java b/src/test/java/com/lambdaworks/redis/sentinel/SentinelCommandTest.java index 853f46f378..76f19d3869 100644 --- a/src/test/java/com/lambdaworks/redis/sentinel/SentinelCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/sentinel/SentinelCommandTest.java @@ -9,6 +9,7 @@ import java.util.List; import java.util.Map; +import com.lambdaworks.TestClientResources; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Rule; @@ -76,7 +77,7 @@ public void masters() throws Exception { @Test public void sentinelConnectWith() throws Exception { - RedisClient client = RedisClient.create( + RedisClient client = RedisClient.create(TestClientResources.get(), RedisURI.Builder.sentinel(TestSettings.host(), 1234, MASTER_ID).withSentinel(TestSettings.host()).build()); RedisSentinelCommands sentinelConnection = client.connectSentinel().sync(); @@ -98,7 +99,7 @@ public void sentinelConnectWith() throws Exception { @Test public void sentinelConnectWrongMaster() throws Exception { - RedisClient client = RedisClient.create( + RedisClient client = RedisClient.create(TestClientResources.get(), RedisURI.Builder.sentinel(TestSettings.host(), 1234, "nonexistent").withSentinel(TestSettings.host()).build()); try { client.connect(); @@ -112,13 +113,14 @@ public void sentinelConnectWrongMaster() throws Exception { @Test public void sentinelConnect() throws Exception { - RedisClient client = RedisClient.create(RedisURI.Builder.redis(TestSettings.host(), TestSettings.port()).build()); + RedisClient client = DefaultRedisClient.get(); - RedisSentinelCommands connection = client.connectSentinel().sync(); + RedisURI redisURI = RedisURI.Builder.redis(TestSettings.host(), TestSettings.port()).build(); + RedisSentinelCommands connection = client + .connectSentinel(redisURI).sync(); assertThat(connection.ping()).isEqualTo("PONG"); connection.getStatefulConnection().close(); - FastShutdown.shutdown(client); } @Test diff --git a/src/test/java/com/lambdaworks/redis/sentinel/SentinelConnectionTest.java b/src/test/java/com/lambdaworks/redis/sentinel/SentinelConnectionTest.java index 2fabac5a1d..fb5cae9f88 100644 --- a/src/test/java/com/lambdaworks/redis/sentinel/SentinelConnectionTest.java +++ b/src/test/java/com/lambdaworks/redis/sentinel/SentinelConnectionTest.java @@ -7,6 +7,7 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; +import com.lambdaworks.TestClientResources; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; @@ -28,7 +29,7 @@ public class SentinelConnectionTest extends AbstractSentinelTest { @BeforeClass public static void setupClient() { - sentinelClient = RedisClient.create(RedisURI.Builder.sentinel(TestSettings.host(), MASTER_ID).build()); + sentinelClient = RedisClient.create(TestClientResources.get(), RedisURI.Builder.sentinel(TestSettings.host(), MASTER_ID).build()); } @Before From 8a77ea031977da8aebbbc4f35264ba1f975506b4 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Mon, 25 Jul 2016 22:50:50 +0200 Subject: [PATCH 005/808] Make DefaultEventPublisherOptions.Builder constructor private and expose builder() method --- .../redis/event/DefaultEventPublisherOptions.java | 13 +++++++++++-- .../event/DefaultEventPublisherOptionsTest.java | 2 +- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/lambdaworks/redis/event/DefaultEventPublisherOptions.java b/src/main/java/com/lambdaworks/redis/event/DefaultEventPublisherOptions.java index 80b634e63c..c05ca16c91 100644 --- a/src/main/java/com/lambdaworks/redis/event/DefaultEventPublisherOptions.java +++ b/src/main/java/com/lambdaworks/redis/event/DefaultEventPublisherOptions.java @@ -20,11 +20,20 @@ public class DefaultEventPublisherOptions implements EventPublisherOptions { private final long eventEmitInterval; private final TimeUnit eventEmitIntervalUnit; - protected DefaultEventPublisherOptions(Builder builder) { + private DefaultEventPublisherOptions(Builder builder) { this.eventEmitInterval = builder.eventEmitInterval; this.eventEmitIntervalUnit = builder.eventEmitIntervalUnit; } + /** + * Returns a new {@link DefaultEventPublisherOptions.Builder} to construct {@link DefaultEventPublisherOptions}. + * + * @return a new {@link DefaultEventPublisherOptions.Builder} to construct {@link DefaultEventPublisherOptions}. + */ + public static Builder builder(){ + return new Builder(); + } + /** * Builder for {@link DefaultEventPublisherOptions}. */ @@ -33,7 +42,7 @@ public static class Builder { private long eventEmitInterval = DEFAULT_EMIT_INTERVAL; private TimeUnit eventEmitIntervalUnit = DEFAULT_EMIT_INTERVAL_UNIT; - public Builder() { + private Builder() { } /** diff --git a/src/test/java/com/lambdaworks/redis/event/DefaultEventPublisherOptionsTest.java b/src/test/java/com/lambdaworks/redis/event/DefaultEventPublisherOptionsTest.java index 004e909587..ccb0ce6621 100644 --- a/src/test/java/com/lambdaworks/redis/event/DefaultEventPublisherOptionsTest.java +++ b/src/test/java/com/lambdaworks/redis/event/DefaultEventPublisherOptionsTest.java @@ -32,7 +32,7 @@ public void testDisabled() throws Exception { @Test public void testBuilder() throws Exception { - DefaultEventPublisherOptions sut = new DefaultEventPublisherOptions.Builder().eventEmitInterval(1, TimeUnit.SECONDS) + DefaultEventPublisherOptions sut = DefaultEventPublisherOptions.builder().eventEmitInterval(1, TimeUnit.SECONDS) .build(); assertThat(sut.eventEmitInterval()).isEqualTo(1); From 8a3656953636e33889d03557b72dc71182d0723c Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Tue, 26 Jul 2016 00:49:29 +0200 Subject: [PATCH 006/808] Use Single and Completable types in RxJava reactive API #214 --- .../redis/AbstractRedisReactiveCommands.java | 1102 +++++++++-------- .../redis/ReactiveCommandDispatcher.java | 170 ++- .../api/rx/BaseRedisReactiveCommands.java | 20 +- .../api/rx/RedisGeoReactiveCommands.java | 12 +- .../api/rx/RedisHLLReactiveCommands.java | 8 +- .../api/rx/RedisHashReactiveCommands.java | 48 +- .../api/rx/RedisKeyReactiveCommands.java | 76 +- .../api/rx/RedisListReactiveCommands.java | 36 +- .../redis/api/rx/RedisReactiveCommands.java | 5 +- .../rx/RedisScriptingReactiveCommands.java | 8 +- .../api/rx/RedisServerReactiveCommands.java | 70 +- .../api/rx/RedisSetReactiveCommands.java | 48 +- .../rx/RedisSortedSetReactiveCommands.java | 106 +- .../api/rx/RedisStringReactiveCommands.java | 60 +- .../RedisTransactionalReactiveCommands.java | 10 +- .../redis/cluster/ClusterScanSupport.java | 36 +- ...isAdvancedClusterReactiveCommandsImpl.java | 160 +-- .../RedisAdvancedClusterReactiveCommands.java | 48 +- .../api/rx/RedisClusterReactiveCommands.java | 57 +- .../redis/protocol/CommandHandler.java | 2 +- .../RedisPubSubReactiveCommandsImpl.java | 26 +- .../api/rx/RedisPubSubReactiveCommands.java | 9 +- .../RedisSentinelReactiveCommandsImpl.java | 51 +- .../api/rx/RedisSentinelReactiveCommands.java | 18 +- .../CreateAsyncNodeSelectionClusterApi.java | 1 - .../apigenerator/CreateReactiveApi.java | 44 +- .../redis/LettucePerformanceTest.java | 15 +- .../redis/ReactiveConnectionTest.java | 50 +- .../cluster/AdvancedClusterReactiveTest.java | 70 +- .../cluster/ClusterReactiveCommandTest.java | 18 +- .../cluster/RedisRxClusterClientTest.java | 29 +- .../commands/CustomClusterCommandTest.java | 3 +- .../redis/commands/CustomCommandTest.java | 2 +- .../commands/rx/RxSyncInvocationHandler.java | 65 +- .../commands/rx/TransactionRxCommandTest.java | 23 +- .../redis/pubsub/PubSubRxTest.java | 31 +- .../redis/reliability/AtMostOnceTest.java | 4 + 37 files changed, 1398 insertions(+), 1143 deletions(-) diff --git a/src/main/java/com/lambdaworks/redis/AbstractRedisReactiveCommands.java b/src/main/java/com/lambdaworks/redis/AbstractRedisReactiveCommands.java index 194c4d50f0..b637ec3d24 100644 --- a/src/main/java/com/lambdaworks/redis/AbstractRedisReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/AbstractRedisReactiveCommands.java @@ -9,7 +9,9 @@ import com.lambdaworks.redis.internal.LettuceAssert; import com.lambdaworks.redis.protocol.*; +import rx.Completable; import rx.Observable; +import rx.Single; import rx.Subscriber; import com.lambdaworks.redis.GeoArgs.Unit; @@ -51,34 +53,34 @@ public AbstractRedisReactiveCommands(StatefulConnection connection, RedisC } @Override - public Observable append(K key, V value) { - return createObservable(() -> commandBuilder.append(key, value)); + public Single append(K key, V value) { + return createSingle(() -> commandBuilder.append(key, value)); } @Override - public Observable auth(String password) { - return createObservable(() -> commandBuilder.auth(password)); + public Single auth(String password) { + return createSingle(() -> commandBuilder.auth(password)); } @Override - public Observable bgrewriteaof() { - return createObservable(commandBuilder::bgrewriteaof); + public Single bgrewriteaof() { + return createSingle(commandBuilder::bgrewriteaof); } @Override - public Observable bgsave() { - return createObservable(commandBuilder::bgsave); + public Single bgsave() { + return createSingle(commandBuilder::bgsave); } @Override - public Observable bitcount(K key) { - return createObservable(() -> commandBuilder.bitcount(key)); + public Single bitcount(K key) { + return createSingle(() -> commandBuilder.bitcount(key)); } @Override - public Observable bitcount(K key, long start, long end) { - return createObservable(() -> commandBuilder.bitcount(key, start, end)); + public Single bitcount(K key, long start, long end) { + return createSingle(() -> commandBuilder.bitcount(key, start, end)); } @Override @@ -87,78 +89,78 @@ public Observable bitfield(K key, BitFieldArgs args) { } @Override - public Observable bitpos(K key, boolean state) { - return createObservable(() -> commandBuilder.bitpos(key, state)); + public Single bitpos(K key, boolean state) { + return createSingle(() -> commandBuilder.bitpos(key, state)); } @Override - public Observable bitpos(K key, boolean state, long start, long end) { - return createObservable(() -> commandBuilder.bitpos(key, state, start, end)); + public Single bitpos(K key, boolean state, long start, long end) { + return createSingle(() -> commandBuilder.bitpos(key, state, start, end)); } @Override - public Observable bitopAnd(K destination, K... keys) { - return createObservable(() -> commandBuilder.bitopAnd(destination, keys)); + public Single bitopAnd(K destination, K... keys) { + return createSingle(() -> commandBuilder.bitopAnd(destination, keys)); } @Override - public Observable bitopNot(K destination, K source) { - return createObservable(() -> commandBuilder.bitopNot(destination, source)); + public Single bitopNot(K destination, K source) { + return createSingle(() -> commandBuilder.bitopNot(destination, source)); } @Override - public Observable bitopOr(K destination, K... keys) { - return createObservable(() -> commandBuilder.bitopOr(destination, keys)); + public Single bitopOr(K destination, K... keys) { + return createSingle(() -> commandBuilder.bitopOr(destination, keys)); } @Override - public Observable bitopXor(K destination, K... keys) { - return createObservable(() -> commandBuilder.bitopXor(destination, keys)); + public Single bitopXor(K destination, K... keys) { + return createSingle(() -> commandBuilder.bitopXor(destination, keys)); } @Override - public Observable> blpop(long timeout, K... keys) { - return createObservable(() -> commandBuilder.blpop(timeout, keys)); + public Single> blpop(long timeout, K... keys) { + return createSingle(() -> commandBuilder.blpop(timeout, keys)); } @Override - public Observable> brpop(long timeout, K... keys) { - return createObservable(() -> commandBuilder.brpop(timeout, keys)); + public Single> brpop(long timeout, K... keys) { + return createSingle(() -> commandBuilder.brpop(timeout, keys)); } @Override - public Observable brpoplpush(long timeout, K source, K destination) { - return createObservable(() -> commandBuilder.brpoplpush(timeout, source, destination)); + public Single brpoplpush(long timeout, K source, K destination) { + return createSingle(() -> commandBuilder.brpoplpush(timeout, source, destination)); } @Override - public Observable clientGetname() { - return createObservable(commandBuilder::clientGetname); + public Single clientGetname() { + return createSingle(commandBuilder::clientGetname); } @Override - public Observable clientSetname(K name) { - return createObservable(() -> commandBuilder.clientSetname(name)); + public Single clientSetname(K name) { + return createSingle(() -> commandBuilder.clientSetname(name)); } @Override - public Observable clientKill(String addr) { - return createObservable(() -> commandBuilder.clientKill(addr)); + public Single clientKill(String addr) { + return createSingle(() -> commandBuilder.clientKill(addr)); } @Override - public Observable clientKill(KillArgs killArgs) { - return createObservable(() -> commandBuilder.clientKill(killArgs)); + public Single clientKill(KillArgs killArgs) { + return createSingle(() -> commandBuilder.clientKill(killArgs)); } @Override - public Observable clientPause(long timeout) { - return createObservable(() -> commandBuilder.clientPause(timeout)); + public Single clientPause(long timeout) { + return createSingle(() -> commandBuilder.clientPause(timeout)); } @Override - public Observable clientList() { - return createObservable(commandBuilder::clientList); + public Single clientList() { + return createSingle(commandBuilder::clientList); } @Override @@ -182,8 +184,8 @@ public Observable commandInfo(CommandType... commands) { } @Override - public Observable commandCount() { - return createObservable(commandBuilder::commandCount); + public Single commandCount() { + return createSingle(commandBuilder::commandCount); } @Override @@ -192,106 +194,106 @@ public Observable configGet(String parameter) { } @Override - public Observable configResetstat() { - return createObservable(commandBuilder::configResetstat); + public Single configResetstat() { + return createSingle(commandBuilder::configResetstat); } @Override - public Observable configSet(String parameter, String value) { - return createObservable(() -> commandBuilder.configSet(parameter, value)); + public Single configSet(String parameter, String value) { + return createSingle(() -> commandBuilder.configSet(parameter, value)); } @Override - public Observable configRewrite() { - return createObservable(commandBuilder::configRewrite); + public Single configRewrite() { + return createSingle(commandBuilder::configRewrite); } @Override - public Observable dbsize() { - return createObservable(commandBuilder::dbsize); + public Single dbsize() { + return createSingle(commandBuilder::dbsize); } @Override - public Observable debugCrashAndRecover(Long delay) { - return createObservable(() -> (commandBuilder.debugCrashAndRecover(delay))); + public Single debugCrashAndRecover(Long delay) { + return createSingle(() -> (commandBuilder.debugCrashAndRecover(delay))); } @Override - public Observable debugHtstats(int db) { - return createObservable(() -> commandBuilder.debugHtstats(db)); + public Single debugHtstats(int db) { + return createSingle(() -> commandBuilder.debugHtstats(db)); } @Override - public Observable debugObject(K key) { - return createObservable(() -> commandBuilder.debugObject(key)); + public Single debugObject(K key) { + return createSingle(() -> commandBuilder.debugObject(key)); } @Override - public Observable debugOom() { - return Observable.just(Success.Success).doOnCompleted(commandBuilder::debugOom); + public Completable debugOom() { + return Completable.fromObservable(createObservable(commandBuilder::debugOom)); } @Override - public Observable debugReload() { - return createObservable(() -> (commandBuilder.debugReload())); + public Single debugReload() { + return createSingle(() -> (commandBuilder.debugReload())); } @Override - public Observable debugRestart(Long delay) { - return createObservable(() -> (commandBuilder.debugRestart(delay))); + public Single debugRestart(Long delay) { + return createSingle(() -> (commandBuilder.debugRestart(delay))); } @Override - public Observable debugSdslen(K key) { - return createObservable(() -> (commandBuilder.debugSdslen(key))); + public Single debugSdslen(K key) { + return createSingle(() -> (commandBuilder.debugSdslen(key))); } @Override - public Observable debugSegfault() { - return Observable.just(Success.Success).doOnCompleted(commandBuilder::debugSegfault); + public Completable debugSegfault() { + return Completable.fromObservable(createObservable(commandBuilder::debugSegfault)); } @Override - public Observable decr(K key) { - return createObservable(() -> commandBuilder.decr(key)); + public Single decr(K key) { + return createSingle(() -> commandBuilder.decr(key)); } @Override - public Observable decrby(K key, long amount) { - return createObservable(() -> commandBuilder.decrby(key, amount)); + public Single decrby(K key, long amount) { + return createSingle(() -> commandBuilder.decrby(key, amount)); } @Override - public Observable del(K... keys) { - return createObservable(() -> commandBuilder.del(keys)); + public Single del(K... keys) { + return createSingle(() -> commandBuilder.del(keys)); } - public Observable del(Iterable keys) { - return createObservable(() -> commandBuilder.del(keys)); + public Single del(Iterable keys) { + return createSingle(() -> commandBuilder.del(keys)); } @Override - public Observable unlink(K... keys) { - return createObservable(() -> commandBuilder.unlink(keys)); + public Single unlink(K... keys) { + return createSingle(() -> commandBuilder.unlink(keys)); } - public Observable unlink(Iterable keys) { - return createObservable(() -> commandBuilder.unlink(keys)); + public Single unlink(Iterable keys) { + return createSingle(() -> commandBuilder.unlink(keys)); } @Override - public Observable discard() { - return createObservable(commandBuilder::discard); + public Single discard() { + return createSingle(commandBuilder::discard); } @Override - public Observable dump(K key) { - return createObservable(() -> commandBuilder.dump(key)); + public Single dump(K key) { + return createSingle(() -> commandBuilder.dump(key)); } @Override - public Observable echo(V msg) { - return createObservable(() -> commandBuilder.echo(msg)); + public Single echo(V msg) { + return createSingle(() -> commandBuilder.echo(msg)); } @Override @@ -318,31 +320,31 @@ public Observable evalsha(String digest, ScriptOutputType type, K[] keys, return (Observable) createObservable(() -> commandBuilder.evalsha(digest, type, keys, values)); } - public Observable exists(K key) { - return createObservable(() -> commandBuilder.exists(key)); + public Single exists(K key) { + return createSingle(() -> commandBuilder.exists(key)); } @Override - public Observable exists(K... keys) { - return createObservable(() -> commandBuilder.exists(keys)); + public Single exists(K... keys) { + return createSingle(() -> commandBuilder.exists(keys)); } - public Observable exists(Iterable keys) { - return createObservable(() -> commandBuilder.exists(keys)); + public Single exists(Iterable keys) { + return createSingle(() -> commandBuilder.exists(keys)); } @Override - public Observable expire(K key, long seconds) { - return createObservable(() -> commandBuilder.expire(key, seconds)); + public Single expire(K key, long seconds) { + return createSingle(() -> commandBuilder.expire(key, seconds)); } @Override - public Observable expireat(K key, long timestamp) { - return createObservable(() -> commandBuilder.expireat(key, timestamp)); + public Single expireat(K key, long timestamp) { + return createSingle(() -> commandBuilder.expireat(key, timestamp)); } @Override - public Observable expireat(K key, Date timestamp) { + public Single expireat(K key, Date timestamp) { return expireat(key, timestamp.getTime() / 1000); } @@ -352,78 +354,78 @@ public Observable exec() { } @Override - public Observable flushall() { - return createObservable(commandBuilder::flushall); + public Single flushall() { + return createSingle(commandBuilder::flushall); } @Override - public Observable flushallAsync() { - return createObservable(commandBuilder::flushallAsync); + public Single flushallAsync() { + return createSingle(commandBuilder::flushallAsync); } @Override - public Observable flushdb() { - return createObservable(commandBuilder::flushdb); + public Single flushdb() { + return createSingle(commandBuilder::flushdb); } @Override - public Observable flushdbAsync() { - return createObservable(commandBuilder::flushdbAsync); + public Single flushdbAsync() { + return createSingle(commandBuilder::flushdbAsync); } @Override - public Observable get(K key) { - return createObservable(() -> commandBuilder.get(key)); + public Single get(K key) { + return createSingle(() -> commandBuilder.get(key)); } @Override - public Observable getbit(K key, long offset) { - return createObservable(() -> commandBuilder.getbit(key, offset)); + public Single getbit(K key, long offset) { + return createSingle(() -> commandBuilder.getbit(key, offset)); } @Override - public Observable getrange(K key, long start, long end) { - return createObservable(() -> commandBuilder.getrange(key, start, end)); + public Single getrange(K key, long start, long end) { + return createSingle(() -> commandBuilder.getrange(key, start, end)); } @Override - public Observable getset(K key, V value) { - return createObservable(() -> commandBuilder.getset(key, value)); + public Single getset(K key, V value) { + return createSingle(() -> commandBuilder.getset(key, value)); } @Override - public Observable hdel(K key, K... fields) { - return createObservable(() -> commandBuilder.hdel(key, fields)); + public Single hdel(K key, K... fields) { + return createSingle(() -> commandBuilder.hdel(key, fields)); } @Override - public Observable hexists(K key, K field) { - return createObservable(() -> commandBuilder.hexists(key, field)); + public Single hexists(K key, K field) { + return createSingle(() -> commandBuilder.hexists(key, field)); } @Override - public Observable hget(K key, K field) { - return createObservable(() -> commandBuilder.hget(key, field)); + public Single hget(K key, K field) { + return createSingle(() -> commandBuilder.hget(key, field)); } @Override - public Observable hincrby(K key, K field, long amount) { - return createObservable(() -> commandBuilder.hincrby(key, field, amount)); + public Single hincrby(K key, K field, long amount) { + return createSingle(() -> commandBuilder.hincrby(key, field, amount)); } @Override - public Observable hincrbyfloat(K key, K field, double amount) { - return createObservable(() -> commandBuilder.hincrbyfloat(key, field, amount)); + public Single hincrbyfloat(K key, K field, double amount) { + return createSingle(() -> commandBuilder.hincrbyfloat(key, field, amount)); } @Override - public Observable> hgetall(K key) { - return createObservable(() -> commandBuilder.hgetall(key)); + public Single> hgetall(K key) { + return createSingle(() -> commandBuilder.hgetall(key)); } @Override - public Observable hgetall(KeyValueStreamingChannel channel, K key) { - return createObservable(() -> commandBuilder.hgetall(channel, key)); + public Single hgetall(KeyValueStreamingChannel channel, K key) { + return createSingle(() -> commandBuilder.hgetall(channel, key)); } @Override @@ -432,18 +434,18 @@ public Observable hkeys(K key) { } @Override - public Observable hkeys(KeyStreamingChannel channel, K key) { - return createObservable(() -> commandBuilder.hkeys(channel, key)); + public Single hkeys(KeyStreamingChannel channel, K key) { + return createSingle(() -> commandBuilder.hkeys(channel, key)); } @Override - public Observable hlen(K key) { - return createObservable(() -> commandBuilder.hlen(key)); + public Single hlen(K key) { + return createSingle(() -> commandBuilder.hlen(key)); } @Override - public Observable hstrlen(K key, K field) { - return createObservable(() -> commandBuilder.hstrlen(key, field)); + public Single hstrlen(K key, K field) { + return createSingle(() -> commandBuilder.hstrlen(key, field)); } @Override @@ -452,23 +454,23 @@ public Observable hmget(K key, K... fields) { } @Override - public Observable hmget(ValueStreamingChannel channel, K key, K... fields) { - return createObservable(() -> commandBuilder.hmget(channel, key, fields)); + public Single hmget(ValueStreamingChannel channel, K key, K... fields) { + return createSingle(() -> commandBuilder.hmget(channel, key, fields)); } @Override - public Observable hmset(K key, Map map) { - return createObservable(() -> commandBuilder.hmset(key, map)); + public Single hmset(K key, Map map) { + return createSingle(() -> commandBuilder.hmset(key, map)); } @Override - public Observable hset(K key, K field, V value) { - return createObservable(() -> commandBuilder.hset(key, field, value)); + public Single hset(K key, K field, V value) { + return createSingle(() -> commandBuilder.hset(key, field, value)); } @Override - public Observable hsetnx(K key, K field, V value) { - return createObservable(() -> commandBuilder.hsetnx(key, field, value)); + public Single hsetnx(K key, K field, V value) { + return createSingle(() -> commandBuilder.hsetnx(key, field, value)); } @Override @@ -477,33 +479,33 @@ public Observable hvals(K key) { } @Override - public Observable hvals(ValueStreamingChannel channel, K key) { - return createObservable(() -> commandBuilder.hvals(channel, key)); + public Single hvals(ValueStreamingChannel channel, K key) { + return createSingle(() -> commandBuilder.hvals(channel, key)); } @Override - public Observable incr(K key) { - return createObservable(() -> commandBuilder.incr(key)); + public Single incr(K key) { + return createSingle(() -> commandBuilder.incr(key)); } @Override - public Observable incrby(K key, long amount) { - return createObservable(() -> commandBuilder.incrby(key, amount)); + public Single incrby(K key, long amount) { + return createSingle(() -> commandBuilder.incrby(key, amount)); } @Override - public Observable incrbyfloat(K key, double amount) { - return createObservable(() -> commandBuilder.incrbyfloat(key, amount)); + public Single incrbyfloat(K key, double amount) { + return createSingle(() -> commandBuilder.incrbyfloat(key, amount)); } @Override - public Observable info() { - return createObservable(commandBuilder::info); + public Single info() { + return createSingle(commandBuilder::info); } @Override - public Observable info(String section) { - return createObservable(() -> commandBuilder.info(section)); + public Single info(String section) { + return createSingle(() -> commandBuilder.info(section)); } @Override @@ -512,43 +514,43 @@ public Observable keys(K pattern) { } @Override - public Observable keys(KeyStreamingChannel channel, K pattern) { - return createObservable(() -> commandBuilder.keys(channel, pattern)); + public Single keys(KeyStreamingChannel channel, K pattern) { + return createSingle(() -> commandBuilder.keys(channel, pattern)); } @Override - public Observable lastsave() { - return createObservable(commandBuilder::lastsave); + public Single lastsave() { + return createSingle(commandBuilder::lastsave); } @Override - public Observable lindex(K key, long index) { - return createObservable(() -> commandBuilder.lindex(key, index)); + public Single lindex(K key, long index) { + return createSingle(() -> commandBuilder.lindex(key, index)); } @Override - public Observable linsert(K key, boolean before, V pivot, V value) { - return createObservable(() -> commandBuilder.linsert(key, before, pivot, value)); + public Single linsert(K key, boolean before, V pivot, V value) { + return createSingle(() -> commandBuilder.linsert(key, before, pivot, value)); } @Override - public Observable llen(K key) { - return createObservable(() -> commandBuilder.llen(key)); + public Single llen(K key) { + return createSingle(() -> commandBuilder.llen(key)); } @Override - public Observable lpop(K key) { - return createObservable(() -> commandBuilder.lpop(key)); + public Single lpop(K key) { + return createSingle(() -> commandBuilder.lpop(key)); } @Override - public Observable lpush(K key, V... values) { - return createObservable(() -> commandBuilder.lpush(key, values)); + public Single lpush(K key, V... values) { + return createSingle(() -> commandBuilder.lpush(key, values)); } @Override - public Observable lpushx(K key, V... values) { - return createObservable(() -> commandBuilder.lpushx(key, values)); + public Single lpushx(K key, V... values) { + return createSingle(() -> commandBuilder.lpushx(key, values)); } @Override @@ -557,33 +559,33 @@ public Observable lrange(K key, long start, long stop) { } @Override - public Observable lrange(ValueStreamingChannel channel, K key, long start, long stop) { - return createObservable(() -> commandBuilder.lrange(channel, key, start, stop)); + public Single lrange(ValueStreamingChannel channel, K key, long start, long stop) { + return createSingle(() -> commandBuilder.lrange(channel, key, start, stop)); } @Override - public Observable lrem(K key, long count, V value) { - return createObservable(() -> commandBuilder.lrem(key, count, value)); + public Single lrem(K key, long count, V value) { + return createSingle(() -> commandBuilder.lrem(key, count, value)); } @Override - public Observable lset(K key, long index, V value) { - return createObservable(() -> commandBuilder.lset(key, index, value)); + public Single lset(K key, long index, V value) { + return createSingle(() -> commandBuilder.lset(key, index, value)); } @Override - public Observable ltrim(K key, long start, long stop) { - return createObservable(() -> commandBuilder.ltrim(key, start, stop)); + public Single ltrim(K key, long start, long stop) { + return createSingle(() -> commandBuilder.ltrim(key, start, stop)); } @Override - public Observable migrate(String host, int port, K key, int db, long timeout) { - return createObservable(() -> commandBuilder.migrate(host, port, key, db, timeout)); + public Single migrate(String host, int port, K key, int db, long timeout) { + return createSingle(() -> commandBuilder.migrate(host, port, key, db, timeout)); } @Override - public Observable migrate(String host, int port, int db, long timeout, MigrateArgs migrateArgs) { - return createObservable(() -> commandBuilder.migrate(host, port, db, timeout, migrateArgs)); + public Single migrate(String host, int port, int db, long timeout, MigrateArgs migrateArgs) { + return createSingle(() -> commandBuilder.migrate(host, port, db, timeout, migrateArgs)); } @Override @@ -596,92 +598,92 @@ public Observable mget(Iterable keys) { } @Override - public Observable mget(ValueStreamingChannel channel, K... keys) { - return createObservable(() -> commandBuilder.mget(channel, keys)); + public Single mget(ValueStreamingChannel channel, K... keys) { + return createSingle(() -> commandBuilder.mget(channel, keys)); } - public Observable mget(ValueStreamingChannel channel, Iterable keys) { - return createObservable(() -> commandBuilder.mget(channel, keys)); + public Single mget(ValueStreamingChannel channel, Iterable keys) { + return createSingle(() -> commandBuilder.mget(channel, keys)); } @Override - public Observable move(K key, int db) { - return createObservable(() -> commandBuilder.move(key, db)); + public Single move(K key, int db) { + return createSingle(() -> commandBuilder.move(key, db)); } @Override - public Observable multi() { - return createObservable(commandBuilder::multi); + public Single multi() { + return createSingle(commandBuilder::multi); } @Override - public Observable mset(Map map) { - return createObservable(() -> commandBuilder.mset(map)); + public Single mset(Map map) { + return createSingle(() -> commandBuilder.mset(map)); } @Override - public Observable msetnx(Map map) { - return createObservable(() -> commandBuilder.msetnx(map)); + public Single msetnx(Map map) { + return createSingle(() -> commandBuilder.msetnx(map)); } @Override - public Observable objectEncoding(K key) { - return createObservable(() -> commandBuilder.objectEncoding(key)); + public Single objectEncoding(K key) { + return createSingle(() -> commandBuilder.objectEncoding(key)); } @Override - public Observable objectIdletime(K key) { - return createObservable(() -> commandBuilder.objectIdletime(key)); + public Single objectIdletime(K key) { + return createSingle(() -> commandBuilder.objectIdletime(key)); } @Override - public Observable objectRefcount(K key) { - return createObservable(() -> commandBuilder.objectRefcount(key)); + public Single objectRefcount(K key) { + return createSingle(() -> commandBuilder.objectRefcount(key)); } @Override - public Observable persist(K key) { - return createObservable(() -> commandBuilder.persist(key)); + public Single persist(K key) { + return createSingle(() -> commandBuilder.persist(key)); } @Override - public Observable pexpire(K key, long milliseconds) { - return createObservable(() -> commandBuilder.pexpire(key, milliseconds)); + public Single pexpire(K key, long milliseconds) { + return createSingle(() -> commandBuilder.pexpire(key, milliseconds)); } @Override - public Observable pexpireat(K key, Date timestamp) { + public Single pexpireat(K key, Date timestamp) { return pexpireat(key, timestamp.getTime()); } @Override - public Observable pexpireat(K key, long timestamp) { - return createObservable(() -> commandBuilder.pexpireat(key, timestamp)); + public Single pexpireat(K key, long timestamp) { + return createSingle(() -> commandBuilder.pexpireat(key, timestamp)); } @Override - public Observable ping() { - return createObservable(commandBuilder::ping); + public Single ping() { + return createSingle(commandBuilder::ping); } @Override - public Observable readOnly() { - return createObservable(commandBuilder::readOnly); + public Single readOnly() { + return createSingle(commandBuilder::readOnly); } @Override - public Observable readWrite() { - return createObservable(commandBuilder::readWrite); + public Single readWrite() { + return createSingle(commandBuilder::readWrite); } @Override - public Observable pttl(K key) { - return createObservable(() -> commandBuilder.pttl(key)); + public Single pttl(K key) { + return createSingle(() -> commandBuilder.pttl(key)); } @Override - public Observable publish(K channel, V message) { - return createObservable(() -> commandBuilder.publish(channel, message)); + public Single publish(K channel, V message) { + return createSingle(() -> commandBuilder.publish(channel, message)); } @Override @@ -695,18 +697,18 @@ public Observable pubsubChannels(K channel) { } @Override - public Observable> pubsubNumsub(K... channels) { - return createObservable(() -> commandBuilder.pubsubNumsub(channels)); + public Single> pubsubNumsub(K... channels) { + return createSingle(() -> commandBuilder.pubsubNumsub(channels)); } @Override - public Observable pubsubNumpat() { - return createObservable(commandBuilder::pubsubNumpat); + public Single pubsubNumpat() { + return createSingle(commandBuilder::pubsubNumpat); } @Override - public Observable quit() { - return createObservable(commandBuilder::quit); + public Single quit() { + return createSingle(commandBuilder::quit); } @Override @@ -715,58 +717,58 @@ public Observable role() { } @Override - public Observable randomkey() { - return createObservable(commandBuilder::randomkey); + public Single randomkey() { + return createSingle(commandBuilder::randomkey); } @Override - public Observable rename(K key, K newKey) { - return createObservable(() -> commandBuilder.rename(key, newKey)); + public Single rename(K key, K newKey) { + return createSingle(() -> commandBuilder.rename(key, newKey)); } @Override - public Observable renamenx(K key, K newKey) { - return createObservable(() -> commandBuilder.renamenx(key, newKey)); + public Single renamenx(K key, K newKey) { + return createSingle(() -> commandBuilder.renamenx(key, newKey)); } @Override - public Observable restore(K key, long ttl, byte[] value) { - return createObservable(() -> commandBuilder.restore(key, ttl, value)); + public Single restore(K key, long ttl, byte[] value) { + return createSingle(() -> commandBuilder.restore(key, ttl, value)); } @Override - public Observable rpop(K key) { - return createObservable(() -> commandBuilder.rpop(key)); + public Single rpop(K key) { + return createSingle(() -> commandBuilder.rpop(key)); } @Override - public Observable rpoplpush(K source, K destination) { - return createObservable(() -> commandBuilder.rpoplpush(source, destination)); + public Single rpoplpush(K source, K destination) { + return createSingle(() -> commandBuilder.rpoplpush(source, destination)); } @Override - public Observable rpush(K key, V... values) { - return createObservable(() -> commandBuilder.rpush(key, values)); + public Single rpush(K key, V... values) { + return createSingle(() -> commandBuilder.rpush(key, values)); } @Override - public Observable rpushx(K key, V... values) { - return createObservable(() -> commandBuilder.rpushx(key, values)); + public Single rpushx(K key, V... values) { + return createSingle(() -> commandBuilder.rpushx(key, values)); } @Override - public Observable sadd(K key, V... members) { - return createObservable(() -> commandBuilder.sadd(key, members)); + public Single sadd(K key, V... members) { + return createSingle(() -> commandBuilder.sadd(key, members)); } @Override - public Observable save() { - return createObservable(commandBuilder::save); + public Single save() { + return createSingle(commandBuilder::save); } @Override - public Observable scard(K key) { - return createObservable(() -> commandBuilder.scard(key)); + public Single scard(K key) { + return createSingle(() -> commandBuilder.scard(key)); } @Override @@ -775,18 +777,18 @@ public Observable scriptExists(String... digests) { } @Override - public Observable scriptFlush() { - return createObservable(commandBuilder::scriptFlush); + public Single scriptFlush() { + return createSingle(commandBuilder::scriptFlush); } @Override - public Observable scriptKill() { - return createObservable(commandBuilder::scriptKill); + public Single scriptKill() { + return createSingle(commandBuilder::scriptKill); } @Override - public Observable scriptLoad(V script) { - return createObservable(() -> commandBuilder.scriptLoad(script)); + public Single scriptLoad(V script) { + return createSingle(() -> commandBuilder.scriptLoad(script)); } @Override @@ -795,57 +797,57 @@ public Observable sdiff(K... keys) { } @Override - public Observable sdiff(ValueStreamingChannel channel, K... keys) { - return createObservable(() -> commandBuilder.sdiff(channel, keys)); + public Single sdiff(ValueStreamingChannel channel, K... keys) { + return createSingle(() -> commandBuilder.sdiff(channel, keys)); } @Override - public Observable sdiffstore(K destination, K... keys) { - return createObservable(() -> commandBuilder.sdiffstore(destination, keys)); + public Single sdiffstore(K destination, K... keys) { + return createSingle(() -> commandBuilder.sdiffstore(destination, keys)); } - public Observable select(int db) { - return createObservable(() -> commandBuilder.select(db)); + public Single select(int db) { + return createSingle(() -> commandBuilder.select(db)); } @Override - public Observable set(K key, V value) { - return createObservable(() -> commandBuilder.set(key, value)); + public Single set(K key, V value) { + return createSingle(() -> commandBuilder.set(key, value)); } @Override - public Observable set(K key, V value, SetArgs setArgs) { - return createObservable(() -> commandBuilder.set(key, value, setArgs)); + public Single set(K key, V value, SetArgs setArgs) { + return createSingle(() -> commandBuilder.set(key, value, setArgs)); } @Override - public Observable setbit(K key, long offset, int value) { - return createObservable(() -> commandBuilder.setbit(key, offset, value)); + public Single setbit(K key, long offset, int value) { + return createSingle(() -> commandBuilder.setbit(key, offset, value)); } @Override - public Observable setex(K key, long seconds, V value) { - return createObservable(() -> commandBuilder.setex(key, seconds, value)); + public Single setex(K key, long seconds, V value) { + return createSingle(() -> commandBuilder.setex(key, seconds, value)); } @Override - public Observable psetex(K key, long milliseconds, V value) { - return createObservable(() -> commandBuilder.psetex(key, milliseconds, value)); + public Single psetex(K key, long milliseconds, V value) { + return createSingle(() -> commandBuilder.psetex(key, milliseconds, value)); } @Override - public Observable setnx(K key, V value) { - return createObservable(() -> commandBuilder.setnx(key, value)); + public Single setnx(K key, V value) { + return createSingle(() -> commandBuilder.setnx(key, value)); } @Override - public Observable setrange(K key, long offset, V value) { - return createObservable(() -> commandBuilder.setrange(key, offset, value)); + public Single setrange(K key, long offset, V value) { + return createSingle(() -> commandBuilder.setrange(key, offset, value)); } @Override - public Observable shutdown(boolean save) { - return getSuccessObservable(createObservable(() -> commandBuilder.shutdown(save))); + public Completable shutdown(boolean save) { + return Completable.fromObservable(createObservable(() -> commandBuilder.shutdown(save))); } @Override @@ -854,33 +856,33 @@ public Observable sinter(K... keys) { } @Override - public Observable sinter(ValueStreamingChannel channel, K... keys) { - return createObservable(() -> commandBuilder.sinter(channel, keys)); + public Single sinter(ValueStreamingChannel channel, K... keys) { + return createSingle(() -> commandBuilder.sinter(channel, keys)); } @Override - public Observable sinterstore(K destination, K... keys) { - return createObservable(() -> commandBuilder.sinterstore(destination, keys)); + public Single sinterstore(K destination, K... keys) { + return createSingle(() -> commandBuilder.sinterstore(destination, keys)); } @Override - public Observable sismember(K key, V member) { - return createObservable(() -> commandBuilder.sismember(key, member)); + public Single sismember(K key, V member) { + return createSingle(() -> commandBuilder.sismember(key, member)); } @Override - public Observable smove(K source, K destination, V member) { - return createObservable(() -> commandBuilder.smove(source, destination, member)); + public Single smove(K source, K destination, V member) { + return createSingle(() -> commandBuilder.smove(source, destination, member)); } @Override - public Observable slaveof(String host, int port) { - return createObservable(() -> commandBuilder.slaveof(host, port)); + public Single slaveof(String host, int port) { + return createSingle(() -> commandBuilder.slaveof(host, port)); } @Override - public Observable slaveofNoOne() { - return createObservable(() -> commandBuilder.slaveofNoOne()); + public Single slaveofNoOne() { + return createSingle(() -> commandBuilder.slaveofNoOne()); } @Override @@ -894,13 +896,13 @@ public Observable slowlogGet(int count) { } @Override - public Observable slowlogLen() { - return createObservable(() -> commandBuilder.slowlogLen()); + public Single slowlogLen() { + return createSingle(() -> commandBuilder.slowlogLen()); } @Override - public Observable slowlogReset() { - return createObservable(() -> commandBuilder.slowlogReset()); + public Single slowlogReset() { + return createSingle(() -> commandBuilder.slowlogReset()); } @Override @@ -909,8 +911,8 @@ public Observable smembers(K key) { } @Override - public Observable smembers(ValueStreamingChannel channel, K key) { - return createObservable(() -> commandBuilder.smembers(channel, key)); + public Single smembers(ValueStreamingChannel channel, K key) { + return createSingle(() -> commandBuilder.smembers(channel, key)); } @Override @@ -919,8 +921,8 @@ public Observable sort(K key) { } @Override - public Observable sort(ValueStreamingChannel channel, K key) { - return createObservable(() -> commandBuilder.sort(channel, key)); + public Single sort(ValueStreamingChannel channel, K key) { + return createSingle(() -> commandBuilder.sort(channel, key)); } @Override @@ -929,18 +931,18 @@ public Observable sort(K key, SortArgs sortArgs) { } @Override - public Observable sort(ValueStreamingChannel channel, K key, SortArgs sortArgs) { - return createObservable(() -> commandBuilder.sort(channel, key, sortArgs)); + public Single sort(ValueStreamingChannel channel, K key, SortArgs sortArgs) { + return createSingle(() -> commandBuilder.sort(channel, key, sortArgs)); } @Override - public Observable sortStore(K key, SortArgs sortArgs, K destination) { - return createObservable(() -> commandBuilder.sortStore(key, sortArgs, destination)); + public Single sortStore(K key, SortArgs sortArgs, K destination) { + return createSingle(() -> commandBuilder.sortStore(key, sortArgs, destination)); } @Override - public Observable spop(K key) { - return createObservable(() -> commandBuilder.spop(key)); + public Single spop(K key) { + return createSingle(() -> commandBuilder.spop(key)); } @Override @@ -949,8 +951,8 @@ public Observable spop(K key, long count) { } @Override - public Observable srandmember(K key) { - return createObservable(() -> commandBuilder.srandmember(key)); + public Single srandmember(K key) { + return createSingle(() -> commandBuilder.srandmember(key)); } @Override @@ -959,13 +961,13 @@ public Observable srandmember(K key, long count) { } @Override - public Observable srandmember(ValueStreamingChannel channel, K key, long count) { - return createObservable(() -> commandBuilder.srandmember(channel, key, count)); + public Single srandmember(ValueStreamingChannel channel, K key, long count) { + return createSingle(() -> commandBuilder.srandmember(channel, key, count)); } @Override - public Observable srem(K key, V... members) { - return createObservable(() -> commandBuilder.srem(key, members)); + public Single srem(K key, V... members) { + return createSingle(() -> commandBuilder.srem(key, members)); } @Override @@ -974,112 +976,112 @@ public Observable sunion(K... keys) { } @Override - public Observable sunion(ValueStreamingChannel channel, K... keys) { - return createObservable(() -> commandBuilder.sunion(channel, keys)); + public Single sunion(ValueStreamingChannel channel, K... keys) { + return createSingle(() -> commandBuilder.sunion(channel, keys)); } @Override - public Observable sunionstore(K destination, K... keys) { - return createObservable(() -> commandBuilder.sunionstore(destination, keys)); + public Single sunionstore(K destination, K... keys) { + return createSingle(() -> commandBuilder.sunionstore(destination, keys)); } @Override - public Observable strlen(K key) { - return createObservable(() -> commandBuilder.strlen(key)); + public Single strlen(K key) { + return createSingle(() -> commandBuilder.strlen(key)); } @Override - public Observable touch(K... keys) { - return createObservable(() -> commandBuilder.touch(keys)); + public Single touch(K... keys) { + return createSingle(() -> commandBuilder.touch(keys)); } - public Observable touch(Iterable keys) { - return createObservable(() -> commandBuilder.touch(keys)); + public Single touch(Iterable keys) { + return createSingle(() -> commandBuilder.touch(keys)); } @Override - public Observable ttl(K key) { - return createObservable(() -> commandBuilder.ttl(key)); + public Single ttl(K key) { + return createSingle(() -> commandBuilder.ttl(key)); } @Override - public Observable type(K key) { - return createObservable(() -> commandBuilder.type(key)); + public Single type(K key) { + return createSingle(() -> commandBuilder.type(key)); } @Override - public Observable watch(K... keys) { - return createObservable(() -> commandBuilder.watch(keys)); + public Single watch(K... keys) { + return createSingle(() -> commandBuilder.watch(keys)); } @Override - public Observable unwatch() { - return createObservable(commandBuilder::unwatch); + public Single unwatch() { + return createSingle(commandBuilder::unwatch); } @Override - public Observable zadd(K key, double score, V member) { - return createObservable(() -> commandBuilder.zadd(key, null, score, member)); + public Single zadd(K key, double score, V member) { + return createSingle(() -> commandBuilder.zadd(key, null, score, member)); } @Override - public Observable zadd(K key, Object... scoresAndValues) { - return createObservable(() -> commandBuilder.zadd(key, null, scoresAndValues)); + public Single zadd(K key, Object... scoresAndValues) { + return createSingle(() -> commandBuilder.zadd(key, null, scoresAndValues)); } @Override - public Observable zadd(K key, ScoredValue... scoredValues) { - return createObservable(() -> commandBuilder.zadd(key, null, scoredValues)); + public Single zadd(K key, ScoredValue... scoredValues) { + return createSingle(() -> commandBuilder.zadd(key, null, scoredValues)); } @Override - public Observable zadd(K key, ZAddArgs zAddArgs, double score, V member) { - return createObservable(() -> commandBuilder.zadd(key, zAddArgs, score, member)); + public Single zadd(K key, ZAddArgs zAddArgs, double score, V member) { + return createSingle(() -> commandBuilder.zadd(key, zAddArgs, score, member)); } @Override - public Observable zadd(K key, ZAddArgs zAddArgs, Object... scoresAndValues) { - return createObservable(() -> commandBuilder.zadd(key, zAddArgs, scoresAndValues)); + public Single zadd(K key, ZAddArgs zAddArgs, Object... scoresAndValues) { + return createSingle(() -> commandBuilder.zadd(key, zAddArgs, scoresAndValues)); } @Override - public Observable zadd(K key, ZAddArgs zAddArgs, ScoredValue... scoredValues) { - return createObservable(() -> commandBuilder.zadd(key, zAddArgs, scoredValues)); + public Single zadd(K key, ZAddArgs zAddArgs, ScoredValue... scoredValues) { + return createSingle(() -> commandBuilder.zadd(key, zAddArgs, scoredValues)); } @Override - public Observable zaddincr(K key, double score, V member) { - return createObservable(() -> commandBuilder.zaddincr(key, score, member)); + public Single zaddincr(K key, double score, V member) { + return createSingle(() -> commandBuilder.zaddincr(key, score, member)); } @Override - public Observable zcard(K key) { - return createObservable(() -> commandBuilder.zcard(key)); + public Single zcard(K key) { + return createSingle(() -> commandBuilder.zcard(key)); } @Override - public Observable zcount(K key, double min, double max) { - return createObservable(() -> commandBuilder.zcount(key, min, max)); + public Single zcount(K key, double min, double max) { + return createSingle(() -> commandBuilder.zcount(key, min, max)); } @Override - public Observable zcount(K key, String min, String max) { - return createObservable(() -> commandBuilder.zcount(key, min, max)); + public Single zcount(K key, String min, String max) { + return createSingle(() -> commandBuilder.zcount(key, min, max)); } @Override - public Observable zincrby(K key, double amount, K member) { - return createObservable(() -> commandBuilder.zincrby(key, amount, member)); + public Single zincrby(K key, double amount, K member) { + return createSingle(() -> commandBuilder.zincrby(key, amount, member)); } @Override - public Observable zinterstore(K destination, K... keys) { - return createObservable(() -> commandBuilder.zinterstore(destination, keys)); + public Single zinterstore(K destination, K... keys) { + return createSingle(() -> commandBuilder.zinterstore(destination, keys)); } @Override - public Observable zinterstore(K destination, ZStoreArgs storeArgs, K... keys) { - return createObservable(() -> commandBuilder.zinterstore(destination, storeArgs, keys)); + public Single zinterstore(K destination, ZStoreArgs storeArgs, K... keys) { + return createSingle(() -> commandBuilder.zinterstore(destination, storeArgs, keys)); } @Override @@ -1133,82 +1135,82 @@ public Observable> zrangebyscoreWithScores(K key, String min, Str } @Override - public Observable zrange(ValueStreamingChannel channel, K key, long start, long stop) { - return createObservable(() -> commandBuilder.zrange(channel, key, start, stop)); + public Single zrange(ValueStreamingChannel channel, K key, long start, long stop) { + return createSingle(() -> commandBuilder.zrange(channel, key, start, stop)); } @Override - public Observable zrangeWithScores(ScoredValueStreamingChannel channel, K key, long start, long stop) { - return createObservable(() -> commandBuilder.zrangeWithScores(channel, key, start, stop)); + public Single zrangeWithScores(ScoredValueStreamingChannel channel, K key, long start, long stop) { + return createSingle(() -> commandBuilder.zrangeWithScores(channel, key, start, stop)); } @Override - public Observable zrangebyscore(ValueStreamingChannel channel, K key, double min, double max) { - return createObservable(() -> commandBuilder.zrangebyscore(channel, key, min, max)); + public Single zrangebyscore(ValueStreamingChannel channel, K key, double min, double max) { + return createSingle(() -> commandBuilder.zrangebyscore(channel, key, min, max)); } @Override - public Observable zrangebyscore(ValueStreamingChannel channel, K key, String min, String max) { - return createObservable(() -> commandBuilder.zrangebyscore(channel, key, min, max)); + public Single zrangebyscore(ValueStreamingChannel channel, K key, String min, String max) { + return createSingle(() -> commandBuilder.zrangebyscore(channel, key, min, max)); } @Override - public Observable zrangebyscore(ValueStreamingChannel channel, K key, double min, double max, long offset, + public Single zrangebyscore(ValueStreamingChannel channel, K key, double min, double max, long offset, long count) { - return createObservable(() -> commandBuilder.zrangebyscore(channel, key, min, max, offset, count)); + return createSingle(() -> commandBuilder.zrangebyscore(channel, key, min, max, offset, count)); } @Override - public Observable zrangebyscore(ValueStreamingChannel channel, K key, String min, String max, long offset, + public Single zrangebyscore(ValueStreamingChannel channel, K key, String min, String max, long offset, long count) { - return createObservable(() -> commandBuilder.zrangebyscore(channel, key, min, max, offset, count)); + return createSingle(() -> commandBuilder.zrangebyscore(channel, key, min, max, offset, count)); } @Override - public Observable zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, double min, double max) { - return createObservable(() -> commandBuilder.zrangebyscoreWithScores(channel, key, min, max)); + public Single zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, double min, double max) { + return createSingle(() -> commandBuilder.zrangebyscoreWithScores(channel, key, min, max)); } @Override - public Observable zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, String min, String max) { - return createObservable(() -> commandBuilder.zrangebyscoreWithScores(channel, key, min, max)); + public Single zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, String min, String max) { + return createSingle(() -> commandBuilder.zrangebyscoreWithScores(channel, key, min, max)); } @Override - public Observable zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, double min, double max, + public Single zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, double min, double max, long offset, long count) { - return createObservable(() -> commandBuilder.zrangebyscoreWithScores(channel, key, min, max, offset, count)); + return createSingle(() -> commandBuilder.zrangebyscoreWithScores(channel, key, min, max, offset, count)); } @Override - public Observable zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, String min, String max, + public Single zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, String min, String max, long offset, long count) { - return createObservable(() -> commandBuilder.zrangebyscoreWithScores(channel, key, min, max, offset, count)); + return createSingle(() -> commandBuilder.zrangebyscoreWithScores(channel, key, min, max, offset, count)); } @Override - public Observable zrank(K key, V member) { - return createObservable(() -> commandBuilder.zrank(key, member)); + public Single zrank(K key, V member) { + return createSingle(() -> commandBuilder.zrank(key, member)); } @Override - public Observable zrem(K key, V... members) { - return createObservable(() -> commandBuilder.zrem(key, members)); + public Single zrem(K key, V... members) { + return createSingle(() -> commandBuilder.zrem(key, members)); } @Override - public Observable zremrangebyrank(K key, long start, long stop) { - return createObservable(() -> commandBuilder.zremrangebyrank(key, start, stop)); + public Single zremrangebyrank(K key, long start, long stop) { + return createSingle(() -> commandBuilder.zremrangebyrank(key, start, stop)); } @Override - public Observable zremrangebyscore(K key, double min, double max) { - return createObservable(() -> commandBuilder.zremrangebyscore(key, min, max)); + public Single zremrangebyscore(K key, double min, double max) { + return createSingle(() -> commandBuilder.zremrangebyscore(key, min, max)); } @Override - public Observable zremrangebyscore(K key, String min, String max) { - return createObservable(() -> commandBuilder.zremrangebyscore(key, min, max)); + public Single zremrangebyscore(K key, String min, String max) { + return createSingle(() -> commandBuilder.zremrangebyscore(key, min, max)); } @Override @@ -1262,239 +1264,239 @@ public Observable> zrevrangebyscoreWithScores(K key, String max, } @Override - public Observable zrevrange(ValueStreamingChannel channel, K key, long start, long stop) { - return createObservable(() -> commandBuilder.zrevrange(channel, key, start, stop)); + public Single zrevrange(ValueStreamingChannel channel, K key, long start, long stop) { + return createSingle(() -> commandBuilder.zrevrange(channel, key, start, stop)); } @Override - public Observable zrevrangeWithScores(ScoredValueStreamingChannel channel, K key, long start, long stop) { - return createObservable(() -> commandBuilder.zrevrangeWithScores(channel, key, start, stop)); + public Single zrevrangeWithScores(ScoredValueStreamingChannel channel, K key, long start, long stop) { + return createSingle(() -> commandBuilder.zrevrangeWithScores(channel, key, start, stop)); } @Override - public Observable zrevrangebyscore(ValueStreamingChannel channel, K key, double max, double min) { - return createObservable(() -> commandBuilder.zrevrangebyscore(channel, key, max, min)); + public Single zrevrangebyscore(ValueStreamingChannel channel, K key, double max, double min) { + return createSingle(() -> commandBuilder.zrevrangebyscore(channel, key, max, min)); } @Override - public Observable zrevrangebyscore(ValueStreamingChannel channel, K key, String max, String min) { - return createObservable(() -> commandBuilder.zrevrangebyscore(channel, key, max, min)); + public Single zrevrangebyscore(ValueStreamingChannel channel, K key, String max, String min) { + return createSingle(() -> commandBuilder.zrevrangebyscore(channel, key, max, min)); } @Override - public Observable zrevrangebyscore(ValueStreamingChannel channel, K key, double max, double min, long offset, + public Single zrevrangebyscore(ValueStreamingChannel channel, K key, double max, double min, long offset, long count) { - return createObservable(() -> commandBuilder.zrevrangebyscore(channel, key, max, min, offset, count)); + return createSingle(() -> commandBuilder.zrevrangebyscore(channel, key, max, min, offset, count)); } @Override - public Observable zrevrangebyscore(ValueStreamingChannel channel, K key, String max, String min, long offset, + public Single zrevrangebyscore(ValueStreamingChannel channel, K key, String max, String min, long offset, long count) { - return createObservable(() -> commandBuilder.zrevrangebyscore(channel, key, max, min, offset, count)); + return createSingle(() -> commandBuilder.zrevrangebyscore(channel, key, max, min, offset, count)); } @Override - public Observable zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, double max, double min) { - return createObservable(() -> commandBuilder.zrevrangebyscoreWithScores(channel, key, max, min)); + public Single zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, double max, double min) { + return createSingle(() -> commandBuilder.zrevrangebyscoreWithScores(channel, key, max, min)); } @Override - public Observable zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, String max, String min) { - return createObservable(() -> commandBuilder.zrevrangebyscoreWithScores(channel, key, max, min)); + public Single zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, String max, String min) { + return createSingle(() -> commandBuilder.zrevrangebyscoreWithScores(channel, key, max, min)); } @Override - public Observable zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, double max, double min, + public Single zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, double max, double min, long offset, long count) { - return createObservable(() -> commandBuilder.zrevrangebyscoreWithScores(channel, key, max, min, offset, count)); + return createSingle(() -> commandBuilder.zrevrangebyscoreWithScores(channel, key, max, min, offset, count)); } @Override - public Observable zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, String max, String min, + public Single zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, String max, String min, long offset, long count) { - return createObservable(() -> commandBuilder.zrevrangebyscoreWithScores(channel, key, max, min, offset, count)); + return createSingle(() -> commandBuilder.zrevrangebyscoreWithScores(channel, key, max, min, offset, count)); } @Override - public Observable zrevrank(K key, V member) { - return createObservable(() -> commandBuilder.zrevrank(key, member)); + public Single zrevrank(K key, V member) { + return createSingle(() -> commandBuilder.zrevrank(key, member)); } @Override - public Observable zscore(K key, V member) { - return createObservable(() -> commandBuilder.zscore(key, member)); + public Single zscore(K key, V member) { + return createSingle(() -> commandBuilder.zscore(key, member)); } @Override - public Observable zunionstore(K destination, K... keys) { - return createObservable(() -> commandBuilder.zunionstore(destination, keys)); + public Single zunionstore(K destination, K... keys) { + return createSingle(() -> commandBuilder.zunionstore(destination, keys)); } @Override - public Observable zunionstore(K destination, ZStoreArgs storeArgs, K... keys) { - return createObservable(() -> commandBuilder.zunionstore(destination, storeArgs, keys)); + public Single zunionstore(K destination, ZStoreArgs storeArgs, K... keys) { + return createSingle(() -> commandBuilder.zunionstore(destination, storeArgs, keys)); } @Override - public Observable> scan() { - return createObservable(commandBuilder::scan); + public Single> scan() { + return createSingle(commandBuilder::scan); } @Override - public Observable> scan(ScanArgs scanArgs) { - return createObservable(() -> commandBuilder.scan(scanArgs)); + public Single> scan(ScanArgs scanArgs) { + return createSingle(() -> commandBuilder.scan(scanArgs)); } @Override - public Observable> scan(ScanCursor scanCursor, ScanArgs scanArgs) { - return createObservable(() -> commandBuilder.scan(scanCursor, scanArgs)); + public Single> scan(ScanCursor scanCursor, ScanArgs scanArgs) { + return createSingle(() -> commandBuilder.scan(scanCursor, scanArgs)); } @Override - public Observable> scan(ScanCursor scanCursor) { - return createObservable(() -> commandBuilder.scan(scanCursor)); + public Single> scan(ScanCursor scanCursor) { + return createSingle(() -> commandBuilder.scan(scanCursor)); } @Override - public Observable scan(KeyStreamingChannel channel) { - return createObservable(() -> commandBuilder.scanStreaming(channel)); + public Single scan(KeyStreamingChannel channel) { + return createSingle(() -> commandBuilder.scanStreaming(channel)); } @Override - public Observable scan(KeyStreamingChannel channel, ScanArgs scanArgs) { - return createObservable(() -> commandBuilder.scanStreaming(channel, scanArgs)); + public Single scan(KeyStreamingChannel channel, ScanArgs scanArgs) { + return createSingle(() -> commandBuilder.scanStreaming(channel, scanArgs)); } @Override - public Observable scan(KeyStreamingChannel channel, ScanCursor scanCursor, ScanArgs scanArgs) { - return createObservable(() -> commandBuilder.scanStreaming(channel, scanCursor, scanArgs)); + public Single scan(KeyStreamingChannel channel, ScanCursor scanCursor, ScanArgs scanArgs) { + return createSingle(() -> commandBuilder.scanStreaming(channel, scanCursor, scanArgs)); } @Override - public Observable scan(KeyStreamingChannel channel, ScanCursor scanCursor) { - return createObservable(() -> commandBuilder.scanStreaming(channel, scanCursor)); + public Single scan(KeyStreamingChannel channel, ScanCursor scanCursor) { + return createSingle(() -> commandBuilder.scanStreaming(channel, scanCursor)); } @Override - public Observable> sscan(K key) { - return createObservable(() -> commandBuilder.sscan(key)); + public Single> sscan(K key) { + return createSingle(() -> commandBuilder.sscan(key)); } @Override - public Observable> sscan(K key, ScanArgs scanArgs) { - return createObservable(() -> commandBuilder.sscan(key, scanArgs)); + public Single> sscan(K key, ScanArgs scanArgs) { + return createSingle(() -> commandBuilder.sscan(key, scanArgs)); } @Override - public Observable> sscan(K key, ScanCursor scanCursor, ScanArgs scanArgs) { - return createObservable(() -> commandBuilder.sscan(key, scanCursor, scanArgs)); + public Single> sscan(K key, ScanCursor scanCursor, ScanArgs scanArgs) { + return createSingle(() -> commandBuilder.sscan(key, scanCursor, scanArgs)); } @Override - public Observable> sscan(K key, ScanCursor scanCursor) { - return createObservable(() -> commandBuilder.sscan(key, scanCursor)); + public Single> sscan(K key, ScanCursor scanCursor) { + return createSingle(() -> commandBuilder.sscan(key, scanCursor)); } @Override - public Observable sscan(ValueStreamingChannel channel, K key) { - return createObservable(() -> commandBuilder.sscanStreaming(channel, key)); + public Single sscan(ValueStreamingChannel channel, K key) { + return createSingle(() -> commandBuilder.sscanStreaming(channel, key)); } @Override - public Observable sscan(ValueStreamingChannel channel, K key, ScanArgs scanArgs) { - return createObservable(() -> commandBuilder.sscanStreaming(channel, key, scanArgs)); + public Single sscan(ValueStreamingChannel channel, K key, ScanArgs scanArgs) { + return createSingle(() -> commandBuilder.sscanStreaming(channel, key, scanArgs)); } @Override - public Observable sscan(ValueStreamingChannel channel, K key, ScanCursor scanCursor, ScanArgs scanArgs) { - return createObservable(() -> commandBuilder.sscanStreaming(channel, key, scanCursor, scanArgs)); + public Single sscan(ValueStreamingChannel channel, K key, ScanCursor scanCursor, ScanArgs scanArgs) { + return createSingle(() -> commandBuilder.sscanStreaming(channel, key, scanCursor, scanArgs)); } @Override - public Observable sscan(ValueStreamingChannel channel, K key, ScanCursor scanCursor) { - return createObservable(() -> commandBuilder.sscanStreaming(channel, key, scanCursor)); + public Single sscan(ValueStreamingChannel channel, K key, ScanCursor scanCursor) { + return createSingle(() -> commandBuilder.sscanStreaming(channel, key, scanCursor)); } @Override - public Observable> hscan(K key) { - return createObservable(() -> commandBuilder.hscan(key)); + public Single> hscan(K key) { + return createSingle(() -> commandBuilder.hscan(key)); } @Override - public Observable> hscan(K key, ScanArgs scanArgs) { - return createObservable(() -> commandBuilder.hscan(key, scanArgs)); + public Single> hscan(K key, ScanArgs scanArgs) { + return createSingle(() -> commandBuilder.hscan(key, scanArgs)); } @Override - public Observable> hscan(K key, ScanCursor scanCursor, ScanArgs scanArgs) { - return createObservable(() -> commandBuilder.hscan(key, scanCursor, scanArgs)); + public Single> hscan(K key, ScanCursor scanCursor, ScanArgs scanArgs) { + return createSingle(() -> commandBuilder.hscan(key, scanCursor, scanArgs)); } @Override - public Observable> hscan(K key, ScanCursor scanCursor) { - return createObservable(() -> commandBuilder.hscan(key, scanCursor)); + public Single> hscan(K key, ScanCursor scanCursor) { + return createSingle(() -> commandBuilder.hscan(key, scanCursor)); } @Override - public Observable hscan(KeyValueStreamingChannel channel, K key) { - return createObservable(() -> commandBuilder.hscanStreaming(channel, key)); + public Single hscan(KeyValueStreamingChannel channel, K key) { + return createSingle(() -> commandBuilder.hscanStreaming(channel, key)); } @Override - public Observable hscan(KeyValueStreamingChannel channel, K key, ScanArgs scanArgs) { - return createObservable(() -> commandBuilder.hscanStreaming(channel, key, scanArgs)); + public Single hscan(KeyValueStreamingChannel channel, K key, ScanArgs scanArgs) { + return createSingle(() -> commandBuilder.hscanStreaming(channel, key, scanArgs)); } @Override - public Observable hscan(KeyValueStreamingChannel channel, K key, ScanCursor scanCursor, + public Single hscan(KeyValueStreamingChannel channel, K key, ScanCursor scanCursor, ScanArgs scanArgs) { - return createObservable(() -> commandBuilder.hscanStreaming(channel, key, scanCursor, scanArgs)); + return createSingle(() -> commandBuilder.hscanStreaming(channel, key, scanCursor, scanArgs)); } @Override - public Observable hscan(KeyValueStreamingChannel channel, K key, ScanCursor scanCursor) { - return createObservable(() -> commandBuilder.hscanStreaming(channel, key, scanCursor)); + public Single hscan(KeyValueStreamingChannel channel, K key, ScanCursor scanCursor) { + return createSingle(() -> commandBuilder.hscanStreaming(channel, key, scanCursor)); } @Override - public Observable> zscan(K key) { - return createObservable(() -> commandBuilder.zscan(key)); + public Single> zscan(K key) { + return createSingle(() -> commandBuilder.zscan(key)); } @Override - public Observable> zscan(K key, ScanArgs scanArgs) { - return createObservable(() -> commandBuilder.zscan(key, scanArgs)); + public Single> zscan(K key, ScanArgs scanArgs) { + return createSingle(() -> commandBuilder.zscan(key, scanArgs)); } @Override - public Observable> zscan(K key, ScanCursor scanCursor, ScanArgs scanArgs) { - return createObservable(() -> commandBuilder.zscan(key, scanCursor, scanArgs)); + public Single> zscan(K key, ScanCursor scanCursor, ScanArgs scanArgs) { + return createSingle(() -> commandBuilder.zscan(key, scanCursor, scanArgs)); } @Override - public Observable> zscan(K key, ScanCursor scanCursor) { - return createObservable(() -> commandBuilder.zscan(key, scanCursor)); + public Single> zscan(K key, ScanCursor scanCursor) { + return createSingle(() -> commandBuilder.zscan(key, scanCursor)); } @Override - public Observable zscan(ScoredValueStreamingChannel channel, K key) { - return createObservable(() -> commandBuilder.zscanStreaming(channel, key)); + public Single zscan(ScoredValueStreamingChannel channel, K key) { + return createSingle(() -> commandBuilder.zscanStreaming(channel, key)); } @Override - public Observable zscan(ScoredValueStreamingChannel channel, K key, ScanArgs scanArgs) { - return createObservable(() -> commandBuilder.zscanStreaming(channel, key, scanArgs)); + public Single zscan(ScoredValueStreamingChannel channel, K key, ScanArgs scanArgs) { + return createSingle(() -> commandBuilder.zscanStreaming(channel, key, scanArgs)); } @Override - public Observable zscan(ScoredValueStreamingChannel channel, K key, ScanCursor scanCursor, + public Single zscan(ScoredValueStreamingChannel channel, K key, ScanCursor scanCursor, ScanArgs scanArgs) { - return createObservable(() -> commandBuilder.zscanStreaming(channel, key, scanCursor, scanArgs)); + return createSingle(() -> commandBuilder.zscanStreaming(channel, key, scanCursor, scanArgs)); } @Override - public Observable zscan(ScoredValueStreamingChannel channel, K key, ScanCursor scanCursor) { - return createObservable(() -> commandBuilder.zscanStreaming(channel, key, scanCursor)); + public Single zscan(ScoredValueStreamingChannel channel, K key, ScanCursor scanCursor) { + return createSingle(() -> commandBuilder.zscanStreaming(channel, key, scanCursor)); } @Override @@ -1508,75 +1510,75 @@ public Observable time() { } @Override - public Observable waitForReplication(int replicas, long timeout) { - return createObservable(() -> commandBuilder.wait(replicas, timeout)); + public Single waitForReplication(int replicas, long timeout) { + return createSingle(() -> commandBuilder.wait(replicas, timeout)); } @Override - public Observable pfadd(K key, V... values) { - return createObservable(() -> commandBuilder.pfadd(key, values)); + public Single pfadd(K key, V... values) { + return createSingle(() -> commandBuilder.pfadd(key, values)); } - public Observable pfadd(K key, V value, V... values) { - return createObservable(() -> commandBuilder.pfadd(key, value, values)); + public Single pfadd(K key, V value, V... values) { + return createSingle(() -> commandBuilder.pfadd(key, value, values)); } @Override - public Observable pfmerge(K destkey, K... sourcekeys) { - return createObservable(() -> commandBuilder.pfmerge(destkey, sourcekeys)); + public Single pfmerge(K destkey, K... sourcekeys) { + return createSingle(() -> commandBuilder.pfmerge(destkey, sourcekeys)); } - public Observable pfmerge(K destkey, K sourceKey, K... sourcekeys) { - return createObservable(() -> commandBuilder.pfmerge(destkey, sourceKey, sourcekeys)); + public Single pfmerge(K destkey, K sourceKey, K... sourcekeys) { + return createSingle(() -> commandBuilder.pfmerge(destkey, sourceKey, sourcekeys)); } @Override - public Observable pfcount(K... keys) { - return createObservable(() -> commandBuilder.pfcount(keys)); + public Single pfcount(K... keys) { + return createSingle(() -> commandBuilder.pfcount(keys)); } - public Observable pfcount(K key, K... keys) { - return createObservable(() -> commandBuilder.pfcount(key, keys)); + public Single pfcount(K key, K... keys) { + return createSingle(() -> commandBuilder.pfcount(key, keys)); } @Override - public Observable clusterBumpepoch() { - return createObservable(() -> commandBuilder.clusterBumpepoch()); + public Single clusterBumpepoch() { + return createSingle(() -> commandBuilder.clusterBumpepoch()); } @Override - public Observable clusterMeet(String ip, int port) { - return createObservable(() -> commandBuilder.clusterMeet(ip, port)); + public Single clusterMeet(String ip, int port) { + return createSingle(() -> commandBuilder.clusterMeet(ip, port)); } @Override - public Observable clusterForget(String nodeId) { - return createObservable(() -> commandBuilder.clusterForget(nodeId)); + public Single clusterForget(String nodeId) { + return createSingle(() -> commandBuilder.clusterForget(nodeId)); } @Override - public Observable clusterAddSlots(int... slots) { - return createObservable(() -> commandBuilder.clusterAddslots(slots)); + public Single clusterAddSlots(int... slots) { + return createSingle(() -> commandBuilder.clusterAddslots(slots)); } @Override - public Observable clusterDelSlots(int... slots) { - return createObservable(() -> commandBuilder.clusterDelslots(slots)); + public Single clusterDelSlots(int... slots) { + return createSingle(() -> commandBuilder.clusterDelslots(slots)); } @Override - public Observable clusterInfo() { - return createObservable(commandBuilder::clusterInfo); + public Single clusterInfo() { + return createSingle(commandBuilder::clusterInfo); } @Override - public Observable clusterMyId() { - return createObservable(commandBuilder::clusterMyId); + public Single clusterMyId() { + return createSingle(commandBuilder::clusterMyId); } @Override - public Observable clusterNodes() { - return createObservable(commandBuilder::clusterNodes); + public Single clusterNodes() { + return createSingle(commandBuilder::clusterNodes); } @Override @@ -1585,28 +1587,28 @@ public Observable clusterGetKeysInSlot(int slot, int count) { } @Override - public Observable clusterCountKeysInSlot(int slot) { - return createObservable(() -> commandBuilder.clusterCountKeysInSlot(slot)); + public Single clusterCountKeysInSlot(int slot) { + return createSingle(() -> commandBuilder.clusterCountKeysInSlot(slot)); } @Override - public Observable clusterCountFailureReports(String nodeId) { - return createObservable(() -> commandBuilder.clusterCountFailureReports(nodeId)); + public Single clusterCountFailureReports(String nodeId) { + return createSingle(() -> commandBuilder.clusterCountFailureReports(nodeId)); } @Override - public Observable clusterKeyslot(K key) { - return createObservable(() -> commandBuilder.clusterKeyslot(key)); + public Single clusterKeyslot(K key) { + return createSingle(() -> commandBuilder.clusterKeyslot(key)); } @Override - public Observable clusterSaveconfig() { - return createObservable(() -> commandBuilder.clusterSaveconfig()); + public Single clusterSaveconfig() { + return createSingle(() -> commandBuilder.clusterSaveconfig()); } @Override - public Observable clusterSetConfigEpoch(long configEpoch) { - return createObservable(() -> commandBuilder.clusterSetConfigEpoch(configEpoch)); + public Single clusterSetConfigEpoch(long configEpoch) { + return createSingle(() -> commandBuilder.clusterSetConfigEpoch(configEpoch)); } @Override @@ -1615,48 +1617,48 @@ public Observable clusterSlots() { } @Override - public Observable clusterSetSlotNode(int slot, String nodeId) { - return createObservable(() -> commandBuilder.clusterSetSlotNode(slot, nodeId)); + public Single clusterSetSlotNode(int slot, String nodeId) { + return createSingle(() -> commandBuilder.clusterSetSlotNode(slot, nodeId)); } @Override - public Observable clusterSetSlotStable(int slot) { - return createObservable(() -> commandBuilder.clusterSetSlotStable(slot)); + public Single clusterSetSlotStable(int slot) { + return createSingle(() -> commandBuilder.clusterSetSlotStable(slot)); } @Override - public Observable clusterSetSlotMigrating(int slot, String nodeId) { - return createObservable(() -> commandBuilder.clusterSetSlotMigrating(slot, nodeId)); + public Single clusterSetSlotMigrating(int slot, String nodeId) { + return createSingle(() -> commandBuilder.clusterSetSlotMigrating(slot, nodeId)); } @Override - public Observable clusterSetSlotImporting(int slot, String nodeId) { - return createObservable(() -> commandBuilder.clusterSetSlotImporting(slot, nodeId)); + public Single clusterSetSlotImporting(int slot, String nodeId) { + return createSingle(() -> commandBuilder.clusterSetSlotImporting(slot, nodeId)); } @Override - public Observable clusterFailover(boolean force) { - return createObservable(() -> commandBuilder.clusterFailover(force)); + public Single clusterFailover(boolean force) { + return createSingle(() -> commandBuilder.clusterFailover(force)); } @Override - public Observable clusterReset(boolean hard) { - return createObservable(() -> commandBuilder.clusterReset(hard)); + public Single clusterReset(boolean hard) { + return createSingle(() -> commandBuilder.clusterReset(hard)); } @Override - public Observable asking() { - return createObservable(commandBuilder::asking); + public Single asking() { + return createSingle(commandBuilder::asking); } @Override - public Observable clusterReplicate(String nodeId) { - return createObservable(() -> commandBuilder.clusterReplicate(nodeId)); + public Single clusterReplicate(String nodeId) { + return createSingle(() -> commandBuilder.clusterReplicate(nodeId)); } @Override - public Observable clusterFlushslots() { - return createObservable(commandBuilder::clusterFlushslots); + public Single clusterFlushslots() { + return createSingle(commandBuilder::clusterFlushslots); } @Override @@ -1665,13 +1667,13 @@ public Observable clusterSlaves(String nodeId) { } @Override - public Observable zlexcount(K key, String min, String max) { - return createObservable(() -> commandBuilder.zlexcount(key, min, max)); + public Single zlexcount(K key, String min, String max) { + return createSingle(() -> commandBuilder.zlexcount(key, min, max)); } @Override - public Observable zremrangebylex(K key, String min, String max) { - return createObservable(() -> commandBuilder.zremrangebylex(key, min, max)); + public Single zremrangebylex(K key, String min, String max) { + return createSingle(() -> commandBuilder.zremrangebylex(key, min, max)); } @Override @@ -1685,13 +1687,13 @@ public Observable zrangebylex(K key, String min, String max, long offset, lon } @Override - public Observable geoadd(K key, double longitude, double latitude, V member) { - return createObservable(() -> commandBuilder.geoadd(key, longitude, latitude, member)); + public Single geoadd(K key, double longitude, double latitude, V member) { + return createSingle(() -> commandBuilder.geoadd(key, longitude, latitude, member)); } @Override - public Observable geoadd(K key, Object... lngLatMember) { - return createDissolvingObservable(() -> commandBuilder.geoadd(key, lngLatMember)); + public Single geoadd(K key, Object... lngLatMember) { + return createSingle(() -> commandBuilder.geoadd(key, lngLatMember)); } @Override @@ -1712,9 +1714,9 @@ public Observable> georadius(K key, double longitude, double latitu } @Override - public Observable georadius(K key, double longitude, double latitude, double distance, Unit unit, + public Single georadius(K key, double longitude, double latitude, double distance, Unit unit, GeoRadiusStoreArgs geoRadiusStoreArgs) { - return createDissolvingObservable( + return createSingle( () -> commandBuilder.georadius(key, longitude, latitude, distance, unit.name(), geoRadiusStoreArgs)); } @@ -1729,9 +1731,9 @@ public Observable> georadiusbymember(K key, V member, double distan } @Override - public Observable georadiusbymember(K key, V member, double distance, Unit unit, + public Single georadiusbymember(K key, V member, double distance, Unit unit, GeoRadiusStoreArgs geoRadiusStoreArgs) { - return createDissolvingObservable( + return createSingle( () -> commandBuilder.georadiusbymember(key, member, distance, unit.name(), geoRadiusStoreArgs)); } @@ -1741,8 +1743,8 @@ public Observable geopos(K key, V... members) { } @Override - public Observable geodist(K key, V from, V to, GeoArgs.Unit unit) { - return createDissolvingObservable(() -> commandBuilder.geodist(key, from, to, unit)); + public Single geodist(K key, V from, V to, GeoArgs.Unit unit) { + return createSingle(() -> commandBuilder.geodist(key, from, to, unit)); } public Observable dispatch(ProtocolKeyword type, CommandOutput output) { @@ -1767,18 +1769,26 @@ protected Observable createObservable(CommandType type, CommandOutput Observable createObservable(Supplier> commandSupplier) { - return Observable.create(new ReactiveCommandDispatcher(commandSupplier, connection, false)); + return Observable.create(new ReactiveCommandDispatcher(commandSupplier, connection, false).getObservableSubscriber()); } + protected Single createSingle(CommandType type, CommandOutput output, CommandArgs args) { + return createSingle(() -> new Command<>(type, output, args)); + } + + public Single createSingle(Supplier> commandSupplier) { + return Single.create(new ReactiveCommandDispatcher(commandSupplier, connection, false).getSingleSubscriber()); + } + @SuppressWarnings("unchecked") - public R createDissolvingObservable(Supplier> commandSupplier) { - return (R) Observable.create(new ReactiveCommandDispatcher<>(commandSupplier, connection, true)); + public Observable createDissolvingObservable(Supplier> commandSupplier) { + return (Observable) Observable.create(new ReactiveCommandDispatcher<>(commandSupplier, connection, true).getObservableSubscriber()); } @SuppressWarnings("unchecked") public R createDissolvingObservable(CommandType type, CommandOutput output, CommandArgs args) { return (R) Observable.create(new ReactiveCommandDispatcher(() -> new Command<>(type, output, args), - connection, true)); + connection, true).getObservableSubscriber()); } /** diff --git a/src/main/java/com/lambdaworks/redis/ReactiveCommandDispatcher.java b/src/main/java/com/lambdaworks/redis/ReactiveCommandDispatcher.java index dbacd78b53..985b3df83e 100644 --- a/src/main/java/com/lambdaworks/redis/ReactiveCommandDispatcher.java +++ b/src/main/java/com/lambdaworks/redis/ReactiveCommandDispatcher.java @@ -2,6 +2,7 @@ import java.util.Arrays; import java.util.Collection; +import java.util.concurrent.CancellationException; import java.util.function.Supplier; import com.lambdaworks.redis.api.StatefulConnection; @@ -11,7 +12,10 @@ import com.lambdaworks.redis.protocol.CommandWrapper; import com.lambdaworks.redis.protocol.RedisCommand; +import io.netty.util.internal.logging.InternalLogger; +import io.netty.util.internal.logging.InternalLoggerFactory; import rx.Observable; +import rx.Single; import rx.Subscriber; /** @@ -19,7 +23,9 @@ * * @author Mark Paluch */ -public class ReactiveCommandDispatcher implements Observable.OnSubscribe { +public class ReactiveCommandDispatcher { + + private final static InternalLogger LOG = InternalLoggerFactory.getInstance(ReactiveCommandDispatcher.class); private Supplier> commandSupplier; private volatile RedisCommand command; @@ -53,32 +59,71 @@ public ReactiveCommandDispatcher(Supplier> commandSupplier this.connection = connection; this.dissolve = dissolve; this.command = commandSupplier.get(); + } - @Override - public void call(Subscriber subscriber) { + public Single.OnSubscribe getSingleSubscriber() { + return new SingleSubscriber(); + } - // Reuse the first command but then discard it. - RedisCommand command = this.command; - if (command == null) { - command = commandSupplier.get(); - } + public Observable.OnSubscribe getObservableSubscriber() { + return new ObservableSubscriber(); + } - if (command.getOutput() instanceof StreamingOutput) { - StreamingOutput streamingOutput = (StreamingOutput) command.getOutput(); + private class ObservableSubscriber implements Observable.OnSubscribe { - if (connection instanceof StatefulRedisConnection && ((StatefulRedisConnection) connection).isMulti()) { - streamingOutput.setSubscriber(new DelegatingWrapper( - Arrays.asList(new ObservableSubscriberWrapper<>(subscriber), streamingOutput.getSubscriber()))); - } else { - streamingOutput.setSubscriber(new ObservableSubscriberWrapper<>(subscriber)); + @Override + public void call(Subscriber subscriber) { + + // Reuse the first command but then discard it. + RedisCommand command = ReactiveCommandDispatcher.this.command; + if (command == null) { + command = commandSupplier.get(); + } + + if (command.getOutput() instanceof StreamingOutput) { + StreamingOutput streamingOutput = (StreamingOutput) command.getOutput(); + + if (connection instanceof StatefulRedisConnection && ((StatefulRedisConnection) connection).isMulti()) { + streamingOutput.setSubscriber(new DelegatingWrapper( + Arrays.asList(new ObservableSubscriberWrapper<>(subscriber), streamingOutput.getSubscriber()))); + } else { + streamingOutput.setSubscriber(new ObservableSubscriberWrapper<>(subscriber)); + } } + + connection.dispatch(new ObservableCommand<>(command, subscriber, dissolve)); + + ReactiveCommandDispatcher.this.command = null; } + } + + private class SingleSubscriber implements Single.OnSubscribe { + + @Override + public void call(rx.SingleSubscriber subscriber) { + + // Reuse the first command but then discard it. + RedisCommand command = ReactiveCommandDispatcher.this.command; + if (command == null) { + command = commandSupplier.get(); + } - connection.dispatch(new ObservableCommand<>(command, subscriber, dissolve)); + if (command.getOutput() instanceof StreamingOutput) { + StreamingOutput streamingOutput = (StreamingOutput) command.getOutput(); + + if (connection instanceof StatefulRedisConnection && ((StatefulRedisConnection) connection).isMulti()) { + streamingOutput.setSubscriber(new DelegatingWrapper( + Arrays.asList(new SingleSubscriberWrapper(subscriber), streamingOutput.getSubscriber()))); + } else { + streamingOutput.setSubscriber(new SingleSubscriberWrapper(subscriber)); + } + } - this.command = null; + connection.dispatch(new SingleCommand<>(command, subscriber)); + ReactiveCommandDispatcher.this.command = null; + } } private static class ObservableCommand extends CommandWrapper { @@ -105,6 +150,7 @@ public void complete() { if (getOutput() != null) { Object result = getOutput().get(); + if (!(getOutput() instanceof StreamingOutput) && result != null) { if (dissolve && result instanceof Collection) { @@ -118,7 +164,7 @@ public void complete() { } if (getOutput().hasError()) { - subscriber.onError(new RedisCommandExecutionException(getOutput().getError())); + onError(new RedisCommandExecutionException(getOutput().getError())); completed = true; return; } @@ -142,21 +188,91 @@ public void cancel() { } super.cancel(); - subscriber.onCompleted(); + + onError(new CancellationException()); completed = true; } @Override public boolean completeExceptionally(Throwable throwable) { + if (completed || subscriber.isUnsubscribed()) { return false; } boolean b = super.completeExceptionally(throwable); + onError(throwable); + completed = true; + return b; + } + + private void onError(Throwable throwable) { subscriber.onError(throwable); + } + } + + private static class SingleCommand extends CommandWrapper { + + private final rx.SingleSubscriber subscriber; + private boolean completed = false; + + public SingleCommand(RedisCommand command, rx.SingleSubscriber subscriber) { + super(command); + this.subscriber = subscriber; + } + + @Override + @SuppressWarnings("unchecked") + public void complete() { + if (completed) { + return; + } + + super.complete(); + + if (getOutput() != null) { + Object result = getOutput().get(); + + if (getOutput().hasError()) { + onError(new RedisCommandExecutionException(getOutput().getError())); + completed = true; + return; + } else if (!(getOutput() instanceof StreamingOutput)) { + subscriber.onSuccess((T) result); + } + } + + completed = true; + } + + @Override + public void cancel() { + + if (completed) { + return; + } + + super.cancel(); + onError(new CancellationException()); + completed = true; + } + + @Override + public boolean completeExceptionally(Throwable throwable) { + + if (completed) { + return false; + } + + boolean b = super.completeExceptionally(throwable); + onError(throwable); completed = true; return b; } + + private void onError(Throwable throwable) { + subscriber.onError(throwable); + } } static class ObservableSubscriberWrapper implements StreamingOutput.Subscriber { @@ -170,7 +286,7 @@ public ObservableSubscriberWrapper(Subscriber subscriber) { @Override public void onNext(T t) { - if(subscriber.isUnsubscribed()) { + if (subscriber.isUnsubscribed()) { return; } @@ -178,6 +294,20 @@ public void onNext(T t) { } } + static class SingleSubscriberWrapper implements StreamingOutput.Subscriber { + + private rx.SingleSubscriber subscriber; + + public SingleSubscriberWrapper(rx.SingleSubscriber subscriber) { + this.subscriber = subscriber; + } + + @Override + public void onNext(T t) { + subscriber.onSuccess(t); + } + } + static class DelegatingWrapper implements StreamingOutput.Subscriber { private Collection> subscribers; diff --git a/src/main/java/com/lambdaworks/redis/api/rx/BaseRedisReactiveCommands.java b/src/main/java/com/lambdaworks/redis/api/rx/BaseRedisReactiveCommands.java index e257c522b8..b5945b7ae1 100644 --- a/src/main/java/com/lambdaworks/redis/api/rx/BaseRedisReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/rx/BaseRedisReactiveCommands.java @@ -6,6 +6,8 @@ import com.lambdaworks.redis.protocol.ProtocolKeyword; import com.lambdaworks.redis.output.CommandOutput; import rx.Observable; +import rx.Single; +import rx.Completable; /** * @@ -26,7 +28,7 @@ public interface BaseRedisReactiveCommands extends AutoCloseable { * @param message the message type: value * @return Long integer-reply the number of clients that received the message. */ - Observable publish(K channel, V message); + Single publish(K channel, V message); /** * Lists the currently *active channels*. @@ -49,14 +51,14 @@ public interface BaseRedisReactiveCommands extends AutoCloseable { * @param channels channel keys * @return array-reply a list of channels and number of subscribers for every channel. */ - Observable> pubsubNumsub(K... channels); + Single> pubsubNumsub(K... channels); /** * Returns the number of subscriptions to patterns. * * @return Long integer-reply the number of patterns all the clients are subscribed to. */ - Observable pubsubNumpat(); + Single pubsubNumpat(); /** * Echo the given string. @@ -64,7 +66,7 @@ public interface BaseRedisReactiveCommands extends AutoCloseable { * @param msg the message type: value * @return V bulk-string-reply */ - Observable echo(V msg); + Single echo(V msg); /** * Return the role of the instance in the context of replication. @@ -79,28 +81,28 @@ public interface BaseRedisReactiveCommands extends AutoCloseable { * * @return String simple-string-reply */ - Observable ping(); + Single ping(); /** * Switch connection to Read-Only mode when connecting to a cluster. * * @return String simple-string-reply. */ - Observable readOnly(); + Single readOnly(); /** * Switch connection to Read-Write mode (default) when connecting to a cluster. * * @return String simple-string-reply. */ - Observable readWrite(); + Single readWrite(); /** * Close the connection. * * @return String simple-string-reply always OK. */ - Observable quit(); + Single quit(); /** * Wait for replication. @@ -109,7 +111,7 @@ public interface BaseRedisReactiveCommands extends AutoCloseable { * @param timeout timeout in milliseconds * @return number of replicas */ - Observable waitForReplication(int replicas, long timeout); + Single waitForReplication(int replicas, long timeout); /** * Dispatch a command to the Redis Server. Please note the command output type must fit to the command response. diff --git a/src/main/java/com/lambdaworks/redis/api/rx/RedisGeoReactiveCommands.java b/src/main/java/com/lambdaworks/redis/api/rx/RedisGeoReactiveCommands.java index abd49e4011..855b949edc 100644 --- a/src/main/java/com/lambdaworks/redis/api/rx/RedisGeoReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/rx/RedisGeoReactiveCommands.java @@ -7,6 +7,8 @@ import java.util.List; import java.util.Set; import rx.Observable; +import rx.Single; +import rx.Completable; /** * Observable commands for the Geo-API. @@ -26,7 +28,7 @@ public interface RedisGeoReactiveCommands { * @param member the member to add * @return Long integer-reply the number of elements that were added to the set */ - Observable geoadd(K key, double longitude, double latitude, V member); + Single geoadd(K key, double longitude, double latitude, V member); /** * Multi geo add. @@ -35,7 +37,7 @@ public interface RedisGeoReactiveCommands { * @param lngLatMember triplets of double longitude, double latitude and V member * @return Long integer-reply the number of elements that were added to the set */ - Observable geoadd(K key, Object... lngLatMember); + Single geoadd(K key, Object... lngLatMember); /** * Retrieve Geohash strings representing the position of one or more elements in a sorted set value representing a geospatial index. @@ -83,7 +85,7 @@ public interface RedisGeoReactiveCommands { * their locations a sorted set. * @return Long integer-reply the number of elements in the result */ - Observable georadius(K key, double longitude, double latitude, double distance, GeoArgs.Unit unit, GeoRadiusStoreArgs geoRadiusStoreArgs); + Single georadius(K key, double longitude, double latitude, double distance, GeoArgs.Unit unit, GeoRadiusStoreArgs geoRadiusStoreArgs); /** * Retrieve members selected by distance with the center of {@code member}. The member itself is always contained in the @@ -122,7 +124,7 @@ public interface RedisGeoReactiveCommands { * their locations a sorted set. * @return Long integer-reply the number of elements in the result */ - Observable georadiusbymember(K key, V member, double distance, GeoArgs.Unit unit, GeoRadiusStoreArgs geoRadiusStoreArgs); + Single georadiusbymember(K key, V member, double distance, GeoArgs.Unit unit, GeoRadiusStoreArgs geoRadiusStoreArgs); /** * Get geo coordinates for the {@code members}. @@ -148,5 +150,5 @@ public interface RedisGeoReactiveCommands { * @return distance between points {@code from} and {@code to}. If one or more elements are missing {@literal null} is * returned. */ - Observable geodist(K key, V from, V to, GeoArgs.Unit unit); + Single geodist(K key, V from, V to, GeoArgs.Unit unit); } diff --git a/src/main/java/com/lambdaworks/redis/api/rx/RedisHLLReactiveCommands.java b/src/main/java/com/lambdaworks/redis/api/rx/RedisHLLReactiveCommands.java index dd8bd8a351..dc2e8a367c 100644 --- a/src/main/java/com/lambdaworks/redis/api/rx/RedisHLLReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/rx/RedisHLLReactiveCommands.java @@ -1,6 +1,8 @@ package com.lambdaworks.redis.api.rx; import rx.Observable; +import rx.Single; +import rx.Completable; /** * Observable commands for HyperLogLog (PF* commands). @@ -23,7 +25,7 @@ public interface RedisHLLReactiveCommands { * * 1 if at least 1 HyperLogLog internal register was altered. 0 otherwise. */ - Observable pfadd(K key, V... values); + Single pfadd(K key, V... values); /** * Merge N different HyperLogLogs into a single one. @@ -33,7 +35,7 @@ public interface RedisHLLReactiveCommands { * * @return String simple-string-reply The command just returns {@code OK}. */ - Observable pfmerge(K destkey, K... sourcekeys); + Single pfmerge(K destkey, K... sourcekeys); /** * Return the approximated cardinality of the set(s) observed by the HyperLogLog at key(s). @@ -44,5 +46,5 @@ public interface RedisHLLReactiveCommands { * * The approximated number of unique elements observed via {@code PFADD}. */ - Observable pfcount(K... keys); + Single pfcount(K... keys); } diff --git a/src/main/java/com/lambdaworks/redis/api/rx/RedisHashReactiveCommands.java b/src/main/java/com/lambdaworks/redis/api/rx/RedisHashReactiveCommands.java index e10d080d61..21e575bcf8 100644 --- a/src/main/java/com/lambdaworks/redis/api/rx/RedisHashReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/rx/RedisHashReactiveCommands.java @@ -10,6 +10,8 @@ import com.lambdaworks.redis.output.KeyValueStreamingChannel; import com.lambdaworks.redis.output.ValueStreamingChannel; import rx.Observable; +import rx.Single; +import rx.Completable; /** * Observable commands for Hashes (Key-Value pairs). @@ -30,7 +32,7 @@ public interface RedisHashReactiveCommands { * @return Long integer-reply the number of fields that were removed from the hash, not including specified but non existing * fields. */ - Observable hdel(K key, K... fields); + Single hdel(K key, K... fields); /** * Determine if a hash field exists. @@ -42,7 +44,7 @@ public interface RedisHashReactiveCommands { * {@literal true} if the hash contains {@code field}. {@literal false} if the hash does not contain {@code field}, * or {@code key} does not exist. */ - Observable hexists(K key, K field); + Single hexists(K key, K field); /** * Get the value of a hash field. @@ -52,7 +54,7 @@ public interface RedisHashReactiveCommands { * @return V bulk-string-reply the value associated with {@code field}, or {@literal null} when {@code field} is not present * in the hash or {@code key} does not exist. */ - Observable hget(K key, K field); + Single hget(K key, K field); /** * Increment the integer value of a hash field by the given number. @@ -62,7 +64,7 @@ public interface RedisHashReactiveCommands { * @param amount the increment type: long * @return Long integer-reply the value at {@code field} after the increment operation. */ - Observable hincrby(K key, K field, long amount); + Single hincrby(K key, K field, long amount); /** * Increment the float value of a hash field by the given amount. @@ -72,7 +74,7 @@ public interface RedisHashReactiveCommands { * @param amount the increment type: double * @return Double bulk-string-reply the value of {@code field} after the increment. */ - Observable hincrbyfloat(K key, K field, double amount); + Single hincrbyfloat(K key, K field, double amount); /** * Get all the fields and values in a hash. @@ -81,7 +83,7 @@ public interface RedisHashReactiveCommands { * @return Map<K,V> array-reply list of fields and their values stored in the hash, or an empty list when {@code key} * does not exist. */ - Observable> hgetall(K key); + Single> hgetall(K key); /** * Stream over all the fields and values in a hash. @@ -91,7 +93,7 @@ public interface RedisHashReactiveCommands { * * @return Long count of the keys. */ - Observable hgetall(KeyValueStreamingChannel channel, K key); + Single hgetall(KeyValueStreamingChannel channel, K key); /** * Get all the fields in a hash. @@ -109,7 +111,7 @@ public interface RedisHashReactiveCommands { * * @return Long count of the keys. */ - Observable hkeys(KeyStreamingChannel channel, K key); + Single hkeys(KeyStreamingChannel channel, K key); /** * Get the number of fields in a hash. @@ -117,7 +119,7 @@ public interface RedisHashReactiveCommands { * @param key the key * @return Long integer-reply number of fields in the hash, or {@code 0} when {@code key} does not exist. */ - Observable hlen(K key); + Single hlen(K key); /** * Get the values of all the given hash fields. @@ -137,7 +139,7 @@ public interface RedisHashReactiveCommands { * * @return Long count of the keys */ - Observable hmget(ValueStreamingChannel channel, K key, K... fields); + Single hmget(ValueStreamingChannel channel, K key, K... fields); /** * Set multiple hash fields to multiple values. @@ -146,7 +148,7 @@ public interface RedisHashReactiveCommands { * @param map the null * @return String simple-string-reply */ - Observable hmset(K key, Map map); + Single hmset(K key, Map map); /** * Incrementally iterate hash fields and associated values. @@ -154,7 +156,7 @@ public interface RedisHashReactiveCommands { * @param key the key * @return MapScanCursor<K, V> map scan cursor. */ - Observable> hscan(K key); + Single> hscan(K key); /** * Incrementally iterate hash fields and associated values. @@ -163,7 +165,7 @@ public interface RedisHashReactiveCommands { * @param scanArgs scan arguments * @return MapScanCursor<K, V> map scan cursor. */ - Observable> hscan(K key, ScanArgs scanArgs); + Single> hscan(K key, ScanArgs scanArgs); /** * Incrementally iterate hash fields and associated values. @@ -173,7 +175,7 @@ public interface RedisHashReactiveCommands { * @param scanArgs scan arguments * @return MapScanCursor<K, V> map scan cursor. */ - Observable> hscan(K key, ScanCursor scanCursor, ScanArgs scanArgs); + Single> hscan(K key, ScanCursor scanCursor, ScanArgs scanArgs); /** * Incrementally iterate hash fields and associated values. @@ -182,7 +184,7 @@ public interface RedisHashReactiveCommands { * @param scanCursor cursor to resume from a previous scan, must not be {@literal null} * @return MapScanCursor<K, V> map scan cursor. */ - Observable> hscan(K key, ScanCursor scanCursor); + Single> hscan(K key, ScanCursor scanCursor); /** * Incrementally iterate hash fields and associated values. @@ -191,7 +193,7 @@ public interface RedisHashReactiveCommands { * @param key the key * @return StreamScanCursor scan cursor. */ - Observable hscan(KeyValueStreamingChannel channel, K key); + Single hscan(KeyValueStreamingChannel channel, K key); /** * Incrementally iterate hash fields and associated values. @@ -201,7 +203,7 @@ public interface RedisHashReactiveCommands { * @param scanArgs scan arguments * @return StreamScanCursor scan cursor. */ - Observable hscan(KeyValueStreamingChannel channel, K key, ScanArgs scanArgs); + Single hscan(KeyValueStreamingChannel channel, K key, ScanArgs scanArgs); /** * Incrementally iterate hash fields and associated values. @@ -212,7 +214,7 @@ public interface RedisHashReactiveCommands { * @param scanArgs scan arguments * @return StreamScanCursor scan cursor. */ - Observable hscan(KeyValueStreamingChannel channel, K key, ScanCursor scanCursor, ScanArgs scanArgs); + Single hscan(KeyValueStreamingChannel channel, K key, ScanCursor scanCursor, ScanArgs scanArgs); /** * Incrementally iterate hash fields and associated values. @@ -222,7 +224,7 @@ public interface RedisHashReactiveCommands { * @param scanCursor cursor to resume from a previous scan, must not be {@literal null} * @return StreamScanCursor scan cursor. */ - Observable hscan(KeyValueStreamingChannel channel, K key, ScanCursor scanCursor); + Single hscan(KeyValueStreamingChannel channel, K key, ScanCursor scanCursor); /** * Set the string value of a hash field. @@ -235,7 +237,7 @@ public interface RedisHashReactiveCommands { * {@literal true} if {@code field} is a new field in the hash and {@code value} was set. {@literal false} if * {@code field} already exists in the hash and the value was updated. */ - Observable hset(K key, K field, V value); + Single hset(K key, K field, V value); /** * Set the value of a hash field, only if the field does not exist. @@ -248,7 +250,7 @@ public interface RedisHashReactiveCommands { * {@code 1} if {@code field} is a new field in the hash and {@code value} was set. {@code 0} if {@code field} * already exists in the hash and no operation was performed. */ - Observable hsetnx(K key, K field, V value); + Single hsetnx(K key, K field, V value); /** * Get the string length of the field value in a hash. @@ -258,7 +260,7 @@ public interface RedisHashReactiveCommands { * @return Long integer-reply the string length of the {@code field} value, or {@code 0} when {@code field} is not present * in the hash or {@code key} does not exist at all. */ - Observable hstrlen(K key, K field); + Single hstrlen(K key, K field); /** * Get all the values in a hash. @@ -276,5 +278,5 @@ public interface RedisHashReactiveCommands { * * @return Long count of the keys. */ - Observable hvals(ValueStreamingChannel channel, K key); + Single hvals(ValueStreamingChannel channel, K key); } diff --git a/src/main/java/com/lambdaworks/redis/api/rx/RedisKeyReactiveCommands.java b/src/main/java/com/lambdaworks/redis/api/rx/RedisKeyReactiveCommands.java index 5fd66b53f5..8cc15286cc 100644 --- a/src/main/java/com/lambdaworks/redis/api/rx/RedisKeyReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/rx/RedisKeyReactiveCommands.java @@ -11,6 +11,8 @@ import com.lambdaworks.redis.output.KeyStreamingChannel; import com.lambdaworks.redis.output.ValueStreamingChannel; import rx.Observable; +import rx.Single; +import rx.Completable; /** * Observable commands for Keys (Key manipulation/querying). @@ -29,7 +31,7 @@ public interface RedisKeyReactiveCommands { * @param keys the keys * @return Long integer-reply The number of keys that were removed. */ - Observable del(K... keys); + Single del(K... keys); /** * Unlink one or more keys (non blocking DEL). @@ -37,7 +39,7 @@ public interface RedisKeyReactiveCommands { * @param keys the keys * @return Long integer-reply The number of keys that were removed. */ - Observable unlink(K... keys); + Single unlink(K... keys); /** * Return a serialized version of the value stored at the specified key. @@ -45,7 +47,7 @@ public interface RedisKeyReactiveCommands { * @param key the key * @return byte[] bulk-string-reply the serialized value. */ - Observable dump(K key); + Single dump(K key); /** * Determine how many keys exist. @@ -53,7 +55,7 @@ public interface RedisKeyReactiveCommands { * @param keys the keys * @return Long integer-reply specifically: Number of existing keys */ - Observable exists(K... keys); + Single exists(K... keys); /** * Set a key's time to live in seconds. @@ -65,7 +67,7 @@ public interface RedisKeyReactiveCommands { * {@literal true} if the timeout was set. {@literal false} if {@code key} does not exist or the timeout could not * be set. */ - Observable expire(K key, long seconds); + Single expire(K key, long seconds); /** * Set the expiration for a key as a UNIX timestamp. @@ -77,7 +79,7 @@ public interface RedisKeyReactiveCommands { * {@literal true} if the timeout was set. {@literal false} if {@code key} does not exist or the timeout could not * be set (see: {@code EXPIRE}). */ - Observable expireat(K key, Date timestamp); + Single expireat(K key, Date timestamp); /** * Set the expiration for a key as a UNIX timestamp. @@ -89,7 +91,7 @@ public interface RedisKeyReactiveCommands { * {@literal true} if the timeout was set. {@literal false} if {@code key} does not exist or the timeout could not * be set (see: {@code EXPIRE}). */ - Observable expireat(K key, long timestamp); + Single expireat(K key, long timestamp); /** * Find all keys matching the given pattern. @@ -106,7 +108,7 @@ public interface RedisKeyReactiveCommands { * @param pattern the pattern * @return Long array-reply list of keys matching {@code pattern}. */ - Observable keys(KeyStreamingChannel channel, K pattern); + Single keys(KeyStreamingChannel channel, K pattern); /** * Atomically transfer a key from a Redis instance to another one. @@ -118,7 +120,7 @@ public interface RedisKeyReactiveCommands { * @param timeout the timeout in milliseconds * @return String simple-string-reply The command returns OK on success. */ - Observable migrate(String host, int port, K key, int db, long timeout); + Single migrate(String host, int port, K key, int db, long timeout); /** * Atomically transfer one or more keys from a Redis instance to another one. @@ -130,7 +132,7 @@ public interface RedisKeyReactiveCommands { * @param migrateArgs migrate args that allow to configure further options * @return String simple-string-reply The command returns OK on success. */ - Observable migrate(String host, int port, int db, long timeout, MigrateArgs migrateArgs); + Single migrate(String host, int port, int db, long timeout, MigrateArgs migrateArgs); /** * Move a key to another database. @@ -139,7 +141,7 @@ public interface RedisKeyReactiveCommands { * @param db the db type: long * @return Boolean integer-reply specifically: */ - Observable move(K key, int db); + Single move(K key, int db); /** * returns the kind of internal representation used in order to store the value associated with a key. @@ -147,7 +149,7 @@ public interface RedisKeyReactiveCommands { * @param key the key * @return String */ - Observable objectEncoding(K key); + Single objectEncoding(K key); /** * returns the number of seconds since the object stored at the specified key is idle (not requested by read or write @@ -156,7 +158,7 @@ public interface RedisKeyReactiveCommands { * @param key the key * @return number of seconds since the object stored at the specified key is idle. */ - Observable objectIdletime(K key); + Single objectIdletime(K key); /** * returns the number of references of the value associated with the specified key. @@ -164,7 +166,7 @@ public interface RedisKeyReactiveCommands { * @param key the key * @return Long */ - Observable objectRefcount(K key); + Single objectRefcount(K key); /** * Remove the expiration from a key. @@ -175,7 +177,7 @@ public interface RedisKeyReactiveCommands { * {@literal true} if the timeout was removed. {@literal false} if {@code key} does not exist or does not have an * associated timeout. */ - Observable persist(K key); + Single persist(K key); /** * Set a key's time to live in milliseconds. @@ -187,7 +189,7 @@ public interface RedisKeyReactiveCommands { * {@literal true} if the timeout was set. {@literal false} if {@code key} does not exist or the timeout could not * be set. */ - Observable pexpire(K key, long milliseconds); + Single pexpire(K key, long milliseconds); /** * Set the expiration for a key as a UNIX timestamp specified in milliseconds. @@ -199,7 +201,7 @@ public interface RedisKeyReactiveCommands { * {@literal true} if the timeout was set. {@literal false} if {@code key} does not exist or the timeout could not * be set (see: {@code EXPIRE}). */ - Observable pexpireat(K key, Date timestamp); + Single pexpireat(K key, Date timestamp); /** * Set the expiration for a key as a UNIX timestamp specified in milliseconds. @@ -211,7 +213,7 @@ public interface RedisKeyReactiveCommands { * {@literal true} if the timeout was set. {@literal false} if {@code key} does not exist or the timeout could not * be set (see: {@code EXPIRE}). */ - Observable pexpireat(K key, long timestamp); + Single pexpireat(K key, long timestamp); /** * Get the time to live for a key in milliseconds. @@ -220,14 +222,14 @@ public interface RedisKeyReactiveCommands { * @return Long integer-reply TTL in milliseconds, or a negative value in order to signal an error (see the description * above). */ - Observable pttl(K key); + Single pttl(K key); /** * Return a random key from the keyspace. * * @return V bulk-string-reply the random key, or {@literal null} when the database is empty. */ - Observable randomkey(); + Single randomkey(); /** * Rename a key. @@ -236,7 +238,7 @@ public interface RedisKeyReactiveCommands { * @param newKey the newkey type: key * @return String simple-string-reply */ - Observable rename(K key, K newKey); + Single rename(K key, K newKey); /** * Rename a key, only if the new key does not exist. @@ -247,7 +249,7 @@ public interface RedisKeyReactiveCommands { * * {@literal true} if {@code key} was renamed to {@code newkey}. {@literal false} if {@code newkey} already exists. */ - Observable renamenx(K key, K newKey); + Single renamenx(K key, K newKey); /** * Create a key using the provided serialized value, previously obtained using DUMP. @@ -257,7 +259,7 @@ public interface RedisKeyReactiveCommands { * @param value the serialized-value type: string * @return String simple-string-reply The command returns OK on success. */ - Observable restore(K key, long ttl, byte[] value); + Single restore(K key, long ttl, byte[] value); /** * Sort the elements in a list, set or sorted set. @@ -274,7 +276,7 @@ public interface RedisKeyReactiveCommands { * @param key the key * @return Long number of values. */ - Observable sort(ValueStreamingChannel channel, K key); + Single sort(ValueStreamingChannel channel, K key); /** * Sort the elements in a list, set or sorted set. @@ -293,7 +295,7 @@ public interface RedisKeyReactiveCommands { * @param sortArgs sort arguments * @return Long number of values. */ - Observable sort(ValueStreamingChannel channel, K key, SortArgs sortArgs); + Single sort(ValueStreamingChannel channel, K key, SortArgs sortArgs); /** * Sort the elements in a list, set or sorted set. @@ -303,7 +305,7 @@ public interface RedisKeyReactiveCommands { * @param destination the destination key to store sort results * @return Long number of values. */ - Observable sortStore(K key, SortArgs sortArgs, K destination); + Single sortStore(K key, SortArgs sortArgs, K destination); /** * Touch one or more keys. Touch sets the last accessed time for a key. Non-exsitent keys wont get created. @@ -311,7 +313,7 @@ public interface RedisKeyReactiveCommands { * @param keys the keys * @return Long integer-reply the number of found keys. */ - Observable touch(K... keys); + Single touch(K... keys); /** * Get the time to live for a key. @@ -319,7 +321,7 @@ public interface RedisKeyReactiveCommands { * @param key the key * @return Long integer-reply TTL in seconds, or a negative value in order to signal an error (see the description above). */ - Observable ttl(K key); + Single ttl(K key); /** * Determine the type stored at key. @@ -327,14 +329,14 @@ public interface RedisKeyReactiveCommands { * @param key the key * @return String simple-string-reply type of {@code key}, or {@code none} when {@code key} does not exist. */ - Observable type(K key); + Single type(K key); /** * Incrementally iterate the keys space. * * @return KeyScanCursor<K> scan cursor. */ - Observable> scan(); + Single> scan(); /** * Incrementally iterate the keys space. @@ -342,7 +344,7 @@ public interface RedisKeyReactiveCommands { * @param scanArgs scan arguments * @return KeyScanCursor<K> scan cursor. */ - Observable> scan(ScanArgs scanArgs); + Single> scan(ScanArgs scanArgs); /** * Incrementally iterate the keys space. @@ -351,7 +353,7 @@ public interface RedisKeyReactiveCommands { * @param scanArgs scan arguments * @return KeyScanCursor<K> scan cursor. */ - Observable> scan(ScanCursor scanCursor, ScanArgs scanArgs); + Single> scan(ScanCursor scanCursor, ScanArgs scanArgs); /** * Incrementally iterate the keys space. @@ -359,7 +361,7 @@ public interface RedisKeyReactiveCommands { * @param scanCursor cursor to resume from a previous scan, must not be {@literal null} * @return KeyScanCursor<K> scan cursor. */ - Observable> scan(ScanCursor scanCursor); + Single> scan(ScanCursor scanCursor); /** * Incrementally iterate the keys space. @@ -367,7 +369,7 @@ public interface RedisKeyReactiveCommands { * @param channel streaming channel that receives a call for every key * @return StreamScanCursor scan cursor. */ - Observable scan(KeyStreamingChannel channel); + Single scan(KeyStreamingChannel channel); /** * Incrementally iterate the keys space. @@ -376,7 +378,7 @@ public interface RedisKeyReactiveCommands { * @param scanArgs scan arguments * @return StreamScanCursor scan cursor. */ - Observable scan(KeyStreamingChannel channel, ScanArgs scanArgs); + Single scan(KeyStreamingChannel channel, ScanArgs scanArgs); /** * Incrementally iterate the keys space. @@ -386,7 +388,7 @@ public interface RedisKeyReactiveCommands { * @param scanArgs scan arguments * @return StreamScanCursor scan cursor. */ - Observable scan(KeyStreamingChannel channel, ScanCursor scanCursor, ScanArgs scanArgs); + Single scan(KeyStreamingChannel channel, ScanCursor scanCursor, ScanArgs scanArgs); /** * Incrementally iterate the keys space. @@ -395,5 +397,5 @@ public interface RedisKeyReactiveCommands { * @param scanCursor cursor to resume from a previous scan, must not be {@literal null} * @return StreamScanCursor scan cursor. */ - Observable scan(KeyStreamingChannel channel, ScanCursor scanCursor); + Single scan(KeyStreamingChannel channel, ScanCursor scanCursor); } diff --git a/src/main/java/com/lambdaworks/redis/api/rx/RedisListReactiveCommands.java b/src/main/java/com/lambdaworks/redis/api/rx/RedisListReactiveCommands.java index 4f9b4d4832..24f98351e9 100644 --- a/src/main/java/com/lambdaworks/redis/api/rx/RedisListReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/rx/RedisListReactiveCommands.java @@ -4,6 +4,8 @@ import com.lambdaworks.redis.KeyValue; import com.lambdaworks.redis.output.ValueStreamingChannel; import rx.Observable; +import rx.Single; +import rx.Completable; /** * Observable commands for Lists. @@ -27,7 +29,7 @@ public interface RedisListReactiveCommands { * with the first element being the name of the key where an element was popped and the second element being the * value of the popped element. */ - Observable> blpop(long timeout, K... keys); + Single> blpop(long timeout, K... keys); /** * Remove and get the last element in a list, or block until one is available. @@ -40,7 +42,7 @@ public interface RedisListReactiveCommands { * with the first element being the name of the key where an element was popped and the second element being the * value of the popped element. */ - Observable> brpop(long timeout, K... keys); + Single> brpop(long timeout, K... keys); /** * Pop a value from a list, push it to another list and return it; or block until one is available. @@ -51,7 +53,7 @@ public interface RedisListReactiveCommands { * @return V bulk-string-reply the element being popped from {@code source} and pushed to {@code destination}. If * {@code timeout} is reached, a */ - Observable brpoplpush(long timeout, K source, K destination); + Single brpoplpush(long timeout, K source, K destination); /** * Get an element from a list by its index. @@ -60,7 +62,7 @@ public interface RedisListReactiveCommands { * @param index the index type: long * @return V bulk-string-reply the requested element, or {@literal null} when {@code index} is out of range. */ - Observable lindex(K key, long index); + Single lindex(K key, long index); /** * Insert an element before or after another element in a list. @@ -72,7 +74,7 @@ public interface RedisListReactiveCommands { * @return Long integer-reply the length of the list after the insert operation, or {@code -1} when the value {@code pivot} * was not found. */ - Observable linsert(K key, boolean before, V pivot, V value); + Single linsert(K key, boolean before, V pivot, V value); /** * Get the length of a list. @@ -80,7 +82,7 @@ public interface RedisListReactiveCommands { * @param key the key * @return Long integer-reply the length of the list at {@code key}. */ - Observable llen(K key); + Single llen(K key); /** * Remove and get the first element in a list. @@ -88,7 +90,7 @@ public interface RedisListReactiveCommands { * @param key the key * @return V bulk-string-reply the value of the first element, or {@literal null} when {@code key} does not exist. */ - Observable lpop(K key); + Single lpop(K key); /** * Prepend one or multiple values to a list. @@ -97,7 +99,7 @@ public interface RedisListReactiveCommands { * @param values the value * @return Long integer-reply the length of the list after the push operations. */ - Observable lpush(K key, V... values); + Single lpush(K key, V... values); /** * Prepend values to a list, only if the list exists. @@ -106,7 +108,7 @@ public interface RedisListReactiveCommands { * @param values the values * @return Long integer-reply the length of the list after the push operation. */ - Observable lpushx(K key, V... values); + Single lpushx(K key, V... values); /** * Get a range of elements from a list. @@ -127,7 +129,7 @@ public interface RedisListReactiveCommands { * @param stop the stop type: long * @return Long count of elements in the specified range. */ - Observable lrange(ValueStreamingChannel channel, K key, long start, long stop); + Single lrange(ValueStreamingChannel channel, K key, long start, long stop); /** * Remove elements from a list. @@ -137,7 +139,7 @@ public interface RedisListReactiveCommands { * @param value the value * @return Long integer-reply the number of removed elements. */ - Observable lrem(K key, long count, V value); + Single lrem(K key, long count, V value); /** * Set the value of an element in a list by its index. @@ -147,7 +149,7 @@ public interface RedisListReactiveCommands { * @param value the value * @return String simple-string-reply */ - Observable lset(K key, long index, V value); + Single lset(K key, long index, V value); /** * Trim a list to the specified range. @@ -157,7 +159,7 @@ public interface RedisListReactiveCommands { * @param stop the stop type: long * @return String simple-string-reply */ - Observable ltrim(K key, long start, long stop); + Single ltrim(K key, long start, long stop); /** * Remove and get the last element in a list. @@ -165,7 +167,7 @@ public interface RedisListReactiveCommands { * @param key the key * @return V bulk-string-reply the value of the last element, or {@literal null} when {@code key} does not exist. */ - Observable rpop(K key); + Single rpop(K key); /** * Remove the last element in a list, append it to another list and return it. @@ -174,7 +176,7 @@ public interface RedisListReactiveCommands { * @param destination the destination type: key * @return V bulk-string-reply the element being popped and pushed. */ - Observable rpoplpush(K source, K destination); + Single rpoplpush(K source, K destination); /** * Append one or multiple values to a list. @@ -183,7 +185,7 @@ public interface RedisListReactiveCommands { * @param values the value * @return Long integer-reply the length of the list after the push operation. */ - Observable rpush(K key, V... values); + Single rpush(K key, V... values); /** * Append values to a list, only if the list exists. @@ -192,5 +194,5 @@ public interface RedisListReactiveCommands { * @param values the values * @return Long integer-reply the length of the list after the push operation. */ - Observable rpushx(K key, V... values); + Single rpushx(K key, V... values); } diff --git a/src/main/java/com/lambdaworks/redis/api/rx/RedisReactiveCommands.java b/src/main/java/com/lambdaworks/redis/api/rx/RedisReactiveCommands.java index 01182aa4b8..1c3901423a 100644 --- a/src/main/java/com/lambdaworks/redis/api/rx/RedisReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/rx/RedisReactiveCommands.java @@ -6,6 +6,7 @@ import com.lambdaworks.redis.api.StatefulRedisConnection; import com.lambdaworks.redis.cluster.api.rx.RedisClusterReactiveCommands; +import rx.Single; /** * A complete reactive and thread-safe Redis API with 400+ Methods. @@ -35,7 +36,7 @@ public interface RedisReactiveCommands extends RedisHashReactiveCommands auth(String password); + Single auth(String password); /** * Change the selected database for the current connection. @@ -43,7 +44,7 @@ public interface RedisReactiveCommands extends RedisHashReactiveCommands select(int db); + Single select(int db); /** * @return the underlying connection. diff --git a/src/main/java/com/lambdaworks/redis/api/rx/RedisScriptingReactiveCommands.java b/src/main/java/com/lambdaworks/redis/api/rx/RedisScriptingReactiveCommands.java index c20b82292d..ceb47dee70 100644 --- a/src/main/java/com/lambdaworks/redis/api/rx/RedisScriptingReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/rx/RedisScriptingReactiveCommands.java @@ -3,6 +3,8 @@ import java.util.List; import com.lambdaworks.redis.ScriptOutputType; import rx.Observable; +import rx.Single; +import rx.Completable; /** * Observable commands for Scripting. @@ -76,14 +78,14 @@ public interface RedisScriptingReactiveCommands { * * @return String simple-string-reply */ - Observable scriptFlush(); + Single scriptFlush(); /** * Kill the script currently in execution. * * @return String simple-string-reply */ - Observable scriptKill(); + Single scriptKill(); /** * Load the specified Lua script into the script cache. @@ -91,7 +93,7 @@ public interface RedisScriptingReactiveCommands { * @param script script content * @return String bulk-string-reply This command returns the SHA1 digest of the script added into the script cache. */ - Observable scriptLoad(V script); + Single scriptLoad(V script); /** * Create a SHA1 digest from a Lua script. diff --git a/src/main/java/com/lambdaworks/redis/api/rx/RedisServerReactiveCommands.java b/src/main/java/com/lambdaworks/redis/api/rx/RedisServerReactiveCommands.java index bcf8575949..883904d090 100644 --- a/src/main/java/com/lambdaworks/redis/api/rx/RedisServerReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/rx/RedisServerReactiveCommands.java @@ -5,6 +5,8 @@ import com.lambdaworks.redis.KillArgs; import com.lambdaworks.redis.protocol.CommandType; import rx.Observable; +import rx.Single; +import rx.Completable; /** * Observable commands for Server Control. @@ -22,21 +24,21 @@ public interface RedisServerReactiveCommands { * * @return String simple-string-reply always {@code OK}. */ - Observable bgrewriteaof(); + Single bgrewriteaof(); /** * Asynchronously save the dataset to disk. * * @return String simple-string-reply */ - Observable bgsave(); + Single bgsave(); /** * Get the current connection name. * * @return K bulk-string-reply The connection name, or a null bulk reply if no name is set. */ - Observable clientGetname(); + Single clientGetname(); /** * Set the current connection name. @@ -44,7 +46,7 @@ public interface RedisServerReactiveCommands { * @param name the client name * @return simple-string-reply {@code OK} if the connection name was successfully set. */ - Observable clientSetname(K name); + Single clientSetname(K name); /** * Kill the connection of a client identified by ip:port. @@ -52,7 +54,7 @@ public interface RedisServerReactiveCommands { * @param addr ip:port * @return String simple-string-reply {@code OK} if the connection exists and has been closed */ - Observable clientKill(String addr); + Single clientKill(String addr); /** * Kill connections of clients which are filtered by {@code killArgs} @@ -60,7 +62,7 @@ public interface RedisServerReactiveCommands { * @param killArgs args for the kill operation * @return Long integer-reply number of killed connections */ - Observable clientKill(KillArgs killArgs); + Single clientKill(KillArgs killArgs); /** * Stop processing commands from clients for some time. @@ -68,7 +70,7 @@ public interface RedisServerReactiveCommands { * @param timeout the timeout value in milliseconds * @return String simple-string-reply The command returns OK or an error if the timeout is invalid. */ - Observable clientPause(long timeout); + Single clientPause(long timeout); /** * Get the list of client connections. @@ -76,7 +78,7 @@ public interface RedisServerReactiveCommands { * @return String bulk-string-reply a unique string, formatted as follows: One client connection per line (separated by LF), * each line is composed of a succession of property=value fields separated by a space character. */ - Observable clientList(); + Single clientList(); /** * Returns an array reply of details about all Redis commands. @@ -106,7 +108,7 @@ public interface RedisServerReactiveCommands { * * @return Long integer-reply of number of total commands in this Redis server. */ - Observable commandCount(); + Single commandCount(); /** * Get the value of a configuration parameter. @@ -121,7 +123,7 @@ public interface RedisServerReactiveCommands { * * @return String simple-string-reply always {@code OK}. */ - Observable configResetstat(); + Single configResetstat(); /** * Rewrite the configuration file with the in memory configuration. @@ -129,7 +131,7 @@ public interface RedisServerReactiveCommands { * @return String simple-string-reply {@code OK} when the configuration was rewritten properly. Otherwise an error is * returned. */ - Observable configRewrite(); + Single configRewrite(); /** * Set a configuration parameter to the given value. @@ -138,21 +140,21 @@ public interface RedisServerReactiveCommands { * @param value the parameter value * @return String simple-string-reply: {@code OK} when the configuration was set properly. Otherwise an error is returned. */ - Observable configSet(String parameter, String value); + Single configSet(String parameter, String value); /** * Return the number of keys in the selected database. * * @return Long integer-reply */ - Observable dbsize(); + Single dbsize(); /** * Crash and recover * @param delay optional delay in milliseconds * @return String simple-string-reply */ - Observable debugCrashAndRecover(Long delay); + Single debugCrashAndRecover(Long delay); /** * Get debugging information about the internal hash-table state. @@ -160,7 +162,7 @@ public interface RedisServerReactiveCommands { * @param db the database number * @return String simple-string-reply */ - Observable debugHtstats(int db); + Single debugHtstats(int db); /** * Get debugging information about a key. @@ -168,35 +170,35 @@ public interface RedisServerReactiveCommands { * @param key the key * @return String simple-string-reply */ - Observable debugObject(K key); + Single debugObject(K key); /** * Make the server crash: Out of memory. * * @return nothing, because the server crashes before returning. */ - Observable debugOom(); + Completable debugOom(); /** * Make the server crash: Invalid pointer access. * * @return nothing, because the server crashes before returning. */ - Observable debugSegfault(); + Completable debugSegfault(); /** * Save RDB, clear the database and reload RDB. * * @return String simple-string-reply The commands returns OK on success. */ - Observable debugReload(); + Single debugReload(); /** * Restart the server gracefully. * @param delay optional delay in milliseconds * @return String simple-string-reply */ - Observable debugRestart(Long delay); + Single debugRestart(Long delay); /** * Get debugging information about the internal SDS length. @@ -204,42 +206,42 @@ public interface RedisServerReactiveCommands { * @param key the key * @return String simple-string-reply */ - Observable debugSdslen(K key); + Single debugSdslen(K key); /** * Remove all keys from all databases. * * @return String simple-string-reply */ - Observable flushall(); + Single flushall(); /** * Remove all keys asynchronously from all databases. * * @return String simple-string-reply */ - Observable flushallAsync(); + Single flushallAsync(); /** * Remove all keys from the current database. * * @return String simple-string-reply */ - Observable flushdb(); + Single flushdb(); /** * Remove all keys asynchronously from the current database. * * @return String simple-string-reply */ - Observable flushdbAsync(); + Single flushdbAsync(); /** * Get information and statistics about the server. * * @return String bulk-string-reply as a collection of text lines. */ - Observable info(); + Single info(); /** * Get information and statistics about the server. @@ -247,28 +249,28 @@ public interface RedisServerReactiveCommands { * @param section the section type: string * @return String bulk-string-reply as a collection of text lines. */ - Observable info(String section); + Single info(String section); /** * Get the UNIX time stamp of the last successful save to disk. * * @return Date integer-reply an UNIX time stamp. */ - Observable lastsave(); + Single lastsave(); /** * Synchronously save the dataset to disk. * * @return String simple-string-reply The commands returns OK on success. */ - Observable save(); + Single save(); /** * Synchronously save the dataset to disk and then shut down the server. * * @param save {@literal true} force save operation */ - Observable shutdown(boolean save); + Completable shutdown(boolean save); /** * Make the server a slave of another instance, or promote it as master. @@ -277,14 +279,14 @@ public interface RedisServerReactiveCommands { * @param port the port type: string * @return String simple-string-reply */ - Observable slaveof(String host, int port); + Single slaveof(String host, int port); /** * Promote server as master. * * @return String simple-string-reply */ - Observable slaveofNoOne(); + Single slaveofNoOne(); /** * Read the slow log. @@ -306,14 +308,14 @@ public interface RedisServerReactiveCommands { * * @return Long length of the slow log. */ - Observable slowlogLen(); + Single slowlogLen(); /** * Resetting the slow log. * * @return String simple-string-reply The commands returns OK on success. */ - Observable slowlogReset(); + Single slowlogReset(); /** * Return the current server time. diff --git a/src/main/java/com/lambdaworks/redis/api/rx/RedisSetReactiveCommands.java b/src/main/java/com/lambdaworks/redis/api/rx/RedisSetReactiveCommands.java index 5ddcb7c9c1..15bce1cc47 100644 --- a/src/main/java/com/lambdaworks/redis/api/rx/RedisSetReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/rx/RedisSetReactiveCommands.java @@ -7,6 +7,8 @@ import com.lambdaworks.redis.ValueScanCursor; import com.lambdaworks.redis.output.ValueStreamingChannel; import rx.Observable; +import rx.Single; +import rx.Completable; /** * Observable commands for Sets. @@ -27,7 +29,7 @@ public interface RedisSetReactiveCommands { * @return Long integer-reply the number of elements that were added to the set, not including all the elements already * present into the set. */ - Observable sadd(K key, V... members); + Single sadd(K key, V... members); /** * Get the number of members in a set. @@ -36,7 +38,7 @@ public interface RedisSetReactiveCommands { * @return Long integer-reply the cardinality (number of elements) of the set, or {@literal false} if {@code key} does not * exist. */ - Observable scard(K key); + Single scard(K key); /** * Subtract multiple sets. @@ -53,7 +55,7 @@ public interface RedisSetReactiveCommands { * @param keys the keys * @return Long count of members of the resulting set. */ - Observable sdiff(ValueStreamingChannel channel, K... keys); + Single sdiff(ValueStreamingChannel channel, K... keys); /** * Subtract multiple sets and store the resulting set in a key. @@ -62,7 +64,7 @@ public interface RedisSetReactiveCommands { * @param keys the key * @return Long integer-reply the number of elements in the resulting set. */ - Observable sdiffstore(K destination, K... keys); + Single sdiffstore(K destination, K... keys); /** * Intersect multiple sets. @@ -79,7 +81,7 @@ public interface RedisSetReactiveCommands { * @param keys the keys * @return Long count of members of the resulting set. */ - Observable sinter(ValueStreamingChannel channel, K... keys); + Single sinter(ValueStreamingChannel channel, K... keys); /** * Intersect multiple sets and store the resulting set in a key. @@ -88,7 +90,7 @@ public interface RedisSetReactiveCommands { * @param keys the key * @return Long integer-reply the number of elements in the resulting set. */ - Observable sinterstore(K destination, K... keys); + Single sinterstore(K destination, K... keys); /** * Determine if a given value is a member of a set. @@ -100,7 +102,7 @@ public interface RedisSetReactiveCommands { * {@literal true} if the element is a member of the set. {@literal false} if the element is not a member of the * set, or if {@code key} does not exist. */ - Observable sismember(K key, V member); + Single sismember(K key, V member); /** * Move a member from one set to another. @@ -113,7 +115,7 @@ public interface RedisSetReactiveCommands { * {@literal true} if the element is moved. {@literal false} if the element is not a member of {@code source} and no * operation was performed. */ - Observable smove(K source, K destination, V member); + Single smove(K source, K destination, V member); /** * Get all the members in a set. @@ -130,7 +132,7 @@ public interface RedisSetReactiveCommands { * @param key the keys * @return Long count of members of the resulting set. */ - Observable smembers(ValueStreamingChannel channel, K key); + Single smembers(ValueStreamingChannel channel, K key); /** * Remove and return a random member from a set. @@ -138,7 +140,7 @@ public interface RedisSetReactiveCommands { * @param key the key * @return V bulk-string-reply the removed element, or {@literal null} when {@code key} does not exist. */ - Observable spop(K key); + Single spop(K key); /** * Remove and return one or multiple random members from a set. @@ -157,7 +159,7 @@ public interface RedisSetReactiveCommands { * @return V bulk-string-reply without the additional {@code count} argument the command returns a Bulk Reply with the * randomly selected element, or {@literal null} when {@code key} does not exist. */ - Observable srandmember(K key); + Single srandmember(K key); /** * Get one or multiple random members from a set. @@ -177,7 +179,7 @@ public interface RedisSetReactiveCommands { * @param count the count * @return Long count of members of the resulting set. */ - Observable srandmember(ValueStreamingChannel channel, K key, long count); + Single srandmember(ValueStreamingChannel channel, K key, long count); /** * Remove one or more members from a set. @@ -186,7 +188,7 @@ public interface RedisSetReactiveCommands { * @param members the member type: value * @return Long integer-reply the number of members that were removed from the set, not including non existing members. */ - Observable srem(K key, V... members); + Single srem(K key, V... members); /** * Add multiple sets. @@ -203,7 +205,7 @@ public interface RedisSetReactiveCommands { * @param keys the keys * @return Long count of members of the resulting set. */ - Observable sunion(ValueStreamingChannel channel, K... keys); + Single sunion(ValueStreamingChannel channel, K... keys); /** * Add multiple sets and store the resulting set in a key. @@ -212,7 +214,7 @@ public interface RedisSetReactiveCommands { * @param keys the key * @return Long integer-reply the number of elements in the resulting set. */ - Observable sunionstore(K destination, K... keys); + Single sunionstore(K destination, K... keys); /** * Incrementally iterate Set elements. @@ -220,7 +222,7 @@ public interface RedisSetReactiveCommands { * @param key the key * @return ValueScanCursor<V> scan cursor. */ - Observable> sscan(K key); + Single> sscan(K key); /** * Incrementally iterate Set elements. @@ -229,7 +231,7 @@ public interface RedisSetReactiveCommands { * @param scanArgs scan arguments * @return ValueScanCursor<V> scan cursor. */ - Observable> sscan(K key, ScanArgs scanArgs); + Single> sscan(K key, ScanArgs scanArgs); /** * Incrementally iterate Set elements. @@ -239,7 +241,7 @@ public interface RedisSetReactiveCommands { * @param scanArgs scan arguments * @return ValueScanCursor<V> scan cursor. */ - Observable> sscan(K key, ScanCursor scanCursor, ScanArgs scanArgs); + Single> sscan(K key, ScanCursor scanCursor, ScanArgs scanArgs); /** * Incrementally iterate Set elements. @@ -248,7 +250,7 @@ public interface RedisSetReactiveCommands { * @param scanCursor cursor to resume from a previous scan, must not be {@literal null} * @return ValueScanCursor<V> scan cursor. */ - Observable> sscan(K key, ScanCursor scanCursor); + Single> sscan(K key, ScanCursor scanCursor); /** * Incrementally iterate Set elements. @@ -257,7 +259,7 @@ public interface RedisSetReactiveCommands { * @param key the key * @return StreamScanCursor scan cursor. */ - Observable sscan(ValueStreamingChannel channel, K key); + Single sscan(ValueStreamingChannel channel, K key); /** * Incrementally iterate Set elements. @@ -267,7 +269,7 @@ public interface RedisSetReactiveCommands { * @param scanArgs scan arguments * @return StreamScanCursor scan cursor. */ - Observable sscan(ValueStreamingChannel channel, K key, ScanArgs scanArgs); + Single sscan(ValueStreamingChannel channel, K key, ScanArgs scanArgs); /** * Incrementally iterate Set elements. @@ -278,7 +280,7 @@ public interface RedisSetReactiveCommands { * @param scanArgs scan arguments * @return StreamScanCursor scan cursor. */ - Observable sscan(ValueStreamingChannel channel, K key, ScanCursor scanCursor, ScanArgs scanArgs); + Single sscan(ValueStreamingChannel channel, K key, ScanCursor scanCursor, ScanArgs scanArgs); /** * Incrementally iterate Set elements. @@ -288,5 +290,5 @@ public interface RedisSetReactiveCommands { * @param scanCursor cursor to resume from a previous scan, must not be {@literal null} * @return StreamScanCursor scan cursor. */ - Observable sscan(ValueStreamingChannel channel, K key, ScanCursor scanCursor); + Single sscan(ValueStreamingChannel channel, K key, ScanCursor scanCursor); } diff --git a/src/main/java/com/lambdaworks/redis/api/rx/RedisSortedSetReactiveCommands.java b/src/main/java/com/lambdaworks/redis/api/rx/RedisSortedSetReactiveCommands.java index bdc42ded83..0da8841703 100644 --- a/src/main/java/com/lambdaworks/redis/api/rx/RedisSortedSetReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/rx/RedisSortedSetReactiveCommands.java @@ -11,6 +11,8 @@ import com.lambdaworks.redis.output.ScoredValueStreamingChannel; import com.lambdaworks.redis.output.ValueStreamingChannel; import rx.Observable; +import rx.Single; +import rx.Completable; /** * Observable commands for Sorted Sets. @@ -35,7 +37,7 @@ public interface RedisSortedSetReactiveCommands { * The number of elements added to the sorted sets, not including elements already existing for which the score was * updated. */ - Observable zadd(K key, double score, V member); + Single zadd(K key, double score, V member); /** * Add one or more members to a sorted set, or update its score if it already exists. @@ -47,7 +49,7 @@ public interface RedisSortedSetReactiveCommands { * The number of elements added to the sorted sets, not including elements already existing for which the score was * updated. */ - Observable zadd(K key, Object... scoresAndValues); + Single zadd(K key, Object... scoresAndValues); /** * Add one or more members to a sorted set, or update its score if it already exists. @@ -59,7 +61,7 @@ public interface RedisSortedSetReactiveCommands { * The number of elements added to the sorted sets, not including elements already existing for which the score was * updated. */ - Observable zadd(K key, ScoredValue... scoredValues); + Single zadd(K key, ScoredValue... scoredValues); /** * Add one or more members to a sorted set, or update its score if it already exists. @@ -74,7 +76,7 @@ public interface RedisSortedSetReactiveCommands { * The number of elements added to the sorted sets, not including elements already existing for which the score was * updated. */ - Observable zadd(K key, ZAddArgs zAddArgs, double score, V member); + Single zadd(K key, ZAddArgs zAddArgs, double score, V member); /** * Add one or more members to a sorted set, or update its score if it already exists. @@ -87,7 +89,7 @@ public interface RedisSortedSetReactiveCommands { * The number of elements added to the sorted sets, not including elements already existing for which the score was * updated. */ - Observable zadd(K key, ZAddArgs zAddArgs, Object... scoresAndValues); + Single zadd(K key, ZAddArgs zAddArgs, Object... scoresAndValues); /** * Add one or more members to a sorted set, or update its score if it already exists. @@ -100,7 +102,7 @@ public interface RedisSortedSetReactiveCommands { * The number of elements added to the sorted sets, not including elements already existing for which the score was * updated. */ - Observable zadd(K key, ZAddArgs zAddArgs, ScoredValue... scoredValues); + Single zadd(K key, ZAddArgs zAddArgs, ScoredValue... scoredValues); /** * ZADD acts like ZINCRBY @@ -113,7 +115,7 @@ public interface RedisSortedSetReactiveCommands { * * The total number of elements changed */ - Observable zaddincr(K key, double score, V member); + Single zaddincr(K key, double score, V member); /** * Get the number of members in a sorted set. @@ -122,7 +124,7 @@ public interface RedisSortedSetReactiveCommands { * @return Long integer-reply the cardinality (number of elements) of the sorted set, or {@literal false} if {@code key} * does not exist. */ - Observable zcard(K key); + Single zcard(K key); /** * Count the members in a sorted set with scores within the given values. @@ -132,7 +134,7 @@ public interface RedisSortedSetReactiveCommands { * @param max max score * @return Long integer-reply the number of elements in the specified score range. */ - Observable zcount(K key, double min, double max); + Single zcount(K key, double min, double max); /** * Count the members in a sorted set with scores within the given values. @@ -142,7 +144,7 @@ public interface RedisSortedSetReactiveCommands { * @param max max score * @return Long integer-reply the number of elements in the specified score range. */ - Observable zcount(K key, String min, String max); + Single zcount(K key, String min, String max); /** * Increment the score of a member in a sorted set. @@ -153,7 +155,7 @@ public interface RedisSortedSetReactiveCommands { * @return Double bulk-string-reply the new score of {@code member} (a double precision floating point number), represented * as string. */ - Observable zincrby(K key, double amount, K member); + Single zincrby(K key, double amount, K member); /** * Intersect multiple sorted sets and store the resulting sorted set in a new key. @@ -162,7 +164,7 @@ public interface RedisSortedSetReactiveCommands { * @param keys the keys * @return Long integer-reply the number of elements in the resulting sorted set at {@code destination}. */ - Observable zinterstore(K destination, K... keys); + Single zinterstore(K destination, K... keys); /** * Intersect multiple sorted sets and store the resulting sorted set in a new key. @@ -172,7 +174,7 @@ public interface RedisSortedSetReactiveCommands { * @param keys the keys * @return Long integer-reply the number of elements in the resulting sorted set at {@code destination}. */ - Observable zinterstore(K destination, ZStoreArgs storeArgs, K... keys); + Single zinterstore(K destination, ZStoreArgs storeArgs, K... keys); /** * Return a range of members in a sorted set, by index. @@ -291,7 +293,7 @@ public interface RedisSortedSetReactiveCommands { * @param stop the stop * @return Long count of elements in the specified range. */ - Observable zrange(ValueStreamingChannel channel, K key, long start, long stop); + Single zrange(ValueStreamingChannel channel, K key, long start, long stop); /** * Stream over a range of members with scores in a sorted set, by index. @@ -302,7 +304,7 @@ public interface RedisSortedSetReactiveCommands { * @param stop the stop * @return Long count of elements in the specified range. */ - Observable zrangeWithScores(ScoredValueStreamingChannel channel, K key, long start, long stop); + Single zrangeWithScores(ScoredValueStreamingChannel channel, K key, long start, long stop); /** * Stream over a range of members in a sorted set, by score. @@ -313,7 +315,7 @@ public interface RedisSortedSetReactiveCommands { * @param max max score * @return Long count of elements in the specified score range. */ - Observable zrangebyscore(ValueStreamingChannel channel, K key, double min, double max); + Single zrangebyscore(ValueStreamingChannel channel, K key, double min, double max); /** * Stream over a range of members in a sorted set, by score. @@ -324,7 +326,7 @@ public interface RedisSortedSetReactiveCommands { * @param max max score * @return Long count of elements in the specified score range. */ - Observable zrangebyscore(ValueStreamingChannel channel, K key, String min, String max); + Single zrangebyscore(ValueStreamingChannel channel, K key, String min, String max); /** * Stream over range of members in a sorted set, by score. @@ -337,7 +339,7 @@ public interface RedisSortedSetReactiveCommands { * @param count the count * @return Long count of elements in the specified score range. */ - Observable zrangebyscore(ValueStreamingChannel channel, K key, double min, double max, long offset, long count); + Single zrangebyscore(ValueStreamingChannel channel, K key, double min, double max, long offset, long count); /** * Stream over a range of members in a sorted set, by score. @@ -350,7 +352,7 @@ public interface RedisSortedSetReactiveCommands { * @param count the count * @return Long count of elements in the specified score range. */ - Observable zrangebyscore(ValueStreamingChannel channel, K key, String min, String max, long offset, long count); + Single zrangebyscore(ValueStreamingChannel channel, K key, String min, String max, long offset, long count); /** * Stream over a range of members with scores in a sorted set, by score. @@ -361,7 +363,7 @@ public interface RedisSortedSetReactiveCommands { * @param max max score * @return Long count of elements in the specified score range. */ - Observable zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, double min, double max); + Single zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, double min, double max); /** * Stream over a range of members with scores in a sorted set, by score. @@ -372,7 +374,7 @@ public interface RedisSortedSetReactiveCommands { * @param max max score * @return Long count of elements in the specified score range. */ - Observable zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, String min, String max); + Single zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, String min, String max); /** * Stream over a range of members with scores in a sorted set, by score. @@ -385,7 +387,7 @@ public interface RedisSortedSetReactiveCommands { * @param count the count * @return Long count of elements in the specified score range. */ - Observable zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, double min, double max, long offset, long count); + Single zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, double min, double max, long offset, long count); /** * Stream over a range of members with scores in a sorted set, by score. @@ -398,7 +400,7 @@ public interface RedisSortedSetReactiveCommands { * @param count the count * @return Long count of elements in the specified score range. */ - Observable zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, String min, String max, long offset, long count); + Single zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, String min, String max, long offset, long count); /** * Determine the index of a member in a sorted set. @@ -408,7 +410,7 @@ public interface RedisSortedSetReactiveCommands { * @return Long integer-reply the rank of {@code member}. If {@code member} does not exist in the sorted set or {@code key} * does not exist, */ - Observable zrank(K key, V member); + Single zrank(K key, V member); /** * Remove one or more members from a sorted set. @@ -419,7 +421,7 @@ public interface RedisSortedSetReactiveCommands { * * The number of members removed from the sorted set, not including non existing members. */ - Observable zrem(K key, V... members); + Single zrem(K key, V... members); /** * Remove all members in a sorted set within the given indexes. @@ -429,7 +431,7 @@ public interface RedisSortedSetReactiveCommands { * @param stop the stop type: long * @return Long integer-reply the number of elements removed. */ - Observable zremrangebyrank(K key, long start, long stop); + Single zremrangebyrank(K key, long start, long stop); /** * Remove all members in a sorted set within the given scores. @@ -439,7 +441,7 @@ public interface RedisSortedSetReactiveCommands { * @param max max score * @return Long integer-reply the number of elements removed. */ - Observable zremrangebyscore(K key, double min, double max); + Single zremrangebyscore(K key, double min, double max); /** * Remove all members in a sorted set within the given scores. @@ -449,7 +451,7 @@ public interface RedisSortedSetReactiveCommands { * @param max max score * @return Long integer-reply the number of elements removed. */ - Observable zremrangebyscore(K key, String min, String max); + Single zremrangebyscore(K key, String min, String max); /** * Return a range of members in a sorted set, by index, with scores ordered from high to low. @@ -568,7 +570,7 @@ public interface RedisSortedSetReactiveCommands { * @param stop the stop * @return Long count of elements in the specified range. */ - Observable zrevrange(ValueStreamingChannel channel, K key, long start, long stop); + Single zrevrange(ValueStreamingChannel channel, K key, long start, long stop); /** * Stream over a range of members with scores in a sorted set, by index, with scores ordered from high to low. @@ -579,7 +581,7 @@ public interface RedisSortedSetReactiveCommands { * @param stop the stop * @return Long count of elements in the specified range. */ - Observable zrevrangeWithScores(ScoredValueStreamingChannel channel, K key, long start, long stop); + Single zrevrangeWithScores(ScoredValueStreamingChannel channel, K key, long start, long stop); /** * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. @@ -590,7 +592,7 @@ public interface RedisSortedSetReactiveCommands { * @param min min score * @return Long count of elements in the specified range. */ - Observable zrevrangebyscore(ValueStreamingChannel channel, K key, double max, double min); + Single zrevrangebyscore(ValueStreamingChannel channel, K key, double max, double min); /** * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. @@ -601,7 +603,7 @@ public interface RedisSortedSetReactiveCommands { * @param max max score * @return Long count of elements in the specified range. */ - Observable zrevrangebyscore(ValueStreamingChannel channel, K key, String max, String min); + Single zrevrangebyscore(ValueStreamingChannel channel, K key, String max, String min); /** * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. @@ -614,7 +616,7 @@ public interface RedisSortedSetReactiveCommands { * @param count the count * @return Long count of elements in the specified range. */ - Observable zrevrangebyscore(ValueStreamingChannel channel, K key, double max, double min, long offset, long count); + Single zrevrangebyscore(ValueStreamingChannel channel, K key, double max, double min, long offset, long count); /** * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. @@ -627,7 +629,7 @@ public interface RedisSortedSetReactiveCommands { * @param count the count * @return Long count of elements in the specified range. */ - Observable zrevrangebyscore(ValueStreamingChannel channel, K key, String max, String min, long offset, long count); + Single zrevrangebyscore(ValueStreamingChannel channel, K key, String max, String min, long offset, long count); /** * Stream over a range of members with scores in a sorted set, by score, with scores ordered from high to low. @@ -638,7 +640,7 @@ public interface RedisSortedSetReactiveCommands { * @param max max score * @return Long count of elements in the specified range. */ - Observable zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, double max, double min); + Single zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, double max, double min); /** * Stream over a range of members with scores in a sorted set, by score, with scores ordered from high to low. @@ -649,7 +651,7 @@ public interface RedisSortedSetReactiveCommands { * @param max max score * @return Long count of elements in the specified range. */ - Observable zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, String max, String min); + Single zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, String max, String min); /** * Stream over a range of members with scores in a sorted set, by score, with scores ordered from high to low. @@ -662,7 +664,7 @@ public interface RedisSortedSetReactiveCommands { * @param count the count * @return Long count of elements in the specified range. */ - Observable zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, double max, double min, long offset, long count); + Single zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, double max, double min, long offset, long count); /** * Stream over a range of members with scores in a sorted set, by score, with scores ordered from high to low. @@ -675,7 +677,7 @@ public interface RedisSortedSetReactiveCommands { * @param count the count * @return Long count of elements in the specified range. */ - Observable zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, String max, String min, long offset, long count); + Single zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, String max, String min, long offset, long count); /** * Determine the index of a member in a sorted set, with scores ordered from high to low. @@ -685,7 +687,7 @@ public interface RedisSortedSetReactiveCommands { * @return Long integer-reply the rank of {@code member}. If {@code member} does not exist in the sorted set or {@code key} * does not exist, */ - Observable zrevrank(K key, V member); + Single zrevrank(K key, V member); /** * Get the score associated with the given member in a sorted set. @@ -695,7 +697,7 @@ public interface RedisSortedSetReactiveCommands { * @return Double bulk-string-reply the score of {@code member} (a double precision floating point number), represented as * string. */ - Observable zscore(K key, V member); + Single zscore(K key, V member); /** * Add multiple sorted sets and store the resulting sorted set in a new key. @@ -704,7 +706,7 @@ public interface RedisSortedSetReactiveCommands { * @param keys source keys * @return Long integer-reply the number of elements in the resulting sorted set at {@code destination}. */ - Observable zunionstore(K destination, K... keys); + Single zunionstore(K destination, K... keys); /** * Add multiple sorted sets and store the resulting sorted set in a new key. @@ -714,7 +716,7 @@ public interface RedisSortedSetReactiveCommands { * @param keys the keys * @return Long integer-reply the number of elements in the resulting sorted set at {@code destination}. */ - Observable zunionstore(K destination, ZStoreArgs storeArgs, K... keys); + Single zunionstore(K destination, ZStoreArgs storeArgs, K... keys); /** * Incrementally iterate sorted sets elements and associated scores. @@ -722,7 +724,7 @@ public interface RedisSortedSetReactiveCommands { * @param key the key * @return ScoredValueScanCursor<V> scan cursor. */ - Observable> zscan(K key); + Single> zscan(K key); /** * Incrementally iterate sorted sets elements and associated scores. @@ -731,7 +733,7 @@ public interface RedisSortedSetReactiveCommands { * @param scanArgs scan arguments * @return ScoredValueScanCursor<V> scan cursor. */ - Observable> zscan(K key, ScanArgs scanArgs); + Single> zscan(K key, ScanArgs scanArgs); /** * Incrementally iterate sorted sets elements and associated scores. @@ -741,7 +743,7 @@ public interface RedisSortedSetReactiveCommands { * @param scanArgs scan arguments * @return ScoredValueScanCursor<V> scan cursor. */ - Observable> zscan(K key, ScanCursor scanCursor, ScanArgs scanArgs); + Single> zscan(K key, ScanCursor scanCursor, ScanArgs scanArgs); /** * Incrementally iterate sorted sets elements and associated scores. @@ -750,7 +752,7 @@ public interface RedisSortedSetReactiveCommands { * @param scanCursor cursor to resume from a previous scan, must not be {@literal null} * @return ScoredValueScanCursor<V> scan cursor. */ - Observable> zscan(K key, ScanCursor scanCursor); + Single> zscan(K key, ScanCursor scanCursor); /** * Incrementally iterate sorted sets elements and associated scores. @@ -759,7 +761,7 @@ public interface RedisSortedSetReactiveCommands { * @param key the key * @return StreamScanCursor scan cursor. */ - Observable zscan(ScoredValueStreamingChannel channel, K key); + Single zscan(ScoredValueStreamingChannel channel, K key); /** * Incrementally iterate sorted sets elements and associated scores. @@ -769,7 +771,7 @@ public interface RedisSortedSetReactiveCommands { * @param scanArgs scan arguments * @return StreamScanCursor scan cursor. */ - Observable zscan(ScoredValueStreamingChannel channel, K key, ScanArgs scanArgs); + Single zscan(ScoredValueStreamingChannel channel, K key, ScanArgs scanArgs); /** * Incrementally iterate sorted sets elements and associated scores. @@ -780,7 +782,7 @@ public interface RedisSortedSetReactiveCommands { * @param scanArgs scan arguments * @return StreamScanCursor scan cursor. */ - Observable zscan(ScoredValueStreamingChannel channel, K key, ScanCursor scanCursor, ScanArgs scanArgs); + Single zscan(ScoredValueStreamingChannel channel, K key, ScanCursor scanCursor, ScanArgs scanArgs); /** * Incrementally iterate sorted sets elements and associated scores. @@ -790,7 +792,7 @@ public interface RedisSortedSetReactiveCommands { * @param scanCursor cursor to resume from a previous scan, must not be {@literal null} * @return StreamScanCursor scan cursor. */ - Observable zscan(ScoredValueStreamingChannel channel, K key, ScanCursor scanCursor); + Single zscan(ScoredValueStreamingChannel channel, K key, ScanCursor scanCursor); /** * Count the number of members in a sorted set between a given lexicographical range. @@ -800,7 +802,7 @@ public interface RedisSortedSetReactiveCommands { * @param max max score * @return Long integer-reply the number of elements in the specified score range. */ - Observable zlexcount(K key, String min, String max); + Single zlexcount(K key, String min, String max); /** * Remove all members in a sorted set between the given lexicographical range. @@ -810,7 +812,7 @@ public interface RedisSortedSetReactiveCommands { * @param max max score * @return Long integer-reply the number of elements removed. */ - Observable zremrangebylex(K key, String min, String max); + Single zremrangebylex(K key, String min, String max); /** * Return a range of members in a sorted set, by lexicographical range. diff --git a/src/main/java/com/lambdaworks/redis/api/rx/RedisStringReactiveCommands.java b/src/main/java/com/lambdaworks/redis/api/rx/RedisStringReactiveCommands.java index 1d26d273d9..347e825982 100644 --- a/src/main/java/com/lambdaworks/redis/api/rx/RedisStringReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/rx/RedisStringReactiveCommands.java @@ -6,6 +6,8 @@ import com.lambdaworks.redis.BitFieldArgs; import com.lambdaworks.redis.SetArgs; import rx.Observable; +import rx.Single; +import rx.Completable; /** * Observable commands for Strings. @@ -25,7 +27,7 @@ public interface RedisStringReactiveCommands { * @param value the value * @return Long integer-reply the length of the string after the append operation. */ - Observable append(K key, V value); + Single append(K key, V value); /** * Count set bits in a string. @@ -34,7 +36,7 @@ public interface RedisStringReactiveCommands { * * @return Long integer-reply The number of bits set to 1. */ - Observable bitcount(K key); + Single bitcount(K key); /** * Count set bits in a string. @@ -45,7 +47,7 @@ public interface RedisStringReactiveCommands { * * @return Long integer-reply The number of bits set to 1. */ - Observable bitcount(K key, long start, long end); + Single bitcount(K key, long start, long end); /** * Execute {@code BITFIELD} with its subcommands. @@ -79,7 +81,7 @@ public interface RedisStringReactiveCommands { * start and end. If no clear bit is found in the specified range, the function * returns -1 as the user specified a clear range and there are no 0 bits in that range. */ - Observable bitpos(K key, boolean state); + Single bitpos(K key, boolean state); /** * Find first bit set or clear in a string. @@ -104,7 +106,7 @@ public interface RedisStringReactiveCommands { * start and end. If no clear bit is found in the specified range, the function * returns -1 as the user specified a clear range and there are no 0 bits in that range. */ - Observable bitpos(K key, boolean state, long start, long end); + Single bitpos(K key, boolean state, long start, long end); /** * Perform bitwise AND between strings. @@ -114,7 +116,7 @@ public interface RedisStringReactiveCommands { * @return Long integer-reply The size of the string stored in the destination key, that is equal to the size of the longest * input string. */ - Observable bitopAnd(K destination, K... keys); + Single bitopAnd(K destination, K... keys); /** * Perform bitwise NOT between strings. @@ -124,7 +126,7 @@ public interface RedisStringReactiveCommands { * @return Long integer-reply The size of the string stored in the destination key, that is equal to the size of the longest * input string. */ - Observable bitopNot(K destination, K source); + Single bitopNot(K destination, K source); /** * Perform bitwise OR between strings. @@ -134,7 +136,7 @@ public interface RedisStringReactiveCommands { * @return Long integer-reply The size of the string stored in the destination key, that is equal to the size of the longest * input string. */ - Observable bitopOr(K destination, K... keys); + Single bitopOr(K destination, K... keys); /** * Perform bitwise XOR between strings. @@ -144,7 +146,7 @@ public interface RedisStringReactiveCommands { * @return Long integer-reply The size of the string stored in the destination key, that is equal to the size of the longest * input string. */ - Observable bitopXor(K destination, K... keys); + Single bitopXor(K destination, K... keys); /** * Decrement the integer value of a key by one. @@ -152,7 +154,7 @@ public interface RedisStringReactiveCommands { * @param key the key * @return Long integer-reply the value of {@code key} after the decrement */ - Observable decr(K key); + Single decr(K key); /** * Decrement the integer value of a key by the given number. @@ -161,7 +163,7 @@ public interface RedisStringReactiveCommands { * @param amount the decrement type: long * @return Long integer-reply the value of {@code key} after the decrement */ - Observable decrby(K key, long amount); + Single decrby(K key, long amount); /** * Get the value of a key. @@ -169,7 +171,7 @@ public interface RedisStringReactiveCommands { * @param key the key * @return V bulk-string-reply the value of {@code key}, or {@literal null} when {@code key} does not exist. */ - Observable get(K key); + Single get(K key); /** * Returns the bit value at offset in the string value stored at key. @@ -178,7 +180,7 @@ public interface RedisStringReactiveCommands { * @param offset the offset type: long * @return Long integer-reply the bit value stored at offset. */ - Observable getbit(K key, long offset); + Single getbit(K key, long offset); /** * Get a substring of the string stored at a key. @@ -188,7 +190,7 @@ public interface RedisStringReactiveCommands { * @param end the end type: long * @return V bulk-string-reply */ - Observable getrange(K key, long start, long end); + Single getrange(K key, long start, long end); /** * Set the string value of a key and return its old value. @@ -197,7 +199,7 @@ public interface RedisStringReactiveCommands { * @param value the value * @return V bulk-string-reply the old value stored at {@code key}, or {@literal null} when {@code key} did not exist. */ - Observable getset(K key, V value); + Single getset(K key, V value); /** * Increment the integer value of a key by one. @@ -205,7 +207,7 @@ public interface RedisStringReactiveCommands { * @param key the key * @return Long integer-reply the value of {@code key} after the increment */ - Observable incr(K key); + Single incr(K key); /** * Increment the integer value of a key by the given amount. @@ -214,7 +216,7 @@ public interface RedisStringReactiveCommands { * @param amount the increment type: long * @return Long integer-reply the value of {@code key} after the increment */ - Observable incrby(K key, long amount); + Single incrby(K key, long amount); /** * Increment the float value of a key by the given amount. @@ -223,7 +225,7 @@ public interface RedisStringReactiveCommands { * @param amount the increment type: double * @return Double bulk-string-reply the value of {@code key} after the increment. */ - Observable incrbyfloat(K key, double amount); + Single incrbyfloat(K key, double amount); /** * Get the values of all the given keys. @@ -241,7 +243,7 @@ public interface RedisStringReactiveCommands { * * @return Long array-reply list of values at the specified keys. */ - Observable mget(ValueStreamingChannel channel, K... keys); + Single mget(ValueStreamingChannel channel, K... keys); /** * Set multiple keys to multiple values. @@ -249,7 +251,7 @@ public interface RedisStringReactiveCommands { * @param map the null * @return String simple-string-reply always {@code OK} since {@code MSET} can't fail. */ - Observable mset(Map map); + Single mset(Map map); /** * Set multiple keys to multiple values, only if none of the keys exist. @@ -259,7 +261,7 @@ public interface RedisStringReactiveCommands { * * {@code 1} if the all the keys were set. {@code 0} if no key was set (at least one key already existed). */ - Observable msetnx(Map map); + Single msetnx(Map map); /** * Set the string value of a key. @@ -269,7 +271,7 @@ public interface RedisStringReactiveCommands { * * @return String simple-string-reply {@code OK} if {@code SET} was executed correctly. */ - Observable set(K key, V value); + Single set(K key, V value); /** * Set the string value of a key. @@ -280,7 +282,7 @@ public interface RedisStringReactiveCommands { * * @return String simple-string-reply {@code OK} if {@code SET} was executed correctly. */ - Observable set(K key, V value, SetArgs setArgs); + Single set(K key, V value, SetArgs setArgs); /** * Sets or clears the bit at offset in the string value stored at key. @@ -290,7 +292,7 @@ public interface RedisStringReactiveCommands { * @param value the value type: string * @return Long integer-reply the original bit value stored at offset. */ - Observable setbit(K key, long offset, int value); + Single setbit(K key, long offset, int value); /** * Set the value and expiration of a key. @@ -300,7 +302,7 @@ public interface RedisStringReactiveCommands { * @param value the value * @return String simple-string-reply */ - Observable setex(K key, long seconds, V value); + Single setex(K key, long seconds, V value); /** * Set the value and expiration in milliseconds of a key. @@ -310,7 +312,7 @@ public interface RedisStringReactiveCommands { * @param value the value * @return String simple-string-reply */ - Observable psetex(K key, long milliseconds, V value); + Single psetex(K key, long milliseconds, V value); /** * Set the value of a key, only if the key does not exist. @@ -321,7 +323,7 @@ public interface RedisStringReactiveCommands { * * {@code 1} if the key was set {@code 0} if the key was not set */ - Observable setnx(K key, V value); + Single setnx(K key, V value); /** * Overwrite part of a string at key starting at the specified offset. @@ -331,7 +333,7 @@ public interface RedisStringReactiveCommands { * @param value the value * @return Long integer-reply the length of the string after it was modified by the command. */ - Observable setrange(K key, long offset, V value); + Single setrange(K key, long offset, V value); /** * Get the length of the value stored in a key. @@ -339,5 +341,5 @@ public interface RedisStringReactiveCommands { * @param key the key * @return Long integer-reply the length of the string at {@code key}, or {@code 0} when {@code key} does not exist. */ - Observable strlen(K key); + Single strlen(K key); } diff --git a/src/main/java/com/lambdaworks/redis/api/rx/RedisTransactionalReactiveCommands.java b/src/main/java/com/lambdaworks/redis/api/rx/RedisTransactionalReactiveCommands.java index 3cc1f8e776..5472ecff6d 100644 --- a/src/main/java/com/lambdaworks/redis/api/rx/RedisTransactionalReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/rx/RedisTransactionalReactiveCommands.java @@ -2,6 +2,8 @@ import java.util.List; import rx.Observable; +import rx.Single; +import rx.Completable; /** * Observable commands for Transactions. @@ -19,7 +21,7 @@ public interface RedisTransactionalReactiveCommands { * * @return String simple-string-reply always {@code OK}. */ - Observable discard(); + Single discard(); /** * Execute all commands issued after MULTI. @@ -35,7 +37,7 @@ public interface RedisTransactionalReactiveCommands { * * @return String simple-string-reply always {@code OK}. */ - Observable multi(); + Single multi(); /** * Watch the given keys to determine execution of the MULTI/EXEC block. @@ -43,12 +45,12 @@ public interface RedisTransactionalReactiveCommands { * @param keys the key * @return String simple-string-reply always {@code OK}. */ - Observable watch(K... keys); + Single watch(K... keys); /** * Forget about all watched keys. * * @return String simple-string-reply always {@code OK}. */ - Observable unwatch(); + Single unwatch(); } diff --git a/src/main/java/com/lambdaworks/redis/cluster/ClusterScanSupport.java b/src/main/java/com/lambdaworks/redis/cluster/ClusterScanSupport.java index 991b9076c3..2151558aac 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/ClusterScanSupport.java +++ b/src/main/java/com/lambdaworks/redis/cluster/ClusterScanSupport.java @@ -5,14 +5,15 @@ import java.util.List; import java.util.function.Function; -import rx.Observable; -import rx.functions.Func1; - import com.lambdaworks.redis.*; import com.lambdaworks.redis.cluster.api.StatefulRedisClusterConnection; import com.lambdaworks.redis.cluster.models.partitions.RedisClusterNode; import com.lambdaworks.redis.models.role.RedisNodeDescription; +import rx.Observable; +import rx.Single; +import rx.functions.Func1; + /** * Methods to support a Cluster-wide SCAN operation over multiple hosts. * @@ -53,34 +54,21 @@ public StreamScanCursor apply(StreamScanCursor result) { }; /** - * Map a {@link Observable} of {@link KeyScanCursor} to a {@link Observable} of {@link ClusterKeyScanCursor}. + * Map a {@link Single} of {@link KeyScanCursor} to a {@link Observable} of {@link ClusterKeyScanCursor}. */ - final static ScanCursorMapper>> reactiveKeyScanCursorMapper = new ScanCursorMapper>>() { - @Override - public Observable> map(List nodeIds, String currentNodeId, Observable> cursor) { - return cursor.map(new Func1, KeyScanCursor>() { - @Override - public KeyScanCursor call(KeyScanCursor keyScanCursor) { - return new ClusterKeyScanCursor<>(nodeIds, currentNodeId, keyScanCursor); - } - }); - } - }; + final static ScanCursorMapper>> reactiveKeyScanCursorMapper = (nodeIds, currentNodeId, + cursor) -> cursor.map(keyScanCursor -> new ClusterKeyScanCursor<>(nodeIds, currentNodeId, keyScanCursor)); /** - * Map a {@link Observable} of {@link StreamScanCursor} to a {@link Observable} of {@link ClusterStreamScanCursor}. + * Map a {@link Single} of {@link StreamScanCursor} to a {@link Observable} of {@link ClusterStreamScanCursor}. */ - final static ScanCursorMapper> reactiveStreamScanCursorMapper = new ScanCursorMapper>() { - @Override - public Observable map(List nodeIds, String currentNodeId, Observable cursor) { - return cursor.map(new Func1() { + final static ScanCursorMapper> reactiveStreamScanCursorMapper = (nodeIds, currentNodeId, + cursor) -> cursor.map(new Func1() { @Override public StreamScanCursor call(StreamScanCursor streamScanCursor) { return new ClusterStreamScanCursor(nodeIds, currentNodeId, streamScanCursor); } }); - } - }; /** * Retrieve the cursor to continue the scan. @@ -202,11 +190,11 @@ static ScanCursorMapper> asyncClusterStreamScanCur return futureStreamScanCursorMapper; } - static ScanCursorMapper>> reactiveClusterKeyScanCursorMapper() { + static ScanCursorMapper>> reactiveClusterKeyScanCursorMapper() { return (ScanCursorMapper) reactiveKeyScanCursorMapper; } - static ScanCursorMapper> reactiveClusterStreamScanCursorMapper() { + static ScanCursorMapper> reactiveClusterStreamScanCursorMapper() { return reactiveStreamScanCursorMapper; } diff --git a/src/main/java/com/lambdaworks/redis/cluster/RedisAdvancedClusterReactiveCommandsImpl.java b/src/main/java/com/lambdaworks/redis/cluster/RedisAdvancedClusterReactiveCommandsImpl.java index 219487850a..f112c4f181 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/RedisAdvancedClusterReactiveCommandsImpl.java +++ b/src/main/java/com/lambdaworks/redis/cluster/RedisAdvancedClusterReactiveCommandsImpl.java @@ -15,9 +15,6 @@ import com.lambdaworks.redis.*; import com.lambdaworks.redis.api.StatefulRedisConnection; import com.lambdaworks.redis.api.rx.RedisKeyReactiveCommands; -import com.lambdaworks.redis.api.rx.RedisScriptingReactiveCommands; -import com.lambdaworks.redis.api.rx.RedisServerReactiveCommands; -import com.lambdaworks.redis.api.rx.Success; import com.lambdaworks.redis.cluster.api.StatefulRedisClusterConnection; import com.lambdaworks.redis.cluster.api.rx.RedisAdvancedClusterReactiveCommands; import com.lambdaworks.redis.cluster.api.rx.RedisClusterReactiveCommands; @@ -27,7 +24,9 @@ import com.lambdaworks.redis.output.KeyStreamingChannel; import com.lambdaworks.redis.output.ValueStreamingChannel; +import rx.Completable; import rx.Observable; +import rx.Single; /** * An advanced reactive and thread-safe API to a Redis Cluster connection. @@ -35,8 +34,8 @@ * @author Mark Paluch * @since 4.0 */ -public class RedisAdvancedClusterReactiveCommandsImpl extends AbstractRedisReactiveCommands implements - RedisAdvancedClusterReactiveCommands { +public class RedisAdvancedClusterReactiveCommandsImpl extends AbstractRedisReactiveCommands + implements RedisAdvancedClusterReactiveCommands { private Random random = new Random(); @@ -46,17 +45,18 @@ public class RedisAdvancedClusterReactiveCommandsImpl extends AbstractRedi * @param connection the stateful connection * @param codec Codec used to encode/decode keys and values. */ - public RedisAdvancedClusterReactiveCommandsImpl(StatefulRedisClusterConnectionImpl connection, RedisCodec codec) { + public RedisAdvancedClusterReactiveCommandsImpl(StatefulRedisClusterConnectionImpl connection, + RedisCodec codec) { super(connection, codec); } @Override - public Observable del(K... keys) { + public Single del(K... keys) { return del(Arrays.asList(keys)); } @Override - public Observable del(Iterable keys) { + public Single del(Iterable keys) { Map> partitioned = SlotHash.partition(codec, keys); @@ -67,19 +67,19 @@ public Observable del(Iterable keys) { List> observables = new ArrayList<>(); for (Map.Entry> entry : partitioned.entrySet()) { - observables.add(super.del(entry.getValue())); + observables.add(super.del(entry.getValue()).toObservable()); } - return Observable.merge(observables).reduce((accu, next) -> accu + next); + return Observable.merge(observables).reduce((accu, next) -> accu + next).last().toSingle(); } @Override - public Observable unlink(K... keys) { + public Single unlink(K... keys) { return unlink(Arrays.asList(keys)); } @Override - public Observable unlink(Iterable keys) { + public Single unlink(Iterable keys) { Map> partitioned = SlotHash.partition(codec, keys); @@ -90,32 +90,34 @@ public Observable unlink(Iterable keys) { List> observables = new ArrayList<>(); for (Map.Entry> entry : partitioned.entrySet()) { - observables.add(super.unlink(entry.getValue())); + observables.add(super.unlink(entry.getValue()).toObservable()); } - return Observable.merge(observables).reduce((accu, next) -> accu + next); + return Observable.merge(observables).reduce((accu, next) -> accu + next).last().toSingle(); } @Override - public Observable exists(K... keys) { + public Single exists(K... keys) { return exists(Arrays.asList(keys)); } - public Observable exists(Iterable keys) { + public Single exists(Iterable keys) { - Map> partitioned = SlotHash.partition(codec, keys); + List keyList = LettuceLists.newList(keys); + + Map> partitioned = SlotHash.partition(codec, keyList); if (partitioned.size() < 2) { - return super.exists(keys); + return super.exists(keyList); } List> observables = new ArrayList<>(); for (Map.Entry> entry : partitioned.entrySet()) { - observables.add(super.exists(entry.getValue())); + observables.add(super.exists(entry.getValue()).toObservable()); } - return Observable.merge(observables).reduce((accu, next) -> accu + next); + return Observable.merge(observables).reduce((accu, next) -> accu + next).toSingle(); } @Override @@ -166,13 +168,15 @@ public Observable mget(Iterable keys) { } @Override - public Observable mget(ValueStreamingChannel channel, K... keys) { + public Single mget(ValueStreamingChannel channel, K... keys) { return mget(channel, Arrays.asList(keys)); } - public Observable mget(ValueStreamingChannel channel, Iterable keys) { + @Override + public Single mget(ValueStreamingChannel channel, Iterable keys) { List keyList = LettuceLists.newList(keys); + Map> partitioned = SlotHash.partition(codec, keyList); if (partitioned.size() < 2) { @@ -182,22 +186,22 @@ public Observable mget(ValueStreamingChannel channel, Iterable keys) List> observables = new ArrayList<>(); for (Map.Entry> entry : partitioned.entrySet()) { - observables.add(super.mget(channel, entry.getValue())); + observables.add(super.mget(channel, entry.getValue()).toObservable()); } - return Observable.merge(observables).reduce((accu, next) -> accu + next); + return Observable.merge(observables).reduce((accu, next) -> accu + next).last().toSingle(); } @Override - public Observable msetnx(Map map) { + public Single msetnx(Map map) { - return pipeliningWithMap(map, kvMap -> super.msetnx(kvMap), - booleanObservable -> booleanObservable.reduce((accu, next) -> accu || next)); + return pipeliningWithMap(map, kvMap -> super.msetnx(kvMap).toObservable(), + booleanObservable -> booleanObservable.reduce((accu, next) -> accu || next)).last().toSingle(); } @Override - public Observable mset(Map map) { - return pipeliningWithMap(map, kvMap -> super.mset(kvMap), Observable::last); + public Single mset(Map map) { + return pipeliningWithMap(map, kvMap -> super.mset(kvMap).toObservable(), Observable::last).last().toSingle(); } @Override @@ -212,7 +216,7 @@ public Observable clusterGetKeysInSlot(int slot, int count) { } @Override - public Observable clusterCountKeysInSlot(int slot) { + public Single clusterCountKeysInSlot(int slot) { RedisClusterReactiveCommands connectionBySlot = findConnectionBySlot(slot); if (connectionBySlot != null) { @@ -223,41 +227,42 @@ public Observable clusterCountKeysInSlot(int slot) { } @Override - public Observable clientSetname(K name) { + public Single clientSetname(K name) { List> observables = new ArrayList<>(); for (RedisClusterNode redisClusterNode : getStatefulConnection().getPartitions()) { StatefulRedisConnection byNodeId = getStatefulConnection().getConnection(redisClusterNode.getNodeId()); if (byNodeId.isOpen()) { - observables.add(byNodeId.reactive().clientSetname(name)); + observables.add(byNodeId.reactive().clientSetname(name).toObservable()); } - StatefulRedisConnection byHost = getStatefulConnection().getConnection(redisClusterNode.getUri().getHost(), redisClusterNode - .getUri().getPort()); + StatefulRedisConnection byHost = getStatefulConnection().getConnection(redisClusterNode.getUri().getHost(), + redisClusterNode.getUri().getPort()); if (byHost.isOpen()) { - observables.add(byHost.reactive().clientSetname(name)); + observables.add(byHost.reactive().clientSetname(name).toObservable()); } } - return Observable.merge(observables).last(); + return Observable.merge(observables).last().last().toSingle(); } @Override - public Observable dbsize() { - Map> observables = executeOnMasters(RedisServerReactiveCommands::dbsize); - return Observable.merge(observables.values()).reduce((accu, next) -> accu + next); + public Single dbsize() { + Map> observables = executeOnMasters((commands) -> commands.dbsize().toObservable()); + return Observable.merge(observables.values()).reduce((accu, next) -> accu + next).toSingle(); } @Override - public Observable flushall() { - Map> observables = executeOnMasters(RedisServerReactiveCommands::flushall); - return Observable.merge(observables.values()).last(); + public Single flushall() { + Map> observables = executeOnMasters( + (kvRedisClusterReactiveCommancommandss) -> kvRedisClusterReactiveCommancommandss.flushall().toObservable()); + return Observable.merge(observables.values()).last().last().toSingle(); } @Override - public Observable flushdb() { - Map> observables = executeOnMasters(RedisServerReactiveCommands::flushdb); - return Observable.merge(observables.values()).last(); + public Single flushdb() { + Map> observables = executeOnMasters((commands) -> commands.flushdb().toObservable()); + return Observable.merge(observables.values()).last().last().toSingle(); } @Override @@ -267,13 +272,14 @@ public Observable keys(K pattern) { } @Override - public Observable keys(KeyStreamingChannel channel, K pattern) { - Map> observables = executeOnMasters(commands -> commands.keys(channel, pattern)); - return Observable.merge(observables.values()).reduce((accu, next) -> accu + next); + public Single keys(KeyStreamingChannel channel, K pattern) { + Map> observables = executeOnMasters( + commands -> commands.keys(channel, pattern).toObservable()); + return Observable.merge(observables.values()).reduce((accu, next) -> accu + next).last().toSingle(); } @Override - public Observable randomkey() { + public Single randomkey() { Partitions partitions = getStatefulConnection().getPartitions(); int index = random.nextInt(partitions.size()); @@ -283,32 +289,32 @@ public Observable randomkey() { } @Override - public Observable scriptFlush() { - Map> observables = executeOnNodes(RedisScriptingReactiveCommands::scriptFlush, + public Single scriptFlush() { + Map> observables = executeOnNodes((commands) -> commands.scriptFlush().toObservable(), redisClusterNode -> true); - return Observable.merge(observables.values()).last(); + return Observable.merge(observables.values()).last().last().toSingle(); } @Override - public Observable scriptKill() { - Map> observables = executeOnNodes(RedisScriptingReactiveCommands::scriptFlush, + public Single scriptKill() { + Map> observables = executeOnNodes((commands) -> commands.scriptFlush().toObservable(), redisClusterNode -> true); - return Observable.merge(observables.values()).onErrorReturn(throwable -> "OK").last(); + return Observable.merge(observables.values()).onErrorReturn(throwable -> "OK").last().toSingle(); } @Override - public Observable shutdown(boolean save) { - Map> observables = executeOnNodes(commands -> commands.shutdown(save), + public Completable shutdown(boolean save) { + Map> observables = executeOnNodes(commands -> commands.shutdown(save).toObservable(), redisClusterNode -> true); - return Observable.merge(observables.values()).onErrorReturn(throwable -> null).last(); + return Completable.fromObservable(Observable.merge(observables.values()).onErrorReturn(throwable -> null).last()); } @Override - public Observable touch(K... keys) { + public Single touch(K... keys) { return touch(Arrays.asList(keys)); } - public Observable touch(Iterable keys) { + public Single touch(Iterable keys) { List keyList = LettuceLists.newList(keys); Map> partitioned = SlotHash.partition(codec, keyList); @@ -320,10 +326,10 @@ public Observable touch(Iterable keys) { List> observables = new ArrayList<>(); for (Map.Entry> entry : partitioned.entrySet()) { - observables.add(super.touch(entry.getValue())); + observables.add(super.touch(entry.getValue()).toObservable()); } - return Observable.merge(observables).reduce((accu, next) -> accu + next); + return Observable.merge(observables).reduce((accu, next) -> accu + next).toSingle(); } /** @@ -390,54 +396,54 @@ public RedisClusterReactiveCommands getConnection(String host, int port) { } @Override - public Observable> scan() { + public Single> scan() { return clusterScan(ScanCursor.INITIAL, (connection, cursor) -> connection.scan(), reactiveClusterKeyScanCursorMapper()); } @Override - public Observable> scan(ScanArgs scanArgs) { + public Single> scan(ScanArgs scanArgs) { return clusterScan(ScanCursor.INITIAL, (connection, cursor) -> connection.scan(scanArgs), reactiveClusterKeyScanCursorMapper()); } @Override - public Observable> scan(ScanCursor scanCursor, ScanArgs scanArgs) { + public Single> scan(ScanCursor scanCursor, ScanArgs scanArgs) { return clusterScan(scanCursor, (connection, cursor) -> connection.scan(cursor, scanArgs), reactiveClusterKeyScanCursorMapper()); } @Override - public Observable> scan(ScanCursor scanCursor) { + public Single> scan(ScanCursor scanCursor) { return clusterScan(scanCursor, (connection, cursor) -> connection.scan(cursor), reactiveClusterKeyScanCursorMapper()); } @Override - public Observable scan(KeyStreamingChannel channel) { + public Single scan(KeyStreamingChannel channel) { return clusterScan(ScanCursor.INITIAL, (connection, cursor) -> connection.scan(channel), reactiveClusterStreamScanCursorMapper()); } @Override - public Observable scan(KeyStreamingChannel channel, ScanArgs scanArgs) { + public Single scan(KeyStreamingChannel channel, ScanArgs scanArgs) { return clusterScan(ScanCursor.INITIAL, (connection, cursor) -> connection.scan(channel, scanArgs), reactiveClusterStreamScanCursorMapper()); } @Override - public Observable scan(KeyStreamingChannel channel, ScanCursor scanCursor, ScanArgs scanArgs) { + public Single scan(KeyStreamingChannel channel, ScanCursor scanCursor, ScanArgs scanArgs) { return clusterScan(scanCursor, (connection, cursor) -> connection.scan(channel, cursor, scanArgs), reactiveClusterStreamScanCursorMapper()); } @Override - public Observable scan(KeyStreamingChannel channel, ScanCursor scanCursor) { + public Single scan(KeyStreamingChannel channel, ScanCursor scanCursor) { return clusterScan(scanCursor, (connection, cursor) -> connection.scan(channel, cursor), reactiveClusterStreamScanCursorMapper()); } - private Observable clusterScan(ScanCursor cursor, - BiFunction, ScanCursor, Observable> scanFunction, - ClusterScanSupport.ScanCursorMapper> resultMapper) { + private Single clusterScan(ScanCursor cursor, + BiFunction, ScanCursor, Single> scanFunction, + ClusterScanSupport.ScanCursorMapper> resultMapper) { return clusterScan(getStatefulConnection(), cursor, scanFunction, (ClusterScanSupport.ScanCursorMapper) resultMapper); } @@ -446,15 +452,15 @@ private Observable clusterScan(ScanCursor cursor, * Perform a SCAN in the cluster. * */ - static Observable clusterScan(StatefulRedisClusterConnection connection, - ScanCursor cursor, BiFunction, ScanCursor, Observable> scanFunction, - ClusterScanSupport.ScanCursorMapper> mapper) { + static Single clusterScan(StatefulRedisClusterConnection connection, + ScanCursor cursor, BiFunction, ScanCursor, Single> scanFunction, + ClusterScanSupport.ScanCursorMapper> mapper) { List nodeIds = ClusterScanSupport.getNodeIds(connection, cursor); String currentNodeId = ClusterScanSupport.getCurrentNodeId(cursor, nodeIds); ScanCursor continuationCursor = ClusterScanSupport.getContinuationCursor(cursor); - Observable scanCursor = scanFunction.apply(connection.getConnection(currentNodeId).reactive(), continuationCursor); + Single scanCursor = scanFunction.apply(connection.getConnection(currentNodeId).reactive(), continuationCursor); return mapper.map(nodeIds, currentNodeId, scanCursor); } diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/rx/RedisAdvancedClusterReactiveCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/rx/RedisAdvancedClusterReactiveCommands.java index 9e038feae3..c4d571c884 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/rx/RedisAdvancedClusterReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/rx/RedisAdvancedClusterReactiveCommands.java @@ -8,7 +8,9 @@ import com.lambdaworks.redis.cluster.api.StatefulRedisClusterConnection; import com.lambdaworks.redis.output.KeyStreamingChannel; +import rx.Completable; import rx.Observable; +import rx.Single; /** * Advanced reactive and thread-safe Redis Cluster API. @@ -52,7 +54,7 @@ public interface RedisAdvancedClusterReactiveCommands extends RedisCluster * @return Long integer-reply The number of keys that were removed. * @see RedisKeyReactiveCommands#del(Object[]) */ - Observable del(K... keys); + Single del(K... keys); /** * Unlink one or more keys with pipelining. Cross-slot keys will result in multiple calls to the particular cluster nodes. @@ -61,7 +63,7 @@ public interface RedisAdvancedClusterReactiveCommands extends RedisCluster * @return Long integer-reply The number of keys that were removed. * @see RedisKeyReactiveCommands#unlink(Object[]) */ - Observable unlink(K... keys); + Single unlink(K... keys); /** * Determine how many keys exist with pipelining. Cross-slot keys will result in multiple calls to the particular cluster nodes. @@ -69,7 +71,7 @@ public interface RedisAdvancedClusterReactiveCommands extends RedisCluster * @param keys the keys * @return Long integer-reply specifically: Number of existing keys */ - Observable exists(K... keys); + Single exists(K... keys); /** * Get the values of all the given keys with pipelining. Cross-slot keys will result in multiple calls to the particular @@ -89,7 +91,7 @@ public interface RedisAdvancedClusterReactiveCommands extends RedisCluster * @return String simple-string-reply always {@code OK} since {@code MSET} can't fail. * @see RedisStringReactiveCommands#mset(Map) */ - Observable mset(Map map); + Single mset(Map map); /** * Set multiple keys to multiple values, only if none of the keys exist with pipelining. Cross-slot keys will result in @@ -102,7 +104,7 @@ public interface RedisAdvancedClusterReactiveCommands extends RedisCluster * * @see RedisStringReactiveCommands#msetnx(Map) */ - Observable msetnx(Map map); + Single msetnx(Map map); /** * Set the current connection name on all cluster nodes with pipelining. @@ -111,7 +113,7 @@ public interface RedisAdvancedClusterReactiveCommands extends RedisCluster * @return simple-string-reply {@code OK} if the connection name was successfully set. * @see RedisServerReactiveCommands#clientSetname(Object) */ - Observable clientSetname(K name); + Single clientSetname(K name); /** * Remove all keys from all databases on all cluster masters with pipelining. @@ -119,7 +121,7 @@ public interface RedisAdvancedClusterReactiveCommands extends RedisCluster * @return String simple-string-reply * @see RedisServerReactiveCommands#flushall() */ - Observable flushall(); + Single flushall(); /** * Remove all keys from the current database on all cluster masters with pipelining. @@ -127,7 +129,7 @@ public interface RedisAdvancedClusterReactiveCommands extends RedisCluster * @return String simple-string-reply * @see RedisServerReactiveCommands#flushdb() */ - Observable flushdb(); + Single flushdb(); /** * Return the number of keys in the selected database on all cluster masters. @@ -135,7 +137,7 @@ public interface RedisAdvancedClusterReactiveCommands extends RedisCluster * @return Long integer-reply * @see RedisServerReactiveCommands#dbsize() */ - Observable dbsize(); + Single dbsize(); /** * Find all keys matching the given pattern on all cluster masters. @@ -154,7 +156,7 @@ public interface RedisAdvancedClusterReactiveCommands extends RedisCluster * @return Long array-reply list of keys matching {@code pattern}. * @see RedisKeyReactiveCommands#keys(KeyStreamingChannel, Object) */ - Observable keys(KeyStreamingChannel channel, K pattern); + Single keys(KeyStreamingChannel channel, K pattern); /** * Return a random key from the keyspace on a random master. @@ -162,7 +164,7 @@ public interface RedisAdvancedClusterReactiveCommands extends RedisCluster * @return V bulk-string-reply the random key, or {@literal null} when the database is empty. * @see RedisKeyReactiveCommands#randomkey() */ - Observable randomkey(); + Single randomkey(); /** * Remove all the scripts from the script cache on all cluster nodes. @@ -170,7 +172,7 @@ public interface RedisAdvancedClusterReactiveCommands extends RedisCluster * @return String simple-string-reply * @see RedisScriptingReactiveCommands#scriptFlush() */ - Observable scriptFlush(); + Single scriptFlush(); /** * Kill the script currently in execution on all cluster nodes. This call does not fail even if no scripts are running. @@ -178,7 +180,7 @@ public interface RedisAdvancedClusterReactiveCommands extends RedisCluster * @return String simple-string-reply, always {@literal OK}. * @see RedisScriptingReactiveCommands#scriptKill() */ - Observable scriptKill(); + Single scriptKill(); /** * Synchronously save the dataset to disk and then shut down all nodes of the cluster. @@ -186,7 +188,7 @@ public interface RedisAdvancedClusterReactiveCommands extends RedisCluster * @param save {@literal true} force save operation * @see RedisServerReactiveCommands#shutdown(boolean) */ - Observable shutdown(boolean save); + Completable shutdown(boolean save); /** * Incrementally iterate the keys space over the whole Cluster. @@ -194,7 +196,7 @@ public interface RedisAdvancedClusterReactiveCommands extends RedisCluster * @return KeyScanCursor<K> scan cursor. * @see RedisKeyReactiveCommands#scan(ScanArgs) */ - Observable> scan(); + Single> scan(); /** * Incrementally iterate the keys space over the whole Cluster. @@ -203,7 +205,7 @@ public interface RedisAdvancedClusterReactiveCommands extends RedisCluster * @return KeyScanCursor<K> scan cursor. * @see RedisKeyReactiveCommands#scan(ScanArgs) */ - Observable> scan(ScanArgs scanArgs); + Single> scan(ScanArgs scanArgs); /** * Incrementally iterate the keys space over the whole Cluster. @@ -214,7 +216,7 @@ public interface RedisAdvancedClusterReactiveCommands extends RedisCluster * @return KeyScanCursor<K> scan cursor. * @see RedisKeyReactiveCommands#scan(ScanCursor, ScanArgs) */ - Observable> scan(ScanCursor scanCursor, ScanArgs scanArgs); + Single> scan(ScanCursor scanCursor, ScanArgs scanArgs); /** * Incrementally iterate the keys space over the whole Cluster. @@ -224,7 +226,7 @@ public interface RedisAdvancedClusterReactiveCommands extends RedisCluster * @return KeyScanCursor<K> scan cursor. * @see RedisKeyReactiveCommands#scan(ScanCursor) */ - Observable> scan(ScanCursor scanCursor); + Single> scan(ScanCursor scanCursor); /** * Incrementally iterate the keys space over the whole Cluster. @@ -233,7 +235,7 @@ public interface RedisAdvancedClusterReactiveCommands extends RedisCluster * @return StreamScanCursor scan cursor. * @see RedisKeyReactiveCommands#scan(KeyStreamingChannel) */ - Observable scan(KeyStreamingChannel channel); + Single scan(KeyStreamingChannel channel); /** * Incrementally iterate the keys space over the whole Cluster. @@ -243,7 +245,7 @@ public interface RedisAdvancedClusterReactiveCommands extends RedisCluster * @return StreamScanCursor scan cursor. * @see RedisKeyReactiveCommands#scan(KeyStreamingChannel, ScanArgs) */ - Observable scan(KeyStreamingChannel channel, ScanArgs scanArgs); + Single scan(KeyStreamingChannel channel, ScanArgs scanArgs); /** * Incrementally iterate the keys space over the whole Cluster. @@ -255,7 +257,7 @@ public interface RedisAdvancedClusterReactiveCommands extends RedisCluster * @return StreamScanCursor scan cursor. * @see RedisKeyReactiveCommands#scan(KeyStreamingChannel, ScanCursor, ScanArgs) */ - Observable scan(KeyStreamingChannel channel, ScanCursor scanCursor, ScanArgs scanArgs); + Single scan(KeyStreamingChannel channel, ScanCursor scanCursor, ScanArgs scanArgs); /** * Incrementally iterate the keys space over the whole Cluster. @@ -266,7 +268,7 @@ public interface RedisAdvancedClusterReactiveCommands extends RedisCluster * @return StreamScanCursor scan cursor. * @see RedisKeyReactiveCommands#scan(ScanCursor, ScanArgs) */ - Observable scan(KeyStreamingChannel channel, ScanCursor scanCursor); + Single scan(KeyStreamingChannel channel, ScanCursor scanCursor); /** * Touch one or more keys with pipelining. Touch sets the last accessed time for a key. Non-exsitent keys wont get created. @@ -275,6 +277,6 @@ public interface RedisAdvancedClusterReactiveCommands extends RedisCluster * @param keys the keys * @return Long integer-reply the number of found keys. */ - Observable touch(K... keys); + Single touch(K... keys); } diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/rx/RedisClusterReactiveCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/rx/RedisClusterReactiveCommands.java index 68b7d483ce..4a209ce319 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/rx/RedisClusterReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/rx/RedisClusterReactiveCommands.java @@ -6,6 +6,7 @@ import rx.Observable; import com.lambdaworks.redis.api.rx.*; +import rx.Single; /** * A complete reactive and thread-safe cluster Redis API with 400+ Methods. @@ -34,7 +35,7 @@ public interface RedisClusterReactiveCommands extends RedisHashReactiveCom * @param password the password * @return String simple-string-reply */ - Observable auth(String password); + Single auth(String password); /** * Generate a new config epoch, incrementing the current epoch, assign the new epoch to this node, WITHOUT any consensus and @@ -43,7 +44,7 @@ public interface RedisClusterReactiveCommands extends RedisHashReactiveCom * @return String simple-string-reply If the new config epoch is generated and assigned either BUMPED (epoch) or STILL * (epoch) are returned. */ - Observable clusterBumpepoch(); + Single clusterBumpepoch(); /** * Meet another cluster node to include the node into the cluster. The command starts the cluster handshake and returns with @@ -53,7 +54,7 @@ public interface RedisClusterReactiveCommands extends RedisHashReactiveCom * @param port port number. * @return String simple-string-reply */ - Observable clusterMeet(String ip, int port); + Single clusterMeet(String ip, int port); /** * Blacklist and remove the cluster node from the cluster. @@ -61,7 +62,7 @@ public interface RedisClusterReactiveCommands extends RedisHashReactiveCom * @param nodeId the node Id * @return String simple-string-reply */ - Observable clusterForget(String nodeId); + Single clusterForget(String nodeId); /** * Adds slots to the cluster node. The current node will become the master for the specified slots. @@ -69,7 +70,7 @@ public interface RedisClusterReactiveCommands extends RedisHashReactiveCom * @param slots one or more slots from {@literal 0} to {@literal 16384} * @return String simple-string-reply */ - Observable clusterAddSlots(int... slots); + Single clusterAddSlots(int... slots); /** * Removes slots from the cluster node. @@ -77,7 +78,7 @@ public interface RedisClusterReactiveCommands extends RedisHashReactiveCom * @param slots one or more slots from {@literal 0} to {@literal 16384} * @return String simple-string-reply */ - Observable clusterDelSlots(int... slots); + Single clusterDelSlots(int... slots); /** * Assign a slot to a node. The command migrates the specified slot from the current node to the specified node in @@ -87,7 +88,7 @@ public interface RedisClusterReactiveCommands extends RedisHashReactiveCom * @param nodeId the id of the node that will become the master for the slot * @return String simple-string-reply */ - Observable clusterSetSlotNode(int slot, String nodeId); + Single clusterSetSlotNode(int slot, String nodeId); /** * Clears migrating / importing state from the slot. @@ -95,7 +96,7 @@ public interface RedisClusterReactiveCommands extends RedisHashReactiveCom * @param slot the slot * @return String simple-string-reply */ - Observable clusterSetSlotStable(int slot); + Single clusterSetSlotStable(int slot); /** * Flag a slot as {@literal MIGRATING} (outgoing) towards the node specified in {@code nodeId}. The slot must be handled by @@ -105,7 +106,7 @@ public interface RedisClusterReactiveCommands extends RedisHashReactiveCom * @param nodeId the id of the node is targeted to become the master for the slot * @return String simple-string-reply */ - Observable clusterSetSlotMigrating(int slot, String nodeId); + Single clusterSetSlotMigrating(int slot, String nodeId); /** * Flag a slot as {@literal IMPORTING} (incoming) from the node specified in {@code nodeId}. @@ -114,21 +115,21 @@ public interface RedisClusterReactiveCommands extends RedisHashReactiveCom * @param nodeId the id of the node is the master of the slot * @return String simple-string-reply */ - Observable clusterSetSlotImporting(int slot, String nodeId); + Single clusterSetSlotImporting(int slot, String nodeId); /** * Get information and statistics about the cluster viewed by the current node. * * @return String bulk-string-reply as a collection of text lines. */ - Observable clusterInfo(); + Single clusterInfo(); /** * Obtain the nodeId for the currently connected node. * * @return String simple-string-reply */ - Observable clusterMyId(); + Single clusterMyId(); /** * Obtain details about all cluster nodes. Can be parsed using @@ -136,7 +137,7 @@ public interface RedisClusterReactiveCommands extends RedisHashReactiveCom * * @return String bulk-string-reply as a collection of text lines */ - Observable clusterNodes(); + Single clusterNodes(); /** * List slaves for a certain node identified by its {@code nodeId}. Can be parsed using @@ -163,7 +164,7 @@ public interface RedisClusterReactiveCommands extends RedisHashReactiveCom * @param slot the slot * @return Integer reply: The number of keys in the specified hash slot, or an error if the hash slot is invalid. */ - Observable clusterCountKeysInSlot(int slot); + Single clusterCountKeysInSlot(int slot); /** * Returns the number of failure reports for the specified node. Failure reports are the way Redis Cluster uses in order to @@ -173,7 +174,7 @@ public interface RedisClusterReactiveCommands extends RedisHashReactiveCom * @param nodeId the node id * @return Integer reply: The number of active failure reports for the node. */ - Observable clusterCountFailureReports(String nodeId); + Single clusterCountFailureReports(String nodeId); /** * Returns an integer identifying the hash slot the specified key hashes to. This command is mainly useful for debugging and @@ -183,14 +184,14 @@ public interface RedisClusterReactiveCommands extends RedisHashReactiveCom * @param key the key. * @return Integer reply: The hash slot number. */ - Observable clusterKeyslot(K key); + Single clusterKeyslot(K key); /** * Forces a node to save the nodes.conf configuration on disk. * * @return String simple-string-reply: {@code OK} or an error if the operation fails. */ - Observable clusterSaveconfig(); + Single clusterSaveconfig(); /** * This command sets a specific config epoch in a fresh node. It only works when: @@ -202,7 +203,7 @@ public interface RedisClusterReactiveCommands extends RedisHashReactiveCom * @param configEpoch the config epoch * @return String simple-string-reply: {@code OK} or an error if the operation fails. */ - Observable clusterSetConfigEpoch(long configEpoch); + Single clusterSetConfigEpoch(long configEpoch); /** * Get array of cluster slots to node mappings. @@ -217,7 +218,7 @@ public interface RedisClusterReactiveCommands extends RedisHashReactiveCom * * @return String simple-string-reply */ - Observable asking(); + Single asking(); /** * Turn this node into a slave of the node with the id {@code nodeId}. @@ -225,7 +226,7 @@ public interface RedisClusterReactiveCommands extends RedisHashReactiveCom * @param nodeId master node id * @return String simple-string-reply */ - Observable clusterReplicate(String nodeId); + Single clusterReplicate(String nodeId); /** * Failover a cluster node. Turns the currently connected node into a master and the master into its slave. @@ -233,7 +234,7 @@ public interface RedisClusterReactiveCommands extends RedisHashReactiveCom * @param force do not coordinate with master if {@literal true} * @return String simple-string-reply */ - Observable clusterFailover(boolean force); + Single clusterFailover(boolean force); /** * Reset a node performing a soft or hard reset: @@ -250,14 +251,14 @@ public interface RedisClusterReactiveCommands extends RedisHashReactiveCom * @param hard {@literal true} for hard reset. Generates a new nodeId and currentEpoch/configEpoch are set to 0 * @return String simple-string-reply */ - Observable clusterReset(boolean hard); + Single clusterReset(boolean hard); /** * Delete all the slots associated with the specified node. The number of deleted slots is returned. * * @return String simple-string-reply */ - Observable clusterFlushslots(); + Single clusterFlushslots(); /** * Tells a Redis cluster slave node that the client is ok reading possibly stale data and is not interested in running write @@ -265,14 +266,14 @@ public interface RedisClusterReactiveCommands extends RedisHashReactiveCom * * @return String simple-string-reply */ - Observable readOnly(); + Single readOnly(); /** * Resets readOnly flag. * * @return String simple-string-reply */ - Observable readWrite(); + Single readWrite(); /** * Delete a key with pipelining. Cross-slot keys will result in multiple calls to the particular cluster nodes. @@ -280,7 +281,7 @@ public interface RedisClusterReactiveCommands extends RedisHashReactiveCom * @param keys the key * @return Observable<Long> integer-reply The number of keys that were removed. */ - Observable del(K... keys); + Single del(K... keys); /** * Get the values of all the given keys with pipelining. Cross-slot keys will result in multiple calls to the particular @@ -298,7 +299,7 @@ public interface RedisClusterReactiveCommands extends RedisHashReactiveCom * @param map the null * @return Observable<String> simple-string-reply always {@code OK} since {@code MSET} can't fail. */ - Observable mset(Map map); + Single mset(Map map); /** * Set multiple keys to multiple values, only if none of the keys exist with pipelining. Cross-slot keys will result in @@ -309,5 +310,5 @@ public interface RedisClusterReactiveCommands extends RedisHashReactiveCom * * {@code 1} if the all the keys were set. {@code 0} if no key was set (at least one key already existed). */ - Observable msetnx(Map map); + Single msetnx(Map map); } diff --git a/src/main/java/com/lambdaworks/redis/protocol/CommandHandler.java b/src/main/java/com/lambdaworks/redis/protocol/CommandHandler.java index f20c72e57b..64f58ce217 100644 --- a/src/main/java/com/lambdaworks/redis/protocol/CommandHandler.java +++ b/src/main/java/com/lambdaworks/redis/protocol/CommandHandler.java @@ -210,7 +210,7 @@ protected void decode(ChannelHandlerContext ctx, ByteBuf buffer) throws Interrup try { command.complete(); } catch (Exception e) { - logger.warn("{} Unexpected exception during command completion: {}", logPrefix, e.toString(), e); + logger.warn("{} Unexpected exception during request: {}", logPrefix, e.toString(), e); } if (buffer.refCnt() != 0) { diff --git a/src/main/java/com/lambdaworks/redis/pubsub/RedisPubSubReactiveCommandsImpl.java b/src/main/java/com/lambdaworks/redis/pubsub/RedisPubSubReactiveCommandsImpl.java index e6b89ced0d..afc9b50b5b 100644 --- a/src/main/java/com/lambdaworks/redis/pubsub/RedisPubSubReactiveCommandsImpl.java +++ b/src/main/java/com/lambdaworks/redis/pubsub/RedisPubSubReactiveCommandsImpl.java @@ -3,7 +3,9 @@ import static com.lambdaworks.redis.protocol.CommandType.*; import com.lambdaworks.redis.protocol.Command; +import rx.Completable; import rx.Observable; +import rx.Single; import rx.Subscriber; import com.lambdaworks.redis.RedisReactiveCommandsImpl; @@ -109,28 +111,28 @@ public void removeListener(RedisPubSubListener listener) { } @Override - public Observable psubscribe(K... patterns) { - return getSuccessObservable(createObservable(() -> commandBuilder.psubscribe(patterns))); + public Completable psubscribe(K... patterns) { + return Completable.fromObservable(createObservable(() -> commandBuilder.psubscribe(patterns))); } @Override - public Observable punsubscribe(K... patterns) { - return getSuccessObservable(createObservable(() -> commandBuilder.punsubscribe(patterns))); + public Completable punsubscribe(K... patterns) { + return Completable.fromObservable(createObservable(() -> commandBuilder.punsubscribe(patterns))); } @Override - public Observable subscribe(K... channels) { - return getSuccessObservable(createObservable(() -> commandBuilder.subscribe(channels))); + public Completable subscribe(K... channels) { + return Completable.fromObservable(createObservable(() -> commandBuilder.subscribe(channels))); } @Override - public Observable unsubscribe(K... channels) { - return getSuccessObservable(createObservable(() -> commandBuilder.unsubscribe(channels))); + public Completable unsubscribe(K... channels) { + return Completable.fromObservable(createObservable(() -> commandBuilder.unsubscribe(channels))); } @Override - public Observable publish(K channel, V message) { - return createObservable(() -> commandBuilder.publish(channel, message)); + public Single publish(K channel, V message) { + return createSingle(() -> commandBuilder.publish(channel, message)); } @Override @@ -139,8 +141,8 @@ public Observable pubsubChannels(K channel) { } @Override - public Observable> pubsubNumsub(K... channels) { - return createObservable(() -> commandBuilder.pubsubNumsub(channels)); + public Single> pubsubNumsub(K... channels) { + return createSingle(() -> commandBuilder.pubsubNumsub(channels)); } @Override diff --git a/src/main/java/com/lambdaworks/redis/pubsub/api/rx/RedisPubSubReactiveCommands.java b/src/main/java/com/lambdaworks/redis/pubsub/api/rx/RedisPubSubReactiveCommands.java index 80866821f8..1d67dee71a 100644 --- a/src/main/java/com/lambdaworks/redis/pubsub/api/rx/RedisPubSubReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/pubsub/api/rx/RedisPubSubReactiveCommands.java @@ -1,6 +1,7 @@ package com.lambdaworks.redis.pubsub.api.rx; import com.lambdaworks.redis.api.rx.Success; +import rx.Completable; import rx.Observable; import com.lambdaworks.redis.api.rx.RedisReactiveCommands; @@ -53,7 +54,7 @@ public interface RedisPubSubReactiveCommands extends RedisReactiveCommands * @param patterns the patterns * @return Observable<Success> Observable for {@code psubscribe} command */ - Observable psubscribe(K... patterns); + Completable psubscribe(K... patterns); /** * Stop listening for messages posted to channels matching the given patterns. @@ -61,7 +62,7 @@ public interface RedisPubSubReactiveCommands extends RedisReactiveCommands * @param patterns the patterns * @return Observable<Success> Observable for {@code punsubscribe} command */ - Observable punsubscribe(K... patterns); + Completable punsubscribe(K... patterns); /** * Listen for messages published to the given channels. @@ -69,7 +70,7 @@ public interface RedisPubSubReactiveCommands extends RedisReactiveCommands * @param channels the channels * @return Observable<Success> Observable for {@code subscribe} command */ - Observable subscribe(K... channels); + Completable subscribe(K... channels); /** * Stop listening for messages posted to the given channels. @@ -77,7 +78,7 @@ public interface RedisPubSubReactiveCommands extends RedisReactiveCommands * @param channels the channels * @return Observable<Success> Observable for {@code unsubscribe} command. */ - Observable unsubscribe(K... channels); + Completable unsubscribe(K... channels); /** * @return the underlying connection. diff --git a/src/main/java/com/lambdaworks/redis/sentinel/RedisSentinelReactiveCommandsImpl.java b/src/main/java/com/lambdaworks/redis/sentinel/RedisSentinelReactiveCommandsImpl.java index 6f70f3de72..fc1335f4b0 100644 --- a/src/main/java/com/lambdaworks/redis/sentinel/RedisSentinelReactiveCommandsImpl.java +++ b/src/main/java/com/lambdaworks/redis/sentinel/RedisSentinelReactiveCommandsImpl.java @@ -5,8 +5,6 @@ import java.util.Map; import java.util.function.Supplier; -import rx.Observable; - import com.lambdaworks.redis.ReactiveCommandDispatcher; import com.lambdaworks.redis.api.StatefulConnection; import com.lambdaworks.redis.codec.RedisCodec; @@ -15,6 +13,9 @@ import com.lambdaworks.redis.sentinel.api.StatefulRedisSentinelConnection; import com.lambdaworks.redis.sentinel.api.rx.RedisSentinelReactiveCommands; +import rx.Observable; +import rx.Single; + /** * A reactive and thread-safe API for a Redis Sentinel connection. * @@ -34,7 +35,7 @@ public RedisSentinelReactiveCommandsImpl(StatefulConnection connection, Re } @Override - public Observable getMasterAddrByName(K key) { + public Single getMasterAddrByName(K key) { Observable observable = createDissolvingObservable(() -> commandBuilder.getMasterAddrByKey(key)); return observable.buffer(2).map(list -> { @@ -46,7 +47,7 @@ public Observable getMasterAddrByName(K key) { String hostname = (String) list.get(0); String port = (String) list.get(1); return new InetSocketAddress(hostname, Integer.parseInt(port)); - }); + }).lastOrDefault(null).cast(SocketAddress.class).toSingle(); } @Override @@ -55,8 +56,8 @@ public Observable> masters() { } @Override - public Observable> master(K key) { - return createObservable(() -> commandBuilder.master(key)); + public Single> master(K key) { + return createSingle(() -> commandBuilder.master(key)); } @Override @@ -65,41 +66,41 @@ public Observable> slaves(K key) { } @Override - public Observable reset(K key) { - return createObservable(() -> commandBuilder.reset(key)); + public Single reset(K key) { + return createSingle(() -> commandBuilder.reset(key)); } @Override - public Observable failover(K key) { - return createObservable(() -> commandBuilder.failover(key)); + public Single failover(K key) { + return createSingle(() -> commandBuilder.failover(key)); } @Override - public Observable monitor(K key, String ip, int port, int quorum) { - return createObservable(() -> commandBuilder.monitor(key, ip, port, quorum)); + public Single monitor(K key, String ip, int port, int quorum) { + return createSingle(() -> commandBuilder.monitor(key, ip, port, quorum)); } @Override - public Observable set(K key, String option, V value) { - return createObservable(() -> commandBuilder.set(key, option, value)); + public Single set(K key, String option, V value) { + return createSingle(() -> commandBuilder.set(key, option, value)); } @Override - public Observable remove(K key) { - return createObservable(() -> commandBuilder.remove(key)); + public Single remove(K key) { + return createSingle(() -> commandBuilder.remove(key)); } @Override - public Observable ping() { - return createObservable(() -> commandBuilder.ping()); + public Single ping() { + return createSingle(() -> commandBuilder.ping()); } - //@Override + // @Override public void close() { connection.close(); } - //@Override + // @Override public boolean isOpen() { return connection.isOpen(); } @@ -110,11 +111,17 @@ public StatefulRedisSentinelConnection getStatefulConnection() { } public Observable createObservable(Supplier> commandSupplier) { - return Observable.create(new ReactiveCommandDispatcher(commandSupplier, connection, false)); + return Observable + .create(new ReactiveCommandDispatcher(commandSupplier, connection, false).getObservableSubscriber()); + } + + public Single createSingle(Supplier> commandSupplier) { + return Single.create(new ReactiveCommandDispatcher(commandSupplier, connection, false).getSingleSubscriber()); } @SuppressWarnings("unchecked") public R createDissolvingObservable(Supplier> commandSupplier) { - return (R) Observable.create(new ReactiveCommandDispatcher<>(commandSupplier, connection, true)); + return (R) Observable + .create(new ReactiveCommandDispatcher<>(commandSupplier, connection, true).getObservableSubscriber()); } } diff --git a/src/main/java/com/lambdaworks/redis/sentinel/api/rx/RedisSentinelReactiveCommands.java b/src/main/java/com/lambdaworks/redis/sentinel/api/rx/RedisSentinelReactiveCommands.java index 74add9e9ef..2bfc480db9 100644 --- a/src/main/java/com/lambdaworks/redis/sentinel/api/rx/RedisSentinelReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/sentinel/api/rx/RedisSentinelReactiveCommands.java @@ -5,6 +5,8 @@ import java.util.Map; import com.lambdaworks.redis.sentinel.api.StatefulRedisSentinelConnection; import rx.Observable; +import rx.Single; +import rx.Completable; /** * Observable commands for Redis Sentinel. @@ -23,7 +25,7 @@ public interface RedisSentinelReactiveCommands { * @param key the key * @return SocketAddress; */ - Observable getMasterAddrByName(K key); + Single getMasterAddrByName(K key); /** * Enumerates all the monitored masters and their states. @@ -38,7 +40,7 @@ public interface RedisSentinelReactiveCommands { * @param key the key * @return Map<K, V> */ - Observable> master(K key); + Single> master(K key); /** * Provides a list of slaves for the master with the specified name. @@ -54,7 +56,7 @@ public interface RedisSentinelReactiveCommands { * @param key the key * @return Long */ - Observable reset(K key); + Single reset(K key); /** * Perform a failover. @@ -62,7 +64,7 @@ public interface RedisSentinelReactiveCommands { * @param key the master id * @return String */ - Observable failover(K key); + Single failover(K key); /** * This command tells the Sentinel to start monitoring a new master with the specified name, ip, port, and quorum. @@ -73,7 +75,7 @@ public interface RedisSentinelReactiveCommands { * @param quorum the quorum count * @return String */ - Observable monitor(K key, String ip, int port, int quorum); + Single monitor(K key, String ip, int port, int quorum); /** * Multiple option / value pairs can be specified (or none at all). @@ -84,7 +86,7 @@ public interface RedisSentinelReactiveCommands { * * @return String simple-string-reply {@code OK} if {@code SET} was executed correctly. */ - Observable set(K key, String option, V value); + Single set(K key, String option, V value); /** * remove the specified master. @@ -92,14 +94,14 @@ public interface RedisSentinelReactiveCommands { * @param key the key * @return String */ - Observable remove(K key); + Single remove(K key); /** * Ping the server. * * @return String simple-string-reply */ - Observable ping(); + Single ping(); /** * close the underlying connection. diff --git a/src/test/java/com/lambdaworks/apigenerator/CreateAsyncNodeSelectionClusterApi.java b/src/test/java/com/lambdaworks/apigenerator/CreateAsyncNodeSelectionClusterApi.java index 5ee043a9fe..7ae6d2cfca 100644 --- a/src/test/java/com/lambdaworks/apigenerator/CreateAsyncNodeSelectionClusterApi.java +++ b/src/test/java/com/lambdaworks/apigenerator/CreateAsyncNodeSelectionClusterApi.java @@ -53,7 +53,6 @@ public CreateAsyncNodeSelectionClusterApi(String templateName) { File templateFile = new File(Constants.TEMPLATES, "com/lambdaworks/redis/api/" + templateName + ".java"); String targetPackage = "com.lambdaworks.redis.cluster.api.async"; - // todo: remove AutoCloseable from BaseNodeSelectionAsyncCommands factory = new CompilationUnitFactory(templateFile, Constants.SOURCES, targetPackage, targetName, commentMutator(), methodTypeMutator(), methodFilter(), importSupplier(), null, null); } diff --git a/src/test/java/com/lambdaworks/apigenerator/CreateReactiveApi.java b/src/test/java/com/lambdaworks/apigenerator/CreateReactiveApi.java index d128097853..fce0f00fb0 100644 --- a/src/test/java/com/lambdaworks/apigenerator/CreateReactiveApi.java +++ b/src/test/java/com/lambdaworks/apigenerator/CreateReactiveApi.java @@ -5,7 +5,6 @@ import java.util.function.Function; import java.util.function.Supplier; -import com.lambdaworks.redis.internal.LettuceSets; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -16,6 +15,7 @@ import com.github.javaparser.ast.type.ClassOrInterfaceType; import com.github.javaparser.ast.type.ReferenceType; import com.github.javaparser.ast.type.Type; +import com.lambdaworks.redis.internal.LettuceSets; /** * Create reactive API based on the templates. @@ -25,9 +25,10 @@ @RunWith(Parameterized.class) public class CreateReactiveApi { - private Set KEEP_METHOD_RESULT_TYPE = LettuceSets.unmodifiableSet( - "digest", "close", "isOpen", "BaseRedisCommands.reset", - "getStatefulConnection", "setAutoFlushCommands", "flushCommands"); + private Set KEEP_METHOD_RESULT_TYPE = LettuceSets.unmodifiableSet("digest", "close", "isOpen", + "BaseRedisCommands.reset", "getStatefulConnection", "setAutoFlushCommands", "flushCommands"); + + private Set FORCE_OBSERVABLE_RESULT = LettuceSets.unmodifiableSet("eval", "evalsha"); private CompilationUnitFactory factory; @@ -74,8 +75,9 @@ protected Function commentMutator() { protected Function methodCommentMutator() { return comment -> { - if(comment != null && comment.getContent() != null){ - comment.setContent(comment.getContent().replaceAll("List<(.*)>", "$1").replaceAll("Set<(.*)>", "$1")); + if (comment != null && comment.getContent() != null) { + comment.setContent( + comment.getContent().replaceAll("List<(.*)>", "$1").replaceAll("Set<(.*)>", "$1")); } return comment; }; @@ -90,33 +92,39 @@ protected Function methodTypeMutator() { return method -> { ClassOrInterfaceDeclaration classOfMethod = (ClassOrInterfaceDeclaration) method.getParentNode(); - if (KEEP_METHOD_RESULT_TYPE.contains(method.getName()) - || KEEP_METHOD_RESULT_TYPE.contains(classOfMethod.getName() + "." + method.getName())) { + if (methodMatch(KEEP_METHOD_RESULT_TYPE, method, classOfMethod)) { return method.getType(); } String typeAsString = method.getType().toStringWithoutComments().trim(); - if (typeAsString.equals("void")) { - typeAsString = "Success"; - } - - if (typeAsString.startsWith("List<")) { - typeAsString = typeAsString.substring(5, typeAsString.length() - 1); + if (methodMatch(FORCE_OBSERVABLE_RESULT, method, classOfMethod)) { + typeAsString = "Observable<" + typeAsString + ">"; + } if (typeAsString.equals("void")) { + typeAsString = "Completable"; + } else if (typeAsString.startsWith("List<")) { + typeAsString = "Observable<" + typeAsString.substring(5, typeAsString.length() - 1) + ">"; } else if (typeAsString.startsWith("Set<")) { - typeAsString = typeAsString.substring(4, typeAsString.length() - 1); + typeAsString = "Observable<" + typeAsString.substring(4, typeAsString.length() - 1) + ">"; + } else { + typeAsString = "Single<" + typeAsString + ">"; } - return new ReferenceType(new ClassOrInterfaceType("Observable<" + typeAsString + ">")); + return new ReferenceType(new ClassOrInterfaceType(typeAsString)); }; } + private boolean methodMatch(Collection methodNames, MethodDeclaration method, + ClassOrInterfaceDeclaration classOfMethod) { + return methodNames.contains(method.getName()) || methodNames.contains(classOfMethod.getName() + "." + method.getName()); + } + /** - * Supply addititional imports. + * Supply additional imports. * * @return */ protected Supplier> importSupplier() { - return () -> Collections.singletonList("rx.Observable"); + return () -> Arrays.asList("rx.Observable", "rx.Single", "rx.Completable"); } @Test diff --git a/src/test/java/com/lambdaworks/redis/LettucePerformanceTest.java b/src/test/java/com/lambdaworks/redis/LettucePerformanceTest.java index 39190be0c7..7df56f4634 100644 --- a/src/test/java/com/lambdaworks/redis/LettucePerformanceTest.java +++ b/src/test/java/com/lambdaworks/redis/LettucePerformanceTest.java @@ -15,6 +15,7 @@ import com.lambdaworks.redis.api.rx.RedisReactiveCommands; import rx.Observable; +import rx.Single; import javax.annotation.Resources; @@ -161,7 +162,7 @@ public void testObservablePerformance() throws Exception { executor = new ThreadPoolExecutor(threads, threads, 1, TimeUnit.MINUTES, new ArrayBlockingQueue(totalCalls)); - List>>> futurama = new ArrayList<>(); + List>>> futurama = new ArrayList<>(); preheat(threads); final int callsPerThread = totalCalls / threads; @@ -172,10 +173,10 @@ public void testObservablePerformance() throws Exception { long start = System.currentTimeMillis(); latch.countDown(); - for (Future>> listFuture : futurama) { - for (Observable future : listFuture.get()) { + for (Future>> listFuture : futurama) { + for (Single future : listFuture.get()) { if (waitForCompletion) { - future.toBlocking().last(); + future.toBlocking().value(); } else { future.subscribe(); } @@ -192,7 +193,7 @@ public void testObservablePerformance() throws Exception { } - protected void submitObservableTasks(int threads, List>>> futurama, final int callsPerThread, + protected void submitObservableTasks(int threads, List>>> futurama, final int callsPerThread, final boolean connectionPerThread) { final StatefulRedisConnection sharedConnection; if (!connectionPerThread) { @@ -202,7 +203,7 @@ protected void submitObservableTasks(int threads, List>> submit = executor.submit(() -> { + Future>> submit = executor.submit(() -> { StatefulRedisConnection connection = sharedConnection; if (connectionPerThread) { @@ -212,7 +213,7 @@ protected void submitObservableTasks(int threads, List> observables = new ArrayList<>(callsPerThread); + List> observables = new ArrayList<>(callsPerThread); latch.await(); for (int i1 = 0; i1 < callsPerThread; i1++) { observables.add(reactive.ping()); diff --git a/src/test/java/com/lambdaworks/redis/ReactiveConnectionTest.java b/src/test/java/com/lambdaworks/redis/ReactiveConnectionTest.java index b9df3f08d2..3b63e65350 100644 --- a/src/test/java/com/lambdaworks/redis/ReactiveConnectionTest.java +++ b/src/test/java/com/lambdaworks/redis/ReactiveConnectionTest.java @@ -7,6 +7,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.concurrent.CancellationException; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -16,10 +17,15 @@ import org.junit.Test; import org.junit.rules.ExpectedException; +import rx.Observable; +import rx.Single; +import rx.Subscriber; + import com.lambdaworks.Delay; import com.lambdaworks.Wait; import com.lambdaworks.redis.api.StatefulRedisConnection; import com.lambdaworks.redis.api.rx.RedisReactiveCommands; +import rx.observers.TestSubscriber; import rx.Observable; import rx.Subscriber; @@ -47,7 +53,7 @@ public void closeReactiveConnection() throws Exception { @Test public void doNotFireCommandUntilObservation() throws Exception { - Observable set = reactive.set(key, value); + Single set = reactive.set(key, value); Delay.delay(millis(200)); assertThat(redis.get(key)).isNull(); set.subscribe(); @@ -58,7 +64,7 @@ public void doNotFireCommandUntilObservation() throws Exception { @Test public void fireCommandAfterObserve() throws Exception { - assertThat(reactive.set(key, value).toBlocking().first()).isEqualTo("OK"); + assertThat(reactive.set(key, value).toBlocking().value()).isEqualTo("OK"); assertThat(redis.get(key)).isEqualTo(value); } @@ -76,40 +82,60 @@ public void getStatefulConnection() throws Exception { public void testCancelCommand() throws Exception { List result = new ArrayList<>(); - reactive.clientPause(1000).subscribe(); + reactive.clientPause(2000).subscribe(TestSubscriber.create()); + Delay.delay(millis(100)); + reactive.set(key, value).subscribe(new CompletionSubscriber(result)); Delay.delay(millis(100)); reactive.reset(); - assertThat(result).hasSize(1).contains("completed"); + assertThat(result).hasSize(1).hasOnlyElementsOfType(CancellationException.class); } @Test public void testEcho() throws Exception { - String result = reactive.echo("echo").toBlocking().first(); + String result = reactive.echo("echo").toBlocking().value(); assertThat(result).isEqualTo("echo"); } @Test - public void testMultiCancel() throws Exception { + public void testSingleMultiCancel() throws Exception { List result = new ArrayList<>(); reactive.clientPause(1000).subscribe(); + Delay.delay(millis(100)); - Observable set = reactive.set(key, value); + Single set = reactive.set(key, value); set.subscribe(new CompletionSubscriber(result)); set.subscribe(new CompletionSubscriber(result)); set.subscribe(new CompletionSubscriber(result)); + Delay.delay(millis(100)); + + reactive.reset(); + assertThat(result).hasSize(3); + } + + @Test + public void testObservableMultiCancel() throws Exception { + List result = new ArrayList<>(); + reactive.clientPause(1000).subscribe(); Delay.delay(millis(100)); + + Observable set = reactive.mget(key, value); + set.subscribe(new CompletionSubscriber(result)); + set.subscribe(new CompletionSubscriber(result)); + set.subscribe(new CompletionSubscriber(result)); + Delay.delay(millis(100)); + reactive.reset(); - assertThat(result).hasSize(3).contains("completed"); + assertThat(result).hasSize(3); } @Test public void multiSubscribe() throws Exception { reactive.set(key, "1").subscribe(); - Observable incr = reactive.incr(key); + Single incr = reactive.incr(key); incr.subscribe(); incr.subscribe(); incr.subscribe(); @@ -147,9 +173,9 @@ public void reactiveChain() throws Exception { map.put(key, value); map.put("key1", "value1"); - reactive.mset(map).toBlocking().first(); + reactive.mset(map).toBlocking().value(); - List values = reactive.keys("*").flatMap(s -> reactive.get(s)).toList().subscribeOn(Schedulers.immediate()) + List values = reactive.keys("*").flatMap(s -> reactive.get(s).toObservable()).toList().subscribeOn(Schedulers.immediate()) .toBlocking().first(); assertThat(values).hasSize(2).contains(value, "value1"); @@ -166,7 +192,7 @@ public void auth() throws Exception { @Test public void subscriberCompletingWithExceptionShouldBeHandledSafely() throws Exception { - Observable.concat(reactive.set("keyA", "valueA"), reactive.set("keyB", "valueB")).toBlocking().last(); + Single.concat(reactive.set("keyA", "valueA"), reactive.set("keyB", "valueB")).toBlocking().last(); reactive.get("keyA").subscribe(createSubscriberWithExceptionOnComplete()); reactive.get("keyA").subscribe(createSubscriberWithExceptionOnComplete()); diff --git a/src/test/java/com/lambdaworks/redis/cluster/AdvancedClusterReactiveTest.java b/src/test/java/com/lambdaworks/redis/cluster/AdvancedClusterReactiveTest.java index 7b6059cdc4..3ee8c4e1c0 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/AdvancedClusterReactiveTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/AdvancedClusterReactiveTest.java @@ -25,9 +25,9 @@ import com.lambdaworks.redis.cluster.models.partitions.RedisClusterNode; import com.lambdaworks.redis.codec.Utf8StringCodec; import com.lambdaworks.redis.commands.rx.RxSyncInvocationHandler; -import com.lambdaworks.redis.internal.LettuceLists; import rx.Observable; +import rx.Single; /** * @author Mark Paluch @@ -80,9 +80,8 @@ public void doWeirdThingsWithClusterconnections() throws Exception { @Test public void msetCrossSlot() throws Exception { - Observable mset = commands.mset(RandomKeys.MAP); - List result = LettuceLists.newList(mset.toBlocking().toIterable()); - assertThat(result).hasSize(1).contains("OK"); + Single mset = commands.mset(RandomKeys.MAP); + assertThat(block(mset)).isEqualTo("OK"); for (String mykey : RandomKeys.KEYS) { String s1 = syncCommands.get(mykey); @@ -93,9 +92,7 @@ public void msetCrossSlot() throws Exception { @Test public void msetnxCrossSlot() throws Exception { - List result = LettuceLists.newList(commands.msetnx(RandomKeys.MAP).toBlocking().toIterable()); - - assertThat(result).hasSize(1).contains(true); + assertThat(block(commands.msetnx(RandomKeys.MAP))).isTrue(); for (String mykey : RandomKeys.KEYS) { String s1 = syncCommands.get(mykey); @@ -125,8 +122,8 @@ public void mgetCrossSlotStreaming() throws Exception { ListStreamingAdapter result = new ListStreamingAdapter<>(); - Observable observable = commands.mget(result, RandomKeys.KEYS.toArray(new String[RandomKeys.COUNT])); - Long count = getSingle(observable); + Single single = commands.mget(result, RandomKeys.KEYS.toArray(new String[RandomKeys.COUNT])); + Long count = block(single); assertThat(result.getList()).hasSize(RandomKeys.COUNT); assertThat(count).isEqualTo(RandomKeys.COUNT); @@ -137,8 +134,8 @@ public void delCrossSlot() throws Exception { msetCrossSlot(); - Observable observable = commands.del(RandomKeys.KEYS.toArray(new String[RandomKeys.COUNT])); - Long result = getSingle(observable); + Single single = commands.del(RandomKeys.KEYS.toArray(new String[RandomKeys.COUNT])); + Long result = block(single); assertThat(result).isEqualTo(RandomKeys.COUNT); @@ -153,8 +150,8 @@ public void unlinkCrossSlot() throws Exception { msetCrossSlot(); - Observable observable = commands.unlink(RandomKeys.KEYS.toArray(new String[RandomKeys.COUNT])); - Long result = getSingle(observable); + Single single = commands.unlink(RandomKeys.KEYS.toArray(new String[RandomKeys.COUNT])); + Long result = block(single); assertThat(result).isEqualTo(RandomKeys.COUNT); @@ -171,7 +168,7 @@ public void clientSetname() throws Exception { assertThat(clusterClient.getPartitions().size()).isGreaterThan(0); - getSingle(commands.clientSetname(name)); + block(commands.clientSetname(name)); for (RedisClusterNode redisClusterNode : clusterClient.getPartitions()) { RedisClusterCommands nodeConnection = commands.getStatefulConnection().sync() @@ -182,7 +179,7 @@ public void clientSetname() throws Exception { @Test(expected = Exception.class) public void clientSetnameRunOnError() throws Exception { - getSingle(commands.clientSetname("not allowed")); + block(commands.clientSetname("not allowed")); } @Test @@ -190,7 +187,7 @@ public void dbSize() throws Exception { writeKeysToTwoNodes(); - Long dbsize = getSingle(commands.dbsize()); + Long dbsize = block(commands.dbsize()); assertThat(dbsize).isEqualTo(2); } @@ -199,7 +196,7 @@ public void flushall() throws Exception { writeKeysToTwoNodes(); - assertThat(getSingle(commands.flushall())).isEqualTo("OK"); + assertThat(block(commands.flushall())).isEqualTo("OK"); Long dbsize = syncCommands.dbsize(); assertThat(dbsize).isEqualTo(0); @@ -210,7 +207,7 @@ public void flushdb() throws Exception { writeKeysToTwoNodes(); - assertThat(getSingle(commands.flushdb())).isEqualTo("OK"); + assertThat(block(commands.flushdb())).isEqualTo("OK"); Long dbsize = syncCommands.dbsize(); assertThat(dbsize).isEqualTo(0); @@ -232,7 +229,7 @@ public void keysStreaming() throws Exception { writeKeysToTwoNodes(); ListStreamingAdapter result = new ListStreamingAdapter<>(); - assertThat(getSingle(commands.keys(result, "*"))).isEqualTo(2); + assertThat(block(commands.keys(result, "*"))).isEqualTo(2); assertThat(result.getList()).contains(KEY_ON_NODE_1, KEY_ON_NODE_2); } @@ -241,17 +238,17 @@ public void randomKey() throws Exception { writeKeysToTwoNodes(); - assertThat(getSingle(commands.randomkey())).isIn(KEY_ON_NODE_1, KEY_ON_NODE_2); + assertThat(block(commands.randomkey())).isIn(KEY_ON_NODE_1, KEY_ON_NODE_2); } @Test public void scriptFlush() throws Exception { - assertThat(getSingle(commands.scriptFlush())).isEqualTo("OK"); + assertThat(block(commands.scriptFlush())).isEqualTo("OK"); } @Test public void scriptKill() throws Exception { - assertThat(getSingle(commands.scriptKill())).isEqualTo("OK"); + assertThat(block(commands.scriptKill())).isEqualTo("OK"); } @Test @@ -264,8 +261,8 @@ public void shutdown() throws Exception { public void readFromSlaves() throws Exception { RedisClusterReactiveCommands connection = commands.getConnection(host, port4); - connection.readOnly().toBlocking().first(); - commands.set(key, value).toBlocking().first(); + block(connection.readOnly()); + block(commands.set(key, value)); NodeSelectionAsyncTest.waitForReplication(commands.getStatefulConnection().async(), key, port4); AtomicBoolean error = new AtomicBoolean(); @@ -273,10 +270,10 @@ public void readFromSlaves() throws Exception { assertThat(error.get()).isFalse(); - connection.readWrite().toBlocking().first(); + block(connection.readWrite()); try { - connection.get(key).doOnError(throwable -> error.set(true)).toBlocking().first(); + block(connection.get(key).doOnError(throwable -> error.set(true))); fail("Missing exception"); } catch (Exception e) { assertThat(error.get()).isTrue(); @@ -295,9 +292,9 @@ public void clusterScan() throws Exception { do { if (scanCursor == null) { - scanCursor = getSingle(commands.scan()); + scanCursor = block(commands.scan()); } else { - scanCursor = getSingle(commands.scan(scanCursor)); + scanCursor = block(commands.scan(scanCursor)); } allKeys.addAll(scanCursor.getKeys()); } while (!scanCursor.isFinished()); @@ -318,9 +315,9 @@ public void clusterScanWithArgs() throws Exception { do { if (scanCursor == null) { - scanCursor = getSingle(commands.scan(ScanArgs.Builder.matches("a*"))); + scanCursor = block(commands.scan(ScanArgs.Builder.matches("a*"))); } else { - scanCursor = getSingle(commands.scan(scanCursor, ScanArgs.Builder.matches("a*"))); + scanCursor = block(commands.scan(scanCursor, ScanArgs.Builder.matches("a*"))); } allKeys.addAll(scanCursor.getKeys()); } while (!scanCursor.isFinished()); @@ -341,9 +338,9 @@ public void clusterScanStreaming() throws Exception { do { if (scanCursor == null) { - scanCursor = getSingle(commands.scan(adapter)); + scanCursor = block(commands.scan(adapter)); } else { - scanCursor = getSingle(commands.scan(adapter, scanCursor)); + scanCursor = block(commands.scan(adapter, scanCursor)); } } while (!scanCursor.isFinished()); @@ -363,9 +360,9 @@ public void clusterScanStreamingWithArgs() throws Exception { do { if (scanCursor == null) { - scanCursor = getSingle(commands.scan(adapter, ScanArgs.Builder.matches("a*"))); + scanCursor = block(commands.scan(adapter, ScanArgs.Builder.matches("a*"))); } else { - scanCursor = getSingle(commands.scan(adapter, scanCursor, ScanArgs.Builder.matches("a*"))); + scanCursor = block(commands.scan(adapter, scanCursor, ScanArgs.Builder.matches("a*"))); } } while (!scanCursor.isFinished()); @@ -374,10 +371,11 @@ public void clusterScanStreamingWithArgs() throws Exception { } - private T getSingle(Observable observable) { - return observable.toBlocking().single(); + private T block(Single single) { + return single.toBlocking().value(); } + private void writeKeysToTwoNodes() { syncCommands.set(KEY_ON_NODE_1, value); syncCommands.set(KEY_ON_NODE_2, value); diff --git a/src/test/java/com/lambdaworks/redis/cluster/ClusterReactiveCommandTest.java b/src/test/java/com/lambdaworks/redis/cluster/ClusterReactiveCommandTest.java index 044025b522..82f2b9ca39 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/ClusterReactiveCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/ClusterReactiveCommandTest.java @@ -18,7 +18,7 @@ import com.lambdaworks.redis.cluster.models.slots.ClusterSlotsParser; import com.lambdaworks.redis.internal.LettuceLists; -import rx.Observable; +import rx.Single; @FixMethodOrder(MethodSorters.NAME_ASCENDING) @SuppressWarnings("unchecked") @@ -61,7 +61,7 @@ public void after() throws Exception { @Test public void testClusterBumpEpoch() throws Exception { - String result = first(reactive.clusterBumpepoch()); + String result = block(reactive.clusterBumpepoch()); assertThat(result).matches("(BUMPED|STILL).*"); } @@ -69,7 +69,7 @@ public void testClusterBumpEpoch() throws Exception { @Test public void testClusterInfo() throws Exception { - String status = first(reactive.clusterInfo()); + String status = block(reactive.clusterInfo()); assertThat(status).contains("cluster_known_nodes:"); assertThat(status).contains("cluster_slots_fail:0"); @@ -79,7 +79,7 @@ public void testClusterInfo() throws Exception { @Test public void testClusterNodes() throws Exception { - String string = first(reactive.clusterNodes()); + String string = block(reactive.clusterNodes()); assertThat(string).contains("connected"); assertThat(string).contains("master"); @@ -89,7 +89,7 @@ public void testClusterNodes() throws Exception { @Test public void testClusterNodesSync() throws Exception { - String string = first(reactive.clusterNodes()); + String string = block(reactive.clusterNodes()); assertThat(string).contains("connected"); assertThat(string).contains("master"); @@ -99,13 +99,13 @@ public void testClusterNodesSync() throws Exception { @Test public void testClusterSlaves() throws Exception { - Long replication = first(reactive.waitForReplication(1, 5)); + Long replication = block(reactive.waitForReplication(1, 5)); assertThat(replication).isNotNull(); } @Test public void testAsking() throws Exception { - assertThat(first(reactive.asking())).isEqualTo("OK"); + assertThat(block(reactive.asking())).isEqualTo("OK"); } @Test @@ -133,8 +133,8 @@ public void clusterSlaves() throws Exception { assertThat(result.size()).isGreaterThan(0); } - private T first(Observable observable) { - return observable.toBlocking().first(); + private T block(Single single) { + return single.toBlocking().value(); } } diff --git a/src/test/java/com/lambdaworks/redis/cluster/RedisRxClusterClientTest.java b/src/test/java/com/lambdaworks/redis/cluster/RedisRxClusterClientTest.java index 5200e8188a..0981e4b517 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/RedisRxClusterClientTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/RedisRxClusterClientTest.java @@ -25,6 +25,7 @@ import com.lambdaworks.redis.cluster.api.rx.RedisAdvancedClusterReactiveCommands; import com.lambdaworks.redis.cluster.api.sync.RedisAdvancedClusterCommands; import com.lambdaworks.redis.cluster.models.partitions.RedisClusterNode; +import rx.Single; @FixMethodOrder(MethodSorters.NAME_ASCENDING) @SuppressWarnings("unchecked") @@ -69,10 +70,10 @@ public void after() throws Exception { @Test public void testClusterCommandRedirection() throws Exception { // Command on node within the default connection - assertThat(getSingle(rx.set(KEY_B, "myValue1"))).isEqualTo("OK"); + assertThat(block(rx.set(KEY_B, "myValue1"))).isEqualTo("OK"); // gets redirection to node 3 - assertThat(getSingle(rx.set(KEY_A, "myValue1"))).isEqualTo("OK"); + assertThat(block(rx.set(KEY_A, "myValue1"))).isEqualTo("OK"); } @Test @@ -81,10 +82,10 @@ public void getKeysInSlot() throws Exception { sync.set(KEY_A, value); sync.set(KEY_B, value); - List keysA = getSingle(rx.clusterGetKeysInSlot(SLOT_A, 10).toList()); + List keysA = block(rx.clusterGetKeysInSlot(SLOT_A, 10).toList()); assertThat(keysA).isEqualTo(Collections.singletonList(KEY_A)); - List keysB = getSingle(rx.clusterGetKeysInSlot(SLOT_B, 10).toList()); + List keysB = block(rx.clusterGetKeysInSlot(SLOT_B, 10).toList()); assertThat(keysB).isEqualTo(Collections.singletonList(KEY_B)); } @@ -94,45 +95,49 @@ public void countKeysInSlot() throws Exception { sync.set(KEY_A, value); sync.set(KEY_B, value); - Long result = getSingle(rx.clusterCountKeysInSlot(SLOT_A)); + Long result = block(rx.clusterCountKeysInSlot(SLOT_A)); assertThat(result).isEqualTo(1L); - result = getSingle(rx.clusterCountKeysInSlot(SLOT_B)); + result = block(rx.clusterCountKeysInSlot(SLOT_B)); assertThat(result).isEqualTo(1L); int slotZZZ = SlotHash.getSlot("ZZZ".getBytes()); - result = getSingle(rx.clusterCountKeysInSlot(slotZZZ)); + result = block(rx.clusterCountKeysInSlot(slotZZZ)); assertThat(result).isEqualTo(0L); } @Test public void testClusterCountFailureReports() throws Exception { RedisClusterNode ownPartition = getOwnPartition(sync); - assertThat(getSingle(rx.clusterCountFailureReports(ownPartition.getNodeId()))).isGreaterThanOrEqualTo(0); + assertThat(block(rx.clusterCountFailureReports(ownPartition.getNodeId()))).isGreaterThanOrEqualTo(0); } @Test public void testClusterKeyslot() throws Exception { - assertThat(getSingle(rx.clusterKeyslot(KEY_A))).isEqualTo(SLOT_A); + assertThat(block(rx.clusterKeyslot(KEY_A))).isEqualTo(SLOT_A); assertThat(SlotHash.getSlot(KEY_A)).isEqualTo(SLOT_A); } @Test public void testClusterSaveconfig() throws Exception { - assertThat(getSingle(rx.clusterSaveconfig())).isEqualTo("OK"); + assertThat(block(rx.clusterSaveconfig())).isEqualTo("OK"); } @Test public void testClusterSetConfigEpoch() throws Exception { try { - getSingle(rx.clusterSetConfigEpoch(1L)); + block(rx.clusterSetConfigEpoch(1L)); } catch (RedisException e) { assertThat(e).hasMessageContaining("ERR The user can assign a config epoch only"); } } - private T getSingle(Observable observable) { + private T block(Observable observable) { return observable.toBlocking().single(); } + private T block(Single observable) { + return observable.toBlocking().value(); + } + } diff --git a/src/test/java/com/lambdaworks/redis/cluster/commands/CustomClusterCommandTest.java b/src/test/java/com/lambdaworks/redis/cluster/commands/CustomClusterCommandTest.java index 34c3b98a3a..d0da760ad7 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/commands/CustomClusterCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/commands/CustomClusterCommandTest.java @@ -20,6 +20,7 @@ import com.lambdaworks.redis.protocol.*; import rx.Observable; +import rx.Single; /** * @author Mark Paluch @@ -103,7 +104,7 @@ public void standaloneReactivePing() throws Exception { ReactiveCommandDispatcher dispatcher = new ReactiveCommandDispatcher<>(command, redisClusterConnection, false); - String result = Observable.create(dispatcher).toBlocking().first(); + String result = Single.create(dispatcher.getSingleSubscriber()).toBlocking().value(); assertThat(result).isEqualTo("PONG"); } diff --git a/src/test/java/com/lambdaworks/redis/commands/CustomCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/CustomCommandTest.java index 41d7ef2160..a9ff76e586 100644 --- a/src/test/java/com/lambdaworks/redis/commands/CustomCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/CustomCommandTest.java @@ -92,7 +92,7 @@ public void standaloneReactivePing() throws Exception { ReactiveCommandDispatcher dispatcher = new ReactiveCommandDispatcher<>(command, getStandaloneConnection(), false); - String result = Observable.create(dispatcher).toBlocking().first(); + String result = Observable.create(dispatcher.getObservableSubscriber()).toBlocking().first(); assertThat(result).isEqualTo("PONG"); } diff --git a/src/test/java/com/lambdaworks/redis/commands/rx/RxSyncInvocationHandler.java b/src/test/java/com/lambdaworks/redis/commands/rx/RxSyncInvocationHandler.java index ea5ef08d62..1a7730d729 100644 --- a/src/test/java/com/lambdaworks/redis/commands/rx/RxSyncInvocationHandler.java +++ b/src/test/java/com/lambdaworks/redis/commands/rx/RxSyncInvocationHandler.java @@ -6,21 +6,25 @@ import java.util.Iterator; import java.util.List; import java.util.Set; - -import com.lambdaworks.redis.internal.AbstractInvocationHandler; -import rx.Observable; +import java.util.concurrent.TimeUnit; import com.lambdaworks.redis.api.StatefulConnection; import com.lambdaworks.redis.api.StatefulRedisConnection; import com.lambdaworks.redis.api.sync.RedisCommands; import com.lambdaworks.redis.cluster.api.StatefulRedisClusterConnection; +import com.lambdaworks.redis.internal.AbstractInvocationHandler; import com.lambdaworks.redis.internal.LettuceLists; import com.lambdaworks.redis.internal.LettuceSets; import com.lambdaworks.redis.sentinel.api.StatefulRedisSentinelConnection; import com.lambdaworks.redis.sentinel.api.sync.RedisSentinelCommands; +import rx.Completable; +import rx.Observable; +import rx.Single; + /** * Invocation handler for testing purposes. + * * @param * @param */ @@ -44,33 +48,58 @@ protected Object handleInvocation(Object proxy, Method method, Object[] args) th Object result = targetMethod.invoke(rxApi, args); - if (result == null || !(result instanceof Observable)) { + if (result == null) { return result; } - Observable observable = (Observable) result; - if (!method.getName().equals("exec") && !method.getName().equals("multi")) { - if (connection instanceof StatefulRedisConnection && ((StatefulRedisConnection) connection).isMulti()) { - observable.subscribe(); - return null; + if (result instanceof Observable) { + Observable observable = (Observable) result; + + if (!method.getName().equals("exec") && !method.getName().equals("multi")) { + if (connection instanceof StatefulRedisConnection && ((StatefulRedisConnection) connection) + .isMulti()) { + observable.subscribe(); + return null; + } } - } - List value = observable.toList().toBlocking().first(); + List value = observable.toList().toBlocking().first(); - if (method.getReturnType().equals(List.class)) { - return value; + if (method.getReturnType().equals(List.class)) { + return value; + } + + if (method.getReturnType().equals(Set.class)) { + return LettuceSets.newHashSet(value); + } + + if (!value.isEmpty()) { + return value.get(0); + } } - if (method.getReturnType().equals(Set.class)) { - return LettuceSets.newHashSet(value); + if (result instanceof Single) { + Single single = (Single) result; + + if (!method.getName().equals("exec") && !method.getName().equals("multi")) { + if (connection instanceof StatefulRedisConnection && ((StatefulRedisConnection) connection).isMulti()) { + single.subscribe(); + return null; + } + } + + return single.toBlocking().value(); } - if (!value.isEmpty()) { - return value.get(0); + if (result instanceof Completable) { + Completable completable = (Completable) result; + completable.await(5, TimeUnit.SECONDS); + if (completable.get() != null) { + throw completable.get(); + } } - return null; + return result; } catch (InvocationTargetException e) { throw e.getTargetException(); diff --git a/src/test/java/com/lambdaworks/redis/commands/rx/TransactionRxCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/rx/TransactionRxCommandTest.java index b269fae367..a83f006b02 100644 --- a/src/test/java/com/lambdaworks/redis/commands/rx/TransactionRxCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/rx/TransactionRxCommandTest.java @@ -17,6 +17,7 @@ import com.lambdaworks.redis.internal.LettuceLists; import rx.Observable; +import rx.Single; import rx.observables.BlockingObservable; import rx.observers.TestSubscriber; @@ -46,31 +47,31 @@ public void closeConnection() throws Exception { @Test public void discard() throws Exception { - assertThat(first(commands.multi())).isEqualTo("OK"); + assertThat(block(commands.multi())).isEqualTo("OK"); commands.set(key, value); - assertThat(first(commands.discard())).isEqualTo("OK"); - assertThat(first(commands.get(key))).isNull(); + assertThat(block(commands.discard())).isEqualTo("OK"); + assertThat(block(commands.get(key))).isNull(); } @Test public void execSingular() throws Exception { - assertThat(first(commands.multi())).isEqualTo("OK"); + assertThat(block(commands.multi())).isEqualTo("OK"); redis.set(key, value); assertThat(first(commands.exec())).isEqualTo("OK"); - assertThat(first(commands.get(key))).isEqualTo(value); + assertThat(block(commands.get(key))).isEqualTo(value); } @Test public void errorInMulti() throws Exception { - commands.multi().subscribe(); - commands.set(key, value).subscribe(); - commands.lpop(key).onExceptionResumeNext(Observable. empty()).subscribe(); - commands.get(key).subscribe(); + commands.multi().subscribe(TestSubscriber.create()); + commands.set(key, value).subscribe(TestSubscriber.create()); + commands.lpop(key).subscribe(TestSubscriber.create()); + commands.get(key).subscribe(TestSubscriber.create()); List values = all(commands.exec()); assertThat(values.get(0)).isEqualTo("OK"); @@ -128,6 +129,10 @@ protected T first(Observable observable) { return null; } + protected T block(Single single) { + return single.toBlocking().value(); + } + protected List all(Observable observable) { BlockingObservable blocking = observable.toBlocking(); Iterator iterator = blocking.getIterator(); diff --git a/src/test/java/com/lambdaworks/redis/pubsub/PubSubRxTest.java b/src/test/java/com/lambdaworks/redis/pubsub/PubSubRxTest.java index 3f5da62c6c..b91e62b11e 100644 --- a/src/test/java/com/lambdaworks/redis/pubsub/PubSubRxTest.java +++ b/src/test/java/com/lambdaworks/redis/pubsub/PubSubRxTest.java @@ -29,7 +29,9 @@ import com.lambdaworks.redis.pubsub.api.rx.RedisPubSubReactiveCommands; import com.lambdaworks.redis.pubsub.api.sync.RedisPubSubCommands; +import rx.Completable; import rx.Observable; +import rx.Single; import rx.Subscription; import rx.observables.BlockingObservable; @@ -189,8 +191,7 @@ public void pmessage() throws Exception { @Test(timeout = 2000) public void psubscribe() throws Exception { - Success sucess = first(pubsub.psubscribe(pattern)); - assertThat(sucess).isEqualTo(Success.Success); + block(pubsub.psubscribe(pattern)); assertThat(patterns.take()).isEqualTo(pattern); assertThat((long) counts.take()).isEqualTo(1); @@ -207,7 +208,7 @@ public void pubsubEmptyChannels() throws Exception { public void pubsubChannels() throws Exception { block(pubsub.subscribe(channel)); - List result = first(pubsub2.pubsubChannels().toList()); + List result = single(pubsub2.pubsubChannels().toList()); assertThat(result).contains(channel); } @@ -216,7 +217,7 @@ public void pubsubMultipleChannels() throws Exception { block(pubsub.subscribe(channel, "channel1", "channel3")); - List result = first(pubsub2.pubsubChannels().toList()); + List result = single(pubsub2.pubsubChannels().toList()); assertThat(result).contains(channel, "channel1", "channel3"); } @@ -224,9 +225,9 @@ public void pubsubMultipleChannels() throws Exception { public void pubsubChannelsWithArg() throws Exception { pubsub.subscribe(channel).subscribe(); - Wait.untilTrue(() -> first(pubsub2.pubsubChannels(pattern).filter(s -> channel.equals(s))) != null).waitOrTimeout(); + Wait.untilTrue(() -> single(pubsub2.pubsubChannels(pattern).filter(s -> channel.equals(s))) != null).waitOrTimeout(); - String result = first(pubsub2.pubsubChannels(pattern).filter(s -> channel.equals(s))); + String result = single(pubsub2.pubsubChannels(pattern).filter(s -> channel.equals(s))); assertThat(result).isEqualToIgnoringCase(channel); } @@ -234,9 +235,9 @@ public void pubsubChannelsWithArg() throws Exception { public void pubsubNumsub() throws Exception { pubsub.subscribe(channel).subscribe(); - Wait.untilEquals(1, () -> first(pubsub2.pubsubNumsub(channel).toList()).size()).waitOrTimeout(); + Wait.untilEquals(1, () -> block(pubsub2.pubsubNumsub(channel)).size()).waitOrTimeout(); - Map result = first(pubsub2.pubsubNumsub(channel)); + Map result = block(pubsub2.pubsubNumsub(channel)); assertThat(result).hasSize(1); assertThat(result.get(channel)).isGreaterThan(0); } @@ -244,12 +245,12 @@ public void pubsubNumsub() throws Exception { @Test public void pubsubNumpat() throws Exception { - Wait.untilEquals(0L, () -> first(pubsub2.pubsubNumpat())).waitOrTimeout(); + Wait.untilEquals(0L, () -> block(pubsub2.pubsubNumpat())).waitOrTimeout(); pubsub.psubscribe(pattern).subscribe(); Wait.untilEquals(1L, () -> redis.pubsubNumpat()).waitOrTimeout(); - Long result = first(pubsub2.pubsubNumpat()); + Long result = block(pubsub2.pubsubNumpat()); assertThat(result.longValue()).isGreaterThan(0); } @@ -434,11 +435,15 @@ public void punsubscribed(String pattern, long count) { counts.add(count); } - protected void block(Observable observable) { - observable.toBlocking().last(); + protected T block(Single single) { + return single.toBlocking().value(); + } + + protected void block(Completable completable) { + completable.get(); } - protected T first(Observable observable) { + protected T single(Observable observable) { BlockingObservable blocking = observable.toBlocking(); Iterator iterator = blocking.getIterator(); diff --git a/src/test/java/com/lambdaworks/redis/reliability/AtMostOnceTest.java b/src/test/java/com/lambdaworks/redis/reliability/AtMostOnceTest.java index 9efe88b3df..072b3c787c 100644 --- a/src/test/java/com/lambdaworks/redis/reliability/AtMostOnceTest.java +++ b/src/test/java/com/lambdaworks/redis/reliability/AtMostOnceTest.java @@ -1,5 +1,6 @@ package com.lambdaworks.redis.reliability; +import static com.google.code.tempusfugit.temporal.Duration.millis; import static com.lambdaworks.Connections.getCommandBuffer; import static com.lambdaworks.Connections.getQueue; import static org.assertj.core.api.Assertions.assertThat; @@ -9,6 +10,8 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; +import com.google.code.tempusfugit.temporal.Duration; +import com.lambdaworks.Delay; import org.junit.Before; import org.junit.Test; @@ -246,6 +249,7 @@ public void noCommandsExecutedAfterConnectionIsDisconnected() throws Exception { StatefulRedisConnection connection2 = client.connect(); connection2.async().quit(); + Delay.delay(millis(100)); try { From 048ee89eda96ffc1a76f95535ea3225886ca01a4 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Tue, 26 Jul 2016 17:32:40 +0200 Subject: [PATCH 007/808] Remove closeable from API interfaces --- .../redis/AbstractRedisAsyncCommands.java | 5 -- .../redis/AbstractRedisReactiveCommands.java | 1 - .../api/async/BaseRedisAsyncCommands.java | 7 +-- .../api/async/RedisStringAsyncCommands.java | 4 +- .../api/rx/BaseRedisReactiveCommands.java | 7 +-- .../redis/api/sync/BaseRedisCommands.java | 7 +-- .../redis/api/sync/RedisStringCommands.java | 5 +- .../NodeSelectionStringAsyncCommands.java | 4 +- .../api/sync/NodeSelectionStringCommands.java | 8 ++-- .../redis/api/BaseRedisCommands.java | 8 +--- .../redis/extensibility/LettuceGeoDemo.java | 2 +- .../java/com/lambdaworks/Connections.java | 16 +++++-- src/test/java/com/lambdaworks/SslTest.java | 12 ++--- .../redis/AbstractRedisClientTest.java | 3 +- .../com/lambdaworks/redis/ClientTest.java | 8 ++-- .../lambdaworks/redis/CustomCodecTest.java | 8 ++-- .../redis/ReactiveConnectionTest.java | 2 +- .../redis/ReactiveStreamingOutputTest.java | 2 +- .../cluster/AdvancedClusterClientTest.java | 29 +++--------- .../cluster/AdvancedClusterReactiveTest.java | 19 +------- .../cluster/ClusterReactiveCommandTest.java | 2 +- .../redis/cluster/ClusterSetup.java | 4 +- .../redis/cluster/ClusterTestUtil.java | 5 +- .../redis/cluster/NodeSelectionAsyncTest.java | 2 +- .../redis/cluster/NodeSelectionSyncTest.java | 2 +- .../redis/cluster/RedisClusterClientTest.java | 40 ++++++++-------- .../cluster/RedisClusterReadFromTest.java | 2 +- .../redis/cluster/RedisClusterSetupTest.java | 29 ++++++------ .../RedisClusterStressScenariosTest.java | 23 ++++++---- .../commands/rx/HashClusterRxCommandTest.java | 2 +- .../commands/rx/ListClusterRxCommandTest.java | 2 +- .../rx/StringClusterRxCommandTest.java | 2 +- .../cluster/topology/TopologyRefreshTest.java | 42 +++++++++-------- .../redis/commands/rx/BitRxCommandTest.java | 1 + .../commands/rx/CustomRxCommandTest.java | 1 + .../redis/commands/rx/GeoRxCommandTest.java | 1 + .../redis/commands/rx/HLLRxCommandTest.java | 1 + .../redis/commands/rx/HashRxCommandTest.java | 1 + .../redis/commands/rx/KeyRxCommandTest.java | 1 + .../redis/commands/rx/ListRxCommandTest.java | 1 + .../commands/rx/NumericRxCommandTest.java | 1 + .../commands/rx/ScriptingRxCommandTest.java | 1 + .../commands/rx/ServerRxCommandTest.java | 1 + .../redis/commands/rx/SetRxCommandTest.java | 1 + .../redis/commands/rx/SortRxCommandTest.java | 1 + .../commands/rx/SortedSetRxCommandTest.java | 1 + .../commands/rx/StringRxCommandTest.java | 1 + .../commands/rx/TransactionRxCommandTest.java | 3 +- .../masterslave/StaticMasterSlaveTest.java | 4 +- .../redis/pubsub/PubSubCommandTest.java | 4 +- .../redis/pubsub/PubSubRxTest.java | 4 +- .../redis/sentinel/SentinelRule.java | 4 +- .../sentinel/rx/SentinelRxCommandTest.java | 2 +- .../redis/support/InjectedClient.java | 2 +- ...ConnectionDecoratingInvocationHandler.java | 46 +++++++++++++++++++ .../util/RoutingInvocationHandler.java | 27 +++++++++++ .../rx => util}/RxSyncInvocationHandler.java | 13 ++++-- 57 files changed, 247 insertions(+), 190 deletions(-) create mode 100644 src/test/java/com/lambdaworks/util/ConnectionDecoratingInvocationHandler.java create mode 100644 src/test/java/com/lambdaworks/util/RoutingInvocationHandler.java rename src/test/java/com/lambdaworks/{redis/commands/rx => util}/RxSyncInvocationHandler.java (93%) diff --git a/src/main/java/com/lambdaworks/redis/AbstractRedisAsyncCommands.java b/src/main/java/com/lambdaworks/redis/AbstractRedisAsyncCommands.java index 862ef8ef69..07820e0551 100644 --- a/src/main/java/com/lambdaworks/redis/AbstractRedisAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/AbstractRedisAsyncCommands.java @@ -1778,11 +1778,6 @@ public void setTimeout(long timeout, TimeUnit unit) { connection.setTimeout(timeout, unit); } - @Override - public void close() { - connection.close(); - } - @Override public boolean isOpen() { return connection.isOpen(); diff --git a/src/main/java/com/lambdaworks/redis/AbstractRedisReactiveCommands.java b/src/main/java/com/lambdaworks/redis/AbstractRedisReactiveCommands.java index b637ec3d24..18a7638fba 100644 --- a/src/main/java/com/lambdaworks/redis/AbstractRedisReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/AbstractRedisReactiveCommands.java @@ -1828,7 +1828,6 @@ public void setTimeout(long timeout, TimeUnit unit) { connection.setTimeout(timeout, unit); } - @Override public void close() { connection.close(); } diff --git a/src/main/java/com/lambdaworks/redis/api/async/BaseRedisAsyncCommands.java b/src/main/java/com/lambdaworks/redis/api/async/BaseRedisAsyncCommands.java index fb4acd1f55..eecb1630d4 100644 --- a/src/main/java/com/lambdaworks/redis/api/async/BaseRedisAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/async/BaseRedisAsyncCommands.java @@ -17,7 +17,7 @@ * @since 4.0 * @generated by com.lambdaworks.apigenerator.CreateAsyncApi */ -public interface BaseRedisAsyncCommands extends AutoCloseable { +public interface BaseRedisAsyncCommands { /** * Post a message to a channel. @@ -132,11 +132,6 @@ public interface BaseRedisAsyncCommands extends AutoCloseable { */ RedisFuture dispatch(ProtocolKeyword type, CommandOutput output, CommandArgs args); - /** - * Close the connection. The connection will become not usable anymore as soon as this method was called. - */ - void close(); - /** * * @return true if the connection is open (connected and not closed). diff --git a/src/main/java/com/lambdaworks/redis/api/async/RedisStringAsyncCommands.java b/src/main/java/com/lambdaworks/redis/api/async/RedisStringAsyncCommands.java index ed2aee7fbf..946ed52717 100644 --- a/src/main/java/com/lambdaworks/redis/api/async/RedisStringAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/async/RedisStringAsyncCommands.java @@ -235,10 +235,10 @@ public interface RedisStringAsyncCommands { /** * Stream over the values of all the given keys. - * + * * @param channel the channel * @param keys the keys - * + * * @return Long array-reply list of values at the specified keys. */ RedisFuture mget(ValueStreamingChannel channel, K... keys); diff --git a/src/main/java/com/lambdaworks/redis/api/rx/BaseRedisReactiveCommands.java b/src/main/java/com/lambdaworks/redis/api/rx/BaseRedisReactiveCommands.java index b5945b7ae1..e31eab0a78 100644 --- a/src/main/java/com/lambdaworks/redis/api/rx/BaseRedisReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/rx/BaseRedisReactiveCommands.java @@ -19,7 +19,7 @@ * @since 4.0 * @generated by com.lambdaworks.apigenerator.CreateReactiveApi */ -public interface BaseRedisReactiveCommands extends AutoCloseable { +public interface BaseRedisReactiveCommands { /** * Post a message to a channel. @@ -134,11 +134,6 @@ public interface BaseRedisReactiveCommands extends AutoCloseable { */ Observable dispatch(ProtocolKeyword type, CommandOutput output, CommandArgs args); - /** - * Close the connection. The connection will become not usable anymore as soon as this method was called. - */ - void close(); - /** * * @return true if the connection is open (connected and not closed). diff --git a/src/main/java/com/lambdaworks/redis/api/sync/BaseRedisCommands.java b/src/main/java/com/lambdaworks/redis/api/sync/BaseRedisCommands.java index a88c2b84dc..f1484d0192 100644 --- a/src/main/java/com/lambdaworks/redis/api/sync/BaseRedisCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/sync/BaseRedisCommands.java @@ -16,7 +16,7 @@ * @since 4.0 * @generated by com.lambdaworks.apigenerator.CreateSyncApi */ -public interface BaseRedisCommands extends AutoCloseable { +public interface BaseRedisCommands { /** * Post a message to a channel. @@ -131,11 +131,6 @@ public interface BaseRedisCommands extends AutoCloseable { */ T dispatch(ProtocolKeyword type, CommandOutput output, CommandArgs args); - /** - * Close the connection. The connection will become not usable anymore as soon as this method was called. - */ - void close(); - /** * * @return true if the connection is open (connected and not closed). diff --git a/src/main/java/com/lambdaworks/redis/api/sync/RedisStringCommands.java b/src/main/java/com/lambdaworks/redis/api/sync/RedisStringCommands.java index f23685f16f..aa15ad93c4 100644 --- a/src/main/java/com/lambdaworks/redis/api/sync/RedisStringCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/sync/RedisStringCommands.java @@ -4,6 +4,7 @@ import java.util.Map; import com.lambdaworks.redis.output.ValueStreamingChannel; import com.lambdaworks.redis.BitFieldArgs; +import com.lambdaworks.redis.KeyValue; import com.lambdaworks.redis.SetArgs; /** @@ -234,10 +235,10 @@ public interface RedisStringCommands { /** * Stream over the values of all the given keys. - * + * * @param channel the channel * @param keys the keys - * + * * @return Long array-reply list of values at the specified keys. */ Long mget(ValueStreamingChannel channel, K... keys); diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionStringAsyncCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionStringAsyncCommands.java index 841a6bea7a..adf5d11c91 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionStringAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionStringAsyncCommands.java @@ -235,10 +235,10 @@ public interface NodeSelectionStringAsyncCommands { /** * Stream over the values of all the given keys. - * + * * @param channel the channel * @param keys the keys - * + * * @return Long array-reply list of values at the specified keys. */ AsyncExecutions mget(ValueStreamingChannel channel, K... keys); diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionStringCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionStringCommands.java index f85d35899e..9539cb5b9b 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionStringCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionStringCommands.java @@ -230,17 +230,17 @@ public interface NodeSelectionStringCommands { * @param keys the key * @return List<V> array-reply list of values at the specified keys. */ - Executions> mget(K... keys); + Executions>> mget(K... keys); /** * Stream over the values of all the given keys. - * + * * @param channel the channel * @param keys the keys - * + * * @return Long array-reply list of values at the specified keys. */ - Executions mget(ValueStreamingChannel channel, K... keys); + Executions mget(KeyValueStreamingChannel channel, K... keys); /** * Set multiple keys to multiple values. diff --git a/src/main/templates/com/lambdaworks/redis/api/BaseRedisCommands.java b/src/main/templates/com/lambdaworks/redis/api/BaseRedisCommands.java index 8242dfaf0d..38731b21dd 100644 --- a/src/main/templates/com/lambdaworks/redis/api/BaseRedisCommands.java +++ b/src/main/templates/com/lambdaworks/redis/api/BaseRedisCommands.java @@ -16,7 +16,7 @@ * @author Mark Paluch * @since 4.0 */ -public interface BaseRedisCommands extends AutoCloseable { +public interface BaseRedisCommands { /** * Post a message to a channel. @@ -131,12 +131,6 @@ public interface BaseRedisCommands extends AutoCloseable { */ T dispatch(ProtocolKeyword type, CommandOutput output, CommandArgs args); - /** - * Close the connection. The connection will become not usable anymore as soon as this method was called. - */ - @Override - void close(); - /** * * @return true if the connection is open (connected and not closed). diff --git a/src/test/java/biz/paluch/redis/extensibility/LettuceGeoDemo.java b/src/test/java/biz/paluch/redis/extensibility/LettuceGeoDemo.java index fad1917949..770b244fd8 100644 --- a/src/test/java/biz/paluch/redis/extensibility/LettuceGeoDemo.java +++ b/src/test/java/biz/paluch/redis/extensibility/LettuceGeoDemo.java @@ -44,7 +44,7 @@ public static void main(String[] args) { GeoCoordinates weinheimGeopos = geopos.get(0); System.out.println("Coordinates: " + weinheimGeopos.x + "/" + weinheimGeopos.y); - redis.close(); + redis.getStatefulConnection().close(); redisClient.shutdown(); } } diff --git a/src/test/java/com/lambdaworks/Connections.java b/src/test/java/com/lambdaworks/Connections.java index f54947a246..7e13bb0b8a 100644 --- a/src/test/java/com/lambdaworks/Connections.java +++ b/src/test/java/com/lambdaworks/Connections.java @@ -2,6 +2,7 @@ import java.util.Queue; +import com.lambdaworks.redis.api.StatefulRedisConnection; import org.springframework.test.util.ReflectionTestUtils; import com.lambdaworks.redis.RedisChannelHandler; @@ -18,13 +19,23 @@ */ public class Connections { + /** + * Extract the {@link Channel} from a stateful connection. + * + * @param connection + * @return + */ public static Channel getChannel(StatefulConnection connection) { RedisChannelHandler channelHandler = (RedisChannelHandler) connection; - Channel channel = (Channel) ReflectionTestUtils.getField(channelHandler.getChannelWriter(), "channel"); - return channel; + return (Channel) ReflectionTestUtils.getField(channelHandler.getChannelWriter(), "channel"); } + /** + * Extract the {@link ConnectionWatchdog} from a stateful connection. + * @param connection + * @return + */ public static ConnectionWatchdog getConnectionWatchdog(StatefulConnection connection) { Channel channel = getChannel(connection); @@ -39,7 +50,6 @@ public static RedisChannelWriter getChannelWriter(StatefulConnectio return ((RedisChannelHandler) connection).getChannelWriter(); } - public static Queue getQueue(StatefulConnection connection) { return (Queue) ReflectionTestUtils.getField(Connections.getChannelWriter(connection), "queue"); } diff --git a/src/test/java/com/lambdaworks/SslTest.java b/src/test/java/com/lambdaworks/SslTest.java index 95969ce31f..de0baa3158 100644 --- a/src/test/java/com/lambdaworks/SslTest.java +++ b/src/test/java/com/lambdaworks/SslTest.java @@ -59,7 +59,7 @@ public void standaloneWithSsl() throws Exception { RedisCommands connection = redisClient.connect(URI_NO_VERIFY).sync(); connection.set("key", "value"); assertThat(connection.get("key")).isEqualTo("value"); - connection.close(); + connection.getStatefulConnection().close(); } @Test @@ -148,7 +148,7 @@ public void regularSslWithReconnect() throws Exception { connection.quit(); Thread.sleep(200); assertThat(connection.ping()).isEqualTo("PONG"); - connection.close(); + connection.getStatefulConnection().close(); } @Test(expected = RedisConnectionException.class) @@ -176,8 +176,8 @@ public void pubSubSsl() throws Exception { assertThat(connection2.pubsubChannels()).contains("c1", "c2"); - connection.close(); - connection2.close(); + connection.getStatefulConnection().close(); + connection2.getStatefulConnection().close(); } @Test @@ -219,8 +219,8 @@ public void pubSubSslAndBreakConnection() throws Exception { assertThat(defectFuture.isDone()).isEqualTo(true); - connection.close(); - connection2.close(); + connection.getStatefulConnection().close(); + connection2.getStatefulConnection().close(); } private void setOptions(SslOptions sslOptions) { diff --git a/src/test/java/com/lambdaworks/redis/AbstractRedisClientTest.java b/src/test/java/com/lambdaworks/redis/AbstractRedisClientTest.java index f64084f7a0..b93781465d 100644 --- a/src/test/java/com/lambdaworks/redis/AbstractRedisClientTest.java +++ b/src/test/java/com/lambdaworks/redis/AbstractRedisClientTest.java @@ -3,6 +3,7 @@ package com.lambdaworks.redis; import com.lambdaworks.TestClientResources; +import com.lambdaworks.redis.api.StatefulConnection; import org.junit.After; import org.junit.Before; import org.junit.BeforeClass; @@ -58,7 +59,7 @@ public void openConnection() throws Exception { @After public void closeConnection() throws Exception { if (redis != null) { - redis.close(); + redis.getStatefulConnection().close(); } } diff --git a/src/test/java/com/lambdaworks/redis/ClientTest.java b/src/test/java/com/lambdaworks/redis/ClientTest.java index ea10cdfd9c..b024ade1d6 100644 --- a/src/test/java/com/lambdaworks/redis/ClientTest.java +++ b/src/test/java/com/lambdaworks/redis/ClientTest.java @@ -38,7 +38,7 @@ public void closeConnection() throws Exception { @Test(expected = RedisException.class) public void close() throws Exception { - redis.close(); + redis.getStatefulConnection().close(); redis.get(key); } @@ -51,14 +51,14 @@ public void statefulConnectionFromSync() throws Exception { public void statefulConnectionFromAsync() throws Exception { RedisAsyncCommands async = client.connect().async(); assertThat(async.getStatefulConnection().async()).isSameAs(async); - async.close(); + async.getStatefulConnection().close(); } @Test public void statefulConnectionFromReactive() throws Exception { RedisAsyncCommands async = client.connect().async(); assertThat(async.getStatefulConnection().reactive().getStatefulConnection()).isSameAs(async.getStatefulConnection()); - async.close(); + async.getStatefulConnection().close(); } @Test @@ -84,7 +84,7 @@ public void listenerTest() throws Exception { assertThat(listener.onDisconnected).isNull(); connection.set(key, value).get(); - connection.close(); + connection.getStatefulConnection().close(); waitOrTimeout(new Condition() { diff --git a/src/test/java/com/lambdaworks/redis/CustomCodecTest.java b/src/test/java/com/lambdaworks/redis/CustomCodecTest.java index a729c17187..693959379f 100644 --- a/src/test/java/com/lambdaworks/redis/CustomCodecTest.java +++ b/src/test/java/com/lambdaworks/redis/CustomCodecTest.java @@ -63,7 +63,7 @@ public void testDeflateCompressedJavaSerializer() throws Exception { connection.set(key, list); assertThat(connection.get(key)).isEqualTo(list); - connection.close(); + connection.getStatefulConnection().close(); } @Test @@ -74,7 +74,7 @@ public void testGzipompressedJavaSerializer() throws Exception { connection.set(key, list); assertThat(connection.get(key)).isEqualTo(list); - connection.close(); + connection.getStatefulConnection().close(); } @Test @@ -89,7 +89,7 @@ public void testByteCodec() throws Exception { List keys = connection.keys(key.getBytes()); assertThat(keys).contains(key.getBytes()); - connection.close(); + connection.getStatefulConnection().close(); } @Test @@ -103,7 +103,7 @@ public void testExperimentalByteCodec() throws Exception { List keys = connection.keys(key.getBytes()); assertThat(keys).contains(key.getBytes()); - connection.close(); + connection.getStatefulConnection().close(); } public class SerializedObjectCodec implements RedisCodec { diff --git a/src/test/java/com/lambdaworks/redis/ReactiveConnectionTest.java b/src/test/java/com/lambdaworks/redis/ReactiveConnectionTest.java index 3b63e65350..d865d30dcf 100644 --- a/src/test/java/com/lambdaworks/redis/ReactiveConnectionTest.java +++ b/src/test/java/com/lambdaworks/redis/ReactiveConnectionTest.java @@ -48,7 +48,7 @@ public void openReactiveConnection() throws Exception { @After public void closeReactiveConnection() throws Exception { - reactive.close(); + reactive.getStatefulConnection().close(); } @Test diff --git a/src/test/java/com/lambdaworks/redis/ReactiveStreamingOutputTest.java b/src/test/java/com/lambdaworks/redis/ReactiveStreamingOutputTest.java index 263a793fad..8e057d5eba 100644 --- a/src/test/java/com/lambdaworks/redis/ReactiveStreamingOutputTest.java +++ b/src/test/java/com/lambdaworks/redis/ReactiveStreamingOutputTest.java @@ -32,7 +32,7 @@ public void openReactiveConnection() throws Exception { @After public void closeReactiveConnection() throws Exception { - reactive.close(); + reactive.getStatefulConnection().close(); } @Test diff --git a/src/test/java/com/lambdaworks/redis/cluster/AdvancedClusterClientTest.java b/src/test/java/com/lambdaworks/redis/cluster/AdvancedClusterClientTest.java index 3a1b7ff77f..aa9b6fa00b 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/AdvancedClusterClientTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/AdvancedClusterClientTest.java @@ -47,7 +47,7 @@ public void before() throws Exception { @After public void after() throws Exception { - commands.close(); + commands.getStatefulConnection().close(); } @Test @@ -81,21 +81,6 @@ public void partitions() throws Exception { assertThat(partitions).hasSize(4); } - @Test - public void doWeirdThingsWithClusterconnections() throws Exception { - - assertThat(clusterClient.getPartitions()).hasSize(4); - - for (RedisClusterNode redisClusterNode : clusterClient.getPartitions()) { - RedisClusterAsyncCommands nodeConnection = commands.getConnection(redisClusterNode.getNodeId()); - - nodeConnection.close(); - - RedisClusterAsyncCommands nextConnection = commands.getConnection(redisClusterNode.getNodeId()); - assertThat(commands).isNotSameAs(nextConnection); - } - } - @Test public void differentConnections() throws Exception { @@ -391,7 +376,7 @@ public void testSync() throws Exception { @Test public void routeCommandTonoAddrPartition() throws Exception { - RedisClusterCommands sync = clusterClient.connect().sync(); + RedisAdvancedClusterCommands sync = clusterClient.connect().sync(); try { Partitions partitions = clusterClient.getPartitions(); @@ -406,13 +391,13 @@ public void routeCommandTonoAddrPartition() throws Exception { clusterClient.getPartitions().clear(); clusterClient.reloadPartitions(); } - sync.close(); + sync.getStatefulConnection().close(); } @Test public void routeCommandToForbiddenHostOnRedirect() throws Exception { - RedisClusterCommands sync = clusterClient.connect().sync(); + RedisAdvancedClusterCommands sync = clusterClient.connect().sync(); try { Partitions partitions = clusterClient.getPartitions(); @@ -434,7 +419,7 @@ public void routeCommandToForbiddenHostOnRedirect() throws Exception { clusterClient.getPartitions().clear(); clusterClient.reloadPartitions(); } - sync.close(); + sync.getStatefulConnection().close(); } @Test @@ -461,7 +446,7 @@ public void getConnectionToNotAClusterMemberAllowed() throws Exception { @Test public void pipelining() throws Exception { - RedisClusterCommands verificationConnection = clusterClient.connect().sync(); + RedisAdvancedClusterCommands verificationConnection = clusterClient.connect().sync(); // preheat the first connection commands.get(key(0)).get(); @@ -485,7 +470,7 @@ public void pipelining() throws Exception { assertThat(verificationConnection.get(key(i))).as("Key " + key(i) + " must be " + value(i)).isEqualTo(value(i)); } - verificationConnection.close(); + verificationConnection.getStatefulConnection().close(); } @Test diff --git a/src/test/java/com/lambdaworks/redis/cluster/AdvancedClusterReactiveTest.java b/src/test/java/com/lambdaworks/redis/cluster/AdvancedClusterReactiveTest.java index 3ee8c4e1c0..92b585eaec 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/AdvancedClusterReactiveTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/AdvancedClusterReactiveTest.java @@ -24,7 +24,7 @@ import com.lambdaworks.redis.cluster.api.sync.RedisClusterCommands; import com.lambdaworks.redis.cluster.models.partitions.RedisClusterNode; import com.lambdaworks.redis.codec.Utf8StringCodec; -import com.lambdaworks.redis.commands.rx.RxSyncInvocationHandler; +import com.lambdaworks.util.RxSyncInvocationHandler; import rx.Observable; import rx.Single; @@ -48,7 +48,7 @@ public void before() throws Exception { @After public void after() throws Exception { - commands.close(); + commands.getStatefulConnection().close(); } @Test(expected = RedisException.class) @@ -62,21 +62,6 @@ public void invalidHost() throws Exception { commands.getConnection("invalid-host", -1); } - @Test - public void doWeirdThingsWithClusterconnections() throws Exception { - - assertThat(clusterClient.getPartitions()).hasSize(4); - - for (RedisClusterNode redisClusterNode : clusterClient.getPartitions()) { - RedisClusterReactiveCommands nodeConnection = commands.getConnection(redisClusterNode.getNodeId()); - - nodeConnection.close(); - - RedisClusterReactiveCommands nextConnection = commands.getConnection(redisClusterNode.getNodeId()); - assertThat(commands).isNotSameAs(nextConnection); - } - } - @Test public void msetCrossSlot() throws Exception { diff --git a/src/test/java/com/lambdaworks/redis/cluster/ClusterReactiveCommandTest.java b/src/test/java/com/lambdaworks/redis/cluster/ClusterReactiveCommandTest.java index 82f2b9ca39..dba6a999ff 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/ClusterReactiveCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/ClusterReactiveCommandTest.java @@ -55,7 +55,7 @@ public void before() throws Exception { @After public void after() throws Exception { - async.close(); + async.getStatefulConnection().close(); } @Test diff --git a/src/test/java/com/lambdaworks/redis/cluster/ClusterSetup.java b/src/test/java/com/lambdaworks/redis/cluster/ClusterSetup.java index e2c9b93964..d098ca6203 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/ClusterSetup.java +++ b/src/test/java/com/lambdaworks/redis/cluster/ClusterSetup.java @@ -77,7 +77,7 @@ public static void setup2Masters(ClusterRule clusterRule) throws InterruptedExce redisClusterNode -> redisClusterNode.is(RedisClusterNode.NodeFlag.MASTER)).count(); }).waitOrTimeout(); - connection.close(); + connection.getStatefulConnection().close(); } /** @@ -131,7 +131,7 @@ public static void setupMasterWithSlave(ClusterRule clusterRule) throws Interrup redisClusterNode -> redisClusterNode.is(RedisClusterNode.NodeFlag.SLAVE)).count(); }).waitOrTimeout(); - connection.close(); + connection.getStatefulConnection().close(); } protected static Stream partitionStream(ClusterRule clusterRule) { diff --git a/src/test/java/com/lambdaworks/redis/cluster/ClusterTestUtil.java b/src/test/java/com/lambdaworks/redis/cluster/ClusterTestUtil.java index fd12451b4e..fd3405d370 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/ClusterTestUtil.java +++ b/src/test/java/com/lambdaworks/redis/cluster/ClusterTestUtil.java @@ -9,6 +9,7 @@ import com.lambdaworks.redis.cluster.models.partitions.ClusterPartitionParser; import com.lambdaworks.redis.cluster.models.partitions.Partitions; import com.lambdaworks.redis.cluster.models.partitions.RedisClusterNode; +import com.lambdaworks.util.RoutingInvocationHandler; /** * @author Mark Paluch @@ -73,7 +74,9 @@ public static void flushDatabaseOfAllNodes(StatefulRedisClusterConnection public static RedisCommands redisCommandsOverCluster( StatefulRedisClusterConnection connection) { StatefulRedisClusterConnectionImpl clusterConnection = (StatefulRedisClusterConnectionImpl) connection; - InvocationHandler h = clusterConnection.syncInvocationHandler(); + + InvocationHandler h = new RoutingInvocationHandler(connection.async(), + clusterConnection.syncInvocationHandler()); return (RedisCommands) Proxy.newProxyInstance(ClusterTestUtil.class.getClassLoader(), new Class[] { RedisCommands.class }, h); } diff --git a/src/test/java/com/lambdaworks/redis/cluster/NodeSelectionAsyncTest.java b/src/test/java/com/lambdaworks/redis/cluster/NodeSelectionAsyncTest.java index c6c38a2bbe..f04f440e1f 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/NodeSelectionAsyncTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/NodeSelectionAsyncTest.java @@ -42,7 +42,7 @@ public void before() throws Exception { @After public void after() throws Exception { - commands.close(); + commands.getStatefulConnection().close(); } @Test diff --git a/src/test/java/com/lambdaworks/redis/cluster/NodeSelectionSyncTest.java b/src/test/java/com/lambdaworks/redis/cluster/NodeSelectionSyncTest.java index c14a497ea3..ff491e4211 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/NodeSelectionSyncTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/NodeSelectionSyncTest.java @@ -40,7 +40,7 @@ public void before() throws Exception { @After public void after() throws Exception { - commands.close(); + commands.getStatefulConnection().close(); } @Test diff --git a/src/test/java/com/lambdaworks/redis/cluster/RedisClusterClientTest.java b/src/test/java/com/lambdaworks/redis/cluster/RedisClusterClientTest.java index a9d6519b4c..1b6cfbc7dd 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/RedisClusterClientTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/RedisClusterClientTest.java @@ -11,6 +11,7 @@ import java.util.concurrent.TimeUnit; import com.lambdaworks.TestClientResources; +import com.lambdaworks.redis.api.sync.RedisCommands; import org.assertj.core.api.AssertionsForClassTypes; import org.junit.*; import org.junit.runners.MethodSorters; @@ -39,10 +40,10 @@ public class RedisClusterClientTest extends AbstractClusterTest { private StatefulRedisConnection redis3; private StatefulRedisConnection redis4; - private RedisClusterCommands redissync1; - private RedisClusterCommands redissync2; - private RedisClusterCommands redissync3; - private RedisClusterCommands redissync4; + private RedisCommands redissync1; + private RedisCommands redissync2; + private RedisCommands redissync3; + private RedisCommands redissync4; protected RedisAdvancedClusterCommands sync; @@ -82,27 +83,27 @@ public void before() throws Exception { @After public void after() throws Exception { - sync.close(); + sync.getStatefulConnection().close(); redis1.close(); - redissync1.close(); - redissync2.close(); - redissync3.close(); - redissync4.close(); + redissync1.getStatefulConnection().close(); + redissync2.getStatefulConnection().close(); + redissync3.getStatefulConnection().close(); + redissync4.getStatefulConnection().close(); } @Test public void statefulConnectionFromSync() throws Exception { RedisAdvancedClusterCommands sync = clusterClient.connect().sync(); assertThat(sync.getStatefulConnection().sync()).isSameAs(sync); - sync.close(); + sync.getStatefulConnection().close(); } @Test public void statefulConnectionFromAsync() throws Exception { RedisAdvancedClusterAsyncCommands async = clusterClient.connect().async(); assertThat(async.getStatefulConnection().async()).isSameAs(async); - async.close(); + async.getStatefulConnection().close(); } @Test @@ -188,14 +189,14 @@ public void testClusteredOperations() throws Exception { } clusterClient.reloadPartitions(); - RedisClusterCommands connection = clusterClient.connect().sync(); + RedisAdvancedClusterCommands connection = clusterClient.connect().sync(); assertThat(connection.set(KEY_A, value)).isEqualTo("OK"); assertThat(connection.set(KEY_B, "myValue2")).isEqualTo("OK"); assertThat(connection.set(KEY_D, "myValue2")).isEqualTo("OK"); - connection.close(); + connection.getStatefulConnection().close(); } @@ -223,7 +224,7 @@ public void testClusterCommandRedirection() throws Exception { // gets redirection to node 3 assertThat(connection.set(KEY_A, value).get()).isEqualTo("OK"); - connection.close(); + connection.getStatefulConnection().close(); } @Test @@ -263,7 +264,7 @@ public void testClusterRedirection() throws Exception { assertThat(setA.getError()).isNull(); assertThat(setA.get()).isEqualTo("OK"); - connection.close(); + connection.getStatefulConnection().close(); } @Test @@ -293,21 +294,20 @@ public void testClusterRedirectionLimit() throws Exception { setA.await(10, TimeUnit.SECONDS); assertThat(setA.getError()).isEqualTo("MOVED 15495 127.0.0.1:7380"); - connection.close(); + connection.getStatefulConnection().close(); } @Test(expected = RedisException.class) public void closeConnection() throws Exception { - try (RedisAdvancedClusterCommands connection = clusterClient.connect().sync()) { + RedisAdvancedClusterCommands connection = clusterClient.connect().sync(); List time = connection.time(); assertThat(time).hasSize(2); - connection.close(); + connection.getStatefulConnection().close(); connection.time(); - } } @Test @@ -531,7 +531,7 @@ public void testPfmerge() throws Exception { assertThat(connection.pfcount("key8885")).isEqualTo(3); - connection.close(); + connection.getStatefulConnection().close(); } private void assertTimeout(StatefulConnection connection, long expectedTimeout, TimeUnit expectedTimeUnit) { diff --git a/src/test/java/com/lambdaworks/redis/cluster/RedisClusterReadFromTest.java b/src/test/java/com/lambdaworks/redis/cluster/RedisClusterReadFromTest.java index 0f9aef7397..d873a27916 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/RedisClusterReadFromTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/RedisClusterReadFromTest.java @@ -43,7 +43,7 @@ public void before() throws Exception { @After public void after() throws Exception { - sync.close(); + sync.getStatefulConnection().close(); } @Test diff --git a/src/test/java/com/lambdaworks/redis/cluster/RedisClusterSetupTest.java b/src/test/java/com/lambdaworks/redis/cluster/RedisClusterSetupTest.java index dfe8a71cc5..9cb11224ed 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/RedisClusterSetupTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/RedisClusterSetupTest.java @@ -14,6 +14,7 @@ import java.util.concurrent.TimeoutException; import com.lambdaworks.TestClientResources; +import com.lambdaworks.redis.api.sync.RedisCommands; import org.junit.*; import com.google.code.tempusfugit.temporal.Condition; @@ -51,8 +52,8 @@ public class RedisClusterSetupTest extends AbstractTest { private static RedisClusterClient clusterClient; private static RedisClient client = DefaultRedisClient.get(); - private RedisClusterCommands redis1; - private RedisClusterCommands redis2; + private RedisCommands redis1; + private RedisCommands redis2; @Rule public ClusterRule clusterRule = new ClusterRule(clusterClient, AbstractClusterTest.port5, AbstractClusterTest.port6); @@ -77,8 +78,8 @@ public void openConnection() throws Exception { @After public void closeConnection() throws Exception { - redis1.close(); - redis2.close(); + redis1.getStatefulConnection().close(); + redis2.getStatefulConnection().close(); } @Test @@ -180,7 +181,7 @@ public void clusterTopologyRefresh() throws Exception { ClusterSetup.setup2Masters(clusterRule); assertThat(clusterClient.getPartitions()).hasSize(2); - clusterConnection.close(); + clusterConnection.getStatefulConnection().close(); } @Test @@ -226,7 +227,7 @@ public void changeTopologyWhileOperations() throws Exception { assertThat(sync.get("t")).isEqualTo("value"); assertThat(sync.get("p")).isEqualTo("value"); - async.close(); + async.getStatefulConnection().close(); } @Test @@ -248,7 +249,7 @@ public void slotMigrationShouldUseAsking() throws Exception { assertThat(sync.get("b")).isNull(); - async.close(); + async.getStatefulConnection().close(); } @Test @@ -280,7 +281,7 @@ public void disconnectedConnectionRejectTest() throws Exception { } catch (ExecutionException e) { assertThat(e).hasRootCauseInstanceOf(RedisException.class).hasMessageContaining("not connected"); } finally { - clusterConnection.close(); + clusterConnection.getStatefulConnection().close(); } } @@ -324,7 +325,7 @@ public void atLeastOnceForgetNodeFailover() throws Exception { assertRoutedExecution(clusterConnection); - clusterConnection.close(); + clusterConnection.getStatefulConnection().close(); } @@ -362,7 +363,7 @@ public void expireStaleNodeIdConnections() throws Exception { Wait.untilEquals(1, () -> clusterClient.getPartitions().size()).waitOrTimeout(); Wait.untilEquals(1, () -> clusterConnectionProvider.getConnectionCount()).waitOrTimeout(); - clusterConnection.close(); + clusterConnection.getStatefulConnection().close(); } @@ -408,7 +409,7 @@ public void doNotExpireStaleNodeIdConnections() throws Exception { assertThat(clusterConnectionProvider.getConnectionCount()).isEqualTo(2); - clusterConnection.close(); + clusterConnection.getStatefulConnection().close(); } @@ -454,7 +455,7 @@ public void expireStaleHostAndPortConnections() throws Exception { Wait.untilEquals(1, () -> clusterClient.getPartitions().size()).waitOrTimeout(); Wait.untilEquals(2L, () -> clusterConnectionProvider.getConnectionCount()).waitOrTimeout(); - clusterConnection.close(); + clusterConnection.getStatefulConnection().close(); } @Test @@ -472,7 +473,7 @@ public void readFromSlaveTest() throws Exception { assertThat(e).hasMessageContaining("Cannot determine a partition to read for slot"); } - clusterConnection.close(); + clusterConnection.getStatefulConnection().close(); } @Test @@ -486,7 +487,7 @@ public void readFromNearestTest() throws Exception { assertThat(clusterConnection.get(key)).isEqualTo(value); - clusterConnection.close(); + clusterConnection.getStatefulConnection().close(); } protected PooledClusterConnectionProvider getPooledClusterConnectionProvider( diff --git a/src/test/java/com/lambdaworks/redis/cluster/RedisClusterStressScenariosTest.java b/src/test/java/com/lambdaworks/redis/cluster/RedisClusterStressScenariosTest.java index abafa964be..29b7e2ff76 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/RedisClusterStressScenariosTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/RedisClusterStressScenariosTest.java @@ -13,6 +13,9 @@ import org.apache.logging.log4j.Logger; import com.lambdaworks.TestClientResources; import org.junit.*; +import com.lambdaworks.redis.api.sync.RedisCommands; +import com.lambdaworks.redis.cluster.api.async.RedisAdvancedClusterAsyncCommands; +import com.lambdaworks.redis.cluster.api.sync.RedisAdvancedClusterCommands; import org.junit.runners.MethodSorters; import com.google.code.tempusfugit.temporal.Duration; @@ -42,8 +45,8 @@ public class RedisClusterStressScenariosTest extends AbstractTest { protected StatefulRedisConnection redis5; protected StatefulRedisConnection redis6; - protected RedisClusterCommands redissync5; - protected RedisClusterCommands redissync6; + protected RedisCommands redissync5; + protected RedisCommands redissync6; protected String key = "key"; protected String value = "value"; @@ -86,8 +89,8 @@ public void before() throws Exception { public void after() throws Exception { redis5.close(); - redissync5.close(); - redissync6.close(); + redissync5.getStatefulConnection().close(); + redissync6.getStatefulConnection().close(); } @Test @@ -135,7 +138,7 @@ public void testClusterConnectionStability() throws Exception { final RedisAsyncCommands slotConnection = statefulSlotConnection.async(); slotConnection.set("a", "b"); - slotConnection.close(); + slotConnection.getStatefulConnection().close(); WaitFor.waitOrTimeout(() -> !slotConnection.isOpen(), timeout(seconds(5))); @@ -152,14 +155,14 @@ public void testClusterConnectionStability() throws Exception { assertThat(e).hasMessageContaining("Connection is closed"); } - connection.close(); + connection.getStatefulConnection().close(); } @Test(timeout = 20000) public void distributedClusteredAccessAsync() throws Exception { - RedisClusterAsyncCommands connection = clusterClient.connect().async(); + RedisAdvancedClusterAsyncCommands connection = clusterClient.connect().async(); List> futures = new ArrayList<>(); for (int i = 0; i < 100; i++) { @@ -190,13 +193,13 @@ public void distributedClusteredAccessAsync() throws Exception { assertThat(setD.get()).isEqualTo("myValue3" + i); } - connection.close(); + connection.getStatefulConnection().close(); } @Test public void distributedClusteredAccessSync() throws Exception { - RedisClusterCommands connection = clusterClient.connect().sync(); + RedisAdvancedClusterCommands connection = clusterClient.connect().sync(); for (int i = 0; i < 100; i++) { connection.set("a" + i, "myValue1" + i); @@ -211,7 +214,7 @@ public void distributedClusteredAccessSync() throws Exception { assertThat(connection.get("d" + i)).isEqualTo("myValue3" + i); } - connection.close(); + connection.getStatefulConnection().close(); } } diff --git a/src/test/java/com/lambdaworks/redis/cluster/commands/rx/HashClusterRxCommandTest.java b/src/test/java/com/lambdaworks/redis/cluster/commands/rx/HashClusterRxCommandTest.java index 0c63ba0d2a..bdbcd39d3e 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/commands/rx/HashClusterRxCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/commands/rx/HashClusterRxCommandTest.java @@ -12,7 +12,7 @@ import com.lambdaworks.redis.cluster.RedisClusterClient; import com.lambdaworks.redis.cluster.api.StatefulRedisClusterConnection; import com.lambdaworks.redis.commands.HashCommandTest; -import com.lambdaworks.redis.commands.rx.RxSyncInvocationHandler; +import com.lambdaworks.util.RxSyncInvocationHandler; /** * @author Mark Paluch diff --git a/src/test/java/com/lambdaworks/redis/cluster/commands/rx/ListClusterRxCommandTest.java b/src/test/java/com/lambdaworks/redis/cluster/commands/rx/ListClusterRxCommandTest.java index 228314d201..340526ec1a 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/commands/rx/ListClusterRxCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/commands/rx/ListClusterRxCommandTest.java @@ -14,7 +14,7 @@ import com.lambdaworks.redis.cluster.RedisClusterClient; import com.lambdaworks.redis.cluster.api.StatefulRedisClusterConnection; import com.lambdaworks.redis.commands.ListCommandTest; -import com.lambdaworks.redis.commands.rx.RxSyncInvocationHandler; +import com.lambdaworks.util.RxSyncInvocationHandler; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/com/lambdaworks/redis/cluster/commands/rx/StringClusterRxCommandTest.java b/src/test/java/com/lambdaworks/redis/cluster/commands/rx/StringClusterRxCommandTest.java index 38bb7b794d..fc0edb35b0 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/commands/rx/StringClusterRxCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/commands/rx/StringClusterRxCommandTest.java @@ -19,7 +19,7 @@ import com.lambdaworks.redis.cluster.api.StatefulRedisClusterConnection; import com.lambdaworks.redis.cluster.api.rx.RedisAdvancedClusterReactiveCommands; import com.lambdaworks.redis.commands.StringCommandTest; -import com.lambdaworks.redis.commands.rx.RxSyncInvocationHandler; +import com.lambdaworks.util.RxSyncInvocationHandler; import rx.Observable; diff --git a/src/test/java/com/lambdaworks/redis/cluster/topology/TopologyRefreshTest.java b/src/test/java/com/lambdaworks/redis/cluster/topology/TopologyRefreshTest.java index a16e817159..35f5024717 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/topology/TopologyRefreshTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/topology/TopologyRefreshTest.java @@ -7,15 +7,16 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.function.BiFunction; -import io.netty.util.concurrent.ScheduledFuture; import org.junit.After; import org.junit.Before; import org.junit.Test; +import org.springframework.test.util.ReflectionTestUtils; import com.lambdaworks.Wait; import com.lambdaworks.category.SlowTests; import com.lambdaworks.redis.*; import com.lambdaworks.redis.api.async.BaseRedisAsyncCommands; +import com.lambdaworks.redis.api.sync.RedisCommands; import com.lambdaworks.redis.cluster.AbstractClusterTest; import com.lambdaworks.redis.cluster.ClusterClientOptions; import com.lambdaworks.redis.cluster.ClusterTopologyRefreshOptions; @@ -23,10 +24,11 @@ import com.lambdaworks.redis.cluster.api.StatefulRedisClusterConnection; import com.lambdaworks.redis.cluster.api.async.RedisAdvancedClusterAsyncCommands; import com.lambdaworks.redis.cluster.api.async.RedisClusterAsyncCommands; -import com.lambdaworks.redis.cluster.api.sync.RedisClusterCommands; +import com.lambdaworks.redis.cluster.api.sync.RedisAdvancedClusterCommands; import com.lambdaworks.redis.cluster.models.partitions.Partitions; import com.lambdaworks.redis.cluster.models.partitions.RedisClusterNode; -import org.springframework.test.util.ReflectionTestUtils; + +import io.netty.util.concurrent.ScheduledFuture; /** * Test for topology refreshing. @@ -41,8 +43,8 @@ public class TopologyRefreshTest extends AbstractTest { private static RedisClient client = DefaultRedisClient.get(); private RedisClusterClient clusterClient; - private RedisClusterCommands redis1; - private RedisClusterCommands redis2; + private RedisCommands redis1; + private RedisCommands redis2; @Before public void openConnection() throws Exception { @@ -54,8 +56,8 @@ public void openConnection() throws Exception { @After public void closeConnection() throws Exception { - redis1.close(); - redis2.close(); + redis1.getStatefulConnection().close(); + redis2.getStatefulConnection().close(); FastShutdown.shutdown(clusterClient); } @@ -69,8 +71,8 @@ public void shouldUnsubscribeTopologyRefresh() throws Exception { RedisAdvancedClusterAsyncCommands clusterConnection = clusterClient.connect().async(); - AtomicBoolean clusterTopologyRefreshActivated = (AtomicBoolean) ReflectionTestUtils - .getField(clusterClient, "clusterTopologyRefreshActivated"); + AtomicBoolean clusterTopologyRefreshActivated = (AtomicBoolean) ReflectionTestUtils.getField(clusterClient, + "clusterTopologyRefreshActivated"); AtomicReference> clusterTopologyRefreshFuture = (AtomicReference) ReflectionTestUtils .getField(clusterClient, "clusterTopologyRefreshFuture"); @@ -80,7 +82,7 @@ public void shouldUnsubscribeTopologyRefresh() throws Exception { ScheduledFuture scheduledFuture = clusterTopologyRefreshFuture.get(); - clusterConnection.close(); + clusterConnection.getStatefulConnection().close(); FastShutdown.shutdown(clusterClient); @@ -106,7 +108,7 @@ public void changeTopologyWhileOperations() throws Exception { return !clusterClient.getPartitions().isEmpty(); }).waitOrTimeout(); - clusterConnection.close(); + clusterConnection.getStatefulConnection().close(); } @Test @@ -123,7 +125,7 @@ public void dynamicSourcesProvidesClientCountForAllNodes() throws Exception { assertThat(snapshot.getConnectedClients()).isNotNull().isGreaterThanOrEqualTo(0); } - clusterConnection.close(); + clusterConnection.getStatefulConnection().close(); } @Test @@ -141,7 +143,7 @@ public void staticSourcesProvidesClientCountForSeedNodes() throws Exception { RedisClusterNodeSnapshot node2 = (RedisClusterNodeSnapshot) partitions.getPartitionBySlot(15000); assertThat(node2.getConnectedClients()).isNull(); - clusterConnection.close(); + clusterConnection.getStatefulConnection().close(); } @Test @@ -199,7 +201,7 @@ public void adaptiveTopologyUpdateIsRateLimited() throws Exception { assertThat(clusterClient.getPartitions()).isEmpty(); - clusterConnection.close(); + clusterConnection.getStatefulConnection().close(); } @Test @@ -227,7 +229,7 @@ public void adaptiveTopologyUpdatetUsesTimeout() throws Exception { return !clusterClient.getPartitions().isEmpty(); }).waitOrTimeout(); - clusterConnection.close(); + clusterConnection.getStatefulConnection().close(); } @Test @@ -245,7 +247,7 @@ public void adaptiveTriggerDoesNotFireOnSingleReconnect() throws Exception { Thread.sleep(500); assertThat(clusterClient.getPartitions()).isEmpty(); - clusterConnection.close(); + clusterConnection.getStatefulConnection().close(); } @Test @@ -281,7 +283,7 @@ public Integer get() throws Exception { assertThat(clusterClient.getPartitions().getPartitionByNodeId(node1.getNodeId()).getSlots()).hasSize(12000); assertThat(clusterClient.getPartitions().getPartitionByNodeId(node2.getNodeId()).getSlots()).hasSize(4384); - clusterConnection.close(); + clusterConnection.getStatefulConnection().close(); } private void runReconnectTest( @@ -305,7 +307,9 @@ private void runReconnectTest( return !clusterClient.getPartitions().isEmpty(); }).waitOrTimeout(); - closeable.close(); - clusterConnection.close(); + if (closeable instanceof RedisAdvancedClusterCommands) { + ((RedisAdvancedClusterCommands) closeable).getStatefulConnection().close(); + } + clusterConnection.getStatefulConnection().close(); } } diff --git a/src/test/java/com/lambdaworks/redis/commands/rx/BitRxCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/rx/BitRxCommandTest.java index 97c3e35199..4bcf9c148d 100644 --- a/src/test/java/com/lambdaworks/redis/commands/rx/BitRxCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/rx/BitRxCommandTest.java @@ -2,6 +2,7 @@ import com.lambdaworks.redis.api.sync.RedisCommands; import com.lambdaworks.redis.commands.BitCommandTest; +import com.lambdaworks.util.RxSyncInvocationHandler; /** * @author Mark Paluch diff --git a/src/test/java/com/lambdaworks/redis/commands/rx/CustomRxCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/rx/CustomRxCommandTest.java index 45e08589bc..5ccbe933c9 100644 --- a/src/test/java/com/lambdaworks/redis/commands/rx/CustomRxCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/rx/CustomRxCommandTest.java @@ -1,5 +1,6 @@ package com.lambdaworks.redis.commands.rx; +import com.lambdaworks.util.RxSyncInvocationHandler; import org.junit.Test; import com.lambdaworks.redis.api.rx.RedisReactiveCommands; diff --git a/src/test/java/com/lambdaworks/redis/commands/rx/GeoRxCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/rx/GeoRxCommandTest.java index d90ec8abdf..685ade80c4 100644 --- a/src/test/java/com/lambdaworks/redis/commands/rx/GeoRxCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/rx/GeoRxCommandTest.java @@ -2,6 +2,7 @@ import com.lambdaworks.redis.api.sync.RedisCommands; import com.lambdaworks.redis.commands.GeoCommandTest; +import com.lambdaworks.util.RxSyncInvocationHandler; public class GeoRxCommandTest extends GeoCommandTest { diff --git a/src/test/java/com/lambdaworks/redis/commands/rx/HLLRxCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/rx/HLLRxCommandTest.java index 5ed77472e4..2b26e3fea9 100644 --- a/src/test/java/com/lambdaworks/redis/commands/rx/HLLRxCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/rx/HLLRxCommandTest.java @@ -2,6 +2,7 @@ import com.lambdaworks.redis.api.sync.RedisCommands; import com.lambdaworks.redis.commands.HLLCommandTest; +import com.lambdaworks.util.RxSyncInvocationHandler; public class HLLRxCommandTest extends HLLCommandTest { diff --git a/src/test/java/com/lambdaworks/redis/commands/rx/HashRxCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/rx/HashRxCommandTest.java index 4b93ca8a1f..a6786af741 100644 --- a/src/test/java/com/lambdaworks/redis/commands/rx/HashRxCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/rx/HashRxCommandTest.java @@ -2,6 +2,7 @@ import com.lambdaworks.redis.api.sync.RedisCommands; import com.lambdaworks.redis.commands.HashCommandTest; +import com.lambdaworks.util.RxSyncInvocationHandler; public class HashRxCommandTest extends HashCommandTest { diff --git a/src/test/java/com/lambdaworks/redis/commands/rx/KeyRxCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/rx/KeyRxCommandTest.java index 679a259b3b..92c51ed297 100644 --- a/src/test/java/com/lambdaworks/redis/commands/rx/KeyRxCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/rx/KeyRxCommandTest.java @@ -2,6 +2,7 @@ import com.lambdaworks.redis.api.sync.RedisCommands; import com.lambdaworks.redis.commands.KeyCommandTest; +import com.lambdaworks.util.RxSyncInvocationHandler; public class KeyRxCommandTest extends KeyCommandTest { @Override diff --git a/src/test/java/com/lambdaworks/redis/commands/rx/ListRxCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/rx/ListRxCommandTest.java index 034ae0f54f..7c25c7ce56 100644 --- a/src/test/java/com/lambdaworks/redis/commands/rx/ListRxCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/rx/ListRxCommandTest.java @@ -2,6 +2,7 @@ import com.lambdaworks.redis.api.sync.RedisCommands; import com.lambdaworks.redis.commands.ListCommandTest; +import com.lambdaworks.util.RxSyncInvocationHandler; public class ListRxCommandTest extends ListCommandTest { @Override diff --git a/src/test/java/com/lambdaworks/redis/commands/rx/NumericRxCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/rx/NumericRxCommandTest.java index 04bf948fc8..e93c0496c9 100644 --- a/src/test/java/com/lambdaworks/redis/commands/rx/NumericRxCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/rx/NumericRxCommandTest.java @@ -2,6 +2,7 @@ import com.lambdaworks.redis.api.sync.RedisCommands; import com.lambdaworks.redis.commands.NumericCommandTest; +import com.lambdaworks.util.RxSyncInvocationHandler; public class NumericRxCommandTest extends NumericCommandTest { @Override diff --git a/src/test/java/com/lambdaworks/redis/commands/rx/ScriptingRxCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/rx/ScriptingRxCommandTest.java index 0674bc083e..33f4c9225e 100644 --- a/src/test/java/com/lambdaworks/redis/commands/rx/ScriptingRxCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/rx/ScriptingRxCommandTest.java @@ -2,6 +2,7 @@ import com.lambdaworks.redis.api.sync.RedisCommands; import com.lambdaworks.redis.commands.ScriptingCommandTest; +import com.lambdaworks.util.RxSyncInvocationHandler; public class ScriptingRxCommandTest extends ScriptingCommandTest { diff --git a/src/test/java/com/lambdaworks/redis/commands/rx/ServerRxCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/rx/ServerRxCommandTest.java index c1cf9f3bf3..f90eef80ca 100644 --- a/src/test/java/com/lambdaworks/redis/commands/rx/ServerRxCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/rx/ServerRxCommandTest.java @@ -2,6 +2,7 @@ import static org.assertj.core.api.Assertions.assertThat; +import com.lambdaworks.util.RxSyncInvocationHandler; import org.junit.Before; import org.junit.Test; diff --git a/src/test/java/com/lambdaworks/redis/commands/rx/SetRxCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/rx/SetRxCommandTest.java index d69b345aa6..091520bfb1 100644 --- a/src/test/java/com/lambdaworks/redis/commands/rx/SetRxCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/rx/SetRxCommandTest.java @@ -2,6 +2,7 @@ import com.lambdaworks.redis.api.sync.RedisCommands; import com.lambdaworks.redis.commands.SetCommandTest; +import com.lambdaworks.util.RxSyncInvocationHandler; public class SetRxCommandTest extends SetCommandTest { diff --git a/src/test/java/com/lambdaworks/redis/commands/rx/SortRxCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/rx/SortRxCommandTest.java index 166522560a..37d1d05719 100644 --- a/src/test/java/com/lambdaworks/redis/commands/rx/SortRxCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/rx/SortRxCommandTest.java @@ -2,6 +2,7 @@ import com.lambdaworks.redis.api.sync.RedisCommands; import com.lambdaworks.redis.commands.SortCommandTest; +import com.lambdaworks.util.RxSyncInvocationHandler; public class SortRxCommandTest extends SortCommandTest { @Override diff --git a/src/test/java/com/lambdaworks/redis/commands/rx/SortedSetRxCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/rx/SortedSetRxCommandTest.java index 4c10f21f18..2e5a153e1d 100644 --- a/src/test/java/com/lambdaworks/redis/commands/rx/SortedSetRxCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/rx/SortedSetRxCommandTest.java @@ -2,6 +2,7 @@ import com.lambdaworks.redis.api.sync.RedisCommands; import com.lambdaworks.redis.commands.SortedSetCommandTest; +import com.lambdaworks.util.RxSyncInvocationHandler; public class SortedSetRxCommandTest extends SortedSetCommandTest { @Override diff --git a/src/test/java/com/lambdaworks/redis/commands/rx/StringRxCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/rx/StringRxCommandTest.java index f18481bd99..5157f6deff 100644 --- a/src/test/java/com/lambdaworks/redis/commands/rx/StringRxCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/rx/StringRxCommandTest.java @@ -2,6 +2,7 @@ import static org.assertj.core.api.Assertions.assertThat; +import com.lambdaworks.util.RxSyncInvocationHandler; import org.junit.Test; import com.lambdaworks.redis.api.StatefulRedisConnection; diff --git a/src/test/java/com/lambdaworks/redis/commands/rx/TransactionRxCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/rx/TransactionRxCommandTest.java index a83f006b02..24741dd299 100644 --- a/src/test/java/com/lambdaworks/redis/commands/rx/TransactionRxCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/rx/TransactionRxCommandTest.java @@ -5,6 +5,7 @@ import java.util.Iterator; import java.util.List; +import com.lambdaworks.util.RxSyncInvocationHandler; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -42,7 +43,7 @@ public void openConnection() throws Exception { @After public void closeConnection() throws Exception { - redis.close(); + redis.getStatefulConnection().close(); } @Test diff --git a/src/test/java/com/lambdaworks/redis/masterslave/StaticMasterSlaveTest.java b/src/test/java/com/lambdaworks/redis/masterslave/StaticMasterSlaveTest.java index 2a6c6399ee..31942a6faf 100644 --- a/src/test/java/com/lambdaworks/redis/masterslave/StaticMasterSlaveTest.java +++ b/src/test/java/com/lambdaworks/redis/masterslave/StaticMasterSlaveTest.java @@ -79,13 +79,13 @@ public void after() throws Exception { if (connectionToNode1 != null) { connectionToNode1.configSet("requirepass", ""); connectionToNode1.configSet("masterauth", "").get(1, TimeUnit.SECONDS); - connectionToNode1.close(); + connectionToNode1.getStatefulConnection().close(); } if (connectionToNode2 != null) { connectionToNode2.configSet("requirepass", ""); connectionToNode2.configSet("masterauth", "").get(1, TimeUnit.SECONDS); - connectionToNode2.close(); + connectionToNode2.getStatefulConnection().close(); } if (connection != null) { diff --git a/src/test/java/com/lambdaworks/redis/pubsub/PubSubCommandTest.java b/src/test/java/com/lambdaworks/redis/pubsub/PubSubCommandTest.java index 471d0463b7..ae6e4fde2e 100644 --- a/src/test/java/com/lambdaworks/redis/pubsub/PubSubCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/pubsub/PubSubCommandTest.java @@ -48,7 +48,7 @@ public void openPubSubConnection() throws Exception { @After public void closePubSubConnection() throws Exception { - pubsub.close(); + pubsub.getStatefulConnection().close(); } @Test @@ -111,7 +111,7 @@ public void pipelinedMessage() throws Exception { assertThat(channels.take()).isEqualTo(channel); assertThat(messages.take()).isEqualTo(message); - connection.close(); + connection.getStatefulConnection().close(); } @Test(timeout = 2000) diff --git a/src/test/java/com/lambdaworks/redis/pubsub/PubSubRxTest.java b/src/test/java/com/lambdaworks/redis/pubsub/PubSubRxTest.java index b91e62b11e..636aa3c57b 100644 --- a/src/test/java/com/lambdaworks/redis/pubsub/PubSubRxTest.java +++ b/src/test/java/com/lambdaworks/redis/pubsub/PubSubRxTest.java @@ -66,8 +66,8 @@ public void openPubSubConnection() throws Exception { @After public void closePubSubConnection() throws Exception { - pubsub.close(); - pubsub2.close(); + pubsub.getStatefulConnection().close(); + pubsub2.getStatefulConnection().close(); } @Test diff --git a/src/test/java/com/lambdaworks/redis/sentinel/SentinelRule.java b/src/test/java/com/lambdaworks/redis/sentinel/SentinelRule.java index ebc42698da..a9c9c4486a 100644 --- a/src/test/java/com/lambdaworks/redis/sentinel/SentinelRule.java +++ b/src/test/java/com/lambdaworks/redis/sentinel/SentinelRule.java @@ -230,7 +230,7 @@ public boolean hasMaster(int... redisPorts) { } } finally { for (RedisCommands commands : connections.values()) { - commands.close(); + commands.getStatefulConnection().close(); } } @@ -312,7 +312,7 @@ public int setupMasterSlave(int... redisPorts) { } } finally { for (RedisCommands commands : connections.values()) { - commands.close(); + commands.getStatefulConnection().close(); } } diff --git a/src/test/java/com/lambdaworks/redis/sentinel/rx/SentinelRxCommandTest.java b/src/test/java/com/lambdaworks/redis/sentinel/rx/SentinelRxCommandTest.java index cf6e5ed6a5..6d0e139289 100644 --- a/src/test/java/com/lambdaworks/redis/sentinel/rx/SentinelRxCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/sentinel/rx/SentinelRxCommandTest.java @@ -4,7 +4,7 @@ import static org.assertj.core.api.Assertions.assertThat; import com.lambdaworks.redis.TestSettings; -import com.lambdaworks.redis.commands.rx.RxSyncInvocationHandler; +import com.lambdaworks.util.RxSyncInvocationHandler; import com.lambdaworks.redis.sentinel.SentinelCommandTest; import com.lambdaworks.redis.sentinel.api.async.RedisSentinelAsyncCommands; import com.lambdaworks.redis.sentinel.api.rx.RedisSentinelReactiveCommands; diff --git a/src/test/java/com/lambdaworks/redis/support/InjectedClient.java b/src/test/java/com/lambdaworks/redis/support/InjectedClient.java index b1897c7ec3..0a81ac8d1e 100644 --- a/src/test/java/com/lambdaworks/redis/support/InjectedClient.java +++ b/src/test/java/com/lambdaworks/redis/support/InjectedClient.java @@ -42,7 +42,7 @@ public void pingRedis() { @PreDestroy public void preDestroy() { if (connection != null) { - connection.close(); + connection.getStatefulConnection().close(); } } } diff --git a/src/test/java/com/lambdaworks/util/ConnectionDecoratingInvocationHandler.java b/src/test/java/com/lambdaworks/util/ConnectionDecoratingInvocationHandler.java new file mode 100644 index 0000000000..378bdc3b30 --- /dev/null +++ b/src/test/java/com/lambdaworks/util/ConnectionDecoratingInvocationHandler.java @@ -0,0 +1,46 @@ +package com.lambdaworks.util; + +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; + +import com.lambdaworks.redis.api.StatefulConnection; +import com.lambdaworks.redis.api.StatefulRedisConnection; +import com.lambdaworks.redis.cluster.api.StatefulRedisClusterConnection; +import com.lambdaworks.redis.internal.AbstractInvocationHandler; + +/** + * @author Mark Paluch + */ +public class ConnectionDecoratingInvocationHandler extends AbstractInvocationHandler { + + private final Object target; + + public ConnectionDecoratingInvocationHandler(Object target) { + this.target = target; + } + + @Override + protected Object handleInvocation(Object proxy, Method method, Object[] args) throws Throwable { + + Method targetMethod = target.getClass().getMethod(method.getName(), method.getParameterTypes()); + Method proxyMethod = proxy.getClass().getMethod(method.getName(), method.getParameterTypes()); + + Object result = targetMethod.invoke(target, args); + + if (result instanceof StatefulConnection) { + + Class[] interfaces; + if (result instanceof StatefulRedisClusterConnection + && proxyMethod.getReturnType().isAssignableFrom(StatefulRedisClusterConnection.class)) { + interfaces = new Class[] { StatefulConnection.class, StatefulRedisClusterConnection.class }; + } else { + interfaces = new Class[] { StatefulConnection.class, StatefulRedisConnection.class }; + } + + return Proxy.newProxyInstance(getClass().getClassLoader(), interfaces, + new ConnectionDecoratingInvocationHandler(result)); + } + + return result; + } +} diff --git a/src/test/java/com/lambdaworks/util/RoutingInvocationHandler.java b/src/test/java/com/lambdaworks/util/RoutingInvocationHandler.java new file mode 100644 index 0000000000..df73250a24 --- /dev/null +++ b/src/test/java/com/lambdaworks/util/RoutingInvocationHandler.java @@ -0,0 +1,27 @@ +package com.lambdaworks.util; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; + +/** + * @author Mark Paluch + */ +public class RoutingInvocationHandler extends ConnectionDecoratingInvocationHandler { + + private final InvocationHandler delegate; + + public RoutingInvocationHandler(Object target, InvocationHandler delegate) { + super(target); + this.delegate = delegate; + } + + @Override + protected Object handleInvocation(Object proxy, Method method, Object[] args) throws Throwable { + + if (method.getName().equals("getStatefulConnection")) { + return super.handleInvocation(proxy, method, args); + } + + return delegate.invoke(proxy, method, args); + } +} diff --git a/src/test/java/com/lambdaworks/redis/commands/rx/RxSyncInvocationHandler.java b/src/test/java/com/lambdaworks/util/RxSyncInvocationHandler.java similarity index 93% rename from src/test/java/com/lambdaworks/redis/commands/rx/RxSyncInvocationHandler.java rename to src/test/java/com/lambdaworks/util/RxSyncInvocationHandler.java index 1a7730d729..46bd2f18bd 100644 --- a/src/test/java/com/lambdaworks/redis/commands/rx/RxSyncInvocationHandler.java +++ b/src/test/java/com/lambdaworks/util/RxSyncInvocationHandler.java @@ -1,4 +1,4 @@ -package com.lambdaworks.redis.commands.rx; +package com.lambdaworks.util; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -28,12 +28,13 @@ * @param * @param */ -public class RxSyncInvocationHandler extends AbstractInvocationHandler { +public class RxSyncInvocationHandler extends ConnectionDecoratingInvocationHandler { private final StatefulConnection connection; private final Object rxApi; public RxSyncInvocationHandler(StatefulConnection connection, Object rxApi) { + super(rxApi); this.connection = connection; this.rxApi = rxApi; } @@ -44,14 +45,16 @@ protected Object handleInvocation(Object proxy, Method method, Object[] args) th try { - Method targetMethod = rxApi.getClass().getMethod(method.getName(), method.getParameterTypes()); - - Object result = targetMethod.invoke(rxApi, args); + Object result = super.handleInvocation(proxy, method, args); if (result == null) { return result; } + if (result instanceof StatefulConnection) { + return result; + } + if (result instanceof Observable) { Observable observable = (Observable) result; From 849cf20bbb6201a697f0da08216dd2985c276dad Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Tue, 26 Jul 2016 20:34:33 +0200 Subject: [PATCH 008/808] Provide Value types #350 Value, KeyValue and ScoredValue now share a common hierarchy that allows transformation and mapping of values. Value types can have either a value or the value can be empty. Value.just("a value") Value.fromNullable(nullableVariable) Value.from(optional) KeyValue.just(key, "value") KeyValue.fromNullable(key, nullableVariable) KeyValue.from(key, optional) --- .../java/com/lambdaworks/redis/KeyValue.java | 153 +++++++++-- .../redis/RedisCommandBuilder.java | 4 +- .../com/lambdaworks/redis/ScoredValue.java | 155 ++++++++++- .../java/com/lambdaworks/redis/Value.java | 247 ++++++++++++++++++ .../redis/output/KeyValueOutput.java | 2 +- .../redis/output/ScoredValueListOutput.java | 2 +- .../redis/output/ScoredValueScanOutput.java | 2 +- .../ScoredValueScanStreamingOutput.java | 2 +- .../output/ScoredValueStreamingOutput.java | 2 +- .../com/lambdaworks/redis/AbstractTest.java | 4 +- .../com/lambdaworks/redis/KeyValueTest.java | 98 ++++++- .../redis/ListStreamingAdapter.java | 4 +- .../lambdaworks/redis/ScoredValueTest.java | 101 ++++++- .../java/com/lambdaworks/redis/ValueTest.java | 203 ++++++++++++++ .../redis/commands/GeoCommandTest.java | 6 +- .../redis/commands/SortedSetCommandTest.java | 10 +- .../output/ScoredValueListOutputTest.java | 2 +- 17 files changed, 921 insertions(+), 76 deletions(-) create mode 100644 src/main/java/com/lambdaworks/redis/Value.java create mode 100644 src/test/java/com/lambdaworks/redis/ValueTest.java diff --git a/src/main/java/com/lambdaworks/redis/KeyValue.java b/src/main/java/com/lambdaworks/redis/KeyValue.java index 5a1e3f3492..0146734468 100644 --- a/src/main/java/com/lambdaworks/redis/KeyValue.java +++ b/src/main/java/com/lambdaworks/redis/KeyValue.java @@ -1,45 +1,162 @@ -// Copyright (C) 2011 - Will Glozer. All rights reserved. - package com.lambdaworks.redis; +import java.util.Optional; +import java.util.function.Function; + +import com.lambdaworks.redis.internal.LettuceAssert; + /** - * A key-value pair. - * + * A key-value container extension to {@link Value}. A {@link KeyValue} requires always a non-null key on construction. + * * @param Key type. * @param Value type. * @author Will Glozer + * @author Mark Paluch */ -public class KeyValue { +public class KeyValue extends Value { - public final K key; - public final V value; + private final K key; /** - * - * @param key the key - * @param value the value + * Serializable constructor. */ - public KeyValue(K key, V value) { + protected KeyValue() { + super(null); + this.key = null; + } + + private KeyValue(K key, V value) { + + super(value); + + LettuceAssert.notNull(key, "Key must not be null"); this.key = key; - this.value = value; + } + + /** + * Creates a {@link KeyValue} from a {@code key} and an {@link Optional}. The resulting value contains the value from the + * {@link Optional} if a value is present. Value is empty if the {@link Optional} is empty. + * + * @param key the key, must not be {@literal null}. + * @param optional the optional. May be empty but never {@literal null}. + * @param + * @param + * @param + * @return the {@link KeyValue} + */ + public static KeyValue from(K key, Optional optional) { + + LettuceAssert.notNull(optional, "Optional must not be null"); + + if (optional.isPresent()) { + return new KeyValue(key, optional.get()); + } + + return empty(key); + } + + /** + * Creates a {@link KeyValue} from a {@code key} and{@code value}. The resulting value contains the value if the + * {@code value} is not null. + * + * @param key the key, must not be {@literal null}. + * @param value the value. May be {@literal null}. + * @param + * @param + * @param + * @return the {@link KeyValue} + */ + public static KeyValue fromNullable(K key, T value) { + + if (value == null) { + return empty(key); + } + + return new KeyValue(key, value); + } + + /** + * Returns an empty {@code KeyValue} instance with the {@code key} set. No value is present for this instance. + * + * @param key the key, must not be {@literal null}. + * @param + * @param + * @return the {@link KeyValue} + */ + public static KeyValue empty(K key) { + return new KeyValue(key, null); + } + + /** + * Creates a {@link KeyValue} from a {@code key} and {@code value}. The resulting value contains the value. + * + * @param key the key. Must not be {@literal null}. + * @param value the value. Must not be {@literal null}. + * @param + * @param + * @param + * @return the {@link KeyValue} + */ + public static KeyValue just(K key, T value) { + + LettuceAssert.notNull(value, "Value must not be null"); + + return new KeyValue(key, value); } @Override public boolean equals(Object o) { - if (o == null || getClass() != o.getClass()) { + + if (this == o) + return true; + if (!(o instanceof KeyValue)) return false; - } - KeyValue that = (KeyValue) o; - return key.equals(that.key) && value.equals(that.value); + + KeyValue keyValue = (KeyValue) o; + + if (!key.equals(keyValue.key)) + return false; + return getValue() != null ? getValue().equals(keyValue.getValue()) : keyValue.getValue() == null; + } @Override public int hashCode() { - return 31 * key.hashCode() + value.hashCode(); + int result = key.hashCode(); + result = 31 * result + (hasValue() ? getValue().hashCode() : 0); + return result; } @Override public String toString() { - return String.format("(%s, %s)", key, value); + return hasValue() ? String.format("KeyValue[%s, %s]", key, getValue()) : String.format("KeyValue[%s].empty", key); + } + + /** + * + * @return the key + */ + public K getKey() { + return key; + } + + /** + * Returns a {@link KeyValue} consisting of the results of applying the given function to the value of this element. Mapping + * is performed only if a {@link #hasValue() value is present}. + * + * @param The element type of the new {@link KeyValue} + * @param mapper a stateless function to apply to each element + * @return the new {@link KeyValue} + */ + @SuppressWarnings("unchecked") + KeyValue map(Function mapper) { + + LettuceAssert.notNull(mapper, "Mapper function must not be null"); + + if (hasValue()) { + return new KeyValue<>(getKey(), mapper.apply(getValue())); + } + + return (KeyValue) this; } } diff --git a/src/main/java/com/lambdaworks/redis/RedisCommandBuilder.java b/src/main/java/com/lambdaworks/redis/RedisCommandBuilder.java index fa4317ff40..47d6d57573 100644 --- a/src/main/java/com/lambdaworks/redis/RedisCommandBuilder.java +++ b/src/main/java/com/lambdaworks/redis/RedisCommandBuilder.java @@ -1402,8 +1402,8 @@ public Command zadd(K key, ZAddArgs zAddArgs, Object... scoresAndVal for (Object o : scoresAndValues) { ScoredValue scoredValue = (ScoredValue) o; - args.add(scoredValue.score); - args.addValue(scoredValue.value); + args.add(scoredValue.getScore()); + args.addValue(scoredValue.getValue()); } } else { diff --git a/src/main/java/com/lambdaworks/redis/ScoredValue.java b/src/main/java/com/lambdaworks/redis/ScoredValue.java index dd6e9679e9..54b902aaf1 100644 --- a/src/main/java/com/lambdaworks/redis/ScoredValue.java +++ b/src/main/java/com/lambdaworks/redis/ScoredValue.java @@ -1,29 +1,118 @@ -// Copyright (C) 2011 - Will Glozer. All rights reserved. - package com.lambdaworks.redis; +import java.util.Optional; +import java.util.function.Function; + +import com.lambdaworks.redis.internal.LettuceAssert; + /** - * A value and its associated score from a ZSET. + * A scored-value extension to {@link Value}. * * @param Value type. * @author Will Glozer + * @author Mark Paluch */ -public class ScoredValue { - public final double score; - public final V value; +public class ScoredValue extends Value { - public ScoredValue(double score, V value) { + private final static ScoredValue EMPTY = new ScoredValue<>(0, null); + + private final double score; + + /** + * Serializable constructor. + */ + protected ScoredValue() { + super(null); + this.score = 0; + } + + private ScoredValue(double score, V value) { + super(value); this.score = score; - this.value = value; + } + + /** + * Creates a {@link ScoredValue} from a {@code key} and an {@link Optional}. The resulting value contains the value from the + * {@link Optional} if a value is present. Value is empty if the {@link Optional} is empty. + * + * @param score the score + * @param optional the optional. May be empty but never {@literal null}. + * @param + * @param + * @return the {@link ScoredValue} + */ + public static ScoredValue from(double score, Optional optional) { + + LettuceAssert.notNull(optional, "Optional must not be null"); + + if (optional.isPresent()) { + return new ScoredValue(score, optional.get()); + } + + return fromNullable(score, null); + } + + /** + * Creates a {@link ScoredValue} from a {@code score} and {@code value}. The resulting value contains the value if the + * {@code value} is not null. + * + * @param score the score + * @param value the value. May be {@literal null}. + * @param + * @param + * @return the {@link ScoredValue} + */ + public static ScoredValue fromNullable(double score, T value) { + + if (value == null) { + return new ScoredValue(score, null); + } + + return new ScoredValue(score, value); + } + + /** + * Returns an empty {@code ScoredValue} instance. No value is present for this instance. + * + * @param + * @return the {@link ScoredValue} + */ + public static ScoredValue empty() { + return (ScoredValue) EMPTY; + } + + /** + * Creates a {@link ScoredValue} from a {@code key} and {@code value}. The resulting value contains the value. + * + * @param score the score + * @param value the value. Must not be {@literal null}. + * @param + * @param + * @return the {@link ScoredValue} + */ + public static ScoredValue just(double score, T value) { + + LettuceAssert.notNull(value, "Value must not be null"); + + return new ScoredValue(score, value); + } + + public double getScore() { + return score; } @Override public boolean equals(Object o) { - if (o == null || getClass() != o.getClass()) { + if (this == o) + return true; + if (!(o instanceof ScoredValue)) return false; - } + if (!super.equals(o)) + return false; + ScoredValue that = (ScoredValue) o; - return Double.compare(that.score, score) == 0 && value.equals(that.value); + + return Double.compare(that.score, score) == 0; } @Override @@ -31,12 +120,52 @@ public int hashCode() { long temp = Double.doubleToLongBits(score); int result = (int) (temp ^ (temp >>> 32)); - result = 31 * result + (value != null ? value.hashCode() : 0); + result = 31 * result + (hasValue() ? getValue().hashCode() : 0); return result; } @Override public String toString() { - return String.format("(%f, %s)", score, value); + return hasValue() ? String.format("ScoredValue[%f, %s]", score, getValue()) + : String.format("ScoredValue[%f].empty", score); + } + + /** + * Returns a {@link ScoredValue} consisting of the results of applying the given function to the value of this element. + * Mapping is performed only if a {@link #hasValue() value is present}. + * + * @param The element type of the new stream + * @param mapper a stateless function to apply to each element + * @return the new {@link ScoredValue} + */ + @SuppressWarnings("unchecked") + ScoredValue map(Function mapper) { + + LettuceAssert.notNull(mapper, "Mapper function must not be null"); + + if (hasValue()) { + return new ScoredValue<>(score, mapper.apply(getValue())); + } + + return (ScoredValue) this; + } + + /** + * Returns a {@link ScoredValue} consisting of the results of applying the given function to the score of this element. + * Mapping is performed only if a {@link #hasValue() value is present}. + * + * @param mapper a stateless function to apply to each element + * @return the new {@link ScoredValue} + */ + @SuppressWarnings("unchecked") + ScoredValue mapScore(Function mapper) { + + LettuceAssert.notNull(mapper, "Mapper function must not be null"); + + if (hasValue()) { + return new ScoredValue(mapper.apply(score).doubleValue(), getValue()); + } + + return this; } } diff --git a/src/main/java/com/lambdaworks/redis/Value.java b/src/main/java/com/lambdaworks/redis/Value.java new file mode 100644 index 0000000000..6f2af1204d --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/Value.java @@ -0,0 +1,247 @@ +package com.lambdaworks.redis; + +import java.io.Serializable; +import java.util.NoSuchElementException; +import java.util.Optional; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.stream.Stream; + +import com.lambdaworks.redis.internal.LettuceAssert; + +/** + * A value container object which may or may not contain a non-null value. If a value is present, {@code isPresent()} will + * return {@code true} and {@code get()} will return the value. + * + *

+ * Additional methods that depend on the presence or absence of a contained value are provided, such as + * {@link #getValueOrElse(java.lang.Object) getValueOrElse()} (return a default value if value not present). + * + * @param Value type. + * @author Mark Paluch + */ +public class Value implements Serializable { + + private final static Value EMPTY = new Value<>(null); + + private final V value; + + /** + * {@link Serializable} constructor. + */ + protected Value() { + this.value = null; + } + + /** + * + * @param value the value, may be {@literal null}. + */ + protected Value(V value) { + this.value = value; + } + + /** + * Creates a {@link Value} from an {@link Optional}. The resulting value contains the value from the {@link Optional} if a + * value is present. Value is empty if the {@link Optional} is empty. + * + * @param optional the optional. May be empty but never {@literal null}. + * @param + * @param + * @return the {@link Value} + */ + public static Value from(Optional optional) { + + LettuceAssert.notNull(optional, "Optional must not be null"); + + if (optional.isPresent()) { + return new Value(optional.get()); + } + + return (Value) EMPTY; + } + + /** + * Creates a {@link Value} from a {@code value}. The resulting value contains the value if the {@code value} is not null. + * + * @param value the value. May be {@literal null}. + * @param + * @param + * @return the {@link Value} + */ + public static Value fromNullable(T value) { + + if (value == null) { + return empty(); + } + + return new Value(value); + } + + /** + * Returns an empty {@code Value} instance. No value is present for this instance. + * + * @param + * @return the {@link Value} + */ + public static Value empty() { + return (Value) EMPTY; + } + + /** + * Creates a {@link Value} from a {@code value}. The resulting value contains the value. + * + * @param value the value. Must not be {@literal null}. + * @param + * @param + * @return the {@link Value} + */ + public static Value just(T value) { + + LettuceAssert.notNull(value, "Value must not be null"); + + return new Value(value); + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (!(o instanceof Value)) + return false; + + Value value1 = (Value) o; + + return value != null ? value.equals(value1.value) : value1.value == null; + + } + + @Override + public int hashCode() { + return value != null ? value.hashCode() : 0; + } + + @Override + public String toString() { + return hasValue() ? String.format("Value[%s]", value) : "Value.empty"; + } + + /** + * If a value is present in this {@code Value}, returns the value, otherwise throws {@code NoSuchElementException}. + * + * @return the non-null value held by this {@code Optional} + * @throws NoSuchElementException if there is no value present + * + * @see Value#hasValue() + */ + public V getValue() { + + if (!hasValue()) { + throw new NoSuchElementException(); + } + + return value; + } + + /** + * Return {@code true} if there is a value present, otherwise {@code false}. + * + * @return {@code true} if there is a value present, otherwise {@code false} + */ + public boolean hasValue() { + return value != null; + } + + /** + * Return the value if present, otherwise invoke {@code other} and return the result of that invocation. + * + * @param otherSupplier a {@code Supplier} whose result is returned if no value is present. Must not be {@literal null}. + * @return the value if present otherwise the result of {@code other.get()} + * @throws NullPointerException if value is not present and {@code other} is null + */ + public V getValueOrElseGet(Supplier otherSupplier) { + + LettuceAssert.notNull(otherSupplier, "Supplier must not be null"); + + if (hasValue()) { + return value; + } + return otherSupplier.get(); + } + + /** + * Return the value if present, otherwise return {@code other}. + * + * @param other the value to be returned if there is no value present, may be null + * @return the value, if present, otherwise {@code other} + */ + public V getValueOrElse(V other) { + + if (hasValue()) { + return this.value; + } + + return other; + } + + /** + * Return the contained value, if present, otherwise throw an exception to be created by the provided supplier. + * + * @param Type of the exception to be thrown + * @param exceptionSupplier The supplier which will return the exception to be thrown, must not be {@literal null}. + * @return the present value + * @throws X if there is no value present + */ + public V getValueOrElseThrow(Supplier exceptionSupplier) throws X { + + LettuceAssert.notNull(exceptionSupplier, "Supplier function must not be null"); + + if (hasValue()) { + return value; + } + + throw exceptionSupplier.get(); + } + + /** + * Returns a {@link Value} consisting of the results of applying the given function to the value of this element. Mapping is + * performed only if a {@link #hasValue() value is present}. + * + * @param The element type of the new value + * @param mapper a stateless function to apply to each element + * @return the new {@link Value} + */ + @SuppressWarnings("unchecked") + Value map(Function mapper) { + LettuceAssert.notNull(mapper, "Mapper function must not be null"); + + if (hasValue()) { + return new Value(mapper.apply(getValue())); + } + + return (Value) this; + } + + /** + * Returns an {@link Optional} wrapper for the value. + * + * @return {@link Optional} wrapper for the value. + */ + public Optional optional() { + return Optional.ofNullable(value); + } + + /** + * Returns a {@link Stream} wrapper for the value. The resulting stream contains either the value if a this value + * {@link #hasValue() has a value} or it is empty if the value is empty. + * + * @return {@link Stream} wrapper for the value. + */ + public Stream stream() { + + if (hasValue()) { + return Stream.of(value); + } + return Stream.empty(); + } +} diff --git a/src/main/java/com/lambdaworks/redis/output/KeyValueOutput.java b/src/main/java/com/lambdaworks/redis/output/KeyValueOutput.java index 127ae29d98..b3519b9c48 100644 --- a/src/main/java/com/lambdaworks/redis/output/KeyValueOutput.java +++ b/src/main/java/com/lambdaworks/redis/output/KeyValueOutput.java @@ -29,7 +29,7 @@ public void set(ByteBuffer bytes) { key = codec.decodeKey(bytes); } else { V value = codec.decodeValue(bytes); - output = new KeyValue(key, value); + output = KeyValue.fromNullable(key, value); } } } diff --git a/src/main/java/com/lambdaworks/redis/output/ScoredValueListOutput.java b/src/main/java/com/lambdaworks/redis/output/ScoredValueListOutput.java index c79f2e72cd..26ee186a43 100644 --- a/src/main/java/com/lambdaworks/redis/output/ScoredValueListOutput.java +++ b/src/main/java/com/lambdaworks/redis/output/ScoredValueListOutput.java @@ -36,7 +36,7 @@ public void set(ByteBuffer bytes) { } double score = Double.parseDouble(decodeAscii(bytes)); - subscriber.onNext(new ScoredValue<>(score, value)); + subscriber.onNext(ScoredValue.fromNullable(score, value)); value = null; } diff --git a/src/main/java/com/lambdaworks/redis/output/ScoredValueScanOutput.java b/src/main/java/com/lambdaworks/redis/output/ScoredValueScanOutput.java index bc9087e2ef..bb59960891 100644 --- a/src/main/java/com/lambdaworks/redis/output/ScoredValueScanOutput.java +++ b/src/main/java/com/lambdaworks/redis/output/ScoredValueScanOutput.java @@ -30,7 +30,7 @@ protected void setOutput(ByteBuffer bytes) { } double score = Double.parseDouble(decodeAscii(bytes)); - output.getValues().add(new ScoredValue(score, value)); + output.getValues().add(ScoredValue.fromNullable(score, value)); value = null; } diff --git a/src/main/java/com/lambdaworks/redis/output/ScoredValueScanStreamingOutput.java b/src/main/java/com/lambdaworks/redis/output/ScoredValueScanStreamingOutput.java index 831159abdf..571284884a 100644 --- a/src/main/java/com/lambdaworks/redis/output/ScoredValueScanStreamingOutput.java +++ b/src/main/java/com/lambdaworks/redis/output/ScoredValueScanStreamingOutput.java @@ -31,7 +31,7 @@ protected void setOutput(ByteBuffer bytes) { } double score = Double.parseDouble(decodeAscii(bytes)); - channel.onValue(new ScoredValue(score, value)); + channel.onValue(ScoredValue.fromNullable(score, value)); value = null; output.setCount(output.getCount() + 1); } diff --git a/src/main/java/com/lambdaworks/redis/output/ScoredValueStreamingOutput.java b/src/main/java/com/lambdaworks/redis/output/ScoredValueStreamingOutput.java index 8c60f3e0c1..90ac7cca3f 100644 --- a/src/main/java/com/lambdaworks/redis/output/ScoredValueStreamingOutput.java +++ b/src/main/java/com/lambdaworks/redis/output/ScoredValueStreamingOutput.java @@ -30,7 +30,7 @@ public void set(ByteBuffer bytes) { } double score = Double.parseDouble(decodeAscii(bytes)); - channel.onValue(new ScoredValue(score, value)); + channel.onValue(ScoredValue.fromNullable(score, value)); value = null; output = output.longValue() + 1; } diff --git a/src/test/java/com/lambdaworks/redis/AbstractTest.java b/src/test/java/com/lambdaworks/redis/AbstractTest.java index d9c6c086e1..a1d693e015 100644 --- a/src/test/java/com/lambdaworks/redis/AbstractTest.java +++ b/src/test/java/com/lambdaworks/redis/AbstractTest.java @@ -40,11 +40,11 @@ public static List> svlist(ScoredValue... args) { } public static KeyValue kv(String key, String value) { - return new KeyValue<>(key, value); + return KeyValue.fromNullable(key, value); } public static ScoredValue sv(double score, String value) { - return new ScoredValue(score, value); + return ScoredValue.fromNullable(score, value); } public static Set set(String... args) { diff --git a/src/test/java/com/lambdaworks/redis/KeyValueTest.java b/src/test/java/com/lambdaworks/redis/KeyValueTest.java index 1a9a26a589..59a81ba8c2 100644 --- a/src/test/java/com/lambdaworks/redis/KeyValueTest.java +++ b/src/test/java/com/lambdaworks/redis/KeyValueTest.java @@ -1,36 +1,108 @@ -// Copyright (C) 2011 - Will Glozer. All rights reserved. package com.lambdaworks.redis; import static org.assertj.core.api.Assertions.assertThat; +import java.util.Optional; + import org.junit.Test; +/** + * @author Will Glozer + * @author Mark Paluch + */ public class KeyValueTest { - protected String key = "key"; - protected String value = "value"; + + @Test + public void shouldCreateEmptyKeyValueFromOptional() { + + KeyValue value = KeyValue.from("key", Optional. empty()); + + assertThat(value.hasValue()).isFalse(); + } + + @Test + public void shouldCreateEmptyValue() { + + KeyValue value = KeyValue.empty("key"); + + assertThat(value.hasValue()).isFalse(); + } + + @Test + public void shouldCreateNonEmptyValueFromOptional() { + + KeyValue value = KeyValue.from(1L, Optional.of("hello")); + + assertThat(value.hasValue()).isTrue(); + assertThat(value.getValue()).isEqualTo("hello"); + } + + @Test + public void shouldCreateEmptyValueFromValue() { + + KeyValue value = KeyValue.fromNullable("key", null); + + assertThat(value.hasValue()).isFalse(); + } + + @Test + public void shouldCreateNonEmptyValueFromValue() { + + KeyValue value = KeyValue.fromNullable("key", "hello"); + + assertThat(value.hasValue()).isTrue(); + assertThat(value.getValue()).isEqualTo("hello"); + } + + @Test + public void justShouldCreateValueFromValue() { + + KeyValue value = KeyValue.just("key", "hello"); + + assertThat(value.hasValue()).isTrue(); + assertThat(value.getKey()).isEqualTo("key"); + } + + @Test(expected = IllegalArgumentException.class) + public void justShouldRejectEmptyValueFromValue() { + Value.just(null); + } + + @Test + public void shouldCreateNonEmptyValue() { + + KeyValue value = KeyValue.from("key", Optional.of("hello")); + + assertThat(value.hasValue()).isTrue(); + assertThat(value.getValue()).isEqualTo("hello"); + } @Test public void equals() throws Exception { - KeyValue kv = kv(key, value); - assertThat(kv.equals(kv(key, value))).isTrue(); + KeyValue kv = kv("key", "value"); + assertThat(kv.equals(kv("key", "value"))).isTrue(); assertThat(kv.equals(null)).isFalse(); - assertThat(kv.equals(kv("a", value))).isFalse(); - assertThat(kv.equals(kv(key, "b"))).isFalse(); + assertThat(kv.equals(kv("a", "value"))).isFalse(); + assertThat(kv.equals(kv("key", "b"))).isFalse(); } @Test - public void testToString() throws Exception { - KeyValue kv = kv(key, value); - assertThat(kv.toString()).isEqualTo(String.format("(%s, %s)", kv.key, kv.value)); + public void testHashCode() throws Exception { + assertThat(kv("key", "value").hashCode() != 0).isTrue(); } @Test - public void testHashCode() throws Exception { - assertThat(kv(key, value).hashCode() != 0).isTrue(); + public void toStringShouldRenderCorrectly() { + + KeyValue value = KeyValue.from("key", Optional.of("hello")); + KeyValue empty = KeyValue.fromNullable("key", null); + + assertThat(value.toString()).isEqualTo("KeyValue[key, hello]"); + assertThat(empty.toString()).isEqualTo("KeyValue[key].empty"); } protected KeyValue kv(String key, String value) { - return new KeyValue(key, value); + return KeyValue.just(key, value); } } diff --git a/src/test/java/com/lambdaworks/redis/ListStreamingAdapter.java b/src/test/java/com/lambdaworks/redis/ListStreamingAdapter.java index 4abe4ce10f..c4be19abc9 100644 --- a/src/test/java/com/lambdaworks/redis/ListStreamingAdapter.java +++ b/src/test/java/com/lambdaworks/redis/ListStreamingAdapter.java @@ -13,7 +13,7 @@ * ValueStreamingChannels. * * @author Mark Paluch - * @param Valu-Type. + * @param Value-Type. * @since 3.0 */ public class ListStreamingAdapter implements KeyStreamingChannel, ValueStreamingChannel, @@ -37,6 +37,6 @@ public List getList() { @Override public void onValue(ScoredValue value) { - list.add(value.value); + list.add(value.getValue()); } } diff --git a/src/test/java/com/lambdaworks/redis/ScoredValueTest.java b/src/test/java/com/lambdaworks/redis/ScoredValueTest.java index 33d843f585..f711d9a354 100644 --- a/src/test/java/com/lambdaworks/redis/ScoredValueTest.java +++ b/src/test/java/com/lambdaworks/redis/ScoredValueTest.java @@ -1,31 +1,108 @@ -// Copyright (C) 2011 - Will Glozer. All rights reserved. package com.lambdaworks.redis; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.offset; + +import java.util.Optional; import org.junit.Test; +/** + * @author Will Glozer + * @author Mark Paluch + */ public class ScoredValueTest { + + @Test + public void shouldCreateEmptyScoredValueFromOptional() { + + ScoredValue value = ScoredValue.from(42, Optional. empty()); + + assertThat(value.hasValue()).isFalse(); + } + + @Test + public void shouldCreateEmptyValue() { + + ScoredValue value = ScoredValue.empty(); + + assertThat(value.hasValue()).isFalse(); + } + + @Test + public void shouldCreateNonEmptyValueFromOptional() { + + ScoredValue value = ScoredValue.from(4.2, Optional.of("hello")); + + assertThat(value.hasValue()).isTrue(); + assertThat(value.getValue()).isEqualTo("hello"); + assertThat(value.getScore()).isCloseTo(4.2, offset(0.01)); + } + + @Test + public void shouldCreateEmptyValueFromValue() { + + ScoredValue value = ScoredValue.fromNullable(42, null); + + assertThat(value.hasValue()).isFalse(); + } + + @Test + public void shouldCreateNonEmptyValueFromValue() { + + ScoredValue value = ScoredValue.fromNullable(42, "hello"); + + assertThat(value.hasValue()).isTrue(); + assertThat(value.getValue()).isEqualTo("hello"); + } + + @Test + public void justShouldCreateValueFromValue() { + + ScoredValue value = ScoredValue.just(42, "hello"); + + assertThat(value.hasValue()).isTrue(); + assertThat(value.getValue()).isEqualTo("hello"); + } + + @Test(expected = IllegalArgumentException.class) + public void justShouldRejectEmptyValueFromValue() { + Value.just(null); + } + + @Test + public void shouldCreateNonEmptyValue() { + + ScoredValue value = ScoredValue.from(12, Optional.of("hello")); + + assertThat(value.hasValue()).isTrue(); + assertThat(value.getValue()).isEqualTo("hello"); + } + @Test public void equals() throws Exception { - ScoredValue sv1 = new ScoredValue(1.0, "a"); - assertThat(sv1.equals(new ScoredValue(1.0, "a"))).isTrue(); + ScoredValue sv1 = ScoredValue.fromNullable(1.0, "a"); + assertThat(sv1.equals(ScoredValue.fromNullable(1.0, "a"))).isTrue(); assertThat(sv1.equals(null)).isFalse(); - assertThat(sv1.equals(new ScoredValue(1.1, "a"))).isFalse(); - assertThat(sv1.equals(new ScoredValue(1.0, "b"))).isFalse(); + assertThat(sv1.equals(ScoredValue.fromNullable(1.1, "a"))).isFalse(); + assertThat(sv1.equals(ScoredValue.fromNullable(1.0, "b"))).isFalse(); } @Test - public void testToString() throws Exception { - ScoredValue sv1 = new ScoredValue(1.0, "a"); - assertThat(sv1.toString()).isEqualTo(String.format("(%f, %s)", sv1.score, sv1.value)); + public void testHashCode() throws Exception { + assertThat(ScoredValue.fromNullable(1.0, "a").hashCode() != 0).isTrue(); + assertThat(ScoredValue.fromNullable(0.0, "a").hashCode() != 0).isTrue(); + assertThat(ScoredValue.fromNullable(0.0, null).hashCode() == 0).isTrue(); } @Test - public void testHashCode() throws Exception { - assertThat(new ScoredValue(1.0, "a").hashCode() != 0).isTrue(); - assertThat(new ScoredValue(0.0, "a").hashCode() != 0).isTrue(); - assertThat(new ScoredValue(0.0, null).hashCode() == 0).isTrue(); + public void toStringShouldRenderCorrectly() { + + ScoredValue value = ScoredValue.from(12.34, Optional.of("hello")); + ScoredValue empty = ScoredValue.fromNullable(34, null); + + assertThat(value.toString()).contains("ScoredValue[12").contains("340000, hello]"); + assertThat(empty.toString()).contains("ScoredValue[34").contains("000000].empty"); } } diff --git a/src/test/java/com/lambdaworks/redis/ValueTest.java b/src/test/java/com/lambdaworks/redis/ValueTest.java new file mode 100644 index 0000000000..40563b35ba --- /dev/null +++ b/src/test/java/com/lambdaworks/redis/ValueTest.java @@ -0,0 +1,203 @@ +package com.lambdaworks.redis; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.NoSuchElementException; +import java.util.Optional; + +import org.junit.Test; + +/** + * @author Mark Paluch + */ +public class ValueTest { + + @Test + public void shouldCreateEmptyValueFromOptional() { + + Value value = Value.from(Optional. empty()); + + assertThat(value.hasValue()).isFalse(); + } + + @Test + public void shouldCreateEmptyValue() { + + Value value = Value.empty(); + + assertThat(value.hasValue()).isFalse(); + } + + @Test + public void shouldCreateNonEmptyValueFromOptional() { + + Value value = Value.from(Optional.of("hello")); + + assertThat(value.hasValue()).isTrue(); + assertThat(value.getValue()).isEqualTo("hello"); + } + + @Test + public void shouldCreateEmptyValueFromValue() { + + Value value = Value.fromNullable(null); + + assertThat(value.hasValue()).isFalse(); + } + + @Test + public void shouldCreateNonEmptyValueFromValue() { + + Value value = Value.fromNullable("hello"); + + assertThat(value.hasValue()).isTrue(); + assertThat(value.getValue()).isEqualTo("hello"); + } + + @Test + public void justShouldCreateValueFromValue() { + + Value value = Value.just("hello"); + + assertThat(value.hasValue()).isTrue(); + } + + @Test(expected = IllegalArgumentException.class) + public void justShouldRejectEmptyValueFromValue() { + Value.just(null); + } + + @Test + public void shouldCreateNonEmptyValue() { + + Value value = Value.from(Optional.of("hello")); + + assertThat(value.hasValue()).isTrue(); + assertThat(value.getValue()).isEqualTo("hello"); + } + + @Test + public void optionalShouldReturnOptional() { + + Value value = Value.from(Optional.of("hello")); + + assertThat(value.optional()).hasValue("hello"); + } + + @Test + public void emptyValueOptionalShouldReturnOptional() { + + Value value = Value.from(Optional.empty()); + + assertThat(value.optional()).isEmpty(); + } + + @Test + public void getValueOrElseShouldReturnValue() { + + Value value = Value.from(Optional.of("hello")); + + assertThat(value.getValueOrElse("world")).isEqualTo("hello"); + } + + @Test + public void getValueOrElseShouldReturnOtherValue() { + + Value value = Value.from(Optional.empty()); + + assertThat(value.getValueOrElse("world")).isEqualTo("world"); + } + + @Test + public void orElseThrowShouldReturnValue() { + + Value value = Value.from(Optional.of("hello")); + + assertThat(value.getValueOrElseThrow(IllegalArgumentException::new)).isEqualTo("hello"); + } + + @Test(expected = IllegalArgumentException.class) + public void emptyValueGetValueOrElseShouldThrowException() { + + Value value = Value.from(Optional.empty()); + + value.getValueOrElseThrow(IllegalArgumentException::new); + } + + @Test + public void getValueOrElseGetShouldReturnValue() { + + Value value = Value.from(Optional.of("hello")); + + assertThat(value.getValueOrElseGet(() -> "world")).isEqualTo("hello"); + } + + @Test + public void emptyValueGetValueOrElseGetShouldReturnOtherValue() { + + Value value = Value.from(Optional.empty()); + + assertThat(value.getValueOrElseGet(() -> "world")).isEqualTo("world"); + } + + @Test + public void mapShouldMapValue() { + + Value value = Value.from(Optional.of("hello")); + + assertThat(value.map(s -> s + "-world").getValue()).isEqualTo("hello-world"); + } + + @Test + public void emptyValueMapShouldNotMapEmptyValue() { + + Value value = Value.from(Optional.empty()); + + assertThat(value.map(s -> s + "-world")).isSameAs(value); + } + + @Test(expected = NoSuchElementException.class) + public void emptyValueGetEmptyValueShouldThrowException() { + Value.from(Optional. empty()).getValue(); + } + + @Test + public void shouldBeEquals() { + + Value value = Value.from(Optional.of("hello")); + Value other = Value.fromNullable("hello"); + Value different = Value.fromNullable("different"); + + assertThat(value).isEqualTo(other); + assertThat(value).isNotEqualTo(different); + + assertThat(value.hashCode()).isEqualTo(other.hashCode()); + assertThat(value.hashCode()).isNotEqualTo(different.hashCode()); + } + + @Test + public void toStringShouldRenderCorrectly() { + + Value value = Value.from(Optional.of("hello")); + Value empty = Value.fromNullable(null); + + assertThat(value.toString()).isEqualTo("Value[hello]"); + assertThat(empty.toString()).isEqualTo("Value.empty"); + } + + @Test + public void emptyValueStreamShouldCreateEmptyStream() { + + Value empty = Value.fromNullable(null); + + assertThat(empty.stream().count()).isEqualTo(0); + } + + @Test + public void streamShouldCreateAStream() { + + Value empty = Value.fromNullable("hello"); + + assertThat(empty.stream().count()).isEqualTo(1); + } +} \ No newline at end of file diff --git a/src/test/java/com/lambdaworks/redis/commands/GeoCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/GeoCommandTest.java index 7f90e0d2da..67a58fb959 100644 --- a/src/test/java/com/lambdaworks/redis/commands/GeoCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/GeoCommandTest.java @@ -275,7 +275,7 @@ public void georadiusStoreWithCountAndSort() throws Exception { List> results = redis.zrangeWithScores(resultKey, 0, -1); assertThat(results).hasSize(1); - assertThat(results.get(0).score).isGreaterThan(99999); + assertThat(results.get(0).getScore()).isGreaterThan(99999); } @Test @@ -305,7 +305,7 @@ public void georadiusStoreDistWithCountAndSort() throws Exception { List> dist = redis.zrangeWithScores(resultKey, 0, -1); assertThat(dist).hasSize(1); - assertThat(dist.get(0).score).isBetween(2d, 3d); + assertThat(dist.get(0).getScore()).isBetween(2d, 3d); } @Test(expected = IllegalArgumentException.class) @@ -343,7 +343,7 @@ public void georadiusbymemberStoreDistWithCountAndSort() throws Exception { List> dist = redis.zrangeWithScores(resultKey, 0, -1); assertThat(dist).hasSize(1); - assertThat(dist.get(0).score).isBetween(2d, 3d); + assertThat(dist.get(0).getScore()).isBetween(2d, 3d); } @Test diff --git a/src/test/java/com/lambdaworks/redis/commands/SortedSetCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/SortedSetCommandTest.java index 884c5b0db2..a8b872e667 100644 --- a/src/test/java/com/lambdaworks/redis/commands/SortedSetCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/SortedSetCommandTest.java @@ -33,20 +33,20 @@ public void zadd() throws Exception { @Test public void zaddScoredValue() throws Exception { - assertThat(redis.zadd(key, new ScoredValue(1.0, "a"))).isEqualTo(1); - assertThat(redis.zadd(key, new ScoredValue(1.0, "a"))).isEqualTo(0); + assertThat(redis.zadd(key, ScoredValue.fromNullable(1.0, "a"))).isEqualTo(1); + assertThat(redis.zadd(key, ScoredValue.fromNullable(1.0, "a"))).isEqualTo(0); assertThat(redis.zrange(key, 0, -1)).isEqualTo(list("a")); - assertThat(redis.zadd(key, new ScoredValue(2.0, "b"), new ScoredValue(3.0, "c"))).isEqualTo(2); + assertThat(redis.zadd(key, ScoredValue.fromNullable(2.0, "b"), ScoredValue.fromNullable(3.0, "c"))).isEqualTo(2); assertThat(redis.zrange(key, 0, -1)).isEqualTo(list("a", "b", "c")); } @Test public void zaddnx() throws Exception { assertThat(redis.zadd(key, 1.0, "a")).isEqualTo(1); - assertThat(redis.zadd(key, ZAddArgs.Builder.nx(), new ScoredValue(2.0, "a"))).isEqualTo(0); + assertThat(redis.zadd(key, ZAddArgs.Builder.nx(), ScoredValue.fromNullable(2.0, "a"))).isEqualTo(0); - assertThat(redis.zadd(key, ZAddArgs.Builder.nx(), new ScoredValue(2.0, "b"))).isEqualTo(1); + assertThat(redis.zadd(key, ZAddArgs.Builder.nx(), ScoredValue.fromNullable(2.0, "b"))).isEqualTo(1); assertThat(redis.zadd(key, ZAddArgs.Builder.nx(), new Object[] { 2.0, "b", 3.0, "c" })).isEqualTo(1); diff --git a/src/test/java/com/lambdaworks/redis/output/ScoredValueListOutputTest.java b/src/test/java/com/lambdaworks/redis/output/ScoredValueListOutputTest.java index 44050ecbed..dc0436d725 100644 --- a/src/test/java/com/lambdaworks/redis/output/ScoredValueListOutputTest.java +++ b/src/test/java/com/lambdaworks/redis/output/ScoredValueListOutputTest.java @@ -33,6 +33,6 @@ public void commandOutputCorrectlyDecoded() throws Exception { sut.set(ByteBuffer.wrap("4.567".getBytes())); sut.multi(-1); - assertThat(sut.get()).contains(new ScoredValue<>(4.567, "key")); + assertThat(sut.get()).contains(ScoredValue.fromNullable(4.567, "key")); } } \ No newline at end of file From 8a0b24fd171a81424c51a8e08e353ff1eb5d6d9c Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Tue, 26 Jul 2016 22:21:12 +0200 Subject: [PATCH 009/808] Use KeyValue in mget, hmget and KeyValueStreamingChannel in mget and hmget #350 --- .../redis/AbstractRedisAsyncCommands.java | 18 ++--- .../redis/AbstractRedisReactiveCommands.java | 24 ++++--- .../java/com/lambdaworks/redis/KeyValue.java | 8 +-- .../redis/ReactiveCommandDispatcher.java | 4 +- .../redis/RedisCommandBuilder.java | 67 +++++++++++++++++-- .../api/async/RedisHashAsyncCommands.java | 6 +- .../api/async/RedisKeyAsyncCommands.java | 1 + .../api/async/RedisStringAsyncCommands.java | 10 +-- .../api/rx/RedisHashReactiveCommands.java | 6 +- .../api/rx/RedisKeyReactiveCommands.java | 1 + .../api/rx/RedisStringReactiveCommands.java | 11 +-- .../redis/api/sync/RedisHashCommands.java | 6 +- .../redis/api/sync/RedisKeyCommands.java | 1 + .../redis/api/sync/RedisStringCommands.java | 8 ++- ...RedisAdvancedClusterAsyncCommandsImpl.java | 17 ++--- ...isAdvancedClusterReactiveCommandsImpl.java | 19 +++--- .../async/BaseNodeSelectionAsyncCommands.java | 2 +- .../async/NodeSelectionHashAsyncCommands.java | 6 +- .../async/NodeSelectionKeyAsyncCommands.java | 1 + .../NodeSelectionStringAsyncCommands.java | 10 +-- .../RedisAdvancedClusterAsyncCommands.java | 2 +- .../api/async/RedisClusterAsyncCommands.java | 3 +- .../RedisAdvancedClusterReactiveCommands.java | 2 +- .../api/rx/RedisClusterReactiveCommands.java | 3 +- .../api/sync/BaseNodeSelectionCommands.java | 2 +- .../api/sync/NodeSelectionHashCommands.java | 6 +- .../api/sync/NodeSelectionKeyCommands.java | 1 + .../api/sync/NodeSelectionStringCommands.java | 4 ++ .../sync/RedisAdvancedClusterCommands.java | 2 +- .../redis/output/KeyStreamingChannel.java | 2 +- .../redis/output/KeyValueListOutput.java | 53 +++++++++++++++ .../output/KeyValueStreamingChannel.java | 11 ++- .../redis/output/KeyValueStreamingOutput.java | 23 ++++++- .../output/ScoredValueStreamingChannel.java | 2 +- .../redis/output/StreamingChannel.java | 10 +++ .../redis/output/ValueValueListOutput.java | 49 ++++++++++++++ .../redis/api/RedisHashCommands.java | 6 +- .../redis/api/RedisKeyCommands.java | 1 + .../redis/api/RedisStringCommands.java | 11 +-- .../apigenerator/CreateReactiveApi.java | 11 ++- .../redis/ReactiveConnectionTest.java | 2 +- .../redis/ReactiveStreamingOutputTest.java | 16 +++-- .../cluster/AdvancedClusterClientTest.java | 8 +-- .../cluster/AdvancedClusterReactiveTest.java | 10 +-- .../commands/StringClusterCommandTest.java | 9 +-- .../commands/rx/KeyClusterRxCommandTest.java | 2 +- .../rx/StringClusterRxCommandTest.java | 7 +- .../redis/commands/HashCommandTest.java | 19 +++--- .../redis/commands/StringCommandTest.java | 18 ++--- .../commands/TransactionCommandTest.java | 2 +- .../commands/rx/StringRxCommandTest.java | 21 +++++- .../commands/rx/TransactionRxCommandTest.java | 10 +-- 52 files changed, 404 insertions(+), 150 deletions(-) create mode 100644 src/main/java/com/lambdaworks/redis/output/KeyValueListOutput.java create mode 100644 src/main/java/com/lambdaworks/redis/output/StreamingChannel.java create mode 100644 src/main/java/com/lambdaworks/redis/output/ValueValueListOutput.java diff --git a/src/main/java/com/lambdaworks/redis/AbstractRedisAsyncCommands.java b/src/main/java/com/lambdaworks/redis/AbstractRedisAsyncCommands.java index 07820e0551..c383cc75a8 100644 --- a/src/main/java/com/lambdaworks/redis/AbstractRedisAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/AbstractRedisAsyncCommands.java @@ -446,12 +446,12 @@ public RedisFuture hstrlen(K key, K field) { } @Override - public RedisFuture> hmget(K key, K... fields) { - return dispatch(commandBuilder.hmget(key, fields)); + public RedisFuture>> hmget(K key, K... fields) { + return dispatch(commandBuilder.hmgetKeyValue(key, fields)); } @Override - public RedisFuture hmget(ValueStreamingChannel channel, K key, K... fields) { + public RedisFuture hmget(KeyValueStreamingChannel channel, K key, K... fields) { return dispatch(commandBuilder.hmget(channel, key, fields)); } @@ -586,20 +586,20 @@ public RedisFuture migrate(String host, int port, int db, long timeout, } @Override - public RedisFuture> mget(K... keys) { - return dispatch(commandBuilder.mget(keys)); + public RedisFuture>> mget(K... keys) { + return dispatch(commandBuilder.mgetKeyValue(keys)); } - public RedisFuture> mget(Iterable keys) { - return dispatch(commandBuilder.mget(keys)); + public RedisFuture>> mget(Iterable keys) { + return dispatch(commandBuilder.mgetKeyValue(keys)); } @Override - public RedisFuture mget(ValueStreamingChannel channel, K... keys) { + public RedisFuture mget(KeyValueStreamingChannel channel, K... keys) { return dispatch(commandBuilder.mget(channel, keys)); } - public RedisFuture mget(ValueStreamingChannel channel, Iterable keys) { + public RedisFuture mget(KeyValueStreamingChannel channel, Iterable keys) { return dispatch(commandBuilder.mget(channel, keys)); } diff --git a/src/main/java/com/lambdaworks/redis/AbstractRedisReactiveCommands.java b/src/main/java/com/lambdaworks/redis/AbstractRedisReactiveCommands.java index 18a7638fba..e2094cd235 100644 --- a/src/main/java/com/lambdaworks/redis/AbstractRedisReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/AbstractRedisReactiveCommands.java @@ -449,12 +449,12 @@ public Single hstrlen(K key, K field) { } @Override - public Observable hmget(K key, K... fields) { - return createDissolvingObservable(() -> commandBuilder.hmget(key, fields)); + public Observable> hmget(K key, K... fields) { + return createDissolvingObservable(() -> commandBuilder.hmgetKeyValue(key, fields)); } @Override - public Single hmget(ValueStreamingChannel channel, K key, K... fields) { + public Single hmget(KeyValueStreamingChannel channel, K key, K... fields) { return createSingle(() -> commandBuilder.hmget(channel, key, fields)); } @@ -589,16 +589,16 @@ public Single migrate(String host, int port, int db, long timeout, Migra } @Override - public Observable mget(K... keys) { - return createDissolvingObservable(() -> commandBuilder.mget(keys)); + public Observable> mget(K... keys) { + return createDissolvingObservable(() -> commandBuilder.mgetKeyValue(keys)); } - public Observable mget(Iterable keys) { - return createDissolvingObservable(() -> commandBuilder.mget(keys)); + public Observable> mget(Iterable keys) { + return createDissolvingObservable(() -> commandBuilder.mgetKeyValue(keys)); } @Override - public Single mget(ValueStreamingChannel channel, K... keys) { + public Single mget(KeyValueStreamingChannel channel, K... keys) { return createSingle(() -> commandBuilder.mget(channel, keys)); } @@ -606,6 +606,10 @@ public Single mget(ValueStreamingChannel channel, Iterable keys) { return createSingle(() -> commandBuilder.mget(channel, keys)); } + public Single mget(KeyValueStreamingChannel channel, Iterable keys) { + return createSingle(() -> commandBuilder.mget(channel, keys)); + } + @Override public Single move(K key, int db) { return createSingle(() -> commandBuilder.move(key, db)); @@ -1031,7 +1035,7 @@ public Single zadd(K key, Object... scoresAndValues) { @Override public Single zadd(K key, ScoredValue... scoredValues) { - return createSingle(() -> commandBuilder.zadd(key, null, scoredValues)); + return createSingle(() -> commandBuilder.zadd(key, null, (Object[]) scoredValues)); } @Override @@ -1046,7 +1050,7 @@ public Single zadd(K key, ZAddArgs zAddArgs, Object... scoresAndValues) { @Override public Single zadd(K key, ZAddArgs zAddArgs, ScoredValue... scoredValues) { - return createSingle(() -> commandBuilder.zadd(key, zAddArgs, scoredValues)); + return createSingle(() -> commandBuilder.zadd(key, zAddArgs, (Object[]) scoredValues)); } @Override diff --git a/src/main/java/com/lambdaworks/redis/KeyValue.java b/src/main/java/com/lambdaworks/redis/KeyValue.java index 0146734468..2120f3d01b 100644 --- a/src/main/java/com/lambdaworks/redis/KeyValue.java +++ b/src/main/java/com/lambdaworks/redis/KeyValue.java @@ -112,12 +112,12 @@ public boolean equals(Object o) { if (!(o instanceof KeyValue)) return false; - KeyValue keyValue = (KeyValue) o; - - if (!key.equals(keyValue.key)) + if (!super.equals(o)) return false; - return getValue() != null ? getValue().equals(keyValue.getValue()) : keyValue.getValue() == null; + KeyValue keyValue = (KeyValue) o; + + return key.equals(keyValue.key); } @Override diff --git a/src/main/java/com/lambdaworks/redis/ReactiveCommandDispatcher.java b/src/main/java/com/lambdaworks/redis/ReactiveCommandDispatcher.java index 985b3df83e..d9c6fc41cc 100644 --- a/src/main/java/com/lambdaworks/redis/ReactiveCommandDispatcher.java +++ b/src/main/java/com/lambdaworks/redis/ReactiveCommandDispatcher.java @@ -156,7 +156,9 @@ public void complete() { if (dissolve && result instanceof Collection) { Collection collection = (Collection) result; for (T t : collection) { - subscriber.onNext(t); + if (t != null) { + subscriber.onNext(t); + } } } else { subscriber.onNext((T) result); diff --git a/src/main/java/com/lambdaworks/redis/RedisCommandBuilder.java b/src/main/java/com/lambdaworks/redis/RedisCommandBuilder.java index 47d6d57573..4691172768 100644 --- a/src/main/java/com/lambdaworks/redis/RedisCommandBuilder.java +++ b/src/main/java/com/lambdaworks/redis/RedisCommandBuilder.java @@ -4,13 +4,11 @@ import static com.lambdaworks.redis.protocol.CommandKeyword.*; import static com.lambdaworks.redis.protocol.CommandType.*; -import java.util.Date; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; import com.lambdaworks.redis.codec.RedisCodec; import com.lambdaworks.redis.internal.LettuceAssert; +import com.lambdaworks.redis.internal.LettuceLists; import com.lambdaworks.redis.output.*; import com.lambdaworks.redis.protocol.BaseRedisCommandBuilder; import com.lambdaworks.redis.protocol.Command; @@ -82,6 +80,18 @@ public Command> bitfield(K key, BitFieldArgs bitFieldArgs) { return createCommand(BITFIELD, (CommandOutput) new ArrayOutput(codec), args); } + public Command>> bitfieldValue(K key, BitFieldArgs bitFieldArgs) { + notNullKey(key); + LettuceAssert.notNull(bitFieldArgs, "BitFieldArgs must not be null"); + + CommandArgs args = new CommandArgs(codec); + args.addKey(key); + + bitFieldArgs.build(args); + + return createCommand(BITFIELD, (CommandOutput) new ValueValueListOutput(codec), args); + } + public Command bitpos(K key, boolean state) { notNullKey(key); @@ -571,6 +581,15 @@ public Command> hmget(K key, K... fields) { return createCommand(HMGET, new ValueListOutput(codec), args); } + public Command>> hmgetKeyValue(K key, K... fields) { + notNullKey(key); + LettuceAssert.notNull(fields, "Fields " + MUST_NOT_BE_NULL); + LettuceAssert.notEmpty(fields, "Fields " + MUST_NOT_BE_EMPTY); + + CommandArgs args = new CommandArgs(codec).addKey(key).addKeys(fields); + return createCommand(HMGET, new KeyValueListOutput(codec, Arrays.asList(fields)), args); + } + public Command hmget(ValueStreamingChannel channel, K key, K... fields) { notNullKey(key); LettuceAssert.notNull(fields, "Fields " + MUST_NOT_BE_NULL); @@ -581,6 +600,16 @@ public Command hmget(ValueStreamingChannel channel, K key, K... f return createCommand(HMGET, new ValueStreamingOutput(codec, channel), args); } + public Command hmget(KeyValueStreamingChannel channel, K key, K... fields) { + notNullKey(key); + LettuceAssert.notNull(fields, "Fields " + MUST_NOT_BE_NULL); + LettuceAssert.notEmpty(fields, "Fields " + MUST_NOT_BE_EMPTY); + notNull(channel); + + CommandArgs args = new CommandArgs(codec).addKey(key).addKeys(fields); + return createCommand(HMGET, new KeyValueStreamingOutput(codec, channel, Arrays.asList(fields)), args); + } + public Command hmset(K key, Map map) { notNullKey(key); LettuceAssert.notNull(map, "Map " + MUST_NOT_BE_NULL); @@ -784,6 +813,13 @@ public Command> mget(K... keys) { return createCommand(MGET, new ValueListOutput(codec), args); } + public Command>> mgetKeyValue(K... keys) { + notEmpty(keys); + + CommandArgs args = new CommandArgs(codec).addKeys(keys); + return createCommand(MGET, new KeyValueListOutput(codec, Arrays.asList(keys)), args); + } + public Command> mget(Iterable keys) { LettuceAssert.notNull(keys, "Keys " + MUST_NOT_BE_NULL); @@ -791,6 +827,13 @@ public Command> mget(Iterable keys) { return createCommand(MGET, new ValueListOutput(codec), args); } + public Command>> mgetKeyValue(Iterable keys) { + LettuceAssert.notNull(keys, "Keys " + MUST_NOT_BE_NULL); + + CommandArgs args = new CommandArgs(codec).addKeys(keys); + return createCommand(MGET, new KeyValueListOutput(codec, keys), args); + } + public Command mget(ValueStreamingChannel channel, K... keys) { notEmpty(keys); notNull(channel); @@ -799,6 +842,14 @@ public Command mget(ValueStreamingChannel channel, K... keys) { return createCommand(MGET, new ValueStreamingOutput(codec, channel), args); } + public Command mget(KeyValueStreamingChannel channel, K... keys) { + notEmpty(keys); + notNull(channel); + + CommandArgs args = new CommandArgs(codec).addKeys(keys); + return createCommand(MGET, new KeyValueStreamingOutput(codec, channel, Arrays.asList(keys)), args); + } + public Command mget(ValueStreamingChannel channel, Iterable keys) { LettuceAssert.notNull(keys, "Keys " + MUST_NOT_BE_NULL); notNull(channel); @@ -807,6 +858,14 @@ public Command mget(ValueStreamingChannel channel, Iterable ke return createCommand(MGET, new ValueStreamingOutput(codec, channel), args); } + public Command mget(KeyValueStreamingChannel channel, Iterable keys) { + LettuceAssert.notNull(keys, "Keys " + MUST_NOT_BE_NULL); + notNull(channel); + + CommandArgs args = new CommandArgs(codec).addKeys(keys); + return createCommand(MGET, new KeyValueStreamingOutput(codec, channel, keys), args); + } + public Command move(K key, int db) { notNullKey(key); diff --git a/src/main/java/com/lambdaworks/redis/api/async/RedisHashAsyncCommands.java b/src/main/java/com/lambdaworks/redis/api/async/RedisHashAsyncCommands.java index 295be6ba7c..03fb42c057 100644 --- a/src/main/java/com/lambdaworks/redis/api/async/RedisHashAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/async/RedisHashAsyncCommands.java @@ -2,6 +2,8 @@ import java.util.List; import java.util.Map; +import com.lambdaworks.redis.KeyValue; +import com.lambdaworks.redis.Value; import com.lambdaworks.redis.MapScanCursor; import com.lambdaworks.redis.ScanArgs; import com.lambdaworks.redis.ScanCursor; @@ -126,7 +128,7 @@ public interface RedisHashAsyncCommands { * @param fields the field type: key * @return List<V> array-reply list of values associated with the given fields, in the same */ - RedisFuture> hmget(K key, K... fields); + RedisFuture>> hmget(K key, K... fields); /** * Stream over the values of all the given hash fields. @@ -137,7 +139,7 @@ public interface RedisHashAsyncCommands { * * @return Long count of the keys */ - RedisFuture hmget(ValueStreamingChannel channel, K key, K... fields); + RedisFuture hmget(KeyValueStreamingChannel channel, K key, K... fields); /** * Set multiple hash fields to multiple values. diff --git a/src/main/java/com/lambdaworks/redis/api/async/RedisKeyAsyncCommands.java b/src/main/java/com/lambdaworks/redis/api/async/RedisKeyAsyncCommands.java index 252db0a0c8..dcd7436618 100644 --- a/src/main/java/com/lambdaworks/redis/api/async/RedisKeyAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/async/RedisKeyAsyncCommands.java @@ -2,6 +2,7 @@ import java.util.Date; import java.util.List; +import com.lambdaworks.redis.Value; import com.lambdaworks.redis.KeyScanCursor; import com.lambdaworks.redis.MigrateArgs; import com.lambdaworks.redis.ScanArgs; diff --git a/src/main/java/com/lambdaworks/redis/api/async/RedisStringAsyncCommands.java b/src/main/java/com/lambdaworks/redis/api/async/RedisStringAsyncCommands.java index 946ed52717..87f7da7c16 100644 --- a/src/main/java/com/lambdaworks/redis/api/async/RedisStringAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/async/RedisStringAsyncCommands.java @@ -2,10 +2,10 @@ import java.util.List; import java.util.Map; + +import com.lambdaworks.redis.*; +import com.lambdaworks.redis.output.KeyValueStreamingChannel; import com.lambdaworks.redis.output.ValueStreamingChannel; -import com.lambdaworks.redis.BitFieldArgs; -import com.lambdaworks.redis.SetArgs; -import com.lambdaworks.redis.RedisFuture; /** * Asynchronous executed commands for Strings. @@ -231,7 +231,7 @@ public interface RedisStringAsyncCommands { * @param keys the key * @return List<V> array-reply list of values at the specified keys. */ - RedisFuture> mget(K... keys); + RedisFuture>> mget(K... keys); /** * Stream over the values of all the given keys. @@ -241,7 +241,7 @@ public interface RedisStringAsyncCommands { * * @return Long array-reply list of values at the specified keys. */ - RedisFuture mget(ValueStreamingChannel channel, K... keys); + RedisFuture mget(KeyValueStreamingChannel channel, K... keys); /** * Set multiple keys to multiple values. diff --git a/src/main/java/com/lambdaworks/redis/api/rx/RedisHashReactiveCommands.java b/src/main/java/com/lambdaworks/redis/api/rx/RedisHashReactiveCommands.java index 21e575bcf8..01b399bcec 100644 --- a/src/main/java/com/lambdaworks/redis/api/rx/RedisHashReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/rx/RedisHashReactiveCommands.java @@ -2,6 +2,8 @@ import java.util.List; import java.util.Map; +import com.lambdaworks.redis.KeyValue; +import com.lambdaworks.redis.Value; import com.lambdaworks.redis.MapScanCursor; import com.lambdaworks.redis.ScanArgs; import com.lambdaworks.redis.ScanCursor; @@ -128,7 +130,7 @@ public interface RedisHashReactiveCommands { * @param fields the field type: key * @return V array-reply list of values associated with the given fields, in the same */ - Observable hmget(K key, K... fields); + Observable> hmget(K key, K... fields); /** * Stream over the values of all the given hash fields. @@ -139,7 +141,7 @@ public interface RedisHashReactiveCommands { * * @return Long count of the keys */ - Single hmget(ValueStreamingChannel channel, K key, K... fields); + Single hmget(KeyValueStreamingChannel channel, K key, K... fields); /** * Set multiple hash fields to multiple values. diff --git a/src/main/java/com/lambdaworks/redis/api/rx/RedisKeyReactiveCommands.java b/src/main/java/com/lambdaworks/redis/api/rx/RedisKeyReactiveCommands.java index 8cc15286cc..18411f7af7 100644 --- a/src/main/java/com/lambdaworks/redis/api/rx/RedisKeyReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/rx/RedisKeyReactiveCommands.java @@ -2,6 +2,7 @@ import java.util.Date; import java.util.List; +import com.lambdaworks.redis.Value; import com.lambdaworks.redis.KeyScanCursor; import com.lambdaworks.redis.MigrateArgs; import com.lambdaworks.redis.ScanArgs; diff --git a/src/main/java/com/lambdaworks/redis/api/rx/RedisStringReactiveCommands.java b/src/main/java/com/lambdaworks/redis/api/rx/RedisStringReactiveCommands.java index 347e825982..5abf9b1b9f 100644 --- a/src/main/java/com/lambdaworks/redis/api/rx/RedisStringReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/rx/RedisStringReactiveCommands.java @@ -2,9 +2,12 @@ import java.util.List; import java.util.Map; +import com.lambdaworks.redis.output.KeyValueStreamingChannel; import com.lambdaworks.redis.output.ValueStreamingChannel; import com.lambdaworks.redis.BitFieldArgs; +import com.lambdaworks.redis.KeyValue; import com.lambdaworks.redis.SetArgs; +import com.lambdaworks.redis.Value; import rx.Observable; import rx.Single; import rx.Completable; @@ -233,17 +236,17 @@ public interface RedisStringReactiveCommands { * @param keys the key * @return V array-reply list of values at the specified keys. */ - Observable mget(K... keys); + Observable> mget(K... keys); /** * Stream over the values of all the given keys. - * + * * @param channel the channel * @param keys the keys - * + * * @return Long array-reply list of values at the specified keys. */ - Single mget(ValueStreamingChannel channel, K... keys); + Single mget(KeyValueStreamingChannel channel, K... keys); /** * Set multiple keys to multiple values. diff --git a/src/main/java/com/lambdaworks/redis/api/sync/RedisHashCommands.java b/src/main/java/com/lambdaworks/redis/api/sync/RedisHashCommands.java index 9fdc19c7fe..1460f29266 100644 --- a/src/main/java/com/lambdaworks/redis/api/sync/RedisHashCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/sync/RedisHashCommands.java @@ -2,6 +2,8 @@ import java.util.List; import java.util.Map; +import com.lambdaworks.redis.KeyValue; +import com.lambdaworks.redis.Value; import com.lambdaworks.redis.MapScanCursor; import com.lambdaworks.redis.ScanArgs; import com.lambdaworks.redis.ScanCursor; @@ -125,7 +127,7 @@ public interface RedisHashCommands { * @param fields the field type: key * @return List<V> array-reply list of values associated with the given fields, in the same */ - List hmget(K key, K... fields); + List> hmget(K key, K... fields); /** * Stream over the values of all the given hash fields. @@ -136,7 +138,7 @@ public interface RedisHashCommands { * * @return Long count of the keys */ - Long hmget(ValueStreamingChannel channel, K key, K... fields); + Long hmget(KeyValueStreamingChannel channel, K key, K... fields); /** * Set multiple hash fields to multiple values. diff --git a/src/main/java/com/lambdaworks/redis/api/sync/RedisKeyCommands.java b/src/main/java/com/lambdaworks/redis/api/sync/RedisKeyCommands.java index e4c2b825dc..f1b618feb0 100644 --- a/src/main/java/com/lambdaworks/redis/api/sync/RedisKeyCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/sync/RedisKeyCommands.java @@ -2,6 +2,7 @@ import java.util.Date; import java.util.List; +import com.lambdaworks.redis.Value; import com.lambdaworks.redis.KeyScanCursor; import com.lambdaworks.redis.MigrateArgs; import com.lambdaworks.redis.ScanArgs; diff --git a/src/main/java/com/lambdaworks/redis/api/sync/RedisStringCommands.java b/src/main/java/com/lambdaworks/redis/api/sync/RedisStringCommands.java index aa15ad93c4..d965a8194d 100644 --- a/src/main/java/com/lambdaworks/redis/api/sync/RedisStringCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/sync/RedisStringCommands.java @@ -2,10 +2,14 @@ import java.util.List; import java.util.Map; + +import com.lambdaworks.redis.KeyValue; +import com.lambdaworks.redis.output.KeyValueStreamingChannel; import com.lambdaworks.redis.output.ValueStreamingChannel; import com.lambdaworks.redis.BitFieldArgs; import com.lambdaworks.redis.KeyValue; import com.lambdaworks.redis.SetArgs; +import com.lambdaworks.redis.Value; /** * Synchronous executed commands for Strings. @@ -231,7 +235,7 @@ public interface RedisStringCommands { * @param keys the key * @return List<V> array-reply list of values at the specified keys. */ - List mget(K... keys); + List> mget(K... keys); /** * Stream over the values of all the given keys. @@ -241,7 +245,7 @@ public interface RedisStringCommands { * * @return Long array-reply list of values at the specified keys. */ - Long mget(ValueStreamingChannel channel, K... keys); + Long mget(KeyValueStreamingChannel channel, K... keys); /** * Set multiple keys to multiple values. diff --git a/src/main/java/com/lambdaworks/redis/cluster/RedisAdvancedClusterAsyncCommandsImpl.java b/src/main/java/com/lambdaworks/redis/cluster/RedisAdvancedClusterAsyncCommandsImpl.java index e207d69155..3db9c0ff02 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/RedisAdvancedClusterAsyncCommandsImpl.java +++ b/src/main/java/com/lambdaworks/redis/cluster/RedisAdvancedClusterAsyncCommandsImpl.java @@ -28,6 +28,7 @@ import com.lambdaworks.redis.codec.RedisCodec; import com.lambdaworks.redis.output.IntegerOutput; import com.lambdaworks.redis.output.KeyStreamingChannel; +import com.lambdaworks.redis.output.KeyValueStreamingChannel; import com.lambdaworks.redis.output.ValueStreamingChannel; import com.lambdaworks.redis.protocol.AsyncCommand; import com.lambdaworks.redis.protocol.Command; @@ -124,12 +125,12 @@ public RedisFuture exists(Iterable keys) { } @Override - public RedisFuture> mget(K... keys) { + public RedisFuture>> mget(K... keys) { return mget(Arrays.asList(keys)); } @Override - public RedisFuture> mget(Iterable keys) { + public RedisFuture>> mget(Iterable keys) { Map> partitioned = SlotHash.partition(codec, keys); if (partitioned.size() < 2) { @@ -137,21 +138,21 @@ public RedisFuture> mget(Iterable keys) { } Map slots = SlotHash.getSlots(partitioned); - Map>> executions = new HashMap<>(); + Map>>> executions = new HashMap<>(); for (Map.Entry> entry : partitioned.entrySet()) { - RedisFuture> mget = super.mget(entry.getValue()); + RedisFuture>> mget = super.mget(entry.getValue()); executions.put(entry.getKey(), mget); } // restore order of key return new PipelinedRedisFuture<>(executions, objectPipelinedRedisFuture -> { - List result = new ArrayList<>(); + List> result = new ArrayList<>(); for (K opKey : keys) { int slot = slots.get(opKey); int position = partitioned.get(slot).indexOf(opKey); - RedisFuture> listRedisFuture = executions.get(slot); + RedisFuture>> listRedisFuture = executions.get(slot); result.add(MultiNodeExecution.execute(() -> listRedisFuture.get().get(position))); } @@ -160,12 +161,12 @@ public RedisFuture> mget(Iterable keys) { } @Override - public RedisFuture mget(ValueStreamingChannel channel, K... keys) { + public RedisFuture mget(KeyValueStreamingChannel channel, K... keys) { return mget(channel, Arrays.asList(keys)); } @Override - public RedisFuture mget(ValueStreamingChannel channel, Iterable keys) { + public RedisFuture mget(KeyValueStreamingChannel channel, Iterable keys) { Map> partitioned = SlotHash.partition(codec, keys); if (partitioned.size() < 2) { diff --git a/src/main/java/com/lambdaworks/redis/cluster/RedisAdvancedClusterReactiveCommandsImpl.java b/src/main/java/com/lambdaworks/redis/cluster/RedisAdvancedClusterReactiveCommandsImpl.java index f112c4f181..1127e06056 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/RedisAdvancedClusterReactiveCommandsImpl.java +++ b/src/main/java/com/lambdaworks/redis/cluster/RedisAdvancedClusterReactiveCommandsImpl.java @@ -22,6 +22,7 @@ import com.lambdaworks.redis.cluster.models.partitions.RedisClusterNode; import com.lambdaworks.redis.codec.RedisCodec; import com.lambdaworks.redis.output.KeyStreamingChannel; +import com.lambdaworks.redis.output.KeyValueStreamingChannel; import com.lambdaworks.redis.output.ValueStreamingChannel; import rx.Completable; @@ -121,11 +122,11 @@ public Single exists(Iterable keys) { } @Override - public Observable mget(K... keys) { + public Observable> mget(K... keys) { return mget(Arrays.asList(keys)); } - public Observable mget(Iterable keys) { + public Observable> mget(Iterable keys) { List keyList = LettuceLists.newList(keys); Map> partitioned = SlotHash.partition(codec, keyList); @@ -134,16 +135,16 @@ public Observable mget(Iterable keys) { return super.mget(keyList); } - List> observables = new ArrayList<>(); + List>> observables = new ArrayList<>(); for (Map.Entry> entry : partitioned.entrySet()) { observables.add(super.mget(entry.getValue())); } - Observable observable = Observable.concat(Observable.from(observables)); + Observable> observable = Observable.concat(Observable.from(observables)); - Observable> map = observable.toList().map(vs -> { + Observable>> map = observable.toList().map(vs -> { - Object[] values = new Object[vs.size()]; + KeyValue[] values = new KeyValue[vs.size()]; int offset = 0; for (Map.Entry> entry : partitioned.entrySet()) { @@ -160,7 +161,7 @@ public Observable mget(Iterable keys) { offset += entry.getValue().size(); } - List objects = (List) new ArrayList<>(Arrays.asList(values)); + List> objects = new ArrayList<>(Arrays.asList(values)); return objects; }); @@ -168,12 +169,12 @@ public Observable mget(Iterable keys) { } @Override - public Single mget(ValueStreamingChannel channel, K... keys) { + public Single mget(KeyValueStreamingChannel channel, K... keys) { return mget(channel, Arrays.asList(keys)); } @Override - public Single mget(ValueStreamingChannel channel, Iterable keys) { + public Single mget(KeyValueStreamingChannel channel, Iterable keys) { List keyList = LettuceLists.newList(keys); diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/async/BaseNodeSelectionAsyncCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/async/BaseNodeSelectionAsyncCommands.java index 4aa308f69f..9d87be0ee8 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/async/BaseNodeSelectionAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/async/BaseNodeSelectionAsyncCommands.java @@ -17,7 +17,7 @@ * @since 4.0 * @generated by com.lambdaworks.apigenerator.CreateAsyncNodeSelectionClusterApi */ -public interface BaseNodeSelectionAsyncCommands extends AutoCloseable { +public interface BaseNodeSelectionAsyncCommands { /** * Post a message to a channel. diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionHashAsyncCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionHashAsyncCommands.java index dec72c511f..43d9b3935f 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionHashAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionHashAsyncCommands.java @@ -2,6 +2,8 @@ import java.util.List; import java.util.Map; +import com.lambdaworks.redis.KeyValue; +import com.lambdaworks.redis.Value; import com.lambdaworks.redis.MapScanCursor; import com.lambdaworks.redis.ScanArgs; import com.lambdaworks.redis.ScanCursor; @@ -126,7 +128,7 @@ public interface NodeSelectionHashAsyncCommands { * @param fields the field type: key * @return List<V> array-reply list of values associated with the given fields, in the same */ - AsyncExecutions> hmget(K key, K... fields); + AsyncExecutions>> hmget(K key, K... fields); /** * Stream over the values of all the given hash fields. @@ -137,7 +139,7 @@ public interface NodeSelectionHashAsyncCommands { * * @return Long count of the keys */ - AsyncExecutions hmget(ValueStreamingChannel channel, K key, K... fields); + AsyncExecutions hmget(KeyValueStreamingChannel channel, K key, K... fields); /** * Set multiple hash fields to multiple values. diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionKeyAsyncCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionKeyAsyncCommands.java index 184e953757..a6d7633c2d 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionKeyAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionKeyAsyncCommands.java @@ -2,6 +2,7 @@ import java.util.Date; import java.util.List; +import com.lambdaworks.redis.Value; import com.lambdaworks.redis.KeyScanCursor; import com.lambdaworks.redis.MigrateArgs; import com.lambdaworks.redis.ScanArgs; diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionStringAsyncCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionStringAsyncCommands.java index adf5d11c91..25d70d1654 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionStringAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionStringAsyncCommands.java @@ -2,10 +2,10 @@ import java.util.List; import java.util.Map; + +import com.lambdaworks.redis.*; +import com.lambdaworks.redis.output.KeyValueStreamingChannel; import com.lambdaworks.redis.output.ValueStreamingChannel; -import com.lambdaworks.redis.BitFieldArgs; -import com.lambdaworks.redis.SetArgs; -import com.lambdaworks.redis.RedisFuture; /** * Asynchronous executed commands on a node selection for Strings. @@ -231,7 +231,7 @@ public interface NodeSelectionStringAsyncCommands { * @param keys the key * @return List<V> array-reply list of values at the specified keys. */ - AsyncExecutions> mget(K... keys); + AsyncExecutions>> mget(K... keys); /** * Stream over the values of all the given keys. @@ -241,7 +241,7 @@ public interface NodeSelectionStringAsyncCommands { * * @return Long array-reply list of values at the specified keys. */ - AsyncExecutions mget(ValueStreamingChannel channel, K... keys); + AsyncExecutions mget(KeyValueStreamingChannel channel, K... keys); /** * Set multiple keys to multiple values. diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/async/RedisAdvancedClusterAsyncCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/async/RedisAdvancedClusterAsyncCommands.java index 33fe6f5432..0bdacab505 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/async/RedisAdvancedClusterAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/async/RedisAdvancedClusterAsyncCommands.java @@ -152,7 +152,7 @@ default AsyncNodeSelection all() { * @return List<V> array-reply list of values at the specified keys. * @see RedisStringAsyncCommands#mget(Object[]) */ - RedisFuture> mget(K... keys); + RedisFuture>> mget(K... keys); /** * Set multiple keys to multiple values with pipelining. Cross-slot keys will result in multiple calls to the particular diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/async/RedisClusterAsyncCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/async/RedisClusterAsyncCommands.java index dced1f67ce..6f3c8dd841 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/async/RedisClusterAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/async/RedisClusterAsyncCommands.java @@ -4,6 +4,7 @@ import java.util.Map; import java.util.concurrent.TimeUnit; +import com.lambdaworks.redis.KeyValue; import com.lambdaworks.redis.RedisFuture; import com.lambdaworks.redis.api.async.*; @@ -290,7 +291,7 @@ public interface RedisClusterAsyncCommands * @param keys the key * @return RedisFuture<List<V>> array-reply list of values at the specified keys. */ - RedisFuture> mget(K... keys); + RedisFuture>> mget(K... keys); /** * Set multiple keys to multiple values with pipelining. Cross-slot keys will result in multiple calls to the particular diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/rx/RedisAdvancedClusterReactiveCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/rx/RedisAdvancedClusterReactiveCommands.java index c4d571c884..8afbd0e3ca 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/rx/RedisAdvancedClusterReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/rx/RedisAdvancedClusterReactiveCommands.java @@ -81,7 +81,7 @@ public interface RedisAdvancedClusterReactiveCommands extends RedisCluster * @return V array-reply list of values at the specified keys. * @see RedisStringReactiveCommands#mget(Object[]) */ - Observable mget(K... keys); + Observable> mget(K... keys); /** * Set multiple keys to multiple values with pipelining. Cross-slot keys will result in multiple calls to the particular diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/rx/RedisClusterReactiveCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/rx/RedisClusterReactiveCommands.java index 4a209ce319..f3365643a3 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/rx/RedisClusterReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/rx/RedisClusterReactiveCommands.java @@ -3,6 +3,7 @@ import java.util.Map; import java.util.concurrent.TimeUnit; +import com.lambdaworks.redis.KeyValue; import rx.Observable; import com.lambdaworks.redis.api.rx.*; @@ -290,7 +291,7 @@ public interface RedisClusterReactiveCommands extends RedisHashReactiveCom * @param keys the key * @return Observable<List<V>> array-reply list of values at the specified keys. */ - Observable mget(K... keys); + Observable> mget(K... keys); /** * Set multiple keys to multiple values with pipelining. Cross-slot keys will result in multiple calls to the particular diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/sync/BaseNodeSelectionCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/sync/BaseNodeSelectionCommands.java index 31cbb13e8b..e81667ebc6 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/sync/BaseNodeSelectionCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/sync/BaseNodeSelectionCommands.java @@ -16,7 +16,7 @@ * @since 4.0 * @generated by com.lambdaworks.apigenerator.CreateSyncNodeSelectionClusterApi */ -public interface BaseNodeSelectionCommands extends AutoCloseable { +public interface BaseNodeSelectionCommands { /** * Post a message to a channel. diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionHashCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionHashCommands.java index 924acb1aaf..07942954d7 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionHashCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionHashCommands.java @@ -2,6 +2,8 @@ import java.util.List; import java.util.Map; +import com.lambdaworks.redis.KeyValue; +import com.lambdaworks.redis.Value; import com.lambdaworks.redis.MapScanCursor; import com.lambdaworks.redis.ScanArgs; import com.lambdaworks.redis.ScanCursor; @@ -125,7 +127,7 @@ public interface NodeSelectionHashCommands { * @param fields the field type: key * @return List<V> array-reply list of values associated with the given fields, in the same */ - Executions> hmget(K key, K... fields); + Executions>> hmget(K key, K... fields); /** * Stream over the values of all the given hash fields. @@ -136,7 +138,7 @@ public interface NodeSelectionHashCommands { * * @return Long count of the keys */ - Executions hmget(ValueStreamingChannel channel, K key, K... fields); + Executions hmget(KeyValueStreamingChannel channel, K key, K... fields); /** * Set multiple hash fields to multiple values. diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionKeyCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionKeyCommands.java index d43d141f9e..24b28c25f8 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionKeyCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionKeyCommands.java @@ -2,6 +2,7 @@ import java.util.Date; import java.util.List; +import com.lambdaworks.redis.Value; import com.lambdaworks.redis.KeyScanCursor; import com.lambdaworks.redis.MigrateArgs; import com.lambdaworks.redis.ScanArgs; diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionStringCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionStringCommands.java index 9539cb5b9b..041140dd53 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionStringCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionStringCommands.java @@ -2,9 +2,13 @@ import java.util.List; import java.util.Map; + +import com.lambdaworks.redis.KeyValue; +import com.lambdaworks.redis.output.KeyValueStreamingChannel; import com.lambdaworks.redis.output.ValueStreamingChannel; import com.lambdaworks.redis.BitFieldArgs; import com.lambdaworks.redis.SetArgs; +import com.lambdaworks.redis.Value; /** * Synchronous executed commands on a node selection for Strings. diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/sync/RedisAdvancedClusterCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/sync/RedisAdvancedClusterCommands.java index 19bb507013..72492ab8ac 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/sync/RedisAdvancedClusterCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/sync/RedisAdvancedClusterCommands.java @@ -149,7 +149,7 @@ default NodeSelection all() { * @return List<V> array-reply list of values at the specified keys. * @see RedisStringCommands#mget(Object[]) */ - List mget(K... keys); + List> mget(K... keys); /** * Set multiple keys to multiple values with pipelining. Cross-slot keys will result in multiple calls to the particular diff --git a/src/main/java/com/lambdaworks/redis/output/KeyStreamingChannel.java b/src/main/java/com/lambdaworks/redis/output/KeyStreamingChannel.java index 296a0186e0..bf97f8ff6b 100644 --- a/src/main/java/com/lambdaworks/redis/output/KeyStreamingChannel.java +++ b/src/main/java/com/lambdaworks/redis/output/KeyStreamingChannel.java @@ -9,7 +9,7 @@ * @since 3.0 */ @FunctionalInterface -public interface KeyStreamingChannel { +public interface KeyStreamingChannel extends StreamingChannel{ /** * Called on every incoming key. * diff --git a/src/main/java/com/lambdaworks/redis/output/KeyValueListOutput.java b/src/main/java/com/lambdaworks/redis/output/KeyValueListOutput.java new file mode 100644 index 0000000000..2da58e2714 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/output/KeyValueListOutput.java @@ -0,0 +1,53 @@ +package com.lambdaworks.redis.output; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import com.lambdaworks.redis.KeyValue; +import com.lambdaworks.redis.codec.RedisCodec; +import com.lambdaworks.redis.internal.LettuceAssert; + +/** + * {@link List} of values output. + * + * @param Key type. + * @param Value type. + * + * @author Mark Paluch + */ +public class KeyValueListOutput extends CommandOutput>> + implements StreamingOutput> { + + private Subscriber> subscriber; + private Iterable keys; + private Iterator keyIterator; + + public KeyValueListOutput(RedisCodec codec, Iterable keys) { + super(codec, new ArrayList<>()); + setSubscriber(ListSubscriber.of(output)); + this.keys = keys; + } + + @Override + public void set(ByteBuffer bytes) { + + if(keyIterator == null) { + keyIterator = keys.iterator(); + } + + subscriber.onNext(KeyValue.fromNullable(keyIterator.next(), bytes == null ? null : codec.decodeValue(bytes))); + } + + @Override + public void setSubscriber(Subscriber> subscriber) { + LettuceAssert.notNull(subscriber, "Subscriber must not be null"); + this.subscriber = subscriber; + } + + @Override + public Subscriber> getSubscriber() { + return subscriber; + } +} diff --git a/src/main/java/com/lambdaworks/redis/output/KeyValueStreamingChannel.java b/src/main/java/com/lambdaworks/redis/output/KeyValueStreamingChannel.java index 40f3cdd30f..73ab97729b 100644 --- a/src/main/java/com/lambdaworks/redis/output/KeyValueStreamingChannel.java +++ b/src/main/java/com/lambdaworks/redis/output/KeyValueStreamingChannel.java @@ -1,18 +1,17 @@ package com.lambdaworks.redis.output; /** - * Streaming API for multiple Key-Values. You can implement this interface in order to receive a call to {@code onKeyValue} on - * every key-value pair. Key uniqueness is not guaranteed. + * Streaming API for multiple keys and values (tuples). You can implement this interface in order to receive a call to + * {@code onKeyValue} on every key-value. * - * @param Key type. * @param Value type. * @author Mark Paluch - * @since 3.0 + * @since 5.0 */ @FunctionalInterface -public interface KeyValueStreamingChannel { +public interface KeyValueStreamingChannel extends StreamingChannel { + /** - * * Called on every incoming key/value pair. * * @param key the key diff --git a/src/main/java/com/lambdaworks/redis/output/KeyValueStreamingOutput.java b/src/main/java/com/lambdaworks/redis/output/KeyValueStreamingOutput.java index c6d023c0d2..567b84e8de 100644 --- a/src/main/java/com/lambdaworks/redis/output/KeyValueStreamingOutput.java +++ b/src/main/java/com/lambdaworks/redis/output/KeyValueStreamingOutput.java @@ -3,6 +3,7 @@ package com.lambdaworks.redis.output; import java.nio.ByteBuffer; +import java.util.Iterator; import com.lambdaworks.redis.codec.RedisCodec; @@ -15,6 +16,9 @@ * @author Mark Paluch */ public class KeyValueStreamingOutput extends CommandOutput { + + private Iterable keys; + private Iterator keyIterator; private K key; private KeyValueStreamingChannel channel; @@ -23,11 +27,24 @@ public KeyValueStreamingOutput(RedisCodec codec, KeyValueStreamingChannel< this.channel = channel; } + public KeyValueStreamingOutput(RedisCodec codec, KeyValueStreamingChannel channel, Iterable keys) { + super(codec, Long.valueOf(0)); + this.channel = channel; + this.keys = keys; + } + @Override public void set(ByteBuffer bytes) { - if (key == null) { - key = codec.decodeKey(bytes); - return; + if (keys == null) { + if (key == null) { + key = codec.decodeKey(bytes); + return; + } + } else { + if (keyIterator == null) { + keyIterator = keys.iterator(); + } + key = keyIterator.next(); } V value = (bytes == null) ? null : codec.decodeValue(bytes); diff --git a/src/main/java/com/lambdaworks/redis/output/ScoredValueStreamingChannel.java b/src/main/java/com/lambdaworks/redis/output/ScoredValueStreamingChannel.java index 95fb429128..ba7db3c2ba 100644 --- a/src/main/java/com/lambdaworks/redis/output/ScoredValueStreamingChannel.java +++ b/src/main/java/com/lambdaworks/redis/output/ScoredValueStreamingChannel.java @@ -11,7 +11,7 @@ * @since 3.0 */ @FunctionalInterface -public interface ScoredValueStreamingChannel { +public interface ScoredValueStreamingChannel extends StreamingChannel { /** * Called on every incoming ScoredValue. * diff --git a/src/main/java/com/lambdaworks/redis/output/StreamingChannel.java b/src/main/java/com/lambdaworks/redis/output/StreamingChannel.java new file mode 100644 index 0000000000..91aca606b9 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/output/StreamingChannel.java @@ -0,0 +1,10 @@ +package com.lambdaworks.redis.output; + +/** + * Marker interface for streaming channels. + * + * @author Mark Paluch + * @since 5.0 + */ +public interface StreamingChannel { +} diff --git a/src/main/java/com/lambdaworks/redis/output/ValueValueListOutput.java b/src/main/java/com/lambdaworks/redis/output/ValueValueListOutput.java new file mode 100644 index 0000000000..1f0b4d6d9a --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/output/ValueValueListOutput.java @@ -0,0 +1,49 @@ + +package com.lambdaworks.redis.output; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; + +import com.lambdaworks.redis.Value; +import com.lambdaworks.redis.codec.RedisCodec; +import com.lambdaworks.redis.internal.LettuceAssert; + +/** + * {@link List} of {@link Value} wrapped values output. + * + * @param Key type. + * @param Value type. + * + * @author Mark Paluch + */ +public class ValueValueListOutput extends CommandOutput>> implements StreamingOutput> { + + private Subscriber> subscriber; + + public ValueValueListOutput(RedisCodec codec) { + super(codec, new ArrayList<>()); + setSubscriber(ListSubscriber.of(output)); + } + + @Override + public void set(ByteBuffer bytes) { + subscriber.onNext(Value.fromNullable(bytes == null ? null : codec.decodeValue(bytes))); + } + + @Override + public void set(long integer) { + subscriber.onNext(Value.fromNullable((V) Long.valueOf(integer))); + } + + @Override + public void setSubscriber(Subscriber> subscriber) { + LettuceAssert.notNull(subscriber, "Subscriber must not be null"); + this.subscriber = subscriber; + } + + @Override + public Subscriber> getSubscriber() { + return subscriber; + } +} diff --git a/src/main/templates/com/lambdaworks/redis/api/RedisHashCommands.java b/src/main/templates/com/lambdaworks/redis/api/RedisHashCommands.java index e180cd2c81..340de0b50b 100644 --- a/src/main/templates/com/lambdaworks/redis/api/RedisHashCommands.java +++ b/src/main/templates/com/lambdaworks/redis/api/RedisHashCommands.java @@ -3,6 +3,8 @@ import java.util.List; import java.util.Map; +import com.lambdaworks.redis.KeyValue; +import com.lambdaworks.redis.Value; import com.lambdaworks.redis.MapScanCursor; import com.lambdaworks.redis.ScanArgs; import com.lambdaworks.redis.ScanCursor; @@ -125,7 +127,7 @@ public interface RedisHashCommands { * @param fields the field type: key * @return List<V> array-reply list of values associated with the given fields, in the same */ - List hmget(K key, K... fields); + List> hmget(K key, K... fields); /** * Stream over the values of all the given hash fields. @@ -136,7 +138,7 @@ public interface RedisHashCommands { * * @return Long count of the keys */ - Long hmget(ValueStreamingChannel channel, K key, K... fields); + Long hmget(KeyValueStreamingChannel channel, K key, K... fields); /** * Set multiple hash fields to multiple values. diff --git a/src/main/templates/com/lambdaworks/redis/api/RedisKeyCommands.java b/src/main/templates/com/lambdaworks/redis/api/RedisKeyCommands.java index e835b6c082..bcf563fc1c 100644 --- a/src/main/templates/com/lambdaworks/redis/api/RedisKeyCommands.java +++ b/src/main/templates/com/lambdaworks/redis/api/RedisKeyCommands.java @@ -3,6 +3,7 @@ import java.util.Date; import java.util.List; +import com.lambdaworks.redis.Value; import com.lambdaworks.redis.KeyScanCursor; import com.lambdaworks.redis.MigrateArgs; import com.lambdaworks.redis.ScanArgs; diff --git a/src/main/templates/com/lambdaworks/redis/api/RedisStringCommands.java b/src/main/templates/com/lambdaworks/redis/api/RedisStringCommands.java index e45d23bff8..c087d0aca6 100644 --- a/src/main/templates/com/lambdaworks/redis/api/RedisStringCommands.java +++ b/src/main/templates/com/lambdaworks/redis/api/RedisStringCommands.java @@ -3,9 +3,12 @@ import java.util.List; import java.util.Map; +import com.lambdaworks.redis.output.KeyValueStreamingChannel; import com.lambdaworks.redis.output.ValueStreamingChannel; import com.lambdaworks.redis.BitFieldArgs; +import com.lambdaworks.redis.KeyValue; import com.lambdaworks.redis.SetArgs; +import com.lambdaworks.redis.Value; /** * ${intent} for Strings. @@ -230,17 +233,17 @@ public interface RedisStringCommands { * @param keys the key * @return List<V> array-reply list of values at the specified keys. */ - List mget(K... keys); + List> mget(K... keys); /** * Stream over the values of all the given keys. - * + * * @param channel the channel * @param keys the keys - * + * * @return Long array-reply list of values at the specified keys. */ - Long mget(ValueStreamingChannel channel, K... keys); + Long mget(KeyValueStreamingChannel channel, K... keys); /** * Set multiple keys to multiple values. diff --git a/src/test/java/com/lambdaworks/apigenerator/CreateReactiveApi.java b/src/test/java/com/lambdaworks/apigenerator/CreateReactiveApi.java index fce0f00fb0..1dbf8a61ad 100644 --- a/src/test/java/com/lambdaworks/apigenerator/CreateReactiveApi.java +++ b/src/test/java/com/lambdaworks/apigenerator/CreateReactiveApi.java @@ -25,10 +25,10 @@ @RunWith(Parameterized.class) public class CreateReactiveApi { - private Set KEEP_METHOD_RESULT_TYPE = LettuceSets.unmodifiableSet("digest", "close", "isOpen", + private static Set KEEP_METHOD_RESULT_TYPE = LettuceSets.unmodifiableSet("digest", "close", "isOpen", "BaseRedisCommands.reset", "getStatefulConnection", "setAutoFlushCommands", "flushCommands"); - private Set FORCE_OBSERVABLE_RESULT = LettuceSets.unmodifiableSet("eval", "evalsha"); + private static Set FORCE_OBSERVABLE_RESULT = LettuceSets.unmodifiableSet("eval", "evalsha", "dispatch"); private CompilationUnitFactory factory; @@ -96,10 +96,15 @@ protected Function methodTypeMutator() { return method.getType(); } + if (method.getName().equals("sort")) { + System.out.println(); + } + String typeAsString = method.getType().toStringWithoutComments().trim(); + if (methodMatch(FORCE_OBSERVABLE_RESULT, method, classOfMethod)) { typeAsString = "Observable<" + typeAsString + ">"; - } if (typeAsString.equals("void")) { + } else if (typeAsString.equals("void")) { typeAsString = "Completable"; } else if (typeAsString.startsWith("List<")) { typeAsString = "Observable<" + typeAsString.substring(5, typeAsString.length() - 1) + ">"; diff --git a/src/test/java/com/lambdaworks/redis/ReactiveConnectionTest.java b/src/test/java/com/lambdaworks/redis/ReactiveConnectionTest.java index d865d30dcf..409d702bb4 100644 --- a/src/test/java/com/lambdaworks/redis/ReactiveConnectionTest.java +++ b/src/test/java/com/lambdaworks/redis/ReactiveConnectionTest.java @@ -122,7 +122,7 @@ public void testObservableMultiCancel() throws Exception { reactive.clientPause(1000).subscribe(); Delay.delay(millis(100)); - Observable set = reactive.mget(key, value); + Observable> set = reactive.mget(key, value); set.subscribe(new CompletionSubscriber(result)); set.subscribe(new CompletionSubscriber(result)); set.subscribe(new CompletionSubscriber(result)); diff --git a/src/test/java/com/lambdaworks/redis/ReactiveStreamingOutputTest.java b/src/test/java/com/lambdaworks/redis/ReactiveStreamingOutputTest.java index 8e057d5eba..f0809a4641 100644 --- a/src/test/java/com/lambdaworks/redis/ReactiveStreamingOutputTest.java +++ b/src/test/java/com/lambdaworks/redis/ReactiveStreamingOutputTest.java @@ -1,6 +1,7 @@ package com.lambdaworks.redis; -import static org.assertj.core.api.Assertions.*; + +import java.util.stream.Collectors; import org.junit.After; import org.junit.Before; @@ -8,13 +9,15 @@ import org.junit.Test; import org.junit.rules.ExpectedException; -import rx.observers.TestSubscriber; - import com.lambdaworks.RandomKeys; import com.lambdaworks.redis.GeoArgs.Unit; import com.lambdaworks.redis.api.StatefulRedisConnection; import com.lambdaworks.redis.api.rx.RedisReactiveCommands; +import rx.observers.TestSubscriber; + +import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; + public class ReactiveStreamingOutputTest extends AbstractRedisClientTest { private RedisReactiveCommands reactive; @@ -51,10 +54,15 @@ public void valueListCommandShouldReturnAllElements() throws Exception { redis.mset(RandomKeys.MAP); + TestSubscriber> subscriber = TestSubscriber.create(); + reactive.mget(RandomKeys.KEYS.toArray(new String[RandomKeys.COUNT])).subscribe(subscriber); subscriber.awaitTerminalEvent(); - assertThat(subscriber.getOnNextEvents()).containsAll(RandomKeys.VALUES); + assertThat(subscriber.getOnNextEvents().stream().map(KeyValue::getValue).collect(Collectors.toList())) + .containsAll(RandomKeys.VALUES); + assertThat(subscriber.getOnNextEvents().stream().map(KeyValue::getKey).collect(Collectors.toList())) + .containsAll(RandomKeys.KEYS); } @Test diff --git a/src/test/java/com/lambdaworks/redis/cluster/AdvancedClusterClientTest.java b/src/test/java/com/lambdaworks/redis/cluster/AdvancedClusterClientTest.java index aa9b6fa00b..a9f1f643b6 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/AdvancedClusterClientTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/AdvancedClusterClientTest.java @@ -177,7 +177,7 @@ public void msetnxCrossSlot() throws Exception { public void mgetRegular() throws Exception { msetRegular(); - List result = syncCommands.mget(key); + List> result = syncCommands.mget(key); assertThat(result).hasSize(1); } @@ -187,14 +187,14 @@ public void mgetCrossSlot() throws Exception { msetCrossSlot(); List keys = new ArrayList<>(); - List expectation = new ArrayList<>(); + List> expectation = new ArrayList<>(); for (char c = 'a'; c < 'z'; c++) { String key = new String(new char[] { c, c, c }); keys.add(key); - expectation.add("value-" + key); + expectation.add(kv(key, "value-" + key)); } - List result = syncCommands.mget(keys.toArray(new String[keys.size()])); + List> result = syncCommands.mget(keys.toArray(new String[keys.size()])); assertThat(result).hasSize(keys.size()); assertThat(result).isEqualTo(expectation); diff --git a/src/test/java/com/lambdaworks/redis/cluster/AdvancedClusterReactiveTest.java b/src/test/java/com/lambdaworks/redis/cluster/AdvancedClusterReactiveTest.java index 92b585eaec..f6608daf4c 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/AdvancedClusterReactiveTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/AdvancedClusterReactiveTest.java @@ -93,11 +93,11 @@ public void mgetCrossSlot() throws Exception { Map> partitioned = SlotHash.partition(new Utf8StringCodec(), RandomKeys.KEYS); assertThat(partitioned.size()).isGreaterThan(100); - Observable observable = commands.mget(RandomKeys.KEYS.toArray(new String[RandomKeys.COUNT])); - List result = observable.toList().toBlocking().single(); + Observable> observable = commands.mget(RandomKeys.KEYS.toArray(new String[RandomKeys.COUNT])); + List> result = observable.toList().toBlocking().single(); assertThat(result).hasSize(RandomKeys.COUNT); - assertThat(result).isEqualTo(RandomKeys.VALUES); + assertThat(result.stream().map(Value::getValue).collect(Collectors.toList())).isEqualTo(RandomKeys.VALUES); } @Test @@ -105,12 +105,12 @@ public void mgetCrossSlotStreaming() throws Exception { msetCrossSlot(); - ListStreamingAdapter result = new ListStreamingAdapter<>(); + KeyValueStreamingAdapter result = new KeyValueStreamingAdapter<>(); Single single = commands.mget(result, RandomKeys.KEYS.toArray(new String[RandomKeys.COUNT])); Long count = block(single); - assertThat(result.getList()).hasSize(RandomKeys.COUNT); + assertThat(result.getMap()).hasSize(RandomKeys.COUNT); assertThat(count).isEqualTo(RandomKeys.COUNT); } diff --git a/src/test/java/com/lambdaworks/redis/cluster/commands/StringClusterCommandTest.java b/src/test/java/com/lambdaworks/redis/cluster/commands/StringClusterCommandTest.java index b791f47b26..3739ed8a87 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/commands/StringClusterCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/commands/StringClusterCommandTest.java @@ -6,15 +6,12 @@ import java.util.Map; import com.lambdaworks.TestClientResources; +import com.lambdaworks.redis.*; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; -import com.lambdaworks.redis.FastShutdown; -import com.lambdaworks.redis.ListStreamingAdapter; -import com.lambdaworks.redis.RedisURI; -import com.lambdaworks.redis.TestSettings; import com.lambdaworks.redis.api.sync.RedisCommands; import com.lambdaworks.redis.cluster.ClusterTestUtil; import com.lambdaworks.redis.cluster.RedisClusterClient; @@ -69,10 +66,10 @@ public void msetnx() throws Exception { public void mgetStreaming() throws Exception { setupMget(); - ListStreamingAdapter streamingAdapter = new ListStreamingAdapter(); + KeyValueStreamingAdapter streamingAdapter = new KeyValueStreamingAdapter<>(); Long count = redis.mget(streamingAdapter, "one", "two"); - assertThat(LettuceSets.newHashSet(streamingAdapter.getList())).isEqualTo(LettuceSets.newHashSet(list("1", "2"))); + assertThat(streamingAdapter.getMap()).containsEntry("one", "1").containsEntry("two", "2"); assertThat(count.intValue()).isEqualTo(2); } diff --git a/src/test/java/com/lambdaworks/redis/cluster/commands/rx/KeyClusterRxCommandTest.java b/src/test/java/com/lambdaworks/redis/cluster/commands/rx/KeyClusterRxCommandTest.java index d7f93062a6..dc89c09554 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/commands/rx/KeyClusterRxCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/commands/rx/KeyClusterRxCommandTest.java @@ -1,6 +1,7 @@ package com.lambdaworks.redis.cluster.commands.rx; import com.lambdaworks.TestClientResources; +import com.lambdaworks.util.RxSyncInvocationHandler; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; @@ -13,7 +14,6 @@ import com.lambdaworks.redis.cluster.RedisClusterClient; import com.lambdaworks.redis.cluster.api.StatefulRedisClusterConnection; import com.lambdaworks.redis.cluster.commands.KeyClusterCommandTest; -import com.lambdaworks.redis.commands.rx.RxSyncInvocationHandler; /** * @author Mark Paluch diff --git a/src/test/java/com/lambdaworks/redis/cluster/commands/rx/StringClusterRxCommandTest.java b/src/test/java/com/lambdaworks/redis/cluster/commands/rx/StringClusterRxCommandTest.java index fc0edb35b0..127a8938a7 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/commands/rx/StringClusterRxCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/commands/rx/StringClusterRxCommandTest.java @@ -5,6 +5,7 @@ import java.util.LinkedHashMap; import java.util.Map; +import com.lambdaworks.redis.KeyValue; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; @@ -73,9 +74,9 @@ public void mget() throws Exception { RedisAdvancedClusterReactiveCommands reactive = clusterConnection.reactive(); - Observable mget = reactive.mget(key, "key1", "key2"); - String first = mget.toBlocking().first(); - assertThat(first).isEqualTo(value); + Observable> mget = reactive.mget(key, "key1", "key2"); + KeyValue first = mget.toBlocking().first(); + assertThat(first).isEqualTo(KeyValue.just(key, value)); } } diff --git a/src/test/java/com/lambdaworks/redis/commands/HashCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/HashCommandTest.java index 430fa5e06a..0a60e32a06 100644 --- a/src/test/java/com/lambdaworks/redis/commands/HashCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/HashCommandTest.java @@ -5,6 +5,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.offset; +import java.security.Key; import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; @@ -130,13 +131,13 @@ public void hstrlen() throws Exception { @Test public void hmget() throws Exception { setupHmget(); - List values = redis.hmget(key, "one", "two"); + List> values = redis.hmget(key, "one", "two"); assertThat(values).hasSize(2); - assertThat(values.containsAll(list("1", "1"))).isTrue(); + assertThat(values.containsAll(list(kv("one", "1"), kv("two", "2")))).isTrue(); } private void setupHmget() { - assertThat(redis.hmget(key, "one", "two")).isEqualTo(list(null, null)); + assertThat(redis.hmget(key, "one", "two")).isEqualTo(list(KeyValue.empty("one"), KeyValue.empty("two"))); redis.hset(key, "one", "1"); redis.hset(key, "two", "2"); } @@ -145,12 +146,12 @@ private void setupHmget() { public void hmgetStreaming() throws Exception { setupHmget(); - ListStreamingAdapter streamingAdapter = new ListStreamingAdapter(); + KeyValueStreamingAdapter streamingAdapter = new KeyValueStreamingAdapter<>(); Long count = redis.hmget(streamingAdapter, key, "one", "two"); - List values = streamingAdapter.getList(); + Map values = streamingAdapter.getMap(); assertThat(count.intValue()).isEqualTo(2); assertThat(values).hasSize(2); - assertThat(values.containsAll(list("1", "1"))).isTrue(); + assertThat(values).containsEntry("one", "1").containsEntry("two", "2"); } @Test @@ -159,7 +160,7 @@ public void hmset() throws Exception { hash.put("one", "1"); hash.put("two", "2"); assertThat(redis.hmset(key, hash)).isEqualTo("OK"); - assertThat(redis.hmget(key, "one", "two")).isEqualTo(list("1", "2")); + assertThat(redis.hmget(key, "one", "two")).isEqualTo(list(kv("one", "1"), kv("two", "2"))); } @Test @@ -167,11 +168,11 @@ public void hmsetWithNulls() throws Exception { Map hash = new LinkedHashMap<>(); hash.put("one", null); assertThat(redis.hmset(key, hash)).isEqualTo("OK"); - assertThat(redis.hmget(key, "one")).isEqualTo(list("")); + assertThat(redis.hmget(key, "one")).isEqualTo(list(kv("one", ""))); hash.put("one", ""); assertThat(redis.hmset(key, hash)).isEqualTo("OK"); - assertThat(redis.hmget(key, "one")).isEqualTo(list("")); + assertThat(redis.hmget(key, "one")).isEqualTo(list(kv("one", ""))); } @Test diff --git a/src/test/java/com/lambdaworks/redis/commands/StringCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/StringCommandTest.java index 533da3a708..0b4455505e 100644 --- a/src/test/java/com/lambdaworks/redis/commands/StringCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/StringCommandTest.java @@ -12,16 +12,12 @@ import java.util.List; import java.util.Map; +import com.lambdaworks.redis.*; import com.lambdaworks.redis.codec.ByteArrayCodec; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; -import com.lambdaworks.redis.AbstractRedisClientTest; -import com.lambdaworks.redis.ListStreamingAdapter; -import com.lambdaworks.redis.RedisCommandExecutionException; -import com.lambdaworks.redis.RedisException; - public class StringCommandTest extends AbstractRedisClientTest { @Rule public ExpectedException exception = ExpectedException.none(); @@ -64,11 +60,11 @@ public void getset() throws Exception { @Test public void mget() throws Exception { setupMget(); - assertThat(redis.mget("one", "two")).isEqualTo(list("1", "2") ); + assertThat(redis.mget("one", "two")).isEqualTo(list(kv("one", "1"), kv("two", "2"))); } protected void setupMget() { - assertThat(redis.mget(key)).isEqualTo(list((String) null)); + assertThat(redis.mget(key)).isEqualTo(list(KeyValue.empty("key"))); redis.set("one", "1"); redis.set("two", "2"); } @@ -77,21 +73,21 @@ protected void setupMget() { public void mgetStreaming() throws Exception { setupMget(); - ListStreamingAdapter streamingAdapter = new ListStreamingAdapter(); + KeyValueStreamingAdapter streamingAdapter = new KeyValueStreamingAdapter<>(); Long count = redis.mget(streamingAdapter, "one", "two"); assertThat(count.intValue()).isEqualTo(2); - assertThat(streamingAdapter.getList()).isEqualTo(list("1", "2")); + assertThat(streamingAdapter.getMap()).containsEntry("one", "1").containsEntry("two", "2"); } @Test public void mset() throws Exception { - assertThat(redis.mget("one", "two")).isEqualTo(list(null, null)); + assertThat(redis.mget("one", "two")).isEqualTo(list(KeyValue.empty("one"), KeyValue.empty("two"))); Map map = new LinkedHashMap<>(); map.put("one", "1"); map.put("two", "2"); assertThat(redis.mset(map)).isEqualTo("OK"); - assertThat(redis.mget("one", "two")).isEqualTo(list("1", "2")); + assertThat(redis.mget("one", "two")).isEqualTo(list(kv("one", "1"), kv("two", "2"))); } @Test diff --git a/src/test/java/com/lambdaworks/redis/commands/TransactionCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/TransactionCommandTest.java index f041c5f8f8..a280093076 100644 --- a/src/test/java/com/lambdaworks/redis/commands/TransactionCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/TransactionCommandTest.java @@ -71,7 +71,7 @@ public void execmulti() throws Exception { redis.set("two", "2"); redis.mget("one", "two"); redis.llen(key); - assertThat(redis.exec()).isEqualTo(list("OK", "OK", list("1", "2"), 0L)); + assertThat(redis.exec()).isEqualTo(list("OK", "OK", list(kv("one", "1"), kv("two", "2")), 0L)); } @Test diff --git a/src/test/java/com/lambdaworks/redis/commands/rx/StringRxCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/rx/StringRxCommandTest.java index 5157f6deff..0392f10e40 100644 --- a/src/test/java/com/lambdaworks/redis/commands/rx/StringRxCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/rx/StringRxCommandTest.java @@ -2,6 +2,7 @@ import static org.assertj.core.api.Assertions.assertThat; +import com.lambdaworks.redis.KeyValue; import com.lambdaworks.util.RxSyncInvocationHandler; import org.junit.Test; @@ -26,9 +27,23 @@ public void mget() throws Exception { connection.sync().set("key1", value); connection.sync().set("key2", value); - Observable mget = connection.reactive().mget(key, "key1", "key2"); - String first = mget.toBlocking().first(); - assertThat(first).isEqualTo(value); + Observable> mget = connection.reactive().mget(key, "key1", "key2"); + KeyValue first = mget.toBlocking().first(); + assertThat(first).isEqualTo(KeyValue.just(key, value)); + + connection.close(); + } + + @Test + public void mgetEmpty() throws Exception { + + StatefulRedisConnection connection = client.connect(); + + connection.sync().set(key, value); + + Observable> mget = connection.reactive().mget("unknown"); + KeyValue first = mget.toBlocking().first(); + assertThat(first).isEqualTo(KeyValue.empty("unknown")); connection.close(); } diff --git a/src/test/java/com/lambdaworks/redis/commands/rx/TransactionRxCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/rx/TransactionRxCommandTest.java index 24741dd299..487f9eea93 100644 --- a/src/test/java/com/lambdaworks/redis/commands/rx/TransactionRxCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/rx/TransactionRxCommandTest.java @@ -5,17 +5,18 @@ import java.util.Iterator; import java.util.List; -import com.lambdaworks.util.RxSyncInvocationHandler; import org.junit.After; import org.junit.Before; import org.junit.Test; import com.lambdaworks.redis.ClientOptions; +import com.lambdaworks.redis.KeyValue; import com.lambdaworks.redis.RedisException; import com.lambdaworks.redis.api.rx.RedisReactiveCommands; import com.lambdaworks.redis.api.sync.RedisCommands; import com.lambdaworks.redis.commands.TransactionCommandTest; import com.lambdaworks.redis.internal.LettuceLists; +import com.lambdaworks.util.RxSyncInvocationHandler; import rx.Observable; import rx.Single; @@ -85,7 +86,7 @@ public void resultOfMultiIsContainedInCommandObservables() throws Exception { TestSubscriber set1 = TestSubscriber.create(); TestSubscriber set2 = TestSubscriber.create(); - TestSubscriber mget = TestSubscriber.create(); + TestSubscriber> mget = TestSubscriber.create(); TestSubscriber llen = TestSubscriber.create(); TestSubscriber exec = TestSubscriber.create(); @@ -100,7 +101,7 @@ public void resultOfMultiIsContainedInCommandObservables() throws Exception { set1.assertValue("OK"); set2.assertValue("OK"); - mget.assertValues("value1", "value2"); + mget.assertValues(KeyValue.just("key1", "value1"), KeyValue.just("key2", "value2")); llen.assertValue(0L); } @@ -118,7 +119,8 @@ public void resultOfMultiIsContainedInExecObservable() throws Exception { exec.awaitTerminalEvent(); - assertThat(exec.getOnNextEvents()).hasSize(4).containsExactly("OK", "OK", list("value1", "value2"), 0L); + assertThat(exec.getOnNextEvents()).hasSize(4).containsExactly("OK", "OK", + list(kv("key1", "value1"), kv("key2", "value2")), 0L); } protected T first(Observable observable) { From 703e1e6e5550f258f5573a25e43d11f4f65f9bfc Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Wed, 27 Jul 2016 23:15:50 +0200 Subject: [PATCH 010/808] Use TransactionResult for transaction results #320 Use TransactionResult instead of List to encapsulate transactional results. TransactionResult carries the details about rollback and the transaction responses. Using TransactionResult avoids a null response in case the transaction was rolled back. --- .../redis/AbstractRedisAsyncCommands.java | 2 +- .../redis/AbstractRedisReactiveCommands.java | 4 +- .../lambdaworks/redis/TransactionResult.java | 51 ++++++++++++++ .../RedisTransactionalAsyncCommands.java | 4 +- .../RedisTransactionalReactiveCommands.java | 4 +- .../api/sync/RedisTransactionalCommands.java | 4 +- .../output/DefaultTransactionResult.java | 68 +++++++++++++++++++ .../lambdaworks/redis/output/MultiOutput.java | 24 ++++++- .../redis/api/RedisTransactionalCommands.java | 3 +- .../redis/AsyncConnectionTest.java | 4 +- .../redis/commands/CustomCommandTest.java | 3 +- .../redis/commands/GeoCommandTest.java | 36 +++++----- .../commands/TransactionCommandTest.java | 34 +++++++--- .../commands/rx/TransactionRxCommandTest.java | 13 ++-- .../util/RxSyncInvocationHandler.java | 2 - 15 files changed, 207 insertions(+), 49 deletions(-) create mode 100644 src/main/java/com/lambdaworks/redis/TransactionResult.java create mode 100644 src/main/java/com/lambdaworks/redis/output/DefaultTransactionResult.java diff --git a/src/main/java/com/lambdaworks/redis/AbstractRedisAsyncCommands.java b/src/main/java/com/lambdaworks/redis/AbstractRedisAsyncCommands.java index c383cc75a8..1d94b78a6b 100644 --- a/src/main/java/com/lambdaworks/redis/AbstractRedisAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/AbstractRedisAsyncCommands.java @@ -346,7 +346,7 @@ public RedisFuture expireat(K key, long timestamp) { } @Override - public RedisFuture> exec() { + public RedisFuture exec() { return dispatch(EXEC, null); } diff --git a/src/main/java/com/lambdaworks/redis/AbstractRedisReactiveCommands.java b/src/main/java/com/lambdaworks/redis/AbstractRedisReactiveCommands.java index e2094cd235..d1e64e471e 100644 --- a/src/main/java/com/lambdaworks/redis/AbstractRedisReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/AbstractRedisReactiveCommands.java @@ -349,8 +349,8 @@ public Single expireat(K key, Date timestamp) { } @Override - public Observable exec() { - return createDissolvingObservable(EXEC, null, null); + public Single exec() { + return createSingle(EXEC, null, null); } @Override diff --git a/src/main/java/com/lambdaworks/redis/TransactionResult.java b/src/main/java/com/lambdaworks/redis/TransactionResult.java new file mode 100644 index 0000000000..0bb9afdef8 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/TransactionResult.java @@ -0,0 +1,51 @@ +package com.lambdaworks.redis; + +import java.util.List; +import java.util.stream.Stream; + +/** + * Value interface for a {@code MULTI} transaction result. {@link TransactionResult} contains whether the transaction was rolled + * back (i.e. conditional transaction using {@code WATCH}) and the {@link List} of transaction responses. + * + * @author Mark Paluch + * @since 5.0 + */ +public interface TransactionResult extends Iterable { + + /** + * + * @return {@literal true} if the transaction was rolled back + */ + boolean wasRolledBack(); + + /** + * Returns the number of elements in this collection. If this {@link TransactionResult} contains more than + * {@link Integer#MAX_VALUE} elements, returns {@link Integer#MAX_VALUE}. + * + * @return the number of elements in this collection + */ + int size(); + + /** + * Returns {@literal true} if this {@link TransactionResult} contains no elements. + * + * @return {@literal true} if this {@link TransactionResult} contains no elements + */ + boolean isEmpty(); + + /** + * Returns the element at the specified position in this {@link TransactionResult}. + * + * @param index index of the element to return + * @return the element at the specified position in this {@link TransactionResult} + * @throws IndexOutOfBoundsException if the index is out of range (index < 0 || index >= size()) + */ + T get(int index); + + /** + * Returns a sequential {@code Stream} with this {@link TransactionResult} as its source. + * + * @return a sequential {@code Stream} over the elements in this {@link TransactionResult} + */ + Stream stream(); +} diff --git a/src/main/java/com/lambdaworks/redis/api/async/RedisTransactionalAsyncCommands.java b/src/main/java/com/lambdaworks/redis/api/async/RedisTransactionalAsyncCommands.java index bd35a19d01..d0cf372d5c 100644 --- a/src/main/java/com/lambdaworks/redis/api/async/RedisTransactionalAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/async/RedisTransactionalAsyncCommands.java @@ -1,7 +1,7 @@ package com.lambdaworks.redis.api.async; -import java.util.List; import com.lambdaworks.redis.RedisFuture; +import com.lambdaworks.redis.TransactionResult; /** * Asynchronous executed commands for Transactions. @@ -28,7 +28,7 @@ public interface RedisTransactionalAsyncCommands { * * When using {@code WATCH}, {@code EXEC} can return a */ - RedisFuture> exec(); + RedisFuture exec(); /** * Mark the start of a transaction block. diff --git a/src/main/java/com/lambdaworks/redis/api/rx/RedisTransactionalReactiveCommands.java b/src/main/java/com/lambdaworks/redis/api/rx/RedisTransactionalReactiveCommands.java index 5472ecff6d..aa8b83033c 100644 --- a/src/main/java/com/lambdaworks/redis/api/rx/RedisTransactionalReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/rx/RedisTransactionalReactiveCommands.java @@ -1,6 +1,8 @@ package com.lambdaworks.redis.api.rx; import java.util.List; + +import com.lambdaworks.redis.TransactionResult; import rx.Observable; import rx.Single; import rx.Completable; @@ -30,7 +32,7 @@ public interface RedisTransactionalReactiveCommands { * * When using {@code WATCH}, {@code EXEC} can return a */ - Observable exec(); + Single exec(); /** * Mark the start of a transaction block. diff --git a/src/main/java/com/lambdaworks/redis/api/sync/RedisTransactionalCommands.java b/src/main/java/com/lambdaworks/redis/api/sync/RedisTransactionalCommands.java index 9867968dd3..0c2add2174 100644 --- a/src/main/java/com/lambdaworks/redis/api/sync/RedisTransactionalCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/sync/RedisTransactionalCommands.java @@ -1,6 +1,6 @@ package com.lambdaworks.redis.api.sync; -import java.util.List; +import com.lambdaworks.redis.TransactionResult; /** * Synchronous executed commands for Transactions. @@ -27,7 +27,7 @@ public interface RedisTransactionalCommands { * * When using {@code WATCH}, {@code EXEC} can return a */ - List exec(); + TransactionResult exec(); /** * Mark the start of a transaction block. diff --git a/src/main/java/com/lambdaworks/redis/output/DefaultTransactionResult.java b/src/main/java/com/lambdaworks/redis/output/DefaultTransactionResult.java new file mode 100644 index 0000000000..3e73fdf480 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/output/DefaultTransactionResult.java @@ -0,0 +1,68 @@ +package com.lambdaworks.redis.output; + +import java.util.Iterator; +import java.util.List; +import java.util.stream.Stream; + +import com.lambdaworks.redis.TransactionResult; +import com.lambdaworks.redis.internal.LettuceAssert; + +/** + * Result of a {@code MULTI} transaction. + * + * @author Mark Paluch + * @since 5.0 + */ +class DefaultTransactionResult implements Iterable, TransactionResult { + + private final boolean wasRolledBack; + private final List result; + + /** + * Creates a new {@link DefaultTransactionResult}. + * + * @param wasRolledBack {@literal true} if the transaction was rolled back. + * @param result the transaction result, must not be {@literal null}. + */ + public DefaultTransactionResult(boolean wasRolledBack, List result) { + + LettuceAssert.notNull(result, "Result must not be null"); + + this.wasRolledBack = wasRolledBack; + this.result = result; + } + + /** + * + * @return {@literal true} if the transaction was rolled back + */ + @Override + public boolean wasRolledBack() { + return wasRolledBack; + } + + @Override + public Iterator iterator() { + return result.iterator(); + } + + @Override + public int size() { + return result.size(); + } + + @Override + public boolean isEmpty() { + return result.isEmpty(); + } + + @Override + public T get(int index) { + return (T) result.get(index); + } + + @Override + public Stream stream() { + return result.stream(); + } +} diff --git a/src/main/java/com/lambdaworks/redis/output/MultiOutput.java b/src/main/java/com/lambdaworks/redis/output/MultiOutput.java index 953fe37200..77aec87804 100644 --- a/src/main/java/com/lambdaworks/redis/output/MultiOutput.java +++ b/src/main/java/com/lambdaworks/redis/output/MultiOutput.java @@ -8,6 +8,7 @@ import java.util.Queue; import com.lambdaworks.redis.RedisCommandExecutionException; +import com.lambdaworks.redis.TransactionResult; import com.lambdaworks.redis.codec.RedisCodec; import com.lambdaworks.redis.internal.LettuceFactories; import com.lambdaworks.redis.protocol.RedisCommand; @@ -18,12 +19,16 @@ * @param Key type. * @param Value type. * @author Will Glozer + * @author Mark Paluch */ -public class MultiOutput extends CommandOutput> { +public class MultiOutput extends CommandOutput { + private final Queue> queue; + private List responses = new ArrayList<>(); + private Boolean rolledBack; public MultiOutput(RedisCodec codec) { - super(codec, new ArrayList<>()); + super(codec, null); queue = LettuceFactories.newSpScQueue(); } @@ -56,6 +61,14 @@ public void set(ByteBuffer bytes) { @Override public void multi(int count) { + if (rolledBack == null) { + if (count == -1) { + rolledBack = true; + } else { + rolledBack = false; + } + } + if (count == -1 && !queue.isEmpty()) { queue.peek().getOutput().multi(count); } @@ -82,7 +95,7 @@ public void complete(int depth) { if (depth == 1) { RedisCommand cmd = queue.remove(); CommandOutput o = cmd.getOutput(); - output.add(!o.hasError() ? o.get() : new RedisCommandExecutionException(o.getError())); + responses.add(!o.hasError() ? o.get() : new RedisCommandExecutionException(o.getError())); cmd.complete(); } else if (depth == 0 && !queue.isEmpty()) { for (RedisCommand cmd : queue) { @@ -90,4 +103,9 @@ public void complete(int depth) { } } } + + @Override + public TransactionResult get() { + return new DefaultTransactionResult(rolledBack == null ? false : rolledBack, responses); + } } diff --git a/src/main/templates/com/lambdaworks/redis/api/RedisTransactionalCommands.java b/src/main/templates/com/lambdaworks/redis/api/RedisTransactionalCommands.java index 5da386726d..e6ef5e1c36 100644 --- a/src/main/templates/com/lambdaworks/redis/api/RedisTransactionalCommands.java +++ b/src/main/templates/com/lambdaworks/redis/api/RedisTransactionalCommands.java @@ -1,6 +1,7 @@ package com.lambdaworks.redis.api; import java.util.List; +import com.lambdaworks.redis.TransactionResult; /** * ${intent} for Transactions. @@ -26,7 +27,7 @@ public interface RedisTransactionalCommands { * * When using {@code WATCH}, {@code EXEC} can return a */ - List exec(); + TransactionResult exec(); /** * Mark the start of a transaction block. diff --git a/src/test/java/com/lambdaworks/redis/AsyncConnectionTest.java b/src/test/java/com/lambdaworks/redis/AsyncConnectionTest.java index 00bd094582..052535163c 100644 --- a/src/test/java/com/lambdaworks/redis/AsyncConnectionTest.java +++ b/src/test/java/com/lambdaworks/redis/AsyncConnectionTest.java @@ -41,7 +41,7 @@ public void multi() throws Exception { Future> lrange = async.lrange("list", 0, -1); assertThat(!set.isDone() && !rpush.isDone() && !rpush.isDone()).isTrue(); - assertThat(async.exec().get()).isEqualTo(list("OK", 2L, list("1", "2"))); + assertThat(async.exec().get()).contains("OK", 2L, list("1", "2")); assertThat(set.get()).isEqualTo("OK"); assertThat((long) rpush.get()).isEqualTo(2L); @@ -57,7 +57,7 @@ public void watch() throws Exception { async.multi(); Future set = async.set(key, value); Future append = async.append(key, "foo"); - assertThat(async.exec().get()).isEqualTo(list()); + assertThat(async.exec().get()).isEmpty(); assertThat(set.get()).isNull(); assertThat(append.get()).isNull(); } diff --git a/src/test/java/com/lambdaworks/redis/commands/CustomCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/CustomCommandTest.java index a9ff76e586..6299f62558 100644 --- a/src/test/java/com/lambdaworks/redis/commands/CustomCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/CustomCommandTest.java @@ -5,6 +5,7 @@ import java.util.List; +import com.lambdaworks.redis.TransactionResult; import org.junit.Test; import com.lambdaworks.redis.AbstractRedisClientTest; @@ -56,7 +57,7 @@ public void dispatchTransactions() throws Exception { String response = redis.dispatch(CommandType.SET, new StatusOutput<>(utf8StringCodec), new CommandArgs<>(utf8StringCodec).addKey(key).addValue(value)); - List exec = redis.exec(); + TransactionResult exec = redis.exec(); assertThat(response).isNull(); assertThat(exec).hasSize(1).contains("OK"); diff --git a/src/test/java/com/lambdaworks/redis/commands/GeoCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/GeoCommandTest.java index 67a58fb959..43b2c813fa 100644 --- a/src/test/java/com/lambdaworks/redis/commands/GeoCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/GeoCommandTest.java @@ -85,9 +85,9 @@ public void georadiusWithTransaction() throws Exception { redis.georadius(key, 8.6582861, 49.5285695, 1, GeoArgs.Unit.km); redis.georadius(key, 8.6582861, 49.5285695, 5, GeoArgs.Unit.km); - List exec = redis.exec(); - Set georadius = (Set) exec.get(0); - Set largerGeoradius = (Set) exec.get(1); + TransactionResult exec = redis.exec(); + Set georadius = exec.get(0); + Set largerGeoradius = exec.get(1); assertThat(georadius).hasSize(1).contains("Weinheim"); assertThat(largerGeoradius).hasSize(2).contains("Weinheim").contains("Bahn"); @@ -186,11 +186,11 @@ public void georadiusWithArgsAndTransaction() throws Exception { GeoArgs geoArgs = new GeoArgs().withHash().withCoordinates().withDistance().withCount(1).desc(); redis.georadius(key, 8.665351, 49.553302, 5, GeoArgs.Unit.km, geoArgs); redis.georadius(key, 8.665351, 49.553302, 5, GeoArgs.Unit.km, geoArgs); - List exec = redis.exec(); + TransactionResult exec = redis.exec(); assertThat(exec).hasSize(2); - List> result = (List) exec.get(1); + List> result = exec.get(1); assertThat(result).hasSize(1); GeoWithin weinheim = result.get(0); @@ -242,9 +242,9 @@ public void geohashWithTransaction() throws Exception { redis.multi(); redis.geohash(key, "Weinheim", "Bahn", "dunno"); redis.geohash(key, "Weinheim", "Bahn", "dunno"); - List exec = redis.exec(); + TransactionResult exec = redis.exec(); - List geohash = (List) exec.get(1); + List geohash = exec.get(1); assertThat(geohash).containsSequence("u0y1v0kffz0", "u0y1vhvuvm0", null); } @@ -269,8 +269,8 @@ public void georadiusStoreWithCountAndSort() throws Exception { prepareGeo(); String resultKey = "38o54"; // yields in same slot as "key" - Long result = redis.georadius(key, 8.665351, 49.553302, 5, GeoArgs.Unit.km, new GeoRadiusStoreArgs<>().withCount(1) - .desc().withStore(resultKey)); + Long result = redis.georadius(key, 8.665351, 49.553302, 5, GeoArgs.Unit.km, + new GeoRadiusStoreArgs<>().withCount(1).desc().withStore(resultKey)); assertThat(result).isEqualTo(1); List> results = redis.zrangeWithScores(resultKey, 0, -1); @@ -298,8 +298,8 @@ public void georadiusStoreDistWithCountAndSort() throws Exception { prepareGeo(); String resultKey = "38o54"; // yields in same slot as "key" - Long result = redis.georadius(key, 8.665351, 49.553302, 5, GeoArgs.Unit.km, new GeoRadiusStoreArgs<>().withCount(1) - .desc().withStoreDist("38o54")); + Long result = redis.georadius(key, 8.665351, 49.553302, 5, GeoArgs.Unit.km, + new GeoRadiusStoreArgs<>().withCount(1).desc().withStoreDist("38o54")); assertThat(result).isEqualTo(1); List> dist = redis.zrangeWithScores(resultKey, 0, -1); @@ -336,8 +336,8 @@ public void georadiusbymemberStoreDistWithCountAndSort() throws Exception { prepareGeo(); String resultKey = "38o54"; // yields in same slot as "key" - Long result = redis.georadiusbymember(key, "Bahn", 5, GeoArgs.Unit.km, new GeoRadiusStoreArgs<>().withCount(1).desc() - .withStoreDist("38o54")); + Long result = redis.georadiusbymember(key, "Bahn", 5, GeoArgs.Unit.km, + new GeoRadiusStoreArgs<>().withCount(1).desc().withStoreDist("38o54")); assertThat(result).isEqualTo(1); List> dist = redis.zrangeWithScores(resultKey, 0, -1); @@ -398,12 +398,12 @@ public void georadiusbymemberWithArgsAndTransaction() throws Exception { redis.georadiusbymember(key, "Bahn", 5, GeoArgs.Unit.km, new GeoArgs().withDistance().withHash().desc()); redis.georadiusbymember(key, "Bahn", 5, GeoArgs.Unit.km, new GeoArgs().withCoordinates().desc()); - List exec = redis.exec(); + TransactionResult exec = redis.exec(); - List> empty = (List) exec.get(0); + List> empty = exec.get(0); assertThat(empty).isNotEmpty(); - List> withDistanceAndCoordinates = (List) exec.get(1); + List> withDistanceAndCoordinates = exec.get(1); assertThat(withDistanceAndCoordinates).hasSize(2); GeoWithin weinheim = withDistanceAndCoordinates.get(0); @@ -412,7 +412,7 @@ public void georadiusbymemberWithArgsAndTransaction() throws Exception { assertThat(weinheim.distance).isNotNull(); assertThat(weinheim.coordinates).isNotNull(); - List> withDistanceAndHash = (List) exec.get(2); + List> withDistanceAndHash = exec.get(2); assertThat(withDistanceAndHash).hasSize(2); GeoWithin weinheimDistanceHash = withDistanceAndHash.get(0); @@ -421,7 +421,7 @@ public void georadiusbymemberWithArgsAndTransaction() throws Exception { assertThat(weinheimDistanceHash.distance).isNotNull(); assertThat(weinheimDistanceHash.coordinates).isNull(); - List> withCoordinates = (List) exec.get(3); + List> withCoordinates = exec.get(3); assertThat(withCoordinates).hasSize(2); GeoWithin weinheimCoordinates = withCoordinates.get(0); diff --git a/src/test/java/com/lambdaworks/redis/commands/TransactionCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/TransactionCommandTest.java index a280093076..9b89a9a946 100644 --- a/src/test/java/com/lambdaworks/redis/commands/TransactionCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/TransactionCommandTest.java @@ -6,6 +6,7 @@ import java.util.List; +import com.lambdaworks.redis.TransactionResult; import org.assertj.core.api.Assertions; import org.junit.Rule; import org.junit.Test; @@ -32,7 +33,7 @@ public void discard() throws Exception { public void exec() throws Exception { assertThat(redis.multi()).isEqualTo("OK"); redis.set(key, value); - assertThat(redis.exec()).isEqualTo(list("OK")); + assertThat(redis.exec()).contains("OK"); assertThat(redis.get(key)).isEqualTo(value); } @@ -46,7 +47,11 @@ public void watch() throws Exception { redis.multi(); redis.append(key, "foo"); - assertThat(redis.exec()).isEqualTo(list()); + + TransactionResult transactionResult = redis.exec(); + + assertThat(transactionResult.wasRolledBack()).isTrue(); + assertThat(transactionResult).isEmpty(); } @@ -57,10 +62,15 @@ public void unwatch() throws Exception { @Test public void commandsReturnNullInMulti() throws Exception { + assertThat(redis.multi()).isEqualTo("OK"); assertThat(redis.set(key, value)).isNull(); assertThat(redis.get(key)).isNull(); - assertThat(redis.exec()).isEqualTo(list("OK", value)); + + TransactionResult exec = redis.exec(); + assertThat(exec.wasRolledBack()).isFalse(); + assertThat(exec).contains("OK", value); + assertThat(redis.get(key)).isEqualTo(value); } @@ -71,7 +81,15 @@ public void execmulti() throws Exception { redis.set("two", "2"); redis.mget("one", "two"); redis.llen(key); - assertThat(redis.exec()).isEqualTo(list("OK", "OK", list(kv("one", "1"), kv("two", "2")), 0L)); + assertThat(redis.exec()).contains("OK", "OK", list(kv("one", "1"), kv("two", "2")), 0L); + } + + @Test + public void emptyMulti() throws Exception { + redis.multi(); + TransactionResult exec = redis.exec(); + assertThat(exec.wasRolledBack()).isFalse(); + assertThat(exec).isEmpty(); } @Test @@ -80,10 +98,11 @@ public void errorInMulti() throws Exception { redis.set(key, value); redis.lpop(key); redis.get(key); - List values = redis.exec(); - assertThat(values.get(0)).isEqualTo("OK"); + TransactionResult values = redis.exec(); + assertThat(values.wasRolledBack()).isFalse(); + assertThat((String) values.get(0)).isEqualTo("OK"); assertThat(values.get(1) instanceof RedisException).isTrue(); - assertThat(values.get(2)).isEqualTo(value); + assertThat((String) values.get(2)).isEqualTo(value); } @Test @@ -92,5 +111,4 @@ public void execWithoutMulti() throws Exception { exception.expectMessage("ERR EXEC without MULTI"); redis.exec(); } - } diff --git a/src/test/java/com/lambdaworks/redis/commands/rx/TransactionRxCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/rx/TransactionRxCommandTest.java index 487f9eea93..6eebbd37e7 100644 --- a/src/test/java/com/lambdaworks/redis/commands/rx/TransactionRxCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/rx/TransactionRxCommandTest.java @@ -5,6 +5,7 @@ import java.util.Iterator; import java.util.List; +import com.lambdaworks.redis.TransactionResult; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -64,7 +65,7 @@ public void execSingular() throws Exception { redis.set(key, value); - assertThat(first(commands.exec())).isEqualTo("OK"); + assertThat(block(commands.exec())).contains("OK"); assertThat(block(commands.get(key))).isEqualTo(value); } @@ -75,10 +76,10 @@ public void errorInMulti() throws Exception { commands.lpop(key).subscribe(TestSubscriber.create()); commands.get(key).subscribe(TestSubscriber.create()); - List values = all(commands.exec()); - assertThat(values.get(0)).isEqualTo("OK"); + TransactionResult values = block(commands.exec()); + assertThat((String) values.get(0)).isEqualTo("OK"); assertThat(values.get(1) instanceof RedisException).isTrue(); - assertThat(values.get(2)).isEqualTo(value); + assertThat((String) values.get(2)).isEqualTo(value); } @Test @@ -108,7 +109,7 @@ public void resultOfMultiIsContainedInCommandObservables() throws Exception { @Test public void resultOfMultiIsContainedInExecObservable() throws Exception { - TestSubscriber exec = TestSubscriber.create(); + TestSubscriber exec = TestSubscriber.create(); commands.multi().subscribe(); commands.set("key1", "value1").subscribe(); @@ -119,7 +120,7 @@ public void resultOfMultiIsContainedInExecObservable() throws Exception { exec.awaitTerminalEvent(); - assertThat(exec.getOnNextEvents()).hasSize(4).containsExactly("OK", "OK", + assertThat(exec.getOnNextEvents().get(0)).hasSize(4).containsExactly("OK", "OK", list(kv("key1", "value1"), kv("key2", "value2")), 0L); } diff --git a/src/test/java/com/lambdaworks/util/RxSyncInvocationHandler.java b/src/test/java/com/lambdaworks/util/RxSyncInvocationHandler.java index 46bd2f18bd..1b93cc6f4e 100644 --- a/src/test/java/com/lambdaworks/util/RxSyncInvocationHandler.java +++ b/src/test/java/com/lambdaworks/util/RxSyncInvocationHandler.java @@ -31,12 +31,10 @@ public class RxSyncInvocationHandler extends ConnectionDecoratingInvocationHandler { private final StatefulConnection connection; - private final Object rxApi; public RxSyncInvocationHandler(StatefulConnection connection, Object rxApi) { super(rxApi); this.connection = connection; - this.rxApi = rxApi; } @Override From d450ce78bcd9eec86dac5d24561fae235601c355 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Wed, 31 Aug 2016 15:59:00 +0200 Subject: [PATCH 011/808] Migrate lettuce reactive API to Reactive Streams #349 --- pom.xml | 26 +- .../redis/AbstractRedisAsyncCommands.java | 4 +- .../redis/AbstractRedisReactiveCommands.java | 1422 ++++++++--------- .../lambdaworks/redis/BackpressureUtils.java | 146 ++ .../redis/ReactiveCommandDispatcher.java | 329 ---- .../redis/RedisCommandBuilder.java | 6 +- .../com/lambdaworks/redis/RedisPublisher.java | 578 +++++++ .../redis/RedisReactiveCommandsImpl.java | 4 +- .../redis/StatefulRedisConnectionImpl.java | 2 +- .../redis/api/StatefulRedisConnection.java | 2 +- .../api/async/RedisGeoAsyncCommands.java | 11 +- .../api/async/RedisStringAsyncCommands.java | 7 +- .../RedisTransactionalAsyncCommands.java | 3 +- .../BaseRedisReactiveCommands.java | 37 +- .../RedisGeoReactiveCommands.java | 37 +- .../RedisHLLReactiveCommands.java | 15 +- .../RedisHashReactiveCommands.java | 61 +- .../RedisKeyReactiveCommands.java | 89 +- .../RedisListReactiveCommands.java | 45 +- .../RedisReactiveCommands.java | 15 +- .../RedisScriptingReactiveCommands.java | 25 +- .../RedisServerReactiveCommands.java | 91 +- .../RedisSetReactiveCommands.java | 67 +- .../RedisSortedSetReactiveCommands.java | 157 +- .../RedisStringReactiveCommands.java | 71 +- .../RedisTransactionalReactiveCommands.java | 20 +- .../api/{rx => reactive}/package-info.java | 2 +- .../com/lambdaworks/redis/api/rx/Success.java | 10 - .../redis/api/sync/RedisGeoCommands.java | 12 +- .../redis/api/sync/RedisStringCommands.java | 2 - .../api/sync/RedisTransactionalCommands.java | 1 + .../redis/cluster/ClusterScanSupport.java | 20 +- ...isAdvancedClusterReactiveCommandsImpl.java | 214 ++- .../StatefulRedisClusterConnectionImpl.java | 2 +- .../api/StatefulRedisClusterConnection.java | 2 +- .../async/NodeSelectionGeoAsyncCommands.java | 11 +- .../async/NodeSelectionSetAsyncCommands.java | 1 - .../NodeSelectionStringAsyncCommands.java | 7 +- .../RedisAdvancedClusterReactiveCommands.java | 69 +- .../RedisClusterReactiveCommands.java | 84 +- .../api/{rx => reactive}/package-info.java | 2 +- .../api/sync/NodeSelectionGeoCommands.java | 10 +- .../api/sync/NodeSelectionStringCommands.java | 3 +- .../redis/event/DefaultEventBus.java | 19 +- .../com/lambdaworks/redis/event/EventBus.java | 6 +- .../output/GeoCoordinatesListOutput.java | 13 +- .../redis/output/StringValueListOutput.java | 46 + .../RedisPubSubReactiveCommandsImpl.java | 145 +- .../pubsub/StatefulRedisPubSubConnection.java | 2 +- .../StatefulRedisPubSubConnectionImpl.java | 2 +- .../api/{rx => reactive}/ChannelMessage.java | 2 +- .../api/{rx => reactive}/PatternMessage.java | 2 +- .../reactive/RedisPubSubReactiveCommands.java | 116 ++ .../api/{rx => reactive}/package-info.java | 2 +- .../api/rx/RedisPubSubReactiveCommands.java | 87 - .../resource/DefaultClientResources.java | 3 +- .../RxJavaEventExecutorGroupScheduler.java | 106 -- .../RedisSentinelReactiveCommandsImpl.java | 79 +- .../StatefulRedisSentinelConnectionImpl.java | 2 +- .../api/StatefulRedisSentinelConnection.java | 6 +- .../RedisSentinelReactiveCommands.java | 29 +- .../redis/sentinel/api/rx/package-info.java | 4 - .../redis/api/RedisGeoCommands.java | 9 +- .../redis/api/RedisSetCommands.java | 1 + src/site/markdown/download.md.vm | 3 +- src/site/markdown/index.md.vm | 8 +- .../redis/extensibility/LettuceGeoDemo.java | 4 +- .../apigenerator/CreateReactiveApi.java | 22 +- .../lambdaworks/redis/ClientMetricsTest.java | 70 +- .../lambdaworks/redis/CustomCodecTest.java | 8 +- .../redis/LettucePerformanceTest.java | 39 +- .../redis/ReactiveConnectionTest.java | 68 +- .../redis/ReactiveStreamingOutputTest.java | 53 +- .../cluster/AdvancedClusterClientTest.java | 4 +- .../cluster/AdvancedClusterReactiveTest.java | 38 +- .../cluster/ClusterReactiveCommandTest.java | 12 +- ...va => RedisReactiveClusterClientTest.java} | 55 +- .../commands/CustomClusterCommandTest.java | 16 - .../HashClusterReactiveCommandTest.java} | 8 +- .../KeyClusterReativeCommandTest.java} | 8 +- .../ListClusterRxCommandTest.java | 7 +- .../StringClusterReactiveCommandTest.java} | 16 +- .../redis/commands/CustomCommandTest.java | 21 +- .../redis/commands/GeoCommandTest.java | 26 +- .../reactive/BitReactiveCommandTest.java | 17 + .../reactive/CustomReactiveCommandTest.java | 57 + .../reactive/GeoReactiveCommandTest.java | 13 + .../reactive/HLLReactiveCommandTest.java | 13 + .../reactive/HashReactiveCommandTest.java | 14 + .../reactive/KeyReactiveCommandTest.java | 12 + .../reactive/ListReactiveCommandTest.java | 12 + .../reactive/NumericReactiveCommandTest.java | 12 + .../ScriptingReactiveCommandTest.java | 14 + .../ServerReactiveCommandTest.java} | 10 +- .../reactive/SetReactiveCommandTest.java | 14 + .../reactive/SortReactiveCommandTest.java | 12 + .../SortedSetReactiveCommandTest.java | 12 + .../StringReactiveCommandTest.java} | 19 +- .../TransactionReactiveCommandTest.java} | 77 +- .../redis/commands/rx/BitRxCommandTest.java | 17 - .../commands/rx/CustomRxCommandTest.java | 61 - .../redis/commands/rx/GeoRxCommandTest.java | 13 - .../redis/commands/rx/HLLRxCommandTest.java | 13 - .../redis/commands/rx/HashRxCommandTest.java | 14 - .../redis/commands/rx/KeyRxCommandTest.java | 12 - .../redis/commands/rx/ListRxCommandTest.java | 12 - .../commands/rx/NumericRxCommandTest.java | 12 - .../commands/rx/ScriptingRxCommandTest.java | 14 - .../redis/commands/rx/SetRxCommandTest.java | 14 - .../redis/commands/rx/SortRxCommandTest.java | 12 - .../commands/rx/SortedSetRxCommandTest.java | 12 - .../event/ConnectionEventsTriggeredTest.java | 16 +- .../redis/event/DefaultEventBusTest.java | 30 +- .../output/GeoCoordinatesListOutputTest.java | 3 +- ...SubRxTest.java => PubSubReactiveTest.java} | 67 +- .../resource/DefaultClientResourcesTest.java | 20 +- .../SentinelRxCommandTest.java | 8 +- ...ava => ReactiveSyncInvocationHandler.java} | 43 +- 118 files changed, 2873 insertions(+), 2717 deletions(-) create mode 100644 src/main/java/com/lambdaworks/redis/BackpressureUtils.java delete mode 100644 src/main/java/com/lambdaworks/redis/ReactiveCommandDispatcher.java create mode 100644 src/main/java/com/lambdaworks/redis/RedisPublisher.java rename src/main/java/com/lambdaworks/redis/api/{rx => reactive}/BaseRedisReactiveCommands.java (84%) rename src/main/java/com/lambdaworks/redis/api/{rx => reactive}/RedisGeoReactiveCommands.java (78%) rename src/main/java/com/lambdaworks/redis/api/{rx => reactive}/RedisHLLReactiveCommands.java (77%) rename src/main/java/com/lambdaworks/redis/api/{rx => reactive}/RedisHashReactiveCommands.java (81%) rename src/main/java/com/lambdaworks/redis/api/{rx => reactive}/RedisKeyReactiveCommands.java (82%) rename src/main/java/com/lambdaworks/redis/api/{rx => reactive}/RedisListReactiveCommands.java (83%) rename src/main/java/com/lambdaworks/redis/api/{rx => reactive}/RedisReactiveCommands.java (85%) rename src/main/java/com/lambdaworks/redis/api/{rx => reactive}/RedisScriptingReactiveCommands.java (78%) rename src/main/java/com/lambdaworks/redis/api/{rx => reactive}/RedisServerReactiveCommands.java (80%) rename src/main/java/com/lambdaworks/redis/api/{rx => reactive}/RedisSetReactiveCommands.java (80%) rename src/main/java/com/lambdaworks/redis/api/{rx => reactive}/RedisSortedSetReactiveCommands.java (79%) rename src/main/java/com/lambdaworks/redis/api/{rx => reactive}/RedisStringReactiveCommands.java (86%) rename src/main/java/com/lambdaworks/redis/api/{rx => reactive}/RedisTransactionalReactiveCommands.java (78%) rename src/main/java/com/lambdaworks/redis/api/{rx => reactive}/package-info.java (56%) delete mode 100644 src/main/java/com/lambdaworks/redis/api/rx/Success.java rename src/main/java/com/lambdaworks/redis/cluster/api/{rx => reactive}/RedisAdvancedClusterReactiveCommands.java (84%) rename src/main/java/com/lambdaworks/redis/cluster/api/{rx => reactive}/RedisClusterReactiveCommands.java (82%) rename src/main/java/com/lambdaworks/redis/cluster/api/{rx => reactive}/package-info.java (50%) create mode 100644 src/main/java/com/lambdaworks/redis/output/StringValueListOutput.java rename src/main/java/com/lambdaworks/redis/pubsub/api/{rx => reactive}/ChannelMessage.java (92%) rename src/main/java/com/lambdaworks/redis/pubsub/api/{rx => reactive}/PatternMessage.java (94%) create mode 100644 src/main/java/com/lambdaworks/redis/pubsub/api/reactive/RedisPubSubReactiveCommands.java rename src/main/java/com/lambdaworks/redis/pubsub/api/{rx => reactive}/package-info.java (50%) delete mode 100644 src/main/java/com/lambdaworks/redis/pubsub/api/rx/RedisPubSubReactiveCommands.java delete mode 100644 src/main/java/com/lambdaworks/redis/resource/RxJavaEventExecutorGroupScheduler.java rename src/main/java/com/lambdaworks/redis/sentinel/api/{rx => reactive}/RedisSentinelReactiveCommands.java (79%) delete mode 100644 src/main/java/com/lambdaworks/redis/sentinel/api/rx/package-info.java rename src/test/java/com/lambdaworks/redis/cluster/{RedisRxClusterClientTest.java => RedisReactiveClusterClientTest.java} (68%) rename src/test/java/com/lambdaworks/redis/cluster/commands/{rx/HashClusterRxCommandTest.java => reactive/HashClusterReactiveCommandTest.java} (82%) rename src/test/java/com/lambdaworks/redis/cluster/commands/{rx/KeyClusterRxCommandTest.java => reactive/KeyClusterReativeCommandTest.java} (83%) rename src/test/java/com/lambdaworks/redis/cluster/commands/{rx => reactive}/ListClusterRxCommandTest.java (93%) rename src/test/java/com/lambdaworks/redis/cluster/commands/{rx/StringClusterRxCommandTest.java => reactive/StringClusterReactiveCommandTest.java} (80%) create mode 100644 src/test/java/com/lambdaworks/redis/commands/reactive/BitReactiveCommandTest.java create mode 100644 src/test/java/com/lambdaworks/redis/commands/reactive/CustomReactiveCommandTest.java create mode 100644 src/test/java/com/lambdaworks/redis/commands/reactive/GeoReactiveCommandTest.java create mode 100644 src/test/java/com/lambdaworks/redis/commands/reactive/HLLReactiveCommandTest.java create mode 100644 src/test/java/com/lambdaworks/redis/commands/reactive/HashReactiveCommandTest.java create mode 100644 src/test/java/com/lambdaworks/redis/commands/reactive/KeyReactiveCommandTest.java create mode 100644 src/test/java/com/lambdaworks/redis/commands/reactive/ListReactiveCommandTest.java create mode 100644 src/test/java/com/lambdaworks/redis/commands/reactive/NumericReactiveCommandTest.java create mode 100644 src/test/java/com/lambdaworks/redis/commands/reactive/ScriptingReactiveCommandTest.java rename src/test/java/com/lambdaworks/redis/commands/{rx/ServerRxCommandTest.java => reactive/ServerReactiveCommandTest.java} (82%) create mode 100644 src/test/java/com/lambdaworks/redis/commands/reactive/SetReactiveCommandTest.java create mode 100644 src/test/java/com/lambdaworks/redis/commands/reactive/SortReactiveCommandTest.java create mode 100644 src/test/java/com/lambdaworks/redis/commands/reactive/SortedSetReactiveCommandTest.java rename src/test/java/com/lambdaworks/redis/commands/{rx/StringRxCommandTest.java => reactive/StringReactiveCommandTest.java} (63%) rename src/test/java/com/lambdaworks/redis/commands/{rx/TransactionRxCommandTest.java => reactive/TransactionReactiveCommandTest.java} (66%) delete mode 100644 src/test/java/com/lambdaworks/redis/commands/rx/BitRxCommandTest.java delete mode 100644 src/test/java/com/lambdaworks/redis/commands/rx/CustomRxCommandTest.java delete mode 100644 src/test/java/com/lambdaworks/redis/commands/rx/GeoRxCommandTest.java delete mode 100644 src/test/java/com/lambdaworks/redis/commands/rx/HLLRxCommandTest.java delete mode 100644 src/test/java/com/lambdaworks/redis/commands/rx/HashRxCommandTest.java delete mode 100644 src/test/java/com/lambdaworks/redis/commands/rx/KeyRxCommandTest.java delete mode 100644 src/test/java/com/lambdaworks/redis/commands/rx/ListRxCommandTest.java delete mode 100644 src/test/java/com/lambdaworks/redis/commands/rx/NumericRxCommandTest.java delete mode 100644 src/test/java/com/lambdaworks/redis/commands/rx/ScriptingRxCommandTest.java delete mode 100644 src/test/java/com/lambdaworks/redis/commands/rx/SetRxCommandTest.java delete mode 100644 src/test/java/com/lambdaworks/redis/commands/rx/SortRxCommandTest.java delete mode 100644 src/test/java/com/lambdaworks/redis/commands/rx/SortedSetRxCommandTest.java rename src/test/java/com/lambdaworks/redis/pubsub/{PubSubRxTest.java => PubSubReactiveTest.java} (87%) rename src/test/java/com/lambdaworks/redis/sentinel/{rx => reactive}/SentinelRxCommandTest.java (78%) rename src/test/java/com/lambdaworks/util/{RxSyncInvocationHandler.java => ReactiveSyncInvocationHandler.java} (68%) diff --git a/pom.xml b/pom.xml index c02e5cbc7b..f6245f6b33 100644 --- a/pom.xml +++ b/pom.xml @@ -73,11 +73,10 @@ - - io.reactivex - rxjava - 1.1.9 + io.projectreactor + reactor-core + 3.0.0.RC1 @@ -484,10 +483,9 @@ public - http://netty.io/4.0/api/ + http://netty.io/4.1/api/ http://commons.apache.org/proper/commons-pool/api-2.4.2/ - http://docs.guava-libraries.googlecode.com/git/javadoc/ - http://reactivex.io/RxJava/javadoc/ + https://docs.oracle.com/javase/8/docs/api/ -Xdoclint:all -Xdoclint:-html -Xdoclint:-syntax @@ -622,20 +620,6 @@ shade - - - com.google.guava:guava - - com/google/common/escape/** - com/google/common/eventbus/** - com/google/common/hash/** - com/google/common/html/** - com/google/common/math/** - com/google/common/xml/** - - - - rx diff --git a/src/main/java/com/lambdaworks/redis/AbstractRedisAsyncCommands.java b/src/main/java/com/lambdaworks/redis/AbstractRedisAsyncCommands.java index 1d94b78a6b..be5c55e2c5 100644 --- a/src/main/java/com/lambdaworks/redis/AbstractRedisAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/AbstractRedisAsyncCommands.java @@ -1690,7 +1690,7 @@ public RedisFuture geoadd(K key, Object... lngLatMember) { } @Override - public RedisFuture> geohash(K key, V... members) { + public RedisFuture>> geohash(K key, V... members) { return dispatch(commandBuilder.geohash(key, members)); } @@ -1729,7 +1729,7 @@ public RedisFuture georadiusbymember(K key, V member, double distance, Uni } @Override - public RedisFuture> geopos(K key, V... members) { + public RedisFuture>> geopos(K key, V... members) { return dispatch(commandBuilder.geopos(key, members)); } diff --git a/src/main/java/com/lambdaworks/redis/AbstractRedisReactiveCommands.java b/src/main/java/com/lambdaworks/redis/AbstractRedisReactiveCommands.java index d1e64e471e..01e6ccd96e 100644 --- a/src/main/java/com/lambdaworks/redis/AbstractRedisReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/AbstractRedisReactiveCommands.java @@ -7,19 +7,16 @@ import java.util.concurrent.TimeUnit; import java.util.function.Supplier; -import com.lambdaworks.redis.internal.LettuceAssert; -import com.lambdaworks.redis.protocol.*; -import rx.Completable; -import rx.Observable; -import rx.Single; -import rx.Subscriber; - import com.lambdaworks.redis.GeoArgs.Unit; import com.lambdaworks.redis.api.StatefulConnection; -import com.lambdaworks.redis.api.rx.*; -import com.lambdaworks.redis.cluster.api.rx.RedisClusterReactiveCommands; +import com.lambdaworks.redis.api.reactive.*; +import com.lambdaworks.redis.cluster.api.reactive.RedisClusterReactiveCommands; import com.lambdaworks.redis.codec.RedisCodec; +import com.lambdaworks.redis.internal.LettuceAssert; import com.lambdaworks.redis.output.*; +import com.lambdaworks.redis.protocol.*; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; /** * A reactive and thread-safe API for a Redis connection. @@ -53,128 +50,128 @@ public AbstractRedisReactiveCommands(StatefulConnection connection, RedisC } @Override - public Single append(K key, V value) { - return createSingle(() -> commandBuilder.append(key, value)); + public Mono append(K key, V value) { + return createMono(() -> commandBuilder.append(key, value)); } @Override - public Single auth(String password) { - return createSingle(() -> commandBuilder.auth(password)); + public Mono auth(String password) { + return createMono(() -> commandBuilder.auth(password)); } @Override - public Single bgrewriteaof() { - return createSingle(commandBuilder::bgrewriteaof); + public Mono bgrewriteaof() { + return createMono(commandBuilder::bgrewriteaof); } @Override - public Single bgsave() { - return createSingle(commandBuilder::bgsave); + public Mono bgsave() { + return createMono(commandBuilder::bgsave); } @Override - public Single bitcount(K key) { - return createSingle(() -> commandBuilder.bitcount(key)); + public Mono bitcount(K key) { + return createMono(() -> commandBuilder.bitcount(key)); } @Override - public Single bitcount(K key, long start, long end) { - return createSingle(() -> commandBuilder.bitcount(key, start, end)); + public Mono bitcount(K key, long start, long end) { + return createMono(() -> commandBuilder.bitcount(key, start, end)); } @Override - public Observable bitfield(K key, BitFieldArgs args) { - return createDissolvingObservable(() -> commandBuilder.bitfield(key, args)); + public Flux bitfield(K key, BitFieldArgs args) { + return createDissolvingFlux(() -> commandBuilder.bitfield(key, args)); } @Override - public Single bitpos(K key, boolean state) { - return createSingle(() -> commandBuilder.bitpos(key, state)); + public Mono bitpos(K key, boolean state) { + return createMono(() -> commandBuilder.bitpos(key, state)); } @Override - public Single bitpos(K key, boolean state, long start, long end) { - return createSingle(() -> commandBuilder.bitpos(key, state, start, end)); + public Mono bitpos(K key, boolean state, long start, long end) { + return createMono(() -> commandBuilder.bitpos(key, state, start, end)); } @Override - public Single bitopAnd(K destination, K... keys) { - return createSingle(() -> commandBuilder.bitopAnd(destination, keys)); + public Mono bitopAnd(K destination, K... keys) { + return createMono(() -> commandBuilder.bitopAnd(destination, keys)); } @Override - public Single bitopNot(K destination, K source) { - return createSingle(() -> commandBuilder.bitopNot(destination, source)); + public Mono bitopNot(K destination, K source) { + return createMono(() -> commandBuilder.bitopNot(destination, source)); } @Override - public Single bitopOr(K destination, K... keys) { - return createSingle(() -> commandBuilder.bitopOr(destination, keys)); + public Mono bitopOr(K destination, K... keys) { + return createMono(() -> commandBuilder.bitopOr(destination, keys)); } @Override - public Single bitopXor(K destination, K... keys) { - return createSingle(() -> commandBuilder.bitopXor(destination, keys)); + public Mono bitopXor(K destination, K... keys) { + return createMono(() -> commandBuilder.bitopXor(destination, keys)); } @Override - public Single> blpop(long timeout, K... keys) { - return createSingle(() -> commandBuilder.blpop(timeout, keys)); + public Mono> blpop(long timeout, K... keys) { + return createMono(() -> commandBuilder.blpop(timeout, keys)); } @Override - public Single> brpop(long timeout, K... keys) { - return createSingle(() -> commandBuilder.brpop(timeout, keys)); + public Mono> brpop(long timeout, K... keys) { + return createMono(() -> commandBuilder.brpop(timeout, keys)); } @Override - public Single brpoplpush(long timeout, K source, K destination) { - return createSingle(() -> commandBuilder.brpoplpush(timeout, source, destination)); + public Mono brpoplpush(long timeout, K source, K destination) { + return createMono(() -> commandBuilder.brpoplpush(timeout, source, destination)); } @Override - public Single clientGetname() { - return createSingle(commandBuilder::clientGetname); + public Mono clientGetname() { + return createMono(commandBuilder::clientGetname); } @Override - public Single clientSetname(K name) { - return createSingle(() -> commandBuilder.clientSetname(name)); + public Mono clientSetname(K name) { + return createMono(() -> commandBuilder.clientSetname(name)); } @Override - public Single clientKill(String addr) { - return createSingle(() -> commandBuilder.clientKill(addr)); + public Mono clientKill(String addr) { + return createMono(() -> commandBuilder.clientKill(addr)); } @Override - public Single clientKill(KillArgs killArgs) { - return createSingle(() -> commandBuilder.clientKill(killArgs)); + public Mono clientKill(KillArgs killArgs) { + return createMono(() -> commandBuilder.clientKill(killArgs)); } @Override - public Single clientPause(long timeout) { - return createSingle(() -> commandBuilder.clientPause(timeout)); + public Mono clientPause(long timeout) { + return createMono(() -> commandBuilder.clientPause(timeout)); } @Override - public Single clientList() { - return createSingle(commandBuilder::clientList); + public Mono clientList() { + return createMono(commandBuilder::clientList); } @Override - public Observable command() { - return createDissolvingObservable(commandBuilder::command); + public Flux command() { + return createDissolvingFlux(commandBuilder::command); } @Override - public Observable commandInfo(String... commands) { - return createDissolvingObservable(() -> commandBuilder.commandInfo(commands)); + public Flux commandInfo(String... commands) { + return createDissolvingFlux(() -> commandBuilder.commandInfo(commands)); } @Override - public Observable commandInfo(CommandType... commands) { + public Flux commandInfo(CommandType... commands) { String[] stringCommands = new String[commands.length]; for (int i = 0; i < commands.length; i++) { stringCommands[i] = commands[i].name(); @@ -184,1323 +181,1323 @@ public Observable commandInfo(CommandType... commands) { } @Override - public Single commandCount() { - return createSingle(commandBuilder::commandCount); + public Mono commandCount() { + return createMono(commandBuilder::commandCount); } @Override - public Observable configGet(String parameter) { - return createDissolvingObservable(() -> commandBuilder.configGet(parameter)); + public Flux configGet(String parameter) { + return createDissolvingFlux(() -> commandBuilder.configGet(parameter)); } @Override - public Single configResetstat() { - return createSingle(commandBuilder::configResetstat); + public Mono configResetstat() { + return createMono(commandBuilder::configResetstat); } @Override - public Single configSet(String parameter, String value) { - return createSingle(() -> commandBuilder.configSet(parameter, value)); + public Mono configSet(String parameter, String value) { + return createMono(() -> commandBuilder.configSet(parameter, value)); } @Override - public Single configRewrite() { - return createSingle(commandBuilder::configRewrite); + public Mono configRewrite() { + return createMono(commandBuilder::configRewrite); } @Override - public Single dbsize() { - return createSingle(commandBuilder::dbsize); + public Mono dbsize() { + return createMono(commandBuilder::dbsize); } @Override - public Single debugCrashAndRecover(Long delay) { - return createSingle(() -> (commandBuilder.debugCrashAndRecover(delay))); + public Mono debugCrashAndRecover(Long delay) { + return createMono(() -> (commandBuilder.debugCrashAndRecover(delay))); } @Override - public Single debugHtstats(int db) { - return createSingle(() -> commandBuilder.debugHtstats(db)); + public Mono debugHtstats(int db) { + return createMono(() -> commandBuilder.debugHtstats(db)); } @Override - public Single debugObject(K key) { - return createSingle(() -> commandBuilder.debugObject(key)); + public Mono debugObject(K key) { + return createMono(() -> commandBuilder.debugObject(key)); } @Override - public Completable debugOom() { - return Completable.fromObservable(createObservable(commandBuilder::debugOom)); + public Mono debugOom() { + return createMono(commandBuilder::debugOom).then(); } @Override - public Single debugReload() { - return createSingle(() -> (commandBuilder.debugReload())); + public Mono debugReload() { + return createMono(() -> (commandBuilder.debugReload())); } @Override - public Single debugRestart(Long delay) { - return createSingle(() -> (commandBuilder.debugRestart(delay))); + public Mono debugRestart(Long delay) { + return createMono(() -> (commandBuilder.debugRestart(delay))); } @Override - public Single debugSdslen(K key) { - return createSingle(() -> (commandBuilder.debugSdslen(key))); + public Mono debugSdslen(K key) { + return createMono(() -> (commandBuilder.debugSdslen(key))); } @Override - public Completable debugSegfault() { - return Completable.fromObservable(createObservable(commandBuilder::debugSegfault)); + public Mono debugSegfault() { + return createFlux(commandBuilder::debugSegfault).then(); } @Override - public Single decr(K key) { - return createSingle(() -> commandBuilder.decr(key)); + public Mono decr(K key) { + return createMono(() -> commandBuilder.decr(key)); } @Override - public Single decrby(K key, long amount) { - return createSingle(() -> commandBuilder.decrby(key, amount)); + public Mono decrby(K key, long amount) { + return createMono(() -> commandBuilder.decrby(key, amount)); } @Override - public Single del(K... keys) { - return createSingle(() -> commandBuilder.del(keys)); + public Mono del(K... keys) { + return createMono(() -> commandBuilder.del(keys)); } - public Single del(Iterable keys) { - return createSingle(() -> commandBuilder.del(keys)); + public Mono del(Iterable keys) { + return createMono(() -> commandBuilder.del(keys)); } @Override - public Single unlink(K... keys) { - return createSingle(() -> commandBuilder.unlink(keys)); + public Mono unlink(K... keys) { + return createMono(() -> commandBuilder.unlink(keys)); } - public Single unlink(Iterable keys) { - return createSingle(() -> commandBuilder.unlink(keys)); + public Mono unlink(Iterable keys) { + return createMono(() -> commandBuilder.unlink(keys)); } @Override - public Single discard() { - return createSingle(commandBuilder::discard); + public Mono discard() { + return createMono(commandBuilder::discard); } @Override - public Single dump(K key) { - return createSingle(() -> commandBuilder.dump(key)); + public Mono dump(K key) { + return createMono(() -> commandBuilder.dump(key)); } @Override - public Single echo(V msg) { - return createSingle(() -> commandBuilder.echo(msg)); + public Mono echo(V msg) { + return createMono(() -> commandBuilder.echo(msg)); } @Override @SuppressWarnings("unchecked") - public Observable eval(String script, ScriptOutputType type, K... keys) { - return (Observable) createObservable(() -> commandBuilder.eval(script, type, keys)); + public Flux eval(String script, ScriptOutputType type, K... keys) { + return (Flux) createFlux(() -> commandBuilder.eval(script, type, keys)); } @Override @SuppressWarnings("unchecked") - public Observable eval(String script, ScriptOutputType type, K[] keys, V... values) { - return (Observable) createObservable(() -> commandBuilder.eval(script, type, keys, values)); + public Flux eval(String script, ScriptOutputType type, K[] keys, V... values) { + return (Flux) createFlux(() -> commandBuilder.eval(script, type, keys, values)); } @Override @SuppressWarnings("unchecked") - public Observable evalsha(String digest, ScriptOutputType type, K... keys) { - return (Observable) createObservable(() -> commandBuilder.evalsha(digest, type, keys)); + public Flux evalsha(String digest, ScriptOutputType type, K... keys) { + return (Flux) createFlux(() -> commandBuilder.evalsha(digest, type, keys)); } @Override @SuppressWarnings("unchecked") - public Observable evalsha(String digest, ScriptOutputType type, K[] keys, V... values) { - return (Observable) createObservable(() -> commandBuilder.evalsha(digest, type, keys, values)); + public Flux evalsha(String digest, ScriptOutputType type, K[] keys, V... values) { + return (Flux) createFlux(() -> commandBuilder.evalsha(digest, type, keys, values)); } - public Single exists(K key) { - return createSingle(() -> commandBuilder.exists(key)); + public Mono exists(K key) { + return createMono(() -> commandBuilder.exists(key)); } @Override - public Single exists(K... keys) { - return createSingle(() -> commandBuilder.exists(keys)); + public Mono exists(K... keys) { + return createMono(() -> commandBuilder.exists(keys)); } - public Single exists(Iterable keys) { - return createSingle(() -> commandBuilder.exists(keys)); + public Mono exists(Iterable keys) { + return createMono(() -> commandBuilder.exists(keys)); } @Override - public Single expire(K key, long seconds) { - return createSingle(() -> commandBuilder.expire(key, seconds)); + public Mono expire(K key, long seconds) { + return createMono(() -> commandBuilder.expire(key, seconds)); } @Override - public Single expireat(K key, long timestamp) { - return createSingle(() -> commandBuilder.expireat(key, timestamp)); + public Mono expireat(K key, long timestamp) { + return createMono(() -> commandBuilder.expireat(key, timestamp)); } @Override - public Single expireat(K key, Date timestamp) { + public Mono expireat(K key, Date timestamp) { return expireat(key, timestamp.getTime() / 1000); } @Override - public Single exec() { - return createSingle(EXEC, null, null); + public Mono exec() { + return createMono(EXEC, null, null); } @Override - public Single flushall() { - return createSingle(commandBuilder::flushall); + public Mono flushall() { + return createMono(commandBuilder::flushall); } @Override - public Single flushallAsync() { - return createSingle(commandBuilder::flushallAsync); + public Mono flushallAsync() { + return createMono(commandBuilder::flushallAsync); } @Override - public Single flushdb() { - return createSingle(commandBuilder::flushdb); + public Mono flushdb() { + return createMono(commandBuilder::flushdb); } @Override - public Single flushdbAsync() { - return createSingle(commandBuilder::flushdbAsync); + public Mono flushdbAsync() { + return createMono(commandBuilder::flushdbAsync); } @Override - public Single get(K key) { - return createSingle(() -> commandBuilder.get(key)); + public Mono get(K key) { + return createMono(() -> commandBuilder.get(key)); } @Override - public Single getbit(K key, long offset) { - return createSingle(() -> commandBuilder.getbit(key, offset)); + public Mono getbit(K key, long offset) { + return createMono(() -> commandBuilder.getbit(key, offset)); } @Override - public Single getrange(K key, long start, long end) { - return createSingle(() -> commandBuilder.getrange(key, start, end)); + public Mono getrange(K key, long start, long end) { + return createMono(() -> commandBuilder.getrange(key, start, end)); } @Override - public Single getset(K key, V value) { - return createSingle(() -> commandBuilder.getset(key, value)); + public Mono getset(K key, V value) { + return createMono(() -> commandBuilder.getset(key, value)); } @Override - public Single hdel(K key, K... fields) { - return createSingle(() -> commandBuilder.hdel(key, fields)); + public Mono hdel(K key, K... fields) { + return createMono(() -> commandBuilder.hdel(key, fields)); } @Override - public Single hexists(K key, K field) { - return createSingle(() -> commandBuilder.hexists(key, field)); + public Mono hexists(K key, K field) { + return createMono(() -> commandBuilder.hexists(key, field)); } @Override - public Single hget(K key, K field) { - return createSingle(() -> commandBuilder.hget(key, field)); + public Mono hget(K key, K field) { + return createMono(() -> commandBuilder.hget(key, field)); } @Override - public Single hincrby(K key, K field, long amount) { - return createSingle(() -> commandBuilder.hincrby(key, field, amount)); + public Mono hincrby(K key, K field, long amount) { + return createMono(() -> commandBuilder.hincrby(key, field, amount)); } @Override - public Single hincrbyfloat(K key, K field, double amount) { - return createSingle(() -> commandBuilder.hincrbyfloat(key, field, amount)); + public Mono hincrbyfloat(K key, K field, double amount) { + return createMono(() -> commandBuilder.hincrbyfloat(key, field, amount)); } @Override - public Single> hgetall(K key) { - return createSingle(() -> commandBuilder.hgetall(key)); + public Mono> hgetall(K key) { + return createMono(() -> commandBuilder.hgetall(key)); } @Override - public Single hgetall(KeyValueStreamingChannel channel, K key) { - return createSingle(() -> commandBuilder.hgetall(channel, key)); + public Mono hgetall(KeyValueStreamingChannel channel, K key) { + return createMono(() -> commandBuilder.hgetall(channel, key)); } @Override - public Observable hkeys(K key) { - return createDissolvingObservable(() -> commandBuilder.hkeys(key)); + public Flux hkeys(K key) { + return createDissolvingFlux(() -> commandBuilder.hkeys(key)); } @Override - public Single hkeys(KeyStreamingChannel channel, K key) { - return createSingle(() -> commandBuilder.hkeys(channel, key)); + public Mono hkeys(KeyStreamingChannel channel, K key) { + return createMono(() -> commandBuilder.hkeys(channel, key)); } @Override - public Single hlen(K key) { - return createSingle(() -> commandBuilder.hlen(key)); + public Mono hlen(K key) { + return createMono(() -> commandBuilder.hlen(key)); } @Override - public Single hstrlen(K key, K field) { - return createSingle(() -> commandBuilder.hstrlen(key, field)); + public Mono hstrlen(K key, K field) { + return createMono(() -> commandBuilder.hstrlen(key, field)); } @Override - public Observable> hmget(K key, K... fields) { - return createDissolvingObservable(() -> commandBuilder.hmgetKeyValue(key, fields)); + public Flux> hmget(K key, K... fields) { + return createDissolvingFlux(() -> commandBuilder.hmgetKeyValue(key, fields)); } @Override - public Single hmget(KeyValueStreamingChannel channel, K key, K... fields) { - return createSingle(() -> commandBuilder.hmget(channel, key, fields)); + public Mono hmget(KeyValueStreamingChannel channel, K key, K... fields) { + return createMono(() -> commandBuilder.hmget(channel, key, fields)); } @Override - public Single hmset(K key, Map map) { - return createSingle(() -> commandBuilder.hmset(key, map)); + public Mono hmset(K key, Map map) { + return createMono(() -> commandBuilder.hmset(key, map)); } @Override - public Single hset(K key, K field, V value) { - return createSingle(() -> commandBuilder.hset(key, field, value)); + public Mono hset(K key, K field, V value) { + return createMono(() -> commandBuilder.hset(key, field, value)); } @Override - public Single hsetnx(K key, K field, V value) { - return createSingle(() -> commandBuilder.hsetnx(key, field, value)); + public Mono hsetnx(K key, K field, V value) { + return createMono(() -> commandBuilder.hsetnx(key, field, value)); } @Override - public Observable hvals(K key) { - return createDissolvingObservable(() -> commandBuilder.hvals(key)); + public Flux hvals(K key) { + return createDissolvingFlux(() -> commandBuilder.hvals(key)); } @Override - public Single hvals(ValueStreamingChannel channel, K key) { - return createSingle(() -> commandBuilder.hvals(channel, key)); + public Mono hvals(ValueStreamingChannel channel, K key) { + return createMono(() -> commandBuilder.hvals(channel, key)); } @Override - public Single incr(K key) { - return createSingle(() -> commandBuilder.incr(key)); + public Mono incr(K key) { + return createMono(() -> commandBuilder.incr(key)); } @Override - public Single incrby(K key, long amount) { - return createSingle(() -> commandBuilder.incrby(key, amount)); + public Mono incrby(K key, long amount) { + return createMono(() -> commandBuilder.incrby(key, amount)); } @Override - public Single incrbyfloat(K key, double amount) { - return createSingle(() -> commandBuilder.incrbyfloat(key, amount)); + public Mono incrbyfloat(K key, double amount) { + return createMono(() -> commandBuilder.incrbyfloat(key, amount)); } @Override - public Single info() { - return createSingle(commandBuilder::info); + public Mono info() { + return createMono(commandBuilder::info); } @Override - public Single info(String section) { - return createSingle(() -> commandBuilder.info(section)); + public Mono info(String section) { + return createMono(() -> commandBuilder.info(section)); } @Override - public Observable keys(K pattern) { - return createDissolvingObservable(() -> commandBuilder.keys(pattern)); + public Flux keys(K pattern) { + return createDissolvingFlux(() -> commandBuilder.keys(pattern)); } @Override - public Single keys(KeyStreamingChannel channel, K pattern) { - return createSingle(() -> commandBuilder.keys(channel, pattern)); + public Mono keys(KeyStreamingChannel channel, K pattern) { + return createMono(() -> commandBuilder.keys(channel, pattern)); } @Override - public Single lastsave() { - return createSingle(commandBuilder::lastsave); + public Mono lastsave() { + return createMono(commandBuilder::lastsave); } @Override - public Single lindex(K key, long index) { - return createSingle(() -> commandBuilder.lindex(key, index)); + public Mono lindex(K key, long index) { + return createMono(() -> commandBuilder.lindex(key, index)); } @Override - public Single linsert(K key, boolean before, V pivot, V value) { - return createSingle(() -> commandBuilder.linsert(key, before, pivot, value)); + public Mono linsert(K key, boolean before, V pivot, V value) { + return createMono(() -> commandBuilder.linsert(key, before, pivot, value)); } @Override - public Single llen(K key) { - return createSingle(() -> commandBuilder.llen(key)); + public Mono llen(K key) { + return createMono(() -> commandBuilder.llen(key)); } @Override - public Single lpop(K key) { - return createSingle(() -> commandBuilder.lpop(key)); + public Mono lpop(K key) { + return createMono(() -> commandBuilder.lpop(key)); } @Override - public Single lpush(K key, V... values) { - return createSingle(() -> commandBuilder.lpush(key, values)); + public Mono lpush(K key, V... values) { + return createMono(() -> commandBuilder.lpush(key, values)); } @Override - public Single lpushx(K key, V... values) { - return createSingle(() -> commandBuilder.lpushx(key, values)); + public Mono lpushx(K key, V... values) { + return createMono(() -> commandBuilder.lpushx(key, values)); } @Override - public Observable lrange(K key, long start, long stop) { - return createDissolvingObservable(() -> commandBuilder.lrange(key, start, stop)); + public Flux lrange(K key, long start, long stop) { + return createDissolvingFlux(() -> commandBuilder.lrange(key, start, stop)); } @Override - public Single lrange(ValueStreamingChannel channel, K key, long start, long stop) { - return createSingle(() -> commandBuilder.lrange(channel, key, start, stop)); + public Mono lrange(ValueStreamingChannel channel, K key, long start, long stop) { + return createMono(() -> commandBuilder.lrange(channel, key, start, stop)); } @Override - public Single lrem(K key, long count, V value) { - return createSingle(() -> commandBuilder.lrem(key, count, value)); + public Mono lrem(K key, long count, V value) { + return createMono(() -> commandBuilder.lrem(key, count, value)); } @Override - public Single lset(K key, long index, V value) { - return createSingle(() -> commandBuilder.lset(key, index, value)); + public Mono lset(K key, long index, V value) { + return createMono(() -> commandBuilder.lset(key, index, value)); } @Override - public Single ltrim(K key, long start, long stop) { - return createSingle(() -> commandBuilder.ltrim(key, start, stop)); + public Mono ltrim(K key, long start, long stop) { + return createMono(() -> commandBuilder.ltrim(key, start, stop)); } @Override - public Single migrate(String host, int port, K key, int db, long timeout) { - return createSingle(() -> commandBuilder.migrate(host, port, key, db, timeout)); + public Mono migrate(String host, int port, K key, int db, long timeout) { + return createMono(() -> commandBuilder.migrate(host, port, key, db, timeout)); } @Override - public Single migrate(String host, int port, int db, long timeout, MigrateArgs migrateArgs) { - return createSingle(() -> commandBuilder.migrate(host, port, db, timeout, migrateArgs)); + public Mono migrate(String host, int port, int db, long timeout, MigrateArgs migrateArgs) { + return createMono(() -> commandBuilder.migrate(host, port, db, timeout, migrateArgs)); } @Override - public Observable> mget(K... keys) { - return createDissolvingObservable(() -> commandBuilder.mgetKeyValue(keys)); + public Flux> mget(K... keys) { + return createDissolvingFlux(() -> commandBuilder.mgetKeyValue(keys)); } - public Observable> mget(Iterable keys) { - return createDissolvingObservable(() -> commandBuilder.mgetKeyValue(keys)); + public Flux> mget(Iterable keys) { + return createDissolvingFlux(() -> commandBuilder.mgetKeyValue(keys)); } @Override - public Single mget(KeyValueStreamingChannel channel, K... keys) { - return createSingle(() -> commandBuilder.mget(channel, keys)); + public Mono mget(KeyValueStreamingChannel channel, K... keys) { + return createMono(() -> commandBuilder.mget(channel, keys)); } - public Single mget(ValueStreamingChannel channel, Iterable keys) { - return createSingle(() -> commandBuilder.mget(channel, keys)); + public Mono mget(ValueStreamingChannel channel, Iterable keys) { + return createMono(() -> commandBuilder.mget(channel, keys)); } - public Single mget(KeyValueStreamingChannel channel, Iterable keys) { - return createSingle(() -> commandBuilder.mget(channel, keys)); + public Mono mget(KeyValueStreamingChannel channel, Iterable keys) { + return createMono(() -> commandBuilder.mget(channel, keys)); } @Override - public Single move(K key, int db) { - return createSingle(() -> commandBuilder.move(key, db)); + public Mono move(K key, int db) { + return createMono(() -> commandBuilder.move(key, db)); } @Override - public Single multi() { - return createSingle(commandBuilder::multi); + public Mono multi() { + return createMono(commandBuilder::multi); } @Override - public Single mset(Map map) { - return createSingle(() -> commandBuilder.mset(map)); + public Mono mset(Map map) { + return createMono(() -> commandBuilder.mset(map)); } @Override - public Single msetnx(Map map) { - return createSingle(() -> commandBuilder.msetnx(map)); + public Mono msetnx(Map map) { + return createMono(() -> commandBuilder.msetnx(map)); } @Override - public Single objectEncoding(K key) { - return createSingle(() -> commandBuilder.objectEncoding(key)); + public Mono objectEncoding(K key) { + return createMono(() -> commandBuilder.objectEncoding(key)); } @Override - public Single objectIdletime(K key) { - return createSingle(() -> commandBuilder.objectIdletime(key)); + public Mono objectIdletime(K key) { + return createMono(() -> commandBuilder.objectIdletime(key)); } @Override - public Single objectRefcount(K key) { - return createSingle(() -> commandBuilder.objectRefcount(key)); + public Mono objectRefcount(K key) { + return createMono(() -> commandBuilder.objectRefcount(key)); } @Override - public Single persist(K key) { - return createSingle(() -> commandBuilder.persist(key)); + public Mono persist(K key) { + return createMono(() -> commandBuilder.persist(key)); } @Override - public Single pexpire(K key, long milliseconds) { - return createSingle(() -> commandBuilder.pexpire(key, milliseconds)); + public Mono pexpire(K key, long milliseconds) { + return createMono(() -> commandBuilder.pexpire(key, milliseconds)); } @Override - public Single pexpireat(K key, Date timestamp) { + public Mono pexpireat(K key, Date timestamp) { return pexpireat(key, timestamp.getTime()); } @Override - public Single pexpireat(K key, long timestamp) { - return createSingle(() -> commandBuilder.pexpireat(key, timestamp)); + public Mono pexpireat(K key, long timestamp) { + return createMono(() -> commandBuilder.pexpireat(key, timestamp)); } @Override - public Single ping() { - return createSingle(commandBuilder::ping); + public Mono ping() { + return createMono(commandBuilder::ping); } @Override - public Single readOnly() { - return createSingle(commandBuilder::readOnly); + public Mono readOnly() { + return createMono(commandBuilder::readOnly); } @Override - public Single readWrite() { - return createSingle(commandBuilder::readWrite); + public Mono readWrite() { + return createMono(commandBuilder::readWrite); } @Override - public Single pttl(K key) { - return createSingle(() -> commandBuilder.pttl(key)); + public Mono pttl(K key) { + return createMono(() -> commandBuilder.pttl(key)); } @Override - public Single publish(K channel, V message) { - return createSingle(() -> commandBuilder.publish(channel, message)); + public Mono publish(K channel, V message) { + return createMono(() -> commandBuilder.publish(channel, message)); } @Override - public Observable pubsubChannels() { - return createDissolvingObservable(commandBuilder::pubsubChannels); + public Flux pubsubChannels() { + return createDissolvingFlux(commandBuilder::pubsubChannels); } @Override - public Observable pubsubChannels(K channel) { - return createDissolvingObservable(() -> commandBuilder.pubsubChannels(channel)); + public Flux pubsubChannels(K channel) { + return createDissolvingFlux(() -> commandBuilder.pubsubChannels(channel)); } @Override - public Single> pubsubNumsub(K... channels) { - return createSingle(() -> commandBuilder.pubsubNumsub(channels)); + public Mono> pubsubNumsub(K... channels) { + return createMono(() -> commandBuilder.pubsubNumsub(channels)); } @Override - public Single pubsubNumpat() { - return createSingle(commandBuilder::pubsubNumpat); + public Mono pubsubNumpat() { + return createMono(commandBuilder::pubsubNumpat); } @Override - public Single quit() { - return createSingle(commandBuilder::quit); + public Mono quit() { + return createMono(commandBuilder::quit); } @Override - public Observable role() { - return createDissolvingObservable(commandBuilder::role); + public Flux role() { + return createDissolvingFlux(commandBuilder::role); } @Override - public Single randomkey() { - return createSingle(commandBuilder::randomkey); + public Mono randomkey() { + return createMono(commandBuilder::randomkey); } @Override - public Single rename(K key, K newKey) { - return createSingle(() -> commandBuilder.rename(key, newKey)); + public Mono rename(K key, K newKey) { + return createMono(() -> commandBuilder.rename(key, newKey)); } @Override - public Single renamenx(K key, K newKey) { - return createSingle(() -> commandBuilder.renamenx(key, newKey)); + public Mono renamenx(K key, K newKey) { + return createMono(() -> commandBuilder.renamenx(key, newKey)); } @Override - public Single restore(K key, long ttl, byte[] value) { - return createSingle(() -> commandBuilder.restore(key, ttl, value)); + public Mono restore(K key, long ttl, byte[] value) { + return createMono(() -> commandBuilder.restore(key, ttl, value)); } @Override - public Single rpop(K key) { - return createSingle(() -> commandBuilder.rpop(key)); + public Mono rpop(K key) { + return createMono(() -> commandBuilder.rpop(key)); } @Override - public Single rpoplpush(K source, K destination) { - return createSingle(() -> commandBuilder.rpoplpush(source, destination)); + public Mono rpoplpush(K source, K destination) { + return createMono(() -> commandBuilder.rpoplpush(source, destination)); } @Override - public Single rpush(K key, V... values) { - return createSingle(() -> commandBuilder.rpush(key, values)); + public Mono rpush(K key, V... values) { + return createMono(() -> commandBuilder.rpush(key, values)); } @Override - public Single rpushx(K key, V... values) { - return createSingle(() -> commandBuilder.rpushx(key, values)); + public Mono rpushx(K key, V... values) { + return createMono(() -> commandBuilder.rpushx(key, values)); } @Override - public Single sadd(K key, V... members) { - return createSingle(() -> commandBuilder.sadd(key, members)); + public Mono sadd(K key, V... members) { + return createMono(() -> commandBuilder.sadd(key, members)); } @Override - public Single save() { - return createSingle(commandBuilder::save); + public Mono save() { + return createMono(commandBuilder::save); } @Override - public Single scard(K key) { - return createSingle(() -> commandBuilder.scard(key)); + public Mono scard(K key) { + return createMono(() -> commandBuilder.scard(key)); } @Override - public Observable scriptExists(String... digests) { - return createDissolvingObservable(() -> commandBuilder.scriptExists(digests)); + public Flux scriptExists(String... digests) { + return createDissolvingFlux(() -> commandBuilder.scriptExists(digests)); } @Override - public Single scriptFlush() { - return createSingle(commandBuilder::scriptFlush); + public Mono scriptFlush() { + return createMono(commandBuilder::scriptFlush); } @Override - public Single scriptKill() { - return createSingle(commandBuilder::scriptKill); + public Mono scriptKill() { + return createMono(commandBuilder::scriptKill); } @Override - public Single scriptLoad(V script) { - return createSingle(() -> commandBuilder.scriptLoad(script)); + public Mono scriptLoad(V script) { + return createMono(() -> commandBuilder.scriptLoad(script)); } @Override - public Observable sdiff(K... keys) { - return createDissolvingObservable(() -> commandBuilder.sdiff(keys)); + public Flux sdiff(K... keys) { + return createDissolvingFlux(() -> commandBuilder.sdiff(keys)); } @Override - public Single sdiff(ValueStreamingChannel channel, K... keys) { - return createSingle(() -> commandBuilder.sdiff(channel, keys)); + public Mono sdiff(ValueStreamingChannel channel, K... keys) { + return createMono(() -> commandBuilder.sdiff(channel, keys)); } @Override - public Single sdiffstore(K destination, K... keys) { - return createSingle(() -> commandBuilder.sdiffstore(destination, keys)); + public Mono sdiffstore(K destination, K... keys) { + return createMono(() -> commandBuilder.sdiffstore(destination, keys)); } - public Single select(int db) { - return createSingle(() -> commandBuilder.select(db)); + public Mono select(int db) { + return createMono(() -> commandBuilder.select(db)); } @Override - public Single set(K key, V value) { - return createSingle(() -> commandBuilder.set(key, value)); + public Mono set(K key, V value) { + return createMono(() -> commandBuilder.set(key, value)); } @Override - public Single set(K key, V value, SetArgs setArgs) { - return createSingle(() -> commandBuilder.set(key, value, setArgs)); + public Mono set(K key, V value, SetArgs setArgs) { + return createMono(() -> commandBuilder.set(key, value, setArgs)); } @Override - public Single setbit(K key, long offset, int value) { - return createSingle(() -> commandBuilder.setbit(key, offset, value)); + public Mono setbit(K key, long offset, int value) { + return createMono(() -> commandBuilder.setbit(key, offset, value)); } @Override - public Single setex(K key, long seconds, V value) { - return createSingle(() -> commandBuilder.setex(key, seconds, value)); + public Mono setex(K key, long seconds, V value) { + return createMono(() -> commandBuilder.setex(key, seconds, value)); } @Override - public Single psetex(K key, long milliseconds, V value) { - return createSingle(() -> commandBuilder.psetex(key, milliseconds, value)); + public Mono psetex(K key, long milliseconds, V value) { + return createMono(() -> commandBuilder.psetex(key, milliseconds, value)); } @Override - public Single setnx(K key, V value) { - return createSingle(() -> commandBuilder.setnx(key, value)); + public Mono setnx(K key, V value) { + return createMono(() -> commandBuilder.setnx(key, value)); } @Override - public Single setrange(K key, long offset, V value) { - return createSingle(() -> commandBuilder.setrange(key, offset, value)); + public Mono setrange(K key, long offset, V value) { + return createMono(() -> commandBuilder.setrange(key, offset, value)); } @Override - public Completable shutdown(boolean save) { - return Completable.fromObservable(createObservable(() -> commandBuilder.shutdown(save))); + public Mono shutdown(boolean save) { + return createMono(() -> commandBuilder.shutdown(save)).then(); } @Override - public Observable sinter(K... keys) { - return createDissolvingObservable(() -> commandBuilder.sinter(keys)); + public Flux sinter(K... keys) { + return createDissolvingFlux(() -> commandBuilder.sinter(keys)); } @Override - public Single sinter(ValueStreamingChannel channel, K... keys) { - return createSingle(() -> commandBuilder.sinter(channel, keys)); + public Mono sinter(ValueStreamingChannel channel, K... keys) { + return createMono(() -> commandBuilder.sinter(channel, keys)); } @Override - public Single sinterstore(K destination, K... keys) { - return createSingle(() -> commandBuilder.sinterstore(destination, keys)); + public Mono sinterstore(K destination, K... keys) { + return createMono(() -> commandBuilder.sinterstore(destination, keys)); } @Override - public Single sismember(K key, V member) { - return createSingle(() -> commandBuilder.sismember(key, member)); + public Mono sismember(K key, V member) { + return createMono(() -> commandBuilder.sismember(key, member)); } @Override - public Single smove(K source, K destination, V member) { - return createSingle(() -> commandBuilder.smove(source, destination, member)); + public Mono smove(K source, K destination, V member) { + return createMono(() -> commandBuilder.smove(source, destination, member)); } @Override - public Single slaveof(String host, int port) { - return createSingle(() -> commandBuilder.slaveof(host, port)); + public Mono slaveof(String host, int port) { + return createMono(() -> commandBuilder.slaveof(host, port)); } @Override - public Single slaveofNoOne() { - return createSingle(() -> commandBuilder.slaveofNoOne()); + public Mono slaveofNoOne() { + return createMono(() -> commandBuilder.slaveofNoOne()); } @Override - public Observable slowlogGet() { - return createDissolvingObservable(() -> commandBuilder.slowlogGet()); + public Flux slowlogGet() { + return createDissolvingFlux(() -> commandBuilder.slowlogGet()); } @Override - public Observable slowlogGet(int count) { - return createDissolvingObservable(() -> commandBuilder.slowlogGet(count)); + public Flux slowlogGet(int count) { + return createDissolvingFlux(() -> commandBuilder.slowlogGet(count)); } @Override - public Single slowlogLen() { - return createSingle(() -> commandBuilder.slowlogLen()); + public Mono slowlogLen() { + return createMono(() -> commandBuilder.slowlogLen()); } @Override - public Single slowlogReset() { - return createSingle(() -> commandBuilder.slowlogReset()); + public Mono slowlogReset() { + return createMono(() -> commandBuilder.slowlogReset()); } @Override - public Observable smembers(K key) { - return createDissolvingObservable(() -> commandBuilder.smembers(key)); + public Flux smembers(K key) { + return createDissolvingFlux(() -> commandBuilder.smembers(key)); } @Override - public Single smembers(ValueStreamingChannel channel, K key) { - return createSingle(() -> commandBuilder.smembers(channel, key)); + public Mono smembers(ValueStreamingChannel channel, K key) { + return createMono(() -> commandBuilder.smembers(channel, key)); } @Override - public Observable sort(K key) { - return createDissolvingObservable(() -> commandBuilder.sort(key)); + public Flux sort(K key) { + return createDissolvingFlux(() -> commandBuilder.sort(key)); } @Override - public Single sort(ValueStreamingChannel channel, K key) { - return createSingle(() -> commandBuilder.sort(channel, key)); + public Mono sort(ValueStreamingChannel channel, K key) { + return createMono(() -> commandBuilder.sort(channel, key)); } @Override - public Observable sort(K key, SortArgs sortArgs) { - return createDissolvingObservable(() -> commandBuilder.sort(key, sortArgs)); + public Flux sort(K key, SortArgs sortArgs) { + return createDissolvingFlux(() -> commandBuilder.sort(key, sortArgs)); } @Override - public Single sort(ValueStreamingChannel channel, K key, SortArgs sortArgs) { - return createSingle(() -> commandBuilder.sort(channel, key, sortArgs)); + public Mono sort(ValueStreamingChannel channel, K key, SortArgs sortArgs) { + return createMono(() -> commandBuilder.sort(channel, key, sortArgs)); } @Override - public Single sortStore(K key, SortArgs sortArgs, K destination) { - return createSingle(() -> commandBuilder.sortStore(key, sortArgs, destination)); + public Mono sortStore(K key, SortArgs sortArgs, K destination) { + return createMono(() -> commandBuilder.sortStore(key, sortArgs, destination)); } @Override - public Single spop(K key) { - return createSingle(() -> commandBuilder.spop(key)); + public Mono spop(K key) { + return createMono(() -> commandBuilder.spop(key)); } @Override - public Observable spop(K key, long count) { - return createDissolvingObservable(() -> commandBuilder.spop(key, count)); + public Flux spop(K key, long count) { + return createDissolvingFlux(() -> commandBuilder.spop(key, count)); } @Override - public Single srandmember(K key) { - return createSingle(() -> commandBuilder.srandmember(key)); + public Mono srandmember(K key) { + return createMono(() -> commandBuilder.srandmember(key)); } @Override - public Observable srandmember(K key, long count) { - return createDissolvingObservable(() -> commandBuilder.srandmember(key, count)); + public Flux srandmember(K key, long count) { + return createDissolvingFlux(() -> commandBuilder.srandmember(key, count)); } @Override - public Single srandmember(ValueStreamingChannel channel, K key, long count) { - return createSingle(() -> commandBuilder.srandmember(channel, key, count)); + public Mono srandmember(ValueStreamingChannel channel, K key, long count) { + return createMono(() -> commandBuilder.srandmember(channel, key, count)); } @Override - public Single srem(K key, V... members) { - return createSingle(() -> commandBuilder.srem(key, members)); + public Mono srem(K key, V... members) { + return createMono(() -> commandBuilder.srem(key, members)); } @Override - public Observable sunion(K... keys) { - return createDissolvingObservable(() -> commandBuilder.sunion(keys)); + public Flux sunion(K... keys) { + return createDissolvingFlux(() -> commandBuilder.sunion(keys)); } @Override - public Single sunion(ValueStreamingChannel channel, K... keys) { - return createSingle(() -> commandBuilder.sunion(channel, keys)); + public Mono sunion(ValueStreamingChannel channel, K... keys) { + return createMono(() -> commandBuilder.sunion(channel, keys)); } @Override - public Single sunionstore(K destination, K... keys) { - return createSingle(() -> commandBuilder.sunionstore(destination, keys)); + public Mono sunionstore(K destination, K... keys) { + return createMono(() -> commandBuilder.sunionstore(destination, keys)); } @Override - public Single strlen(K key) { - return createSingle(() -> commandBuilder.strlen(key)); + public Mono strlen(K key) { + return createMono(() -> commandBuilder.strlen(key)); } @Override - public Single touch(K... keys) { - return createSingle(() -> commandBuilder.touch(keys)); + public Mono touch(K... keys) { + return createMono(() -> commandBuilder.touch(keys)); } - public Single touch(Iterable keys) { - return createSingle(() -> commandBuilder.touch(keys)); + public Mono touch(Iterable keys) { + return createMono(() -> commandBuilder.touch(keys)); } @Override - public Single ttl(K key) { - return createSingle(() -> commandBuilder.ttl(key)); + public Mono ttl(K key) { + return createMono(() -> commandBuilder.ttl(key)); } @Override - public Single type(K key) { - return createSingle(() -> commandBuilder.type(key)); + public Mono type(K key) { + return createMono(() -> commandBuilder.type(key)); } @Override - public Single watch(K... keys) { - return createSingle(() -> commandBuilder.watch(keys)); + public Mono watch(K... keys) { + return createMono(() -> commandBuilder.watch(keys)); } @Override - public Single unwatch() { - return createSingle(commandBuilder::unwatch); + public Mono unwatch() { + return createMono(commandBuilder::unwatch); } @Override - public Single zadd(K key, double score, V member) { - return createSingle(() -> commandBuilder.zadd(key, null, score, member)); + public Mono zadd(K key, double score, V member) { + return createMono(() -> commandBuilder.zadd(key, null, score, member)); } @Override - public Single zadd(K key, Object... scoresAndValues) { - return createSingle(() -> commandBuilder.zadd(key, null, scoresAndValues)); + public Mono zadd(K key, Object... scoresAndValues) { + return createMono(() -> commandBuilder.zadd(key, null, scoresAndValues)); } @Override - public Single zadd(K key, ScoredValue... scoredValues) { - return createSingle(() -> commandBuilder.zadd(key, null, (Object[]) scoredValues)); + public Mono zadd(K key, ScoredValue... scoredValues) { + return createMono(() -> commandBuilder.zadd(key, null, (Object[]) scoredValues)); } @Override - public Single zadd(K key, ZAddArgs zAddArgs, double score, V member) { - return createSingle(() -> commandBuilder.zadd(key, zAddArgs, score, member)); + public Mono zadd(K key, ZAddArgs zAddArgs, double score, V member) { + return createMono(() -> commandBuilder.zadd(key, zAddArgs, score, member)); } @Override - public Single zadd(K key, ZAddArgs zAddArgs, Object... scoresAndValues) { - return createSingle(() -> commandBuilder.zadd(key, zAddArgs, scoresAndValues)); + public Mono zadd(K key, ZAddArgs zAddArgs, Object... scoresAndValues) { + return createMono(() -> commandBuilder.zadd(key, zAddArgs, scoresAndValues)); } @Override - public Single zadd(K key, ZAddArgs zAddArgs, ScoredValue... scoredValues) { - return createSingle(() -> commandBuilder.zadd(key, zAddArgs, (Object[]) scoredValues)); + public Mono zadd(K key, ZAddArgs zAddArgs, ScoredValue... scoredValues) { + return createMono(() -> commandBuilder.zadd(key, zAddArgs, (Object[]) scoredValues)); } @Override - public Single zaddincr(K key, double score, V member) { - return createSingle(() -> commandBuilder.zaddincr(key, score, member)); + public Mono zaddincr(K key, double score, V member) { + return createMono(() -> commandBuilder.zaddincr(key, score, member)); } @Override - public Single zcard(K key) { - return createSingle(() -> commandBuilder.zcard(key)); + public Mono zcard(K key) { + return createMono(() -> commandBuilder.zcard(key)); } @Override - public Single zcount(K key, double min, double max) { - return createSingle(() -> commandBuilder.zcount(key, min, max)); + public Mono zcount(K key, double min, double max) { + return createMono(() -> commandBuilder.zcount(key, min, max)); } @Override - public Single zcount(K key, String min, String max) { - return createSingle(() -> commandBuilder.zcount(key, min, max)); + public Mono zcount(K key, String min, String max) { + return createMono(() -> commandBuilder.zcount(key, min, max)); } @Override - public Single zincrby(K key, double amount, K member) { - return createSingle(() -> commandBuilder.zincrby(key, amount, member)); + public Mono zincrby(K key, double amount, K member) { + return createMono(() -> commandBuilder.zincrby(key, amount, member)); } @Override - public Single zinterstore(K destination, K... keys) { - return createSingle(() -> commandBuilder.zinterstore(destination, keys)); + public Mono zinterstore(K destination, K... keys) { + return createMono(() -> commandBuilder.zinterstore(destination, keys)); } @Override - public Single zinterstore(K destination, ZStoreArgs storeArgs, K... keys) { - return createSingle(() -> commandBuilder.zinterstore(destination, storeArgs, keys)); + public Mono zinterstore(K destination, ZStoreArgs storeArgs, K... keys) { + return createMono(() -> commandBuilder.zinterstore(destination, storeArgs, keys)); } @Override - public Observable zrange(K key, long start, long stop) { - return createDissolvingObservable(() -> commandBuilder.zrange(key, start, stop)); + public Flux zrange(K key, long start, long stop) { + return createDissolvingFlux(() -> commandBuilder.zrange(key, start, stop)); } @Override - public Observable> zrangeWithScores(K key, long start, long stop) { - return createDissolvingObservable(() -> commandBuilder.zrangeWithScores(key, start, stop)); + public Flux> zrangeWithScores(K key, long start, long stop) { + return createDissolvingFlux(() -> commandBuilder.zrangeWithScores(key, start, stop)); } @Override - public Observable zrangebyscore(K key, double min, double max) { - return createDissolvingObservable(() -> commandBuilder.zrangebyscore(key, min, max)); + public Flux zrangebyscore(K key, double min, double max) { + return createDissolvingFlux(() -> commandBuilder.zrangebyscore(key, min, max)); } @Override - public Observable zrangebyscore(K key, String min, String max) { - return createDissolvingObservable(() -> commandBuilder.zrangebyscore(key, min, max)); + public Flux zrangebyscore(K key, String min, String max) { + return createDissolvingFlux(() -> commandBuilder.zrangebyscore(key, min, max)); } @Override - public Observable zrangebyscore(K key, double min, double max, long offset, long count) { - return createDissolvingObservable(() -> commandBuilder.zrangebyscore(key, min, max, offset, count)); + public Flux zrangebyscore(K key, double min, double max, long offset, long count) { + return createDissolvingFlux(() -> commandBuilder.zrangebyscore(key, min, max, offset, count)); } @Override - public Observable zrangebyscore(K key, String min, String max, long offset, long count) { - return createDissolvingObservable(() -> commandBuilder.zrangebyscore(key, min, max, offset, count)); + public Flux zrangebyscore(K key, String min, String max, long offset, long count) { + return createDissolvingFlux(() -> commandBuilder.zrangebyscore(key, min, max, offset, count)); } @Override - public Observable> zrangebyscoreWithScores(K key, double min, double max) { - return createDissolvingObservable(() -> commandBuilder.zrangebyscoreWithScores(key, min, max)); + public Flux> zrangebyscoreWithScores(K key, double min, double max) { + return createDissolvingFlux(() -> commandBuilder.zrangebyscoreWithScores(key, min, max)); } @Override - public Observable> zrangebyscoreWithScores(K key, String min, String max) { - return createDissolvingObservable(() -> commandBuilder.zrangebyscoreWithScores(key, min, max)); + public Flux> zrangebyscoreWithScores(K key, String min, String max) { + return createDissolvingFlux(() -> commandBuilder.zrangebyscoreWithScores(key, min, max)); } @Override - public Observable> zrangebyscoreWithScores(K key, double min, double max, long offset, long count) { - return createDissolvingObservable(() -> commandBuilder.zrangebyscoreWithScores(key, min, max, offset, count)); + public Flux> zrangebyscoreWithScores(K key, double min, double max, long offset, long count) { + return createDissolvingFlux(() -> commandBuilder.zrangebyscoreWithScores(key, min, max, offset, count)); } @Override - public Observable> zrangebyscoreWithScores(K key, String min, String max, long offset, long count) { - return createDissolvingObservable(() -> commandBuilder.zrangebyscoreWithScores(key, min, max, offset, count)); + public Flux> zrangebyscoreWithScores(K key, String min, String max, long offset, long count) { + return createDissolvingFlux(() -> commandBuilder.zrangebyscoreWithScores(key, min, max, offset, count)); } @Override - public Single zrange(ValueStreamingChannel channel, K key, long start, long stop) { - return createSingle(() -> commandBuilder.zrange(channel, key, start, stop)); + public Mono zrange(ValueStreamingChannel channel, K key, long start, long stop) { + return createMono(() -> commandBuilder.zrange(channel, key, start, stop)); } @Override - public Single zrangeWithScores(ScoredValueStreamingChannel channel, K key, long start, long stop) { - return createSingle(() -> commandBuilder.zrangeWithScores(channel, key, start, stop)); + public Mono zrangeWithScores(ScoredValueStreamingChannel channel, K key, long start, long stop) { + return createMono(() -> commandBuilder.zrangeWithScores(channel, key, start, stop)); } @Override - public Single zrangebyscore(ValueStreamingChannel channel, K key, double min, double max) { - return createSingle(() -> commandBuilder.zrangebyscore(channel, key, min, max)); + public Mono zrangebyscore(ValueStreamingChannel channel, K key, double min, double max) { + return createMono(() -> commandBuilder.zrangebyscore(channel, key, min, max)); } @Override - public Single zrangebyscore(ValueStreamingChannel channel, K key, String min, String max) { - return createSingle(() -> commandBuilder.zrangebyscore(channel, key, min, max)); + public Mono zrangebyscore(ValueStreamingChannel channel, K key, String min, String max) { + return createMono(() -> commandBuilder.zrangebyscore(channel, key, min, max)); } @Override - public Single zrangebyscore(ValueStreamingChannel channel, K key, double min, double max, long offset, + public Mono zrangebyscore(ValueStreamingChannel channel, K key, double min, double max, long offset, long count) { - return createSingle(() -> commandBuilder.zrangebyscore(channel, key, min, max, offset, count)); + return createMono(() -> commandBuilder.zrangebyscore(channel, key, min, max, offset, count)); } @Override - public Single zrangebyscore(ValueStreamingChannel channel, K key, String min, String max, long offset, + public Mono zrangebyscore(ValueStreamingChannel channel, K key, String min, String max, long offset, long count) { - return createSingle(() -> commandBuilder.zrangebyscore(channel, key, min, max, offset, count)); + return createMono(() -> commandBuilder.zrangebyscore(channel, key, min, max, offset, count)); } @Override - public Single zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, double min, double max) { - return createSingle(() -> commandBuilder.zrangebyscoreWithScores(channel, key, min, max)); + public Mono zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, double min, double max) { + return createMono(() -> commandBuilder.zrangebyscoreWithScores(channel, key, min, max)); } @Override - public Single zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, String min, String max) { - return createSingle(() -> commandBuilder.zrangebyscoreWithScores(channel, key, min, max)); + public Mono zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, String min, String max) { + return createMono(() -> commandBuilder.zrangebyscoreWithScores(channel, key, min, max)); } @Override - public Single zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, double min, double max, + public Mono zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, double min, double max, long offset, long count) { - return createSingle(() -> commandBuilder.zrangebyscoreWithScores(channel, key, min, max, offset, count)); + return createMono(() -> commandBuilder.zrangebyscoreWithScores(channel, key, min, max, offset, count)); } @Override - public Single zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, String min, String max, + public Mono zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, String min, String max, long offset, long count) { - return createSingle(() -> commandBuilder.zrangebyscoreWithScores(channel, key, min, max, offset, count)); + return createMono(() -> commandBuilder.zrangebyscoreWithScores(channel, key, min, max, offset, count)); } @Override - public Single zrank(K key, V member) { - return createSingle(() -> commandBuilder.zrank(key, member)); + public Mono zrank(K key, V member) { + return createMono(() -> commandBuilder.zrank(key, member)); } @Override - public Single zrem(K key, V... members) { - return createSingle(() -> commandBuilder.zrem(key, members)); + public Mono zrem(K key, V... members) { + return createMono(() -> commandBuilder.zrem(key, members)); } @Override - public Single zremrangebyrank(K key, long start, long stop) { - return createSingle(() -> commandBuilder.zremrangebyrank(key, start, stop)); + public Mono zremrangebyrank(K key, long start, long stop) { + return createMono(() -> commandBuilder.zremrangebyrank(key, start, stop)); } @Override - public Single zremrangebyscore(K key, double min, double max) { - return createSingle(() -> commandBuilder.zremrangebyscore(key, min, max)); + public Mono zremrangebyscore(K key, double min, double max) { + return createMono(() -> commandBuilder.zremrangebyscore(key, min, max)); } @Override - public Single zremrangebyscore(K key, String min, String max) { - return createSingle(() -> commandBuilder.zremrangebyscore(key, min, max)); + public Mono zremrangebyscore(K key, String min, String max) { + return createMono(() -> commandBuilder.zremrangebyscore(key, min, max)); } @Override - public Observable zrevrange(K key, long start, long stop) { - return createDissolvingObservable(() -> commandBuilder.zrevrange(key, start, stop)); + public Flux zrevrange(K key, long start, long stop) { + return createDissolvingFlux(() -> commandBuilder.zrevrange(key, start, stop)); } @Override - public Observable> zrevrangeWithScores(K key, long start, long stop) { - return createDissolvingObservable(() -> commandBuilder.zrevrangeWithScores(key, start, stop)); + public Flux> zrevrangeWithScores(K key, long start, long stop) { + return createDissolvingFlux(() -> commandBuilder.zrevrangeWithScores(key, start, stop)); } @Override - public Observable zrevrangebyscore(K key, double max, double min) { - return createDissolvingObservable(() -> commandBuilder.zrevrangebyscore(key, max, min)); + public Flux zrevrangebyscore(K key, double max, double min) { + return createDissolvingFlux(() -> commandBuilder.zrevrangebyscore(key, max, min)); } @Override - public Observable zrevrangebyscore(K key, String max, String min) { - return createDissolvingObservable(() -> commandBuilder.zrevrangebyscore(key, max, min)); + public Flux zrevrangebyscore(K key, String max, String min) { + return createDissolvingFlux(() -> commandBuilder.zrevrangebyscore(key, max, min)); } @Override - public Observable zrevrangebyscore(K key, double max, double min, long offset, long count) { - return createDissolvingObservable(() -> commandBuilder.zrevrangebyscore(key, max, min, offset, count)); + public Flux zrevrangebyscore(K key, double max, double min, long offset, long count) { + return createDissolvingFlux(() -> commandBuilder.zrevrangebyscore(key, max, min, offset, count)); } @Override - public Observable zrevrangebyscore(K key, String max, String min, long offset, long count) { - return createDissolvingObservable(() -> commandBuilder.zrevrangebyscore(key, max, min, offset, count)); + public Flux zrevrangebyscore(K key, String max, String min, long offset, long count) { + return createDissolvingFlux(() -> commandBuilder.zrevrangebyscore(key, max, min, offset, count)); } @Override - public Observable> zrevrangebyscoreWithScores(K key, double max, double min) { - return createDissolvingObservable(() -> commandBuilder.zrevrangebyscoreWithScores(key, max, min)); + public Flux> zrevrangebyscoreWithScores(K key, double max, double min) { + return createDissolvingFlux(() -> commandBuilder.zrevrangebyscoreWithScores(key, max, min)); } @Override - public Observable> zrevrangebyscoreWithScores(K key, String max, String min) { - return createDissolvingObservable(() -> commandBuilder.zrevrangebyscoreWithScores(key, max, min)); + public Flux> zrevrangebyscoreWithScores(K key, String max, String min) { + return createDissolvingFlux(() -> commandBuilder.zrevrangebyscoreWithScores(key, max, min)); } @Override - public Observable> zrevrangebyscoreWithScores(K key, double max, double min, long offset, long count) { - return createDissolvingObservable(() -> commandBuilder.zrevrangebyscoreWithScores(key, max, min, offset, count)); + public Flux> zrevrangebyscoreWithScores(K key, double max, double min, long offset, long count) { + return createDissolvingFlux(() -> commandBuilder.zrevrangebyscoreWithScores(key, max, min, offset, count)); } @Override - public Observable> zrevrangebyscoreWithScores(K key, String max, String min, long offset, long count) { - return createDissolvingObservable(() -> commandBuilder.zrevrangebyscoreWithScores(key, max, min, offset, count)); + public Flux> zrevrangebyscoreWithScores(K key, String max, String min, long offset, long count) { + return createDissolvingFlux(() -> commandBuilder.zrevrangebyscoreWithScores(key, max, min, offset, count)); } @Override - public Single zrevrange(ValueStreamingChannel channel, K key, long start, long stop) { - return createSingle(() -> commandBuilder.zrevrange(channel, key, start, stop)); + public Mono zrevrange(ValueStreamingChannel channel, K key, long start, long stop) { + return createMono(() -> commandBuilder.zrevrange(channel, key, start, stop)); } @Override - public Single zrevrangeWithScores(ScoredValueStreamingChannel channel, K key, long start, long stop) { - return createSingle(() -> commandBuilder.zrevrangeWithScores(channel, key, start, stop)); + public Mono zrevrangeWithScores(ScoredValueStreamingChannel channel, K key, long start, long stop) { + return createMono(() -> commandBuilder.zrevrangeWithScores(channel, key, start, stop)); } @Override - public Single zrevrangebyscore(ValueStreamingChannel channel, K key, double max, double min) { - return createSingle(() -> commandBuilder.zrevrangebyscore(channel, key, max, min)); + public Mono zrevrangebyscore(ValueStreamingChannel channel, K key, double max, double min) { + return createMono(() -> commandBuilder.zrevrangebyscore(channel, key, max, min)); } @Override - public Single zrevrangebyscore(ValueStreamingChannel channel, K key, String max, String min) { - return createSingle(() -> commandBuilder.zrevrangebyscore(channel, key, max, min)); + public Mono zrevrangebyscore(ValueStreamingChannel channel, K key, String max, String min) { + return createMono(() -> commandBuilder.zrevrangebyscore(channel, key, max, min)); } @Override - public Single zrevrangebyscore(ValueStreamingChannel channel, K key, double max, double min, long offset, + public Mono zrevrangebyscore(ValueStreamingChannel channel, K key, double max, double min, long offset, long count) { - return createSingle(() -> commandBuilder.zrevrangebyscore(channel, key, max, min, offset, count)); + return createMono(() -> commandBuilder.zrevrangebyscore(channel, key, max, min, offset, count)); } @Override - public Single zrevrangebyscore(ValueStreamingChannel channel, K key, String max, String min, long offset, + public Mono zrevrangebyscore(ValueStreamingChannel channel, K key, String max, String min, long offset, long count) { - return createSingle(() -> commandBuilder.zrevrangebyscore(channel, key, max, min, offset, count)); + return createMono(() -> commandBuilder.zrevrangebyscore(channel, key, max, min, offset, count)); } @Override - public Single zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, double max, double min) { - return createSingle(() -> commandBuilder.zrevrangebyscoreWithScores(channel, key, max, min)); + public Mono zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, double max, double min) { + return createMono(() -> commandBuilder.zrevrangebyscoreWithScores(channel, key, max, min)); } @Override - public Single zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, String max, String min) { - return createSingle(() -> commandBuilder.zrevrangebyscoreWithScores(channel, key, max, min)); + public Mono zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, String max, String min) { + return createMono(() -> commandBuilder.zrevrangebyscoreWithScores(channel, key, max, min)); } @Override - public Single zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, double max, double min, + public Mono zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, double max, double min, long offset, long count) { - return createSingle(() -> commandBuilder.zrevrangebyscoreWithScores(channel, key, max, min, offset, count)); + return createMono(() -> commandBuilder.zrevrangebyscoreWithScores(channel, key, max, min, offset, count)); } @Override - public Single zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, String max, String min, + public Mono zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, String max, String min, long offset, long count) { - return createSingle(() -> commandBuilder.zrevrangebyscoreWithScores(channel, key, max, min, offset, count)); + return createMono(() -> commandBuilder.zrevrangebyscoreWithScores(channel, key, max, min, offset, count)); } @Override - public Single zrevrank(K key, V member) { - return createSingle(() -> commandBuilder.zrevrank(key, member)); + public Mono zrevrank(K key, V member) { + return createMono(() -> commandBuilder.zrevrank(key, member)); } @Override - public Single zscore(K key, V member) { - return createSingle(() -> commandBuilder.zscore(key, member)); + public Mono zscore(K key, V member) { + return createMono(() -> commandBuilder.zscore(key, member)); } @Override - public Single zunionstore(K destination, K... keys) { - return createSingle(() -> commandBuilder.zunionstore(destination, keys)); + public Mono zunionstore(K destination, K... keys) { + return createMono(() -> commandBuilder.zunionstore(destination, keys)); } @Override - public Single zunionstore(K destination, ZStoreArgs storeArgs, K... keys) { - return createSingle(() -> commandBuilder.zunionstore(destination, storeArgs, keys)); + public Mono zunionstore(K destination, ZStoreArgs storeArgs, K... keys) { + return createMono(() -> commandBuilder.zunionstore(destination, storeArgs, keys)); } @Override - public Single> scan() { - return createSingle(commandBuilder::scan); + public Mono> scan() { + return createMono(commandBuilder::scan); } @Override - public Single> scan(ScanArgs scanArgs) { - return createSingle(() -> commandBuilder.scan(scanArgs)); + public Mono> scan(ScanArgs scanArgs) { + return createMono(() -> commandBuilder.scan(scanArgs)); } @Override - public Single> scan(ScanCursor scanCursor, ScanArgs scanArgs) { - return createSingle(() -> commandBuilder.scan(scanCursor, scanArgs)); + public Mono> scan(ScanCursor scanCursor, ScanArgs scanArgs) { + return createMono(() -> commandBuilder.scan(scanCursor, scanArgs)); } @Override - public Single> scan(ScanCursor scanCursor) { - return createSingle(() -> commandBuilder.scan(scanCursor)); + public Mono> scan(ScanCursor scanCursor) { + return createMono(() -> commandBuilder.scan(scanCursor)); } @Override - public Single scan(KeyStreamingChannel channel) { - return createSingle(() -> commandBuilder.scanStreaming(channel)); + public Mono scan(KeyStreamingChannel channel) { + return createMono(() -> commandBuilder.scanStreaming(channel)); } @Override - public Single scan(KeyStreamingChannel channel, ScanArgs scanArgs) { - return createSingle(() -> commandBuilder.scanStreaming(channel, scanArgs)); + public Mono scan(KeyStreamingChannel channel, ScanArgs scanArgs) { + return createMono(() -> commandBuilder.scanStreaming(channel, scanArgs)); } @Override - public Single scan(KeyStreamingChannel channel, ScanCursor scanCursor, ScanArgs scanArgs) { - return createSingle(() -> commandBuilder.scanStreaming(channel, scanCursor, scanArgs)); + public Mono scan(KeyStreamingChannel channel, ScanCursor scanCursor, ScanArgs scanArgs) { + return createMono(() -> commandBuilder.scanStreaming(channel, scanCursor, scanArgs)); } @Override - public Single scan(KeyStreamingChannel channel, ScanCursor scanCursor) { - return createSingle(() -> commandBuilder.scanStreaming(channel, scanCursor)); + public Mono scan(KeyStreamingChannel channel, ScanCursor scanCursor) { + return createMono(() -> commandBuilder.scanStreaming(channel, scanCursor)); } @Override - public Single> sscan(K key) { - return createSingle(() -> commandBuilder.sscan(key)); + public Mono> sscan(K key) { + return createMono(() -> commandBuilder.sscan(key)); } @Override - public Single> sscan(K key, ScanArgs scanArgs) { - return createSingle(() -> commandBuilder.sscan(key, scanArgs)); + public Mono> sscan(K key, ScanArgs scanArgs) { + return createMono(() -> commandBuilder.sscan(key, scanArgs)); } @Override - public Single> sscan(K key, ScanCursor scanCursor, ScanArgs scanArgs) { - return createSingle(() -> commandBuilder.sscan(key, scanCursor, scanArgs)); + public Mono> sscan(K key, ScanCursor scanCursor, ScanArgs scanArgs) { + return createMono(() -> commandBuilder.sscan(key, scanCursor, scanArgs)); } @Override - public Single> sscan(K key, ScanCursor scanCursor) { - return createSingle(() -> commandBuilder.sscan(key, scanCursor)); + public Mono> sscan(K key, ScanCursor scanCursor) { + return createMono(() -> commandBuilder.sscan(key, scanCursor)); } @Override - public Single sscan(ValueStreamingChannel channel, K key) { - return createSingle(() -> commandBuilder.sscanStreaming(channel, key)); + public Mono sscan(ValueStreamingChannel channel, K key) { + return createMono(() -> commandBuilder.sscanStreaming(channel, key)); } @Override - public Single sscan(ValueStreamingChannel channel, K key, ScanArgs scanArgs) { - return createSingle(() -> commandBuilder.sscanStreaming(channel, key, scanArgs)); + public Mono sscan(ValueStreamingChannel channel, K key, ScanArgs scanArgs) { + return createMono(() -> commandBuilder.sscanStreaming(channel, key, scanArgs)); } @Override - public Single sscan(ValueStreamingChannel channel, K key, ScanCursor scanCursor, ScanArgs scanArgs) { - return createSingle(() -> commandBuilder.sscanStreaming(channel, key, scanCursor, scanArgs)); + public Mono sscan(ValueStreamingChannel channel, K key, ScanCursor scanCursor, ScanArgs scanArgs) { + return createMono(() -> commandBuilder.sscanStreaming(channel, key, scanCursor, scanArgs)); } @Override - public Single sscan(ValueStreamingChannel channel, K key, ScanCursor scanCursor) { - return createSingle(() -> commandBuilder.sscanStreaming(channel, key, scanCursor)); + public Mono sscan(ValueStreamingChannel channel, K key, ScanCursor scanCursor) { + return createMono(() -> commandBuilder.sscanStreaming(channel, key, scanCursor)); } @Override - public Single> hscan(K key) { - return createSingle(() -> commandBuilder.hscan(key)); + public Mono> hscan(K key) { + return createMono(() -> commandBuilder.hscan(key)); } @Override - public Single> hscan(K key, ScanArgs scanArgs) { - return createSingle(() -> commandBuilder.hscan(key, scanArgs)); + public Mono> hscan(K key, ScanArgs scanArgs) { + return createMono(() -> commandBuilder.hscan(key, scanArgs)); } @Override - public Single> hscan(K key, ScanCursor scanCursor, ScanArgs scanArgs) { - return createSingle(() -> commandBuilder.hscan(key, scanCursor, scanArgs)); + public Mono> hscan(K key, ScanCursor scanCursor, ScanArgs scanArgs) { + return createMono(() -> commandBuilder.hscan(key, scanCursor, scanArgs)); } @Override - public Single> hscan(K key, ScanCursor scanCursor) { - return createSingle(() -> commandBuilder.hscan(key, scanCursor)); + public Mono> hscan(K key, ScanCursor scanCursor) { + return createMono(() -> commandBuilder.hscan(key, scanCursor)); } @Override - public Single hscan(KeyValueStreamingChannel channel, K key) { - return createSingle(() -> commandBuilder.hscanStreaming(channel, key)); + public Mono hscan(KeyValueStreamingChannel channel, K key) { + return createMono(() -> commandBuilder.hscanStreaming(channel, key)); } @Override - public Single hscan(KeyValueStreamingChannel channel, K key, ScanArgs scanArgs) { - return createSingle(() -> commandBuilder.hscanStreaming(channel, key, scanArgs)); + public Mono hscan(KeyValueStreamingChannel channel, K key, ScanArgs scanArgs) { + return createMono(() -> commandBuilder.hscanStreaming(channel, key, scanArgs)); } @Override - public Single hscan(KeyValueStreamingChannel channel, K key, ScanCursor scanCursor, + public Mono hscan(KeyValueStreamingChannel channel, K key, ScanCursor scanCursor, ScanArgs scanArgs) { - return createSingle(() -> commandBuilder.hscanStreaming(channel, key, scanCursor, scanArgs)); + return createMono(() -> commandBuilder.hscanStreaming(channel, key, scanCursor, scanArgs)); } @Override - public Single hscan(KeyValueStreamingChannel channel, K key, ScanCursor scanCursor) { - return createSingle(() -> commandBuilder.hscanStreaming(channel, key, scanCursor)); + public Mono hscan(KeyValueStreamingChannel channel, K key, ScanCursor scanCursor) { + return createMono(() -> commandBuilder.hscanStreaming(channel, key, scanCursor)); } @Override - public Single> zscan(K key) { - return createSingle(() -> commandBuilder.zscan(key)); + public Mono> zscan(K key) { + return createMono(() -> commandBuilder.zscan(key)); } @Override - public Single> zscan(K key, ScanArgs scanArgs) { - return createSingle(() -> commandBuilder.zscan(key, scanArgs)); + public Mono> zscan(K key, ScanArgs scanArgs) { + return createMono(() -> commandBuilder.zscan(key, scanArgs)); } @Override - public Single> zscan(K key, ScanCursor scanCursor, ScanArgs scanArgs) { - return createSingle(() -> commandBuilder.zscan(key, scanCursor, scanArgs)); + public Mono> zscan(K key, ScanCursor scanCursor, ScanArgs scanArgs) { + return createMono(() -> commandBuilder.zscan(key, scanCursor, scanArgs)); } @Override - public Single> zscan(K key, ScanCursor scanCursor) { - return createSingle(() -> commandBuilder.zscan(key, scanCursor)); + public Mono> zscan(K key, ScanCursor scanCursor) { + return createMono(() -> commandBuilder.zscan(key, scanCursor)); } @Override - public Single zscan(ScoredValueStreamingChannel channel, K key) { - return createSingle(() -> commandBuilder.zscanStreaming(channel, key)); + public Mono zscan(ScoredValueStreamingChannel channel, K key) { + return createMono(() -> commandBuilder.zscanStreaming(channel, key)); } @Override - public Single zscan(ScoredValueStreamingChannel channel, K key, ScanArgs scanArgs) { - return createSingle(() -> commandBuilder.zscanStreaming(channel, key, scanArgs)); + public Mono zscan(ScoredValueStreamingChannel channel, K key, ScanArgs scanArgs) { + return createMono(() -> commandBuilder.zscanStreaming(channel, key, scanArgs)); } @Override - public Single zscan(ScoredValueStreamingChannel channel, K key, ScanCursor scanCursor, + public Mono zscan(ScoredValueStreamingChannel channel, K key, ScanCursor scanCursor, ScanArgs scanArgs) { - return createSingle(() -> commandBuilder.zscanStreaming(channel, key, scanCursor, scanArgs)); + return createMono(() -> commandBuilder.zscanStreaming(channel, key, scanCursor, scanArgs)); } @Override - public Single zscan(ScoredValueStreamingChannel channel, K key, ScanCursor scanCursor) { - return createSingle(() -> commandBuilder.zscanStreaming(channel, key, scanCursor)); + public Mono zscan(ScoredValueStreamingChannel channel, K key, ScanCursor scanCursor) { + return createMono(() -> commandBuilder.zscanStreaming(channel, key, scanCursor)); } @Override @@ -1509,323 +1506,282 @@ public String digest(V script) { } @Override - public Observable time() { - return createDissolvingObservable(commandBuilder::time); + public Flux time() { + return createDissolvingFlux(commandBuilder::time); } @Override - public Single waitForReplication(int replicas, long timeout) { - return createSingle(() -> commandBuilder.wait(replicas, timeout)); + public Mono waitForReplication(int replicas, long timeout) { + return createMono(() -> commandBuilder.wait(replicas, timeout)); } @Override - public Single pfadd(K key, V... values) { - return createSingle(() -> commandBuilder.pfadd(key, values)); + public Mono pfadd(K key, V... values) { + return createMono(() -> commandBuilder.pfadd(key, values)); } - public Single pfadd(K key, V value, V... values) { - return createSingle(() -> commandBuilder.pfadd(key, value, values)); + public Mono pfadd(K key, V value, V... values) { + return createMono(() -> commandBuilder.pfadd(key, value, values)); } @Override - public Single pfmerge(K destkey, K... sourcekeys) { - return createSingle(() -> commandBuilder.pfmerge(destkey, sourcekeys)); + public Mono pfmerge(K destkey, K... sourcekeys) { + return createMono(() -> commandBuilder.pfmerge(destkey, sourcekeys)); } - public Single pfmerge(K destkey, K sourceKey, K... sourcekeys) { - return createSingle(() -> commandBuilder.pfmerge(destkey, sourceKey, sourcekeys)); + public Mono pfmerge(K destkey, K sourceKey, K... sourcekeys) { + return createMono(() -> commandBuilder.pfmerge(destkey, sourceKey, sourcekeys)); } @Override - public Single pfcount(K... keys) { - return createSingle(() -> commandBuilder.pfcount(keys)); + public Mono pfcount(K... keys) { + return createMono(() -> commandBuilder.pfcount(keys)); } - public Single pfcount(K key, K... keys) { - return createSingle(() -> commandBuilder.pfcount(key, keys)); + public Mono pfcount(K key, K... keys) { + return createMono(() -> commandBuilder.pfcount(key, keys)); } @Override - public Single clusterBumpepoch() { - return createSingle(() -> commandBuilder.clusterBumpepoch()); + public Mono clusterBumpepoch() { + return createMono(() -> commandBuilder.clusterBumpepoch()); } @Override - public Single clusterMeet(String ip, int port) { - return createSingle(() -> commandBuilder.clusterMeet(ip, port)); + public Mono clusterMeet(String ip, int port) { + return createMono(() -> commandBuilder.clusterMeet(ip, port)); } @Override - public Single clusterForget(String nodeId) { - return createSingle(() -> commandBuilder.clusterForget(nodeId)); + public Mono clusterForget(String nodeId) { + return createMono(() -> commandBuilder.clusterForget(nodeId)); } @Override - public Single clusterAddSlots(int... slots) { - return createSingle(() -> commandBuilder.clusterAddslots(slots)); + public Mono clusterAddSlots(int... slots) { + return createMono(() -> commandBuilder.clusterAddslots(slots)); } @Override - public Single clusterDelSlots(int... slots) { - return createSingle(() -> commandBuilder.clusterDelslots(slots)); + public Mono clusterDelSlots(int... slots) { + return createMono(() -> commandBuilder.clusterDelslots(slots)); } @Override - public Single clusterInfo() { - return createSingle(commandBuilder::clusterInfo); + public Mono clusterInfo() { + return createMono(commandBuilder::clusterInfo); } @Override - public Single clusterMyId() { - return createSingle(commandBuilder::clusterMyId); + public Mono clusterMyId() { + return createMono(commandBuilder::clusterMyId); } @Override - public Single clusterNodes() { - return createSingle(commandBuilder::clusterNodes); + public Mono clusterNodes() { + return createMono(commandBuilder::clusterNodes); } @Override - public Observable clusterGetKeysInSlot(int slot, int count) { - return createDissolvingObservable(() -> commandBuilder.clusterGetKeysInSlot(slot, count)); + public Flux clusterGetKeysInSlot(int slot, int count) { + return createDissolvingFlux(() -> commandBuilder.clusterGetKeysInSlot(slot, count)); } @Override - public Single clusterCountKeysInSlot(int slot) { - return createSingle(() -> commandBuilder.clusterCountKeysInSlot(slot)); + public Mono clusterCountKeysInSlot(int slot) { + return createMono(() -> commandBuilder.clusterCountKeysInSlot(slot)); } @Override - public Single clusterCountFailureReports(String nodeId) { - return createSingle(() -> commandBuilder.clusterCountFailureReports(nodeId)); + public Mono clusterCountFailureReports(String nodeId) { + return createMono(() -> commandBuilder.clusterCountFailureReports(nodeId)); } @Override - public Single clusterKeyslot(K key) { - return createSingle(() -> commandBuilder.clusterKeyslot(key)); + public Mono clusterKeyslot(K key) { + return createMono(() -> commandBuilder.clusterKeyslot(key)); } @Override - public Single clusterSaveconfig() { - return createSingle(() -> commandBuilder.clusterSaveconfig()); + public Mono clusterSaveconfig() { + return createMono(() -> commandBuilder.clusterSaveconfig()); } @Override - public Single clusterSetConfigEpoch(long configEpoch) { - return createSingle(() -> commandBuilder.clusterSetConfigEpoch(configEpoch)); + public Mono clusterSetConfigEpoch(long configEpoch) { + return createMono(() -> commandBuilder.clusterSetConfigEpoch(configEpoch)); } @Override - public Observable clusterSlots() { - return createDissolvingObservable(commandBuilder::clusterSlots); + public Flux clusterSlots() { + return createDissolvingFlux(commandBuilder::clusterSlots); } @Override - public Single clusterSetSlotNode(int slot, String nodeId) { - return createSingle(() -> commandBuilder.clusterSetSlotNode(slot, nodeId)); + public Mono clusterSetSlotNode(int slot, String nodeId) { + return createMono(() -> commandBuilder.clusterSetSlotNode(slot, nodeId)); } @Override - public Single clusterSetSlotStable(int slot) { - return createSingle(() -> commandBuilder.clusterSetSlotStable(slot)); + public Mono clusterSetSlotStable(int slot) { + return createMono(() -> commandBuilder.clusterSetSlotStable(slot)); } @Override - public Single clusterSetSlotMigrating(int slot, String nodeId) { - return createSingle(() -> commandBuilder.clusterSetSlotMigrating(slot, nodeId)); + public Mono clusterSetSlotMigrating(int slot, String nodeId) { + return createMono(() -> commandBuilder.clusterSetSlotMigrating(slot, nodeId)); } @Override - public Single clusterSetSlotImporting(int slot, String nodeId) { - return createSingle(() -> commandBuilder.clusterSetSlotImporting(slot, nodeId)); + public Mono clusterSetSlotImporting(int slot, String nodeId) { + return createMono(() -> commandBuilder.clusterSetSlotImporting(slot, nodeId)); } @Override - public Single clusterFailover(boolean force) { - return createSingle(() -> commandBuilder.clusterFailover(force)); + public Mono clusterFailover(boolean force) { + return createMono(() -> commandBuilder.clusterFailover(force)); } @Override - public Single clusterReset(boolean hard) { - return createSingle(() -> commandBuilder.clusterReset(hard)); + public Mono clusterReset(boolean hard) { + return createMono(() -> commandBuilder.clusterReset(hard)); } @Override - public Single asking() { - return createSingle(commandBuilder::asking); + public Mono asking() { + return createMono(commandBuilder::asking); } @Override - public Single clusterReplicate(String nodeId) { - return createSingle(() -> commandBuilder.clusterReplicate(nodeId)); + public Mono clusterReplicate(String nodeId) { + return createMono(() -> commandBuilder.clusterReplicate(nodeId)); } @Override - public Single clusterFlushslots() { - return createSingle(commandBuilder::clusterFlushslots); + public Mono clusterFlushslots() { + return createMono(commandBuilder::clusterFlushslots); } @Override - public Observable clusterSlaves(String nodeId) { - return createDissolvingObservable(() -> commandBuilder.clusterSlaves(nodeId)); + public Flux clusterSlaves(String nodeId) { + return createDissolvingFlux(() -> commandBuilder.clusterSlaves(nodeId)); } @Override - public Single zlexcount(K key, String min, String max) { - return createSingle(() -> commandBuilder.zlexcount(key, min, max)); + public Mono zlexcount(K key, String min, String max) { + return createMono(() -> commandBuilder.zlexcount(key, min, max)); } @Override - public Single zremrangebylex(K key, String min, String max) { - return createSingle(() -> commandBuilder.zremrangebylex(key, min, max)); + public Mono zremrangebylex(K key, String min, String max) { + return createMono(() -> commandBuilder.zremrangebylex(key, min, max)); } @Override - public Observable zrangebylex(K key, String min, String max) { - return createDissolvingObservable(() -> commandBuilder.zrangebylex(key, min, max)); + public Flux zrangebylex(K key, String min, String max) { + return createDissolvingFlux(() -> commandBuilder.zrangebylex(key, min, max)); } @Override - public Observable zrangebylex(K key, String min, String max, long offset, long count) { - return createDissolvingObservable(() -> commandBuilder.zrangebylex(key, min, max, offset, count)); + public Flux zrangebylex(K key, String min, String max, long offset, long count) { + return createDissolvingFlux(() -> commandBuilder.zrangebylex(key, min, max, offset, count)); } @Override - public Single geoadd(K key, double longitude, double latitude, V member) { - return createSingle(() -> commandBuilder.geoadd(key, longitude, latitude, member)); + public Mono geoadd(K key, double longitude, double latitude, V member) { + return createMono(() -> commandBuilder.geoadd(key, longitude, latitude, member)); } @Override - public Single geoadd(K key, Object... lngLatMember) { - return createSingle(() -> commandBuilder.geoadd(key, lngLatMember)); + public Mono geoadd(K key, Object... lngLatMember) { + return createMono(() -> commandBuilder.geoadd(key, lngLatMember)); } @Override - public Observable geohash(K key, V... members) { - return createDissolvingObservable(() -> commandBuilder.geohash(key, members)); + public Flux> geohash(K key, V... members) { + return createDissolvingFlux(() -> commandBuilder.geohash(key, members)); } @Override - public Observable georadius(K key, double longitude, double latitude, double distance, GeoArgs.Unit unit) { - return createDissolvingObservable(() -> commandBuilder.georadius(key, longitude, latitude, distance, unit.name())); + public Flux georadius(K key, double longitude, double latitude, double distance, Unit unit) { + return createDissolvingFlux(() -> commandBuilder.georadius(key, longitude, latitude, distance, unit.name())); } @Override - public Observable> georadius(K key, double longitude, double latitude, double distance, GeoArgs.Unit unit, + public Flux> georadius(K key, double longitude, double latitude, double distance, Unit unit, GeoArgs geoArgs) { - return createDissolvingObservable(() -> commandBuilder.georadius(key, longitude, latitude, distance, unit.name(), + return createDissolvingFlux(() -> commandBuilder.georadius(key, longitude, latitude, distance, unit.name(), geoArgs)); } @Override - public Single georadius(K key, double longitude, double latitude, double distance, Unit unit, + public Mono georadius(K key, double longitude, double latitude, double distance, Unit unit, GeoRadiusStoreArgs geoRadiusStoreArgs) { - return createSingle( + return createMono( () -> commandBuilder.georadius(key, longitude, latitude, distance, unit.name(), geoRadiusStoreArgs)); } @Override - public Observable georadiusbymember(K key, V member, double distance, GeoArgs.Unit unit) { - return createDissolvingObservable(() -> commandBuilder.georadiusbymember(key, member, distance, unit.name())); + public Flux georadiusbymember(K key, V member, double distance, Unit unit) { + return createDissolvingFlux(() -> commandBuilder.georadiusbymember(key, member, distance, unit.name())); } @Override - public Observable> georadiusbymember(K key, V member, double distance, GeoArgs.Unit unit, GeoArgs geoArgs) { - return createDissolvingObservable(() -> commandBuilder.georadiusbymember(key, member, distance, unit.name(), geoArgs)); + public Flux> georadiusbymember(K key, V member, double distance, Unit unit, GeoArgs geoArgs) { + return createDissolvingFlux(() -> commandBuilder.georadiusbymember(key, member, distance, unit.name(), geoArgs)); } @Override - public Single georadiusbymember(K key, V member, double distance, Unit unit, + public Mono georadiusbymember(K key, V member, double distance, Unit unit, GeoRadiusStoreArgs geoRadiusStoreArgs) { - return createSingle( + return createMono( () -> commandBuilder.georadiusbymember(key, member, distance, unit.name(), geoRadiusStoreArgs)); } @Override - public Observable geopos(K key, V... members) { - return createDissolvingObservable(() -> commandBuilder.geopos(key, members)); + public Flux> geopos(K key, V... members) { + return createDissolvingFlux(() -> commandBuilder.geopos(key, members)); } @Override - public Single geodist(K key, V from, V to, GeoArgs.Unit unit) { - return createSingle(() -> commandBuilder.geodist(key, from, to, unit)); + public Mono geodist(K key, V from, V to, Unit unit) { + return createMono(() -> commandBuilder.geodist(key, from, to, unit)); } - public Observable dispatch(ProtocolKeyword type, CommandOutput output) { + @SuppressWarnings("unchecked") + public Flux dispatch(ProtocolKeyword type, CommandOutput output) { LettuceAssert.notNull(type, "Command type must not be null"); LettuceAssert.notNull(output, "CommandOutput type must not be null"); - return createDissolvingObservable(() -> new Command<>(type, output)); + return (Flux) createFlux(() -> new Command<>(type, output)); } - public Observable dispatch(ProtocolKeyword type, CommandOutput output, CommandArgs args) { + @SuppressWarnings("unchecked") + public Flux dispatch(ProtocolKeyword type, CommandOutput output, CommandArgs args) { LettuceAssert.notNull(type, "Command type must not be null"); LettuceAssert.notNull(output, "CommandOutput type must not be null"); LettuceAssert.notNull(args, "CommandArgs type must not be null"); - return createDissolvingObservable(() -> new Command<>(type, output, args)); - } - - protected Observable createObservable(CommandType type, CommandOutput output, CommandArgs args) { - return createObservable(() -> new Command<>(type, output, args)); + return (Flux) createFlux(() -> new Command<>(type, output, args)); } - public Observable createObservable(Supplier> commandSupplier) { - return Observable.create(new ReactiveCommandDispatcher(commandSupplier, connection, false).getObservableSubscriber()); + public Flux createFlux(Supplier> commandSupplier) { + return Flux.from(new RedisPublisher(commandSupplier, connection, false)); } - protected Single createSingle(CommandType type, CommandOutput output, CommandArgs args) { - return createSingle(() -> new Command<>(type, output, args)); + protected Mono createMono(CommandType type, CommandOutput output, CommandArgs args) { + return createMono(() -> new Command<>(type, output, args)); } - public Single createSingle(Supplier> commandSupplier) { - return Single.create(new ReactiveCommandDispatcher(commandSupplier, connection, false).getSingleSubscriber()); + public Mono createMono(Supplier> commandSupplier) { + return Mono.from(new RedisPublisher(commandSupplier, connection, false)); } @SuppressWarnings("unchecked") - public Observable createDissolvingObservable(Supplier> commandSupplier) { - return (Observable) Observable.create(new ReactiveCommandDispatcher<>(commandSupplier, connection, true).getObservableSubscriber()); - } - - @SuppressWarnings("unchecked") - public R createDissolvingObservable(CommandType type, CommandOutput output, CommandArgs args) { - return (R) Observable.create(new ReactiveCommandDispatcher(() -> new Command<>(type, output, args), - connection, true).getObservableSubscriber()); - } - - /** - * Emits just {@link Success#Success} or the {@link Throwable} after the inner observable is completed. - * - * @param observable inner observable - * @param used for type inference - * @return Success observable - */ - protected Observable getSuccessObservable(final Observable observable) { - return Observable.create(new Observable.OnSubscribe() { - @Override - public void call(Subscriber subscriber) { - - observable.subscribe(new Subscriber() { - @Override - public void onCompleted() { - subscriber.onNext(Success.Success); - subscriber.onCompleted(); - } - - @Override - public void onError(Throwable throwable) { - subscriber.onError(throwable); - } - - @Override - public void onNext(Object k) { - - } - }); - } - }); + public Flux createDissolvingFlux(Supplier> commandSupplier) { + return (Flux) Flux.from(new RedisPublisher(commandSupplier, connection, true)); } public void setTimeout(long timeout, TimeUnit unit) { diff --git a/src/main/java/com/lambdaworks/redis/BackpressureUtils.java b/src/main/java/com/lambdaworks/redis/BackpressureUtils.java new file mode 100644 index 0000000000..3a211e789d --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/BackpressureUtils.java @@ -0,0 +1,146 @@ +package com.lambdaworks.redis; + +import java.util.Objects; +import java.util.concurrent.atomic.AtomicLong; + +import org.reactivestreams.Subscriber; +import org.reactivestreams.Subscription; + +import reactor.core.Exceptions; + +enum BackpressureUtils { + ; + + /** + * Check Subscription current state and cancel new Subscription if different null, returning true if ready to subscribe. + * + * @param current current Subscription, expected to be null + * @param next new Subscription + * @return true if Subscription can be used + */ + public static boolean validate(Subscription current, Subscription next) { + Objects.requireNonNull(next, "Subscription cannot be null"); + if (current != null) { + next.cancel(); + // reportSubscriptionSet(); + return false; + } + + return true; + } + + /** + * Evaluate if a request is strictly positive otherwise {@link #reportBadRequest(long)} + * + * @param n the request value + * @return true if valid + */ + public static boolean validate(long n) { + if (n < 0) { + reportBadRequest(n); + return false; + } + return true; + } + + /** + * Throws an exception if request is 0 or negative as specified in rule 3.09 of Reactive Streams + * + * @param n demand to check + * @param subscriber Subscriber to onError if non strict positive n + * + * @return true if valid or false if specification exception occured + * + * @throws IllegalArgumentException if subscriber is null and demand is negative or 0. + */ + public static boolean checkRequest(long n, Subscriber subscriber) { + if (n <= 0L) { + if (null != subscriber) { + subscriber.onError(Exceptions.nullOrNegativeRequestException(n)); + } else { + throw Exceptions.nullOrNegativeRequestException(n); + } + return false; + } + return true; + } + + /** + * Cap an addition to Long.MAX_VALUE + * + * @param a left operand + * @param b right operand + * @return Addition result or Long.MAX_VALUE if overflow + */ + public static long addCap(long a, long b) { + long res = a + b; + if (res < 0L) { + return Long.MAX_VALUE; + } + return res; + } + + /** + * Cap a substraction to 0 + * + * @param a left operand + * @param b right operand + * @return Subscription result or 0 if overflow + */ + public static long subOrZero(long a, long b) { + long res = a - b; + if (res < 0L) { + return 0; + } + return res; + } + + /** + * Concurrent addition bound to Long.MAX_VALUE. Any concurrent write will "happen" before this operation. + * + * @param current current atomic to update + * @param toAdd delta to add + * @return Addition result or Long.MAX_VALUE + */ + public static long addAndGet(AtomicLong current, long toAdd) { + long u, r; + do { + r = current.get(); + if (r == Long.MAX_VALUE) { + return Long.MAX_VALUE; + } + u = addCap(r, toAdd); + } while (!current.compareAndSet(r, u)); + + return u; + } + + /** + * Concurrent substraction bound to 0 and Long.MAX_VALUE. Any concurrent write will "happen" before this operation. + * + * @param sequence current atomic to update + * @param toSub delta to sub + * @return value before subscription, 0 or Long.MAX_VALUE + */ + public static long getAndSub(AtomicLong sequence, long toSub) { + long r, u; + do { + r = sequence.get(); + if (r == 0 || r == Long.MAX_VALUE) { + return r; + } + u = subOrZero(r, toSub); + } while (!sequence.compareAndSet(r, u)); + + return r; + } + + /** + * Throw {@link IllegalArgumentException} + * + * @param n the demand to evaluate + */ + public static void reportBadRequest(long n) { + throw Exceptions.nullOrNegativeRequestException(n); + } +} \ No newline at end of file diff --git a/src/main/java/com/lambdaworks/redis/ReactiveCommandDispatcher.java b/src/main/java/com/lambdaworks/redis/ReactiveCommandDispatcher.java deleted file mode 100644 index d9c6fc41cc..0000000000 --- a/src/main/java/com/lambdaworks/redis/ReactiveCommandDispatcher.java +++ /dev/null @@ -1,329 +0,0 @@ -package com.lambdaworks.redis; - -import java.util.Arrays; -import java.util.Collection; -import java.util.concurrent.CancellationException; -import java.util.function.Supplier; - -import com.lambdaworks.redis.api.StatefulConnection; -import com.lambdaworks.redis.api.StatefulRedisConnection; -import com.lambdaworks.redis.internal.LettuceAssert; -import com.lambdaworks.redis.output.StreamingOutput; -import com.lambdaworks.redis.protocol.CommandWrapper; -import com.lambdaworks.redis.protocol.RedisCommand; - -import io.netty.util.internal.logging.InternalLogger; -import io.netty.util.internal.logging.InternalLoggerFactory; -import rx.Observable; -import rx.Single; -import rx.Subscriber; - -/** - * Reactive command dispatcher. - * - * @author Mark Paluch - */ -public class ReactiveCommandDispatcher { - - private final static InternalLogger LOG = InternalLoggerFactory.getInstance(ReactiveCommandDispatcher.class); - - private Supplier> commandSupplier; - private volatile RedisCommand command; - private StatefulConnection connection; - private boolean dissolve; - - /** - * - * @param staticCommand static command, must not be {@literal null} - * @param connection the connection, must not be {@literal null} - * @param dissolve dissolve collections into particular elements - */ - public ReactiveCommandDispatcher(RedisCommand staticCommand, StatefulConnection connection, - boolean dissolve) { - this(() -> staticCommand, connection, dissolve); - } - - /** - * - * @param commandSupplier command supplier, must not be {@literal null} - * @param connection the connection, must not be {@literal null} - * @param dissolve dissolve collections into particular elements - */ - public ReactiveCommandDispatcher(Supplier> commandSupplier, StatefulConnection connection, - boolean dissolve) { - - LettuceAssert.notNull(commandSupplier, "CommandSupplier must not be null"); - LettuceAssert.notNull(connection, "StatefulConnection must not be null"); - - this.commandSupplier = commandSupplier; - this.connection = connection; - this.dissolve = dissolve; - this.command = commandSupplier.get(); - - } - - public Single.OnSubscribe getSingleSubscriber() { - return new SingleSubscriber(); - } - - public Observable.OnSubscribe getObservableSubscriber() { - return new ObservableSubscriber(); - } - - private class ObservableSubscriber implements Observable.OnSubscribe { - - @Override - public void call(Subscriber subscriber) { - - // Reuse the first command but then discard it. - RedisCommand command = ReactiveCommandDispatcher.this.command; - if (command == null) { - command = commandSupplier.get(); - } - - if (command.getOutput() instanceof StreamingOutput) { - StreamingOutput streamingOutput = (StreamingOutput) command.getOutput(); - - if (connection instanceof StatefulRedisConnection && ((StatefulRedisConnection) connection).isMulti()) { - streamingOutput.setSubscriber(new DelegatingWrapper( - Arrays.asList(new ObservableSubscriberWrapper<>(subscriber), streamingOutput.getSubscriber()))); - } else { - streamingOutput.setSubscriber(new ObservableSubscriberWrapper<>(subscriber)); - } - } - - connection.dispatch(new ObservableCommand<>(command, subscriber, dissolve)); - - ReactiveCommandDispatcher.this.command = null; - } - } - - private class SingleSubscriber implements Single.OnSubscribe { - - @Override - public void call(rx.SingleSubscriber subscriber) { - - // Reuse the first command but then discard it. - RedisCommand command = ReactiveCommandDispatcher.this.command; - if (command == null) { - command = commandSupplier.get(); - } - - if (command.getOutput() instanceof StreamingOutput) { - StreamingOutput streamingOutput = (StreamingOutput) command.getOutput(); - - if (connection instanceof StatefulRedisConnection && ((StatefulRedisConnection) connection).isMulti()) { - streamingOutput.setSubscriber(new DelegatingWrapper( - Arrays.asList(new SingleSubscriberWrapper(subscriber), streamingOutput.getSubscriber()))); - } else { - streamingOutput.setSubscriber(new SingleSubscriberWrapper(subscriber)); - } - } - - connection.dispatch(new SingleCommand<>(command, subscriber)); - - ReactiveCommandDispatcher.this.command = null; - } - } - - private static class ObservableCommand extends CommandWrapper { - - private final Subscriber subscriber; - private final boolean dissolve; - private boolean completed = false; - - public ObservableCommand(RedisCommand command, Subscriber subscriber, boolean dissolve) { - super(command); - this.subscriber = subscriber; - this.dissolve = dissolve; - } - - @Override - @SuppressWarnings("unchecked") - public void complete() { - if (completed || subscriber.isUnsubscribed()) { - return; - } - - try { - super.complete(); - - if (getOutput() != null) { - Object result = getOutput().get(); - - if (!(getOutput() instanceof StreamingOutput) && result != null) { - - if (dissolve && result instanceof Collection) { - Collection collection = (Collection) result; - for (T t : collection) { - if (t != null) { - subscriber.onNext(t); - } - } - } else { - subscriber.onNext((T) result); - } - } - - if (getOutput().hasError()) { - onError(new RedisCommandExecutionException(getOutput().getError())); - completed = true; - return; - } - } - - try { - subscriber.onCompleted(); - } catch (Exception e) { - completeExceptionally(e); - } - } finally { - completed = true; - } - } - - @Override - public void cancel() { - - if (completed || subscriber.isUnsubscribed()) { - return; - } - - super.cancel(); - - onError(new CancellationException()); - completed = true; - } - - @Override - public boolean completeExceptionally(Throwable throwable) { - - if (completed || subscriber.isUnsubscribed()) { - return false; - } - - boolean b = super.completeExceptionally(throwable); - onError(throwable); - completed = true; - return b; - } - - private void onError(Throwable throwable) { - subscriber.onError(throwable); - } - } - - private static class SingleCommand extends CommandWrapper { - - private final rx.SingleSubscriber subscriber; - private boolean completed = false; - - public SingleCommand(RedisCommand command, rx.SingleSubscriber subscriber) { - super(command); - this.subscriber = subscriber; - } - - @Override - @SuppressWarnings("unchecked") - public void complete() { - if (completed) { - return; - } - - super.complete(); - - if (getOutput() != null) { - Object result = getOutput().get(); - - if (getOutput().hasError()) { - onError(new RedisCommandExecutionException(getOutput().getError())); - completed = true; - return; - } else if (!(getOutput() instanceof StreamingOutput)) { - subscriber.onSuccess((T) result); - } - } - - completed = true; - } - - @Override - public void cancel() { - - if (completed) { - return; - } - - super.cancel(); - onError(new CancellationException()); - completed = true; - } - - @Override - public boolean completeExceptionally(Throwable throwable) { - - if (completed) { - return false; - } - - boolean b = super.completeExceptionally(throwable); - onError(throwable); - completed = true; - return b; - } - - private void onError(Throwable throwable) { - subscriber.onError(throwable); - } - } - - static class ObservableSubscriberWrapper implements StreamingOutput.Subscriber { - - private Subscriber subscriber; - - public ObservableSubscriberWrapper(Subscriber subscriber) { - this.subscriber = subscriber; - } - - @Override - public void onNext(T t) { - - if (subscriber.isUnsubscribed()) { - return; - } - - subscriber.onNext(t); - } - } - - static class SingleSubscriberWrapper implements StreamingOutput.Subscriber { - - private rx.SingleSubscriber subscriber; - - public SingleSubscriberWrapper(rx.SingleSubscriber subscriber) { - this.subscriber = subscriber; - } - - @Override - public void onNext(T t) { - subscriber.onSuccess(t); - } - } - - static class DelegatingWrapper implements StreamingOutput.Subscriber { - - private Collection> subscribers; - - public DelegatingWrapper(Collection> subscribers) { - this.subscribers = subscribers; - } - - @Override - public void onNext(T t) { - - for (StreamingOutput.Subscriber subscriber : subscribers) { - subscriber.onNext(t); - } - } - } -} diff --git a/src/main/java/com/lambdaworks/redis/RedisCommandBuilder.java b/src/main/java/com/lambdaworks/redis/RedisCommandBuilder.java index 4691172768..449704ed3f 100644 --- a/src/main/java/com/lambdaworks/redis/RedisCommandBuilder.java +++ b/src/main/java/com/lambdaworks/redis/RedisCommandBuilder.java @@ -2438,13 +2438,13 @@ public Command geoadd(K key, Object[] lngLatMember) { return createCommand(GEOADD, new IntegerOutput(codec), args); } - public Command> geohash(K key, V... members) { + public Command>> geohash(K key, V... members) { notNullKey(key); LettuceAssert.notNull(members, "Members " + MUST_NOT_BE_NULL); LettuceAssert.notEmpty(members, "Members " + MUST_NOT_BE_EMPTY); CommandArgs args = new CommandArgs(codec).addKey(key).addValues(members); - return createCommand(GEOHASH, new StringListOutput(codec), args); + return createCommand(GEOHASH, new StringValueListOutput(codec), args); } public Command> georadius(K key, double longitude, double latitude, double distance, String unit) { @@ -2527,7 +2527,7 @@ public Command georadiusbymember(K key, V member, double distance, S } @SuppressWarnings({ "unchecked", "rawtypes" }) - public Command> geopos(K key, V[] members) { + public Command>> geopos(K key, V[] members) { notNullKey(key); LettuceAssert.notNull(members, "Members " + MUST_NOT_BE_NULL); LettuceAssert.notEmpty(members, "Members " + MUST_NOT_BE_EMPTY); diff --git a/src/main/java/com/lambdaworks/redis/RedisPublisher.java b/src/main/java/com/lambdaworks/redis/RedisPublisher.java new file mode 100644 index 0000000000..f01f0c94db --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/RedisPublisher.java @@ -0,0 +1,578 @@ +package com.lambdaworks.redis; + +import java.io.IOException; +import java.util.Arrays; +import java.util.Collection; +import java.util.Objects; +import java.util.Queue; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Supplier; + +import org.reactivestreams.Publisher; +import org.reactivestreams.Subscriber; +import org.reactivestreams.Subscription; + +import com.lambdaworks.redis.api.StatefulConnection; +import com.lambdaworks.redis.api.StatefulRedisConnection; +import com.lambdaworks.redis.internal.LettuceAssert; +import com.lambdaworks.redis.output.StreamingOutput; +import com.lambdaworks.redis.protocol.CommandWrapper; +import com.lambdaworks.redis.protocol.RedisCommand; + +import io.netty.util.internal.logging.InternalLogger; +import io.netty.util.internal.logging.InternalLoggerFactory; + +/** + * Reactive command {@link Publisher} using ReactiveStreams. + * + * This publisher handles command execution and response propagation to a {@link Subscriber}. Collections can be dissolved into + * individual elements instead of emitting collections. This publisher allows multiple subscriptions if it's backed by a + * {@link Supplier command supplier}. + *

+ * When using streaming outputs ({@link com.lambdaworks.redis.output.CommandOutput} that implement {@link StreamingOutput}) + * elements are emitted as they are decoded. Otherwise, results are processed at command completion. + * + * @author Mark Paluch + * @since 5.0 + */ +class RedisPublisher implements Publisher { + + private final static InternalLogger LOG = InternalLoggerFactory.getInstance(RedisPublisher.class); + + private final boolean traceEnabled = LOG.isTraceEnabled(); + + private final Supplier> commandSupplier; + private final AtomicReference> ref; + private final StatefulConnection connection; + private final boolean dissolve; + + /** + * Creates a new {@link RedisPublisher} for a static command. + * + * @param staticCommand static command, must not be {@literal null} + * @param connection the connection, must not be {@literal null} + * @param dissolve dissolve collections into particular elements + */ + public RedisPublisher(RedisCommand staticCommand, StatefulConnection connection, boolean dissolve) { + this(() -> staticCommand, connection, dissolve); + } + + /** + * Creates a new {@link RedisPublisher} for a command supplier. + * + * @param commandSupplier command supplier, must not be {@literal null} + * @param connection the connection, must not be {@literal null} + * @param dissolve dissolve collections into particular elements + */ + public RedisPublisher(Supplier> commandSupplier, StatefulConnection connection, + boolean dissolve) { + + LettuceAssert.notNull(commandSupplier, "CommandSupplier must not be null"); + LettuceAssert.notNull(connection, "StatefulConnection must not be null"); + + this.commandSupplier = commandSupplier; + this.connection = connection; + this.dissolve = dissolve; + this.ref = new AtomicReference<>(commandSupplier.get()); + } + + @Override + public void subscribe(Subscriber subscriber) { + + if (this.traceEnabled) { + LOG.trace("subscribe: {}@{}", subscriber.getClass().getName(), Objects.hashCode(subscriber)); + } + + // Reuse the first command but then discard it. + RedisCommand command = ref.get(); + + if (command != null) { + if (!ref.compareAndSet(command, null)) { + command = commandSupplier.get(); + } + } else { + command = commandSupplier.get(); + } + + RedisSubscription redisSubscription = new RedisSubscription<>(connection, command, dissolve); + redisSubscription.subscribe(subscriber); + } + + /** + * Implementation of {@link Subscription}. This subscription can receive demand for data signals with {@link #request(long)} + * . It maintains a {@link State} to react on pull signals like demand for data or push signals as soon as data is + * available. Subscription behavior and state transitions are kept inside the {@link State}. + * + * @param data element type + */ + private static class RedisSubscription implements Subscription, StreamingOutput.Subscriber { + + private final static InternalLogger LOG = InternalLoggerFactory.getInstance(RedisPublisher.class); + private final boolean traceEnabled = LOG.isTraceEnabled(); + + private final AtomicLong demand = new AtomicLong(); + private final Queue data = new ConcurrentLinkedQueue(); + private final AtomicBoolean dispatched = new AtomicBoolean(); + + private final StatefulConnection connection; + private final RedisCommand command; + private final boolean dissolve; + + private Subscriber subscriber; + + private final AtomicReference state = new AtomicReference<>(State.UNSUBSCRIBED); + + RedisSubscription(StatefulConnection connection, RedisCommand command, boolean dissolve) { + + LettuceAssert.notNull(connection, "Connection must not be null"); + LettuceAssert.notNull(command, "RedisCommand must not be null"); + + this.connection = connection; + this.command = command; + this.dissolve = dissolve; + } + + /** + * Subscription procedure called by a {@link Publisher} + * + * @param subscriber the subscriber, must not be {@literal null}. + */ + void subscribe(Subscriber subscriber) { + + LettuceAssert.notNull(subscriber, "Subscriber must not be null"); + + if (traceEnabled) { + LOG.trace("{} subscribe: {}@{}", state(), subscriber.getClass().getName(), Objects.hashCode(subscriber)); + } + + state().subscribe(this, subscriber); + } + + /** + * Signal for data demand. + * + * @param n number of requested elements + */ + @Override + public final void request(long n) { + + if (traceEnabled) { + LOG.trace("{} request: {}", state(), n); + } + + state().request(this, n); + } + + /** + * Cancels a command. + */ + @Override + public final void cancel() { + + if (traceEnabled) { + LOG.trace("{} cancel", state()); + } + + state().cancel(this); + } + + private RedisPublisher.State state() { + return this.state.get(); + } + + /** + * Called by {@link StreamingOutput} to dispatch data (push). + * + * @param t element + */ + @Override + public void onNext(T t) { + + LettuceAssert.notNull(t, "Data must not be null"); + + data.add(t); + onDataAvailable(); + } + + /** + * Called via a listener interface to indicate that reading is possible. + * + */ + final void onDataAvailable() { + + if (traceEnabled) { + LOG.trace("{} onDataAvailable()", state()); + } + + this.state.get().onDataAvailable(this); + } + + /** + * Called via a listener interface to indicate that all data has been read. + * + */ + final void onAllDataRead() { + + if (traceEnabled) { + LOG.trace("{} onAllDataRead()", state()); + } + this.state.get().onAllDataRead(this); + } + + /** + * Called by a listener interface to indicate that as error has occured. + * + * @param t the error + */ + final void onError(Throwable t) { + + if (LOG.isErrorEnabled()) { + LOG.trace("{} onError(): {}", state(), t.toString(), t); + } + this.state.get().onError(this, t); + } + + /** + * Reads and publishes data from the input. Continues until either there is no more demand, or until there is no more + * data to be read. + * + * @return {@literal true} if there is more demand, {@literal false} otherwise + */ + private boolean readAndPublish() throws IOException { + + while (hasDemand()) { + T data = read(); + + if (data != null) { + BackpressureUtils.getAndSub(this.demand, 1L); + this.subscriber.onNext(data); + } else { + return true; + } + } + return false; + } + + /** + * Reads data from the input, if possible. + * + * @return the data that was read or {@literal null} + */ + protected T read() { + return data.poll(); + } + + private boolean hasDemand() { + return this.demand.get() > 0; + } + + private boolean changeState(State oldState, State newState) { + return this.state.compareAndSet(oldState, newState); + } + + void checkCommandDispatch() { + + if (!dispatched.get() && dispatched.compareAndSet(false, true)) { + dispatchCommand(); + } + } + + @SuppressWarnings("unchecked") + private void dispatchCommand() { + if (command.getOutput() instanceof StreamingOutput) { + StreamingOutput streamingOutput = (StreamingOutput) command.getOutput(); + + if (connection instanceof StatefulRedisConnection && ((StatefulRedisConnection) connection).isMulti()) { + streamingOutput + .setSubscriber(new CompositeSubscriber(Arrays.asList(this, streamingOutput.getSubscriber()))); + } else { + streamingOutput.setSubscriber(this); + } + } + + connection.dispatch(new SubscriptionCommand(command, this, dissolve)); + } + + void checkOnDataAvailable() { + + if (!data.isEmpty()) { + onDataAvailable(); + } + } + } + + /** + * Represents a state for the {@link Subscription} to be in. The following figure indicate the four different states that + * exist, and the relationships between them. + * + *

+     *       UNSUBSCRIBED
+     *        |
+     *        v
+     * NO_DEMAND -------------------> DEMAND
+     *    |    ^                      ^    |
+     *    |    |                      |    |
+     *    |    --------- READING <-----    |
+     *    |                 |              |
+     *    |                 v              |
+     *    ------------> COMPLETED <---------
+     * 
+ * + * Refer to the individual states for more information. + */ + private enum State { + + /** + * The initial unsubscribed state. Will respond to {@link #subscribe(RedisSubscription, Subscriber)} by changing state + * to {@link #NO_DEMAND}. + */ + UNSUBSCRIBED { + @SuppressWarnings("unchecked") + @Override + void subscribe(RedisSubscription subscription, Subscriber subscriber) { + + LettuceAssert.notNull(subscriber, "Subscriber must not be null"); + + if (subscription.changeState(this, NO_DEMAND)) { + subscription.subscriber = (Subscriber) subscriber; + subscriber.onSubscribe(subscription); + } else { + throw new IllegalStateException(toString()); + } + } + }, + + /** + * State that gets entered when there is no demand. Responds to {@link #request(RedisSubscription, long)} + * (RedisPublisher, long)} by increasing the demand, changing state to {@link #DEMAND} and will check whether there is + * data available for reading. + */ + NO_DEMAND { + @Override + void request(RedisSubscription subscription, long n) { + + if (BackpressureUtils.checkRequest(n, subscription.subscriber)) { + BackpressureUtils.addAndGet(subscription.demand, n); + + if (subscription.changeState(this, DEMAND)) { + subscription.checkCommandDispatch(); + subscription.checkOnDataAvailable(); + } + } + } + }, + + /** + * State that gets entered when there is demand. Responds to {@link #onDataAvailable(RedisSubscription)} by reading the + * available data. The state will be changed to {@link #NO_DEMAND} if there is no demand. + */ + DEMAND { + @Override + void onDataAvailable(RedisSubscription subscription) { + + if (subscription.changeState(this, READING)) { + + try { + + boolean demandAvailable = subscription.readAndPublish(); + if (demandAvailable) { + subscription.changeState(READING, DEMAND); + subscription.checkOnDataAvailable(); + } else { + subscription.changeState(READING, NO_DEMAND); + } + } catch (IOException ex) { + subscription.onError(ex); + } + } + } + }, + + READING { + @Override + void request(RedisSubscription subscription, long n) { + + if (BackpressureUtils.checkRequest(n, subscription.subscriber)) { + BackpressureUtils.addAndGet(subscription.demand, n); + } + } + }, + + /** + * The terminal completed state. Does not respond to any events. + */ + COMPLETED { + + @Override + void request(RedisSubscription subscription, long n) { + // ignore + } + + @Override + void cancel(RedisSubscription subscription) { + // ignore + } + + @Override + void onAllDataRead(RedisSubscription subscription) { + // ignore + } + + @Override + void onError(RedisSubscription subscription, Throwable t) { + // ignore + } + }; + + void subscribe(RedisSubscription subscription, Subscriber subscriber) { + throw new IllegalStateException(toString()); + } + + void request(RedisSubscription subscription, long n) { + throw new IllegalStateException(toString()); + } + + void cancel(RedisSubscription subscription) { + + subscription.command.cancel(); + subscription.changeState(this, COMPLETED); + } + + void onDataAvailable(RedisSubscription subscription) { + // ignore + } + + void onAllDataRead(RedisSubscription subscription) { + + if (subscription.changeState(this, COMPLETED)) { + if (subscription.subscriber != null) { + subscription.subscriber.onComplete(); + } + } + } + + void onError(RedisSubscription subscription, Throwable t) { + + if (subscription.changeState(this, COMPLETED)) { + if (subscription.subscriber != null) { + subscription.subscriber.onError(t); + } + } + } + } + + /** + * Command that emits it data after completion to a {@link RedisSubscription}. + * + * @param key type + * @param value type + * @param response type + */ + private static class SubscriptionCommand extends CommandWrapper { + + private final boolean dissolve; + private final RedisSubscription subscription; + private boolean completed = false; + + public SubscriptionCommand(RedisCommand command, RedisSubscription subscription, boolean dissolve) { + + super(command); + + this.subscription = subscription; + this.dissolve = dissolve; + } + + @Override + @SuppressWarnings("unchecked") + public void complete() { + + if (completed) { + return; + } + + try { + super.complete(); + + if (getOutput() != null) { + Object result = getOutput().get(); + + if (getOutput().hasError()) { + onError(new RedisCommandExecutionException(getOutput().getError())); + completed = true; + return; + } + + if (!(getOutput() instanceof StreamingOutput) && result != null) { + + if (dissolve && result instanceof Collection) { + Collection collection = (Collection) result; + for (T t : collection) { + if (t != null) { + subscription.onNext(t); + } + } + } else { + subscription.onNext((T) result); + } + } + + } + + subscription.onAllDataRead(); + } finally { + completed = true; + } + } + + @Override + public void cancel() { + + if (completed) { + return; + } + + super.cancel(); + + completed = true; + } + + @Override + public boolean completeExceptionally(Throwable throwable) { + + if (completed) { + return false; + } + + boolean b = super.completeExceptionally(throwable); + onError(throwable); + completed = true; + return b; + } + + private void onError(Throwable throwable) { + subscription.onError(throwable); + } + } + + /** + * Composite {@link com.lambdaworks.redis.output.StreamingOutput.Subscriber} that can notify multiple nested subscribers. + * + * @param element type + */ + private static class CompositeSubscriber implements StreamingOutput.Subscriber { + + private final Collection> subscribers; + + CompositeSubscriber(Collection> subscribers) { + this.subscribers = subscribers; + } + + @Override + public void onNext(T t) { + subscribers.forEach(subscriber -> subscriber.onNext(t)); + } + } +} diff --git a/src/main/java/com/lambdaworks/redis/RedisReactiveCommandsImpl.java b/src/main/java/com/lambdaworks/redis/RedisReactiveCommandsImpl.java index 16f29388d4..08f9e1e394 100644 --- a/src/main/java/com/lambdaworks/redis/RedisReactiveCommandsImpl.java +++ b/src/main/java/com/lambdaworks/redis/RedisReactiveCommandsImpl.java @@ -1,8 +1,8 @@ package com.lambdaworks.redis; import com.lambdaworks.redis.api.StatefulRedisConnection; -import com.lambdaworks.redis.api.rx.RedisReactiveCommands; -import com.lambdaworks.redis.cluster.api.rx.RedisClusterReactiveCommands; +import com.lambdaworks.redis.api.reactive.RedisReactiveCommands; +import com.lambdaworks.redis.cluster.api.reactive.RedisClusterReactiveCommands; import com.lambdaworks.redis.codec.RedisCodec; /** diff --git a/src/main/java/com/lambdaworks/redis/StatefulRedisConnectionImpl.java b/src/main/java/com/lambdaworks/redis/StatefulRedisConnectionImpl.java index 65911a1c3a..96fda2aaa3 100644 --- a/src/main/java/com/lambdaworks/redis/StatefulRedisConnectionImpl.java +++ b/src/main/java/com/lambdaworks/redis/StatefulRedisConnectionImpl.java @@ -13,7 +13,7 @@ import com.lambdaworks.redis.api.StatefulRedisConnection; import com.lambdaworks.redis.api.async.RedisAsyncCommands; -import com.lambdaworks.redis.api.rx.RedisReactiveCommands; +import com.lambdaworks.redis.api.reactive.RedisReactiveCommands; import com.lambdaworks.redis.api.sync.RedisCommands; import com.lambdaworks.redis.cluster.api.sync.RedisClusterCommands; import com.lambdaworks.redis.codec.RedisCodec; diff --git a/src/main/java/com/lambdaworks/redis/api/StatefulRedisConnection.java b/src/main/java/com/lambdaworks/redis/api/StatefulRedisConnection.java index 4c59cbe967..94cbdeb24a 100644 --- a/src/main/java/com/lambdaworks/redis/api/StatefulRedisConnection.java +++ b/src/main/java/com/lambdaworks/redis/api/StatefulRedisConnection.java @@ -1,7 +1,7 @@ package com.lambdaworks.redis.api; import com.lambdaworks.redis.api.async.RedisAsyncCommands; -import com.lambdaworks.redis.api.rx.RedisReactiveCommands; +import com.lambdaworks.redis.api.reactive.RedisReactiveCommands; import com.lambdaworks.redis.api.sync.RedisCommands; import com.lambdaworks.redis.protocol.ConnectionWatchdog; diff --git a/src/main/java/com/lambdaworks/redis/api/async/RedisGeoAsyncCommands.java b/src/main/java/com/lambdaworks/redis/api/async/RedisGeoAsyncCommands.java index cdc9b54bba..0709b14176 100644 --- a/src/main/java/com/lambdaworks/redis/api/async/RedisGeoAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/async/RedisGeoAsyncCommands.java @@ -1,12 +1,9 @@ package com.lambdaworks.redis.api.async; -import com.lambdaworks.redis.GeoArgs; -import com.lambdaworks.redis.GeoCoordinates; -import com.lambdaworks.redis.GeoRadiusStoreArgs; -import com.lambdaworks.redis.GeoWithin; +import com.lambdaworks.redis.*; + import java.util.List; import java.util.Set; -import com.lambdaworks.redis.RedisFuture; /** * Asynchronous executed commands for the Geo-API. @@ -44,7 +41,7 @@ public interface RedisGeoAsyncCommands { * @param members the members * @return bulk reply Geohash strings in the order of {@code members}. Returns {@literal null} if a member is not found. */ - RedisFuture> geohash(K key, V... members); + RedisFuture>> geohash(K key, V... members); /** * Retrieve members selected by distance with the center of {@code longitude} and {@code latitude}. @@ -133,7 +130,7 @@ public interface RedisGeoAsyncCommands { * @return a list of {@link GeoCoordinates}s representing the x,y position of each element specified in the arguments. For * missing elements {@literal null} is returned. */ - RedisFuture> geopos(K key, V... members); + RedisFuture>> geopos(K key, V... members); /** * diff --git a/src/main/java/com/lambdaworks/redis/api/async/RedisStringAsyncCommands.java b/src/main/java/com/lambdaworks/redis/api/async/RedisStringAsyncCommands.java index 87f7da7c16..25cc1523db 100644 --- a/src/main/java/com/lambdaworks/redis/api/async/RedisStringAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/async/RedisStringAsyncCommands.java @@ -2,10 +2,13 @@ import java.util.List; import java.util.Map; - -import com.lambdaworks.redis.*; import com.lambdaworks.redis.output.KeyValueStreamingChannel; import com.lambdaworks.redis.output.ValueStreamingChannel; +import com.lambdaworks.redis.BitFieldArgs; +import com.lambdaworks.redis.KeyValue; +import com.lambdaworks.redis.SetArgs; +import com.lambdaworks.redis.Value; +import com.lambdaworks.redis.RedisFuture; /** * Asynchronous executed commands for Strings. diff --git a/src/main/java/com/lambdaworks/redis/api/async/RedisTransactionalAsyncCommands.java b/src/main/java/com/lambdaworks/redis/api/async/RedisTransactionalAsyncCommands.java index d0cf372d5c..815b350750 100644 --- a/src/main/java/com/lambdaworks/redis/api/async/RedisTransactionalAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/async/RedisTransactionalAsyncCommands.java @@ -1,7 +1,8 @@ package com.lambdaworks.redis.api.async; -import com.lambdaworks.redis.RedisFuture; +import java.util.List; import com.lambdaworks.redis.TransactionResult; +import com.lambdaworks.redis.RedisFuture; /** * Asynchronous executed commands for Transactions. diff --git a/src/main/java/com/lambdaworks/redis/api/rx/BaseRedisReactiveCommands.java b/src/main/java/com/lambdaworks/redis/api/reactive/BaseRedisReactiveCommands.java similarity index 84% rename from src/main/java/com/lambdaworks/redis/api/rx/BaseRedisReactiveCommands.java rename to src/main/java/com/lambdaworks/redis/api/reactive/BaseRedisReactiveCommands.java index e31eab0a78..e2ff194e50 100644 --- a/src/main/java/com/lambdaworks/redis/api/rx/BaseRedisReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/reactive/BaseRedisReactiveCommands.java @@ -1,17 +1,16 @@ -package com.lambdaworks.redis.api.rx; +package com.lambdaworks.redis.api.reactive; import java.util.List; import java.util.Map; import com.lambdaworks.redis.protocol.CommandArgs; import com.lambdaworks.redis.protocol.ProtocolKeyword; import com.lambdaworks.redis.output.CommandOutput; -import rx.Observable; -import rx.Single; -import rx.Completable; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; /** * - * Observable commands for basic commands. + * Reactive executed commands for basic commands. * * @param Key type. * @param Value type. @@ -28,14 +27,14 @@ public interface BaseRedisReactiveCommands { * @param message the message type: value * @return Long integer-reply the number of clients that received the message. */ - Single publish(K channel, V message); + Mono publish(K channel, V message); /** * Lists the currently *active channels*. * * @return K array-reply a list of active channels, optionally matching the specified pattern. */ - Observable pubsubChannels(); + Flux pubsubChannels(); /** * Lists the currently *active channels*. @@ -43,7 +42,7 @@ public interface BaseRedisReactiveCommands { * @param channel the key * @return K array-reply a list of active channels, optionally matching the specified pattern. */ - Observable pubsubChannels(K channel); + Flux pubsubChannels(K channel); /** * Returns the number of subscribers (not counting clients subscribed to patterns) for the specified channels. @@ -51,14 +50,14 @@ public interface BaseRedisReactiveCommands { * @param channels channel keys * @return array-reply a list of channels and number of subscribers for every channel. */ - Single> pubsubNumsub(K... channels); + Mono> pubsubNumsub(K... channels); /** * Returns the number of subscriptions to patterns. * * @return Long integer-reply the number of patterns all the clients are subscribed to. */ - Single pubsubNumpat(); + Mono pubsubNumpat(); /** * Echo the given string. @@ -66,7 +65,7 @@ public interface BaseRedisReactiveCommands { * @param msg the message type: value * @return V bulk-string-reply */ - Single echo(V msg); + Mono echo(V msg); /** * Return the role of the instance in the context of replication. @@ -74,35 +73,35 @@ public interface BaseRedisReactiveCommands { * @return Object array-reply where the first element is one of master, slave, sentinel and the additional * elements are role-specific. */ - Observable role(); + Flux role(); /** * Ping the server. * * @return String simple-string-reply */ - Single ping(); + Mono ping(); /** * Switch connection to Read-Only mode when connecting to a cluster. * * @return String simple-string-reply. */ - Single readOnly(); + Mono readOnly(); /** * Switch connection to Read-Write mode (default) when connecting to a cluster. * * @return String simple-string-reply. */ - Single readWrite(); + Mono readWrite(); /** * Close the connection. * * @return String simple-string-reply always OK. */ - Single quit(); + Mono quit(); /** * Wait for replication. @@ -111,7 +110,7 @@ public interface BaseRedisReactiveCommands { * @param timeout timeout in milliseconds * @return number of replicas */ - Single waitForReplication(int replicas, long timeout); + Mono waitForReplication(int replicas, long timeout); /** * Dispatch a command to the Redis Server. Please note the command output type must fit to the command response. @@ -121,7 +120,7 @@ public interface BaseRedisReactiveCommands { * @param response type * @return the command response */ - Observable dispatch(ProtocolKeyword type, CommandOutput output); + Flux dispatch(ProtocolKeyword type, CommandOutput output); /** * Dispatch a command to the Redis Server. Please note the command output type must fit to the command response. @@ -132,7 +131,7 @@ public interface BaseRedisReactiveCommands { * @param response type * @return the command response */ - Observable dispatch(ProtocolKeyword type, CommandOutput output, CommandArgs args); + Flux dispatch(ProtocolKeyword type, CommandOutput output, CommandArgs args); /** * diff --git a/src/main/java/com/lambdaworks/redis/api/rx/RedisGeoReactiveCommands.java b/src/main/java/com/lambdaworks/redis/api/reactive/RedisGeoReactiveCommands.java similarity index 78% rename from src/main/java/com/lambdaworks/redis/api/rx/RedisGeoReactiveCommands.java rename to src/main/java/com/lambdaworks/redis/api/reactive/RedisGeoReactiveCommands.java index 855b949edc..aea256d2c8 100644 --- a/src/main/java/com/lambdaworks/redis/api/rx/RedisGeoReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/reactive/RedisGeoReactiveCommands.java @@ -1,17 +1,14 @@ -package com.lambdaworks.redis.api.rx; +package com.lambdaworks.redis.api.reactive; + +import com.lambdaworks.redis.*; -import com.lambdaworks.redis.GeoArgs; -import com.lambdaworks.redis.GeoCoordinates; -import com.lambdaworks.redis.GeoRadiusStoreArgs; -import com.lambdaworks.redis.GeoWithin; import java.util.List; import java.util.Set; -import rx.Observable; -import rx.Single; -import rx.Completable; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; /** - * Observable commands for the Geo-API. + * Reactive executed commands for the Geo-API. * * @author Mark Paluch * @since 4.0 @@ -28,7 +25,7 @@ public interface RedisGeoReactiveCommands { * @param member the member to add * @return Long integer-reply the number of elements that were added to the set */ - Single geoadd(K key, double longitude, double latitude, V member); + Mono geoadd(K key, double longitude, double latitude, V member); /** * Multi geo add. @@ -37,7 +34,7 @@ public interface RedisGeoReactiveCommands { * @param lngLatMember triplets of double longitude, double latitude and V member * @return Long integer-reply the number of elements that were added to the set */ - Single geoadd(K key, Object... lngLatMember); + Mono geoadd(K key, Object... lngLatMember); /** * Retrieve Geohash strings representing the position of one or more elements in a sorted set value representing a geospatial index. @@ -46,7 +43,7 @@ public interface RedisGeoReactiveCommands { * @param members the members * @return bulk reply Geohash strings in the order of {@code members}. Returns {@literal null} if a member is not found. */ - Observable geohash(K key, V... members); + Flux> geohash(K key, V... members); /** * Retrieve members selected by distance with the center of {@code longitude} and {@code latitude}. @@ -58,7 +55,7 @@ public interface RedisGeoReactiveCommands { * @param unit distance unit * @return bulk reply */ - Observable georadius(K key, double longitude, double latitude, double distance, GeoArgs.Unit unit); + Flux georadius(K key, double longitude, double latitude, double distance, GeoArgs.Unit unit); /** * Retrieve members selected by distance with the center of {@code longitude} and {@code latitude}. @@ -71,7 +68,7 @@ public interface RedisGeoReactiveCommands { * @param geoArgs args to control the result * @return nested multi-bulk reply. The {@link GeoWithin} contains only fields which were requested by {@link GeoArgs} */ - Observable> georadius(K key, double longitude, double latitude, double distance, GeoArgs.Unit unit, GeoArgs geoArgs); + Flux> georadius(K key, double longitude, double latitude, double distance, GeoArgs.Unit unit, GeoArgs geoArgs); /** * Perform a {@link #georadius(Object, double, double, double, Unit, GeoArgs)} query and store the results in a sorted set. @@ -85,7 +82,7 @@ public interface RedisGeoReactiveCommands { * their locations a sorted set. * @return Long integer-reply the number of elements in the result */ - Single georadius(K key, double longitude, double latitude, double distance, GeoArgs.Unit unit, GeoRadiusStoreArgs geoRadiusStoreArgs); + Mono georadius(K key, double longitude, double latitude, double distance, GeoArgs.Unit unit, GeoRadiusStoreArgs geoRadiusStoreArgs); /** * Retrieve members selected by distance with the center of {@code member}. The member itself is always contained in the @@ -97,7 +94,7 @@ public interface RedisGeoReactiveCommands { * @param unit distance unit * @return set of members */ - Observable georadiusbymember(K key, V member, double distance, GeoArgs.Unit unit); + Flux georadiusbymember(K key, V member, double distance, GeoArgs.Unit unit); /** * @@ -111,7 +108,7 @@ public interface RedisGeoReactiveCommands { * @param geoArgs args to control the result * @return nested multi-bulk reply. The {@link GeoWithin} contains only fields which were requested by {@link GeoArgs} */ - Observable> georadiusbymember(K key, V member, double distance, GeoArgs.Unit unit, GeoArgs geoArgs); + Flux> georadiusbymember(K key, V member, double distance, GeoArgs.Unit unit, GeoArgs geoArgs); /** * Perform a {@link #georadiusbymember(Object, Object, double, Unit, GeoArgs)} query and store the results in a sorted set. @@ -124,7 +121,7 @@ public interface RedisGeoReactiveCommands { * their locations a sorted set. * @return Long integer-reply the number of elements in the result */ - Single georadiusbymember(K key, V member, double distance, GeoArgs.Unit unit, GeoRadiusStoreArgs geoRadiusStoreArgs); + Mono georadiusbymember(K key, V member, double distance, GeoArgs.Unit unit, GeoRadiusStoreArgs geoRadiusStoreArgs); /** * Get geo coordinates for the {@code members}. @@ -135,7 +132,7 @@ public interface RedisGeoReactiveCommands { * @return a list of {@link GeoCoordinates}s representing the x,y position of each element specified in the arguments. For * missing elements {@literal null} is returned. */ - Observable geopos(K key, V... members); + Flux> geopos(K key, V... members); /** * @@ -150,5 +147,5 @@ public interface RedisGeoReactiveCommands { * @return distance between points {@code from} and {@code to}. If one or more elements are missing {@literal null} is * returned. */ - Single geodist(K key, V from, V to, GeoArgs.Unit unit); + Mono geodist(K key, V from, V to, GeoArgs.Unit unit); } diff --git a/src/main/java/com/lambdaworks/redis/api/rx/RedisHLLReactiveCommands.java b/src/main/java/com/lambdaworks/redis/api/reactive/RedisHLLReactiveCommands.java similarity index 77% rename from src/main/java/com/lambdaworks/redis/api/rx/RedisHLLReactiveCommands.java rename to src/main/java/com/lambdaworks/redis/api/reactive/RedisHLLReactiveCommands.java index dc2e8a367c..9e8696b8bf 100644 --- a/src/main/java/com/lambdaworks/redis/api/rx/RedisHLLReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/reactive/RedisHLLReactiveCommands.java @@ -1,11 +1,10 @@ -package com.lambdaworks.redis.api.rx; +package com.lambdaworks.redis.api.reactive; -import rx.Observable; -import rx.Single; -import rx.Completable; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; /** - * Observable commands for HyperLogLog (PF* commands). + * Reactive executed commands for HyperLogLog (PF* commands). * * @param Key type. * @param Value type. @@ -25,7 +24,7 @@ public interface RedisHLLReactiveCommands { * * 1 if at least 1 HyperLogLog internal register was altered. 0 otherwise. */ - Single pfadd(K key, V... values); + Mono pfadd(K key, V... values); /** * Merge N different HyperLogLogs into a single one. @@ -35,7 +34,7 @@ public interface RedisHLLReactiveCommands { * * @return String simple-string-reply The command just returns {@code OK}. */ - Single pfmerge(K destkey, K... sourcekeys); + Mono pfmerge(K destkey, K... sourcekeys); /** * Return the approximated cardinality of the set(s) observed by the HyperLogLog at key(s). @@ -46,5 +45,5 @@ public interface RedisHLLReactiveCommands { * * The approximated number of unique elements observed via {@code PFADD}. */ - Single pfcount(K... keys); + Mono pfcount(K... keys); } diff --git a/src/main/java/com/lambdaworks/redis/api/rx/RedisHashReactiveCommands.java b/src/main/java/com/lambdaworks/redis/api/reactive/RedisHashReactiveCommands.java similarity index 81% rename from src/main/java/com/lambdaworks/redis/api/rx/RedisHashReactiveCommands.java rename to src/main/java/com/lambdaworks/redis/api/reactive/RedisHashReactiveCommands.java index 01b399bcec..fe3c4ce58e 100644 --- a/src/main/java/com/lambdaworks/redis/api/rx/RedisHashReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/reactive/RedisHashReactiveCommands.java @@ -1,4 +1,4 @@ -package com.lambdaworks.redis.api.rx; +package com.lambdaworks.redis.api.reactive; import java.util.List; import java.util.Map; @@ -11,12 +11,11 @@ import com.lambdaworks.redis.output.KeyStreamingChannel; import com.lambdaworks.redis.output.KeyValueStreamingChannel; import com.lambdaworks.redis.output.ValueStreamingChannel; -import rx.Observable; -import rx.Single; -import rx.Completable; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; /** - * Observable commands for Hashes (Key-Value pairs). + * Reactive executed commands for Hashes (Key-Value pairs). * * @param Key type. * @param Value type. @@ -34,7 +33,7 @@ public interface RedisHashReactiveCommands { * @return Long integer-reply the number of fields that were removed from the hash, not including specified but non existing * fields. */ - Single hdel(K key, K... fields); + Mono hdel(K key, K... fields); /** * Determine if a hash field exists. @@ -46,7 +45,7 @@ public interface RedisHashReactiveCommands { * {@literal true} if the hash contains {@code field}. {@literal false} if the hash does not contain {@code field}, * or {@code key} does not exist. */ - Single hexists(K key, K field); + Mono hexists(K key, K field); /** * Get the value of a hash field. @@ -56,7 +55,7 @@ public interface RedisHashReactiveCommands { * @return V bulk-string-reply the value associated with {@code field}, or {@literal null} when {@code field} is not present * in the hash or {@code key} does not exist. */ - Single hget(K key, K field); + Mono hget(K key, K field); /** * Increment the integer value of a hash field by the given number. @@ -66,7 +65,7 @@ public interface RedisHashReactiveCommands { * @param amount the increment type: long * @return Long integer-reply the value at {@code field} after the increment operation. */ - Single hincrby(K key, K field, long amount); + Mono hincrby(K key, K field, long amount); /** * Increment the float value of a hash field by the given amount. @@ -76,7 +75,7 @@ public interface RedisHashReactiveCommands { * @param amount the increment type: double * @return Double bulk-string-reply the value of {@code field} after the increment. */ - Single hincrbyfloat(K key, K field, double amount); + Mono hincrbyfloat(K key, K field, double amount); /** * Get all the fields and values in a hash. @@ -85,7 +84,7 @@ public interface RedisHashReactiveCommands { * @return Map<K,V> array-reply list of fields and their values stored in the hash, or an empty list when {@code key} * does not exist. */ - Single> hgetall(K key); + Mono> hgetall(K key); /** * Stream over all the fields and values in a hash. @@ -95,7 +94,7 @@ public interface RedisHashReactiveCommands { * * @return Long count of the keys. */ - Single hgetall(KeyValueStreamingChannel channel, K key); + Mono hgetall(KeyValueStreamingChannel channel, K key); /** * Get all the fields in a hash. @@ -103,7 +102,7 @@ public interface RedisHashReactiveCommands { * @param key the key * @return K array-reply list of fields in the hash, or an empty list when {@code key} does not exist. */ - Observable hkeys(K key); + Flux hkeys(K key); /** * Stream over all the fields in a hash. @@ -113,7 +112,7 @@ public interface RedisHashReactiveCommands { * * @return Long count of the keys. */ - Single hkeys(KeyStreamingChannel channel, K key); + Mono hkeys(KeyStreamingChannel channel, K key); /** * Get the number of fields in a hash. @@ -121,7 +120,7 @@ public interface RedisHashReactiveCommands { * @param key the key * @return Long integer-reply number of fields in the hash, or {@code 0} when {@code key} does not exist. */ - Single hlen(K key); + Mono hlen(K key); /** * Get the values of all the given hash fields. @@ -130,7 +129,7 @@ public interface RedisHashReactiveCommands { * @param fields the field type: key * @return V array-reply list of values associated with the given fields, in the same */ - Observable> hmget(K key, K... fields); + Flux> hmget(K key, K... fields); /** * Stream over the values of all the given hash fields. @@ -141,7 +140,7 @@ public interface RedisHashReactiveCommands { * * @return Long count of the keys */ - Single hmget(KeyValueStreamingChannel channel, K key, K... fields); + Mono hmget(KeyValueStreamingChannel channel, K key, K... fields); /** * Set multiple hash fields to multiple values. @@ -150,7 +149,7 @@ public interface RedisHashReactiveCommands { * @param map the null * @return String simple-string-reply */ - Single hmset(K key, Map map); + Mono hmset(K key, Map map); /** * Incrementally iterate hash fields and associated values. @@ -158,7 +157,7 @@ public interface RedisHashReactiveCommands { * @param key the key * @return MapScanCursor<K, V> map scan cursor. */ - Single> hscan(K key); + Mono> hscan(K key); /** * Incrementally iterate hash fields and associated values. @@ -167,7 +166,7 @@ public interface RedisHashReactiveCommands { * @param scanArgs scan arguments * @return MapScanCursor<K, V> map scan cursor. */ - Single> hscan(K key, ScanArgs scanArgs); + Mono> hscan(K key, ScanArgs scanArgs); /** * Incrementally iterate hash fields and associated values. @@ -177,7 +176,7 @@ public interface RedisHashReactiveCommands { * @param scanArgs scan arguments * @return MapScanCursor<K, V> map scan cursor. */ - Single> hscan(K key, ScanCursor scanCursor, ScanArgs scanArgs); + Mono> hscan(K key, ScanCursor scanCursor, ScanArgs scanArgs); /** * Incrementally iterate hash fields and associated values. @@ -186,7 +185,7 @@ public interface RedisHashReactiveCommands { * @param scanCursor cursor to resume from a previous scan, must not be {@literal null} * @return MapScanCursor<K, V> map scan cursor. */ - Single> hscan(K key, ScanCursor scanCursor); + Mono> hscan(K key, ScanCursor scanCursor); /** * Incrementally iterate hash fields and associated values. @@ -195,7 +194,7 @@ public interface RedisHashReactiveCommands { * @param key the key * @return StreamScanCursor scan cursor. */ - Single hscan(KeyValueStreamingChannel channel, K key); + Mono hscan(KeyValueStreamingChannel channel, K key); /** * Incrementally iterate hash fields and associated values. @@ -205,7 +204,7 @@ public interface RedisHashReactiveCommands { * @param scanArgs scan arguments * @return StreamScanCursor scan cursor. */ - Single hscan(KeyValueStreamingChannel channel, K key, ScanArgs scanArgs); + Mono hscan(KeyValueStreamingChannel channel, K key, ScanArgs scanArgs); /** * Incrementally iterate hash fields and associated values. @@ -216,7 +215,7 @@ public interface RedisHashReactiveCommands { * @param scanArgs scan arguments * @return StreamScanCursor scan cursor. */ - Single hscan(KeyValueStreamingChannel channel, K key, ScanCursor scanCursor, ScanArgs scanArgs); + Mono hscan(KeyValueStreamingChannel channel, K key, ScanCursor scanCursor, ScanArgs scanArgs); /** * Incrementally iterate hash fields and associated values. @@ -226,7 +225,7 @@ public interface RedisHashReactiveCommands { * @param scanCursor cursor to resume from a previous scan, must not be {@literal null} * @return StreamScanCursor scan cursor. */ - Single hscan(KeyValueStreamingChannel channel, K key, ScanCursor scanCursor); + Mono hscan(KeyValueStreamingChannel channel, K key, ScanCursor scanCursor); /** * Set the string value of a hash field. @@ -239,7 +238,7 @@ public interface RedisHashReactiveCommands { * {@literal true} if {@code field} is a new field in the hash and {@code value} was set. {@literal false} if * {@code field} already exists in the hash and the value was updated. */ - Single hset(K key, K field, V value); + Mono hset(K key, K field, V value); /** * Set the value of a hash field, only if the field does not exist. @@ -252,7 +251,7 @@ public interface RedisHashReactiveCommands { * {@code 1} if {@code field} is a new field in the hash and {@code value} was set. {@code 0} if {@code field} * already exists in the hash and no operation was performed. */ - Single hsetnx(K key, K field, V value); + Mono hsetnx(K key, K field, V value); /** * Get the string length of the field value in a hash. @@ -262,7 +261,7 @@ public interface RedisHashReactiveCommands { * @return Long integer-reply the string length of the {@code field} value, or {@code 0} when {@code field} is not present * in the hash or {@code key} does not exist at all. */ - Single hstrlen(K key, K field); + Mono hstrlen(K key, K field); /** * Get all the values in a hash. @@ -270,7 +269,7 @@ public interface RedisHashReactiveCommands { * @param key the key * @return V array-reply list of values in the hash, or an empty list when {@code key} does not exist. */ - Observable hvals(K key); + Flux hvals(K key); /** * Stream over all the values in a hash. @@ -280,5 +279,5 @@ public interface RedisHashReactiveCommands { * * @return Long count of the keys. */ - Single hvals(ValueStreamingChannel channel, K key); + Mono hvals(ValueStreamingChannel channel, K key); } diff --git a/src/main/java/com/lambdaworks/redis/api/rx/RedisKeyReactiveCommands.java b/src/main/java/com/lambdaworks/redis/api/reactive/RedisKeyReactiveCommands.java similarity index 82% rename from src/main/java/com/lambdaworks/redis/api/rx/RedisKeyReactiveCommands.java rename to src/main/java/com/lambdaworks/redis/api/reactive/RedisKeyReactiveCommands.java index 18411f7af7..bf31d9fd27 100644 --- a/src/main/java/com/lambdaworks/redis/api/rx/RedisKeyReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/reactive/RedisKeyReactiveCommands.java @@ -1,4 +1,4 @@ -package com.lambdaworks.redis.api.rx; +package com.lambdaworks.redis.api.reactive; import java.util.Date; import java.util.List; @@ -11,12 +11,11 @@ import com.lambdaworks.redis.StreamScanCursor; import com.lambdaworks.redis.output.KeyStreamingChannel; import com.lambdaworks.redis.output.ValueStreamingChannel; -import rx.Observable; -import rx.Single; -import rx.Completable; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; /** - * Observable commands for Keys (Key manipulation/querying). + * Reactive executed commands for Keys (Key manipulation/querying). * * @param Key type. * @param Value type. @@ -32,7 +31,7 @@ public interface RedisKeyReactiveCommands { * @param keys the keys * @return Long integer-reply The number of keys that were removed. */ - Single del(K... keys); + Mono del(K... keys); /** * Unlink one or more keys (non blocking DEL). @@ -40,7 +39,7 @@ public interface RedisKeyReactiveCommands { * @param keys the keys * @return Long integer-reply The number of keys that were removed. */ - Single unlink(K... keys); + Mono unlink(K... keys); /** * Return a serialized version of the value stored at the specified key. @@ -48,7 +47,7 @@ public interface RedisKeyReactiveCommands { * @param key the key * @return byte[] bulk-string-reply the serialized value. */ - Single dump(K key); + Mono dump(K key); /** * Determine how many keys exist. @@ -56,7 +55,7 @@ public interface RedisKeyReactiveCommands { * @param keys the keys * @return Long integer-reply specifically: Number of existing keys */ - Single exists(K... keys); + Mono exists(K... keys); /** * Set a key's time to live in seconds. @@ -68,7 +67,7 @@ public interface RedisKeyReactiveCommands { * {@literal true} if the timeout was set. {@literal false} if {@code key} does not exist or the timeout could not * be set. */ - Single expire(K key, long seconds); + Mono expire(K key, long seconds); /** * Set the expiration for a key as a UNIX timestamp. @@ -80,7 +79,7 @@ public interface RedisKeyReactiveCommands { * {@literal true} if the timeout was set. {@literal false} if {@code key} does not exist or the timeout could not * be set (see: {@code EXPIRE}). */ - Single expireat(K key, Date timestamp); + Mono expireat(K key, Date timestamp); /** * Set the expiration for a key as a UNIX timestamp. @@ -92,7 +91,7 @@ public interface RedisKeyReactiveCommands { * {@literal true} if the timeout was set. {@literal false} if {@code key} does not exist or the timeout could not * be set (see: {@code EXPIRE}). */ - Single expireat(K key, long timestamp); + Mono expireat(K key, long timestamp); /** * Find all keys matching the given pattern. @@ -100,7 +99,7 @@ public interface RedisKeyReactiveCommands { * @param pattern the pattern type: patternkey (pattern) * @return K array-reply list of keys matching {@code pattern}. */ - Observable keys(K pattern); + Flux keys(K pattern); /** * Find all keys matching the given pattern. @@ -109,7 +108,7 @@ public interface RedisKeyReactiveCommands { * @param pattern the pattern * @return Long array-reply list of keys matching {@code pattern}. */ - Single keys(KeyStreamingChannel channel, K pattern); + Mono keys(KeyStreamingChannel channel, K pattern); /** * Atomically transfer a key from a Redis instance to another one. @@ -121,7 +120,7 @@ public interface RedisKeyReactiveCommands { * @param timeout the timeout in milliseconds * @return String simple-string-reply The command returns OK on success. */ - Single migrate(String host, int port, K key, int db, long timeout); + Mono migrate(String host, int port, K key, int db, long timeout); /** * Atomically transfer one or more keys from a Redis instance to another one. @@ -133,7 +132,7 @@ public interface RedisKeyReactiveCommands { * @param migrateArgs migrate args that allow to configure further options * @return String simple-string-reply The command returns OK on success. */ - Single migrate(String host, int port, int db, long timeout, MigrateArgs migrateArgs); + Mono migrate(String host, int port, int db, long timeout, MigrateArgs migrateArgs); /** * Move a key to another database. @@ -142,7 +141,7 @@ public interface RedisKeyReactiveCommands { * @param db the db type: long * @return Boolean integer-reply specifically: */ - Single move(K key, int db); + Mono move(K key, int db); /** * returns the kind of internal representation used in order to store the value associated with a key. @@ -150,7 +149,7 @@ public interface RedisKeyReactiveCommands { * @param key the key * @return String */ - Single objectEncoding(K key); + Mono objectEncoding(K key); /** * returns the number of seconds since the object stored at the specified key is idle (not requested by read or write @@ -159,7 +158,7 @@ public interface RedisKeyReactiveCommands { * @param key the key * @return number of seconds since the object stored at the specified key is idle. */ - Single objectIdletime(K key); + Mono objectIdletime(K key); /** * returns the number of references of the value associated with the specified key. @@ -167,7 +166,7 @@ public interface RedisKeyReactiveCommands { * @param key the key * @return Long */ - Single objectRefcount(K key); + Mono objectRefcount(K key); /** * Remove the expiration from a key. @@ -178,7 +177,7 @@ public interface RedisKeyReactiveCommands { * {@literal true} if the timeout was removed. {@literal false} if {@code key} does not exist or does not have an * associated timeout. */ - Single persist(K key); + Mono persist(K key); /** * Set a key's time to live in milliseconds. @@ -190,7 +189,7 @@ public interface RedisKeyReactiveCommands { * {@literal true} if the timeout was set. {@literal false} if {@code key} does not exist or the timeout could not * be set. */ - Single pexpire(K key, long milliseconds); + Mono pexpire(K key, long milliseconds); /** * Set the expiration for a key as a UNIX timestamp specified in milliseconds. @@ -202,7 +201,7 @@ public interface RedisKeyReactiveCommands { * {@literal true} if the timeout was set. {@literal false} if {@code key} does not exist or the timeout could not * be set (see: {@code EXPIRE}). */ - Single pexpireat(K key, Date timestamp); + Mono pexpireat(K key, Date timestamp); /** * Set the expiration for a key as a UNIX timestamp specified in milliseconds. @@ -214,7 +213,7 @@ public interface RedisKeyReactiveCommands { * {@literal true} if the timeout was set. {@literal false} if {@code key} does not exist or the timeout could not * be set (see: {@code EXPIRE}). */ - Single pexpireat(K key, long timestamp); + Mono pexpireat(K key, long timestamp); /** * Get the time to live for a key in milliseconds. @@ -223,14 +222,14 @@ public interface RedisKeyReactiveCommands { * @return Long integer-reply TTL in milliseconds, or a negative value in order to signal an error (see the description * above). */ - Single pttl(K key); + Mono pttl(K key); /** * Return a random key from the keyspace. * * @return V bulk-string-reply the random key, or {@literal null} when the database is empty. */ - Single randomkey(); + Mono randomkey(); /** * Rename a key. @@ -239,7 +238,7 @@ public interface RedisKeyReactiveCommands { * @param newKey the newkey type: key * @return String simple-string-reply */ - Single rename(K key, K newKey); + Mono rename(K key, K newKey); /** * Rename a key, only if the new key does not exist. @@ -250,7 +249,7 @@ public interface RedisKeyReactiveCommands { * * {@literal true} if {@code key} was renamed to {@code newkey}. {@literal false} if {@code newkey} already exists. */ - Single renamenx(K key, K newKey); + Mono renamenx(K key, K newKey); /** * Create a key using the provided serialized value, previously obtained using DUMP. @@ -260,7 +259,7 @@ public interface RedisKeyReactiveCommands { * @param value the serialized-value type: string * @return String simple-string-reply The command returns OK on success. */ - Single restore(K key, long ttl, byte[] value); + Mono restore(K key, long ttl, byte[] value); /** * Sort the elements in a list, set or sorted set. @@ -268,7 +267,7 @@ public interface RedisKeyReactiveCommands { * @param key the key * @return V array-reply list of sorted elements. */ - Observable sort(K key); + Flux sort(K key); /** * Sort the elements in a list, set or sorted set. @@ -277,7 +276,7 @@ public interface RedisKeyReactiveCommands { * @param key the key * @return Long number of values. */ - Single sort(ValueStreamingChannel channel, K key); + Mono sort(ValueStreamingChannel channel, K key); /** * Sort the elements in a list, set or sorted set. @@ -286,7 +285,7 @@ public interface RedisKeyReactiveCommands { * @param sortArgs sort arguments * @return V array-reply list of sorted elements. */ - Observable sort(K key, SortArgs sortArgs); + Flux sort(K key, SortArgs sortArgs); /** * Sort the elements in a list, set or sorted set. @@ -296,7 +295,7 @@ public interface RedisKeyReactiveCommands { * @param sortArgs sort arguments * @return Long number of values. */ - Single sort(ValueStreamingChannel channel, K key, SortArgs sortArgs); + Mono sort(ValueStreamingChannel channel, K key, SortArgs sortArgs); /** * Sort the elements in a list, set or sorted set. @@ -306,7 +305,7 @@ public interface RedisKeyReactiveCommands { * @param destination the destination key to store sort results * @return Long number of values. */ - Single sortStore(K key, SortArgs sortArgs, K destination); + Mono sortStore(K key, SortArgs sortArgs, K destination); /** * Touch one or more keys. Touch sets the last accessed time for a key. Non-exsitent keys wont get created. @@ -314,7 +313,7 @@ public interface RedisKeyReactiveCommands { * @param keys the keys * @return Long integer-reply the number of found keys. */ - Single touch(K... keys); + Mono touch(K... keys); /** * Get the time to live for a key. @@ -322,7 +321,7 @@ public interface RedisKeyReactiveCommands { * @param key the key * @return Long integer-reply TTL in seconds, or a negative value in order to signal an error (see the description above). */ - Single ttl(K key); + Mono ttl(K key); /** * Determine the type stored at key. @@ -330,14 +329,14 @@ public interface RedisKeyReactiveCommands { * @param key the key * @return String simple-string-reply type of {@code key}, or {@code none} when {@code key} does not exist. */ - Single type(K key); + Mono type(K key); /** * Incrementally iterate the keys space. * * @return KeyScanCursor<K> scan cursor. */ - Single> scan(); + Mono> scan(); /** * Incrementally iterate the keys space. @@ -345,7 +344,7 @@ public interface RedisKeyReactiveCommands { * @param scanArgs scan arguments * @return KeyScanCursor<K> scan cursor. */ - Single> scan(ScanArgs scanArgs); + Mono> scan(ScanArgs scanArgs); /** * Incrementally iterate the keys space. @@ -354,7 +353,7 @@ public interface RedisKeyReactiveCommands { * @param scanArgs scan arguments * @return KeyScanCursor<K> scan cursor. */ - Single> scan(ScanCursor scanCursor, ScanArgs scanArgs); + Mono> scan(ScanCursor scanCursor, ScanArgs scanArgs); /** * Incrementally iterate the keys space. @@ -362,7 +361,7 @@ public interface RedisKeyReactiveCommands { * @param scanCursor cursor to resume from a previous scan, must not be {@literal null} * @return KeyScanCursor<K> scan cursor. */ - Single> scan(ScanCursor scanCursor); + Mono> scan(ScanCursor scanCursor); /** * Incrementally iterate the keys space. @@ -370,7 +369,7 @@ public interface RedisKeyReactiveCommands { * @param channel streaming channel that receives a call for every key * @return StreamScanCursor scan cursor. */ - Single scan(KeyStreamingChannel channel); + Mono scan(KeyStreamingChannel channel); /** * Incrementally iterate the keys space. @@ -379,7 +378,7 @@ public interface RedisKeyReactiveCommands { * @param scanArgs scan arguments * @return StreamScanCursor scan cursor. */ - Single scan(KeyStreamingChannel channel, ScanArgs scanArgs); + Mono scan(KeyStreamingChannel channel, ScanArgs scanArgs); /** * Incrementally iterate the keys space. @@ -389,7 +388,7 @@ public interface RedisKeyReactiveCommands { * @param scanArgs scan arguments * @return StreamScanCursor scan cursor. */ - Single scan(KeyStreamingChannel channel, ScanCursor scanCursor, ScanArgs scanArgs); + Mono scan(KeyStreamingChannel channel, ScanCursor scanCursor, ScanArgs scanArgs); /** * Incrementally iterate the keys space. @@ -398,5 +397,5 @@ public interface RedisKeyReactiveCommands { * @param scanCursor cursor to resume from a previous scan, must not be {@literal null} * @return StreamScanCursor scan cursor. */ - Single scan(KeyStreamingChannel channel, ScanCursor scanCursor); + Mono scan(KeyStreamingChannel channel, ScanCursor scanCursor); } diff --git a/src/main/java/com/lambdaworks/redis/api/rx/RedisListReactiveCommands.java b/src/main/java/com/lambdaworks/redis/api/reactive/RedisListReactiveCommands.java similarity index 83% rename from src/main/java/com/lambdaworks/redis/api/rx/RedisListReactiveCommands.java rename to src/main/java/com/lambdaworks/redis/api/reactive/RedisListReactiveCommands.java index 24f98351e9..c9f8cbbc37 100644 --- a/src/main/java/com/lambdaworks/redis/api/rx/RedisListReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/reactive/RedisListReactiveCommands.java @@ -1,14 +1,13 @@ -package com.lambdaworks.redis.api.rx; +package com.lambdaworks.redis.api.reactive; import java.util.List; import com.lambdaworks.redis.KeyValue; import com.lambdaworks.redis.output.ValueStreamingChannel; -import rx.Observable; -import rx.Single; -import rx.Completable; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; /** - * Observable commands for Lists. + * Reactive executed commands for Lists. * * @param Key type. * @param Value type. @@ -29,7 +28,7 @@ public interface RedisListReactiveCommands { * with the first element being the name of the key where an element was popped and the second element being the * value of the popped element. */ - Single> blpop(long timeout, K... keys); + Mono> blpop(long timeout, K... keys); /** * Remove and get the last element in a list, or block until one is available. @@ -42,7 +41,7 @@ public interface RedisListReactiveCommands { * with the first element being the name of the key where an element was popped and the second element being the * value of the popped element. */ - Single> brpop(long timeout, K... keys); + Mono> brpop(long timeout, K... keys); /** * Pop a value from a list, push it to another list and return it; or block until one is available. @@ -53,7 +52,7 @@ public interface RedisListReactiveCommands { * @return V bulk-string-reply the element being popped from {@code source} and pushed to {@code destination}. If * {@code timeout} is reached, a */ - Single brpoplpush(long timeout, K source, K destination); + Mono brpoplpush(long timeout, K source, K destination); /** * Get an element from a list by its index. @@ -62,7 +61,7 @@ public interface RedisListReactiveCommands { * @param index the index type: long * @return V bulk-string-reply the requested element, or {@literal null} when {@code index} is out of range. */ - Single lindex(K key, long index); + Mono lindex(K key, long index); /** * Insert an element before or after another element in a list. @@ -74,7 +73,7 @@ public interface RedisListReactiveCommands { * @return Long integer-reply the length of the list after the insert operation, or {@code -1} when the value {@code pivot} * was not found. */ - Single linsert(K key, boolean before, V pivot, V value); + Mono linsert(K key, boolean before, V pivot, V value); /** * Get the length of a list. @@ -82,7 +81,7 @@ public interface RedisListReactiveCommands { * @param key the key * @return Long integer-reply the length of the list at {@code key}. */ - Single llen(K key); + Mono llen(K key); /** * Remove and get the first element in a list. @@ -90,7 +89,7 @@ public interface RedisListReactiveCommands { * @param key the key * @return V bulk-string-reply the value of the first element, or {@literal null} when {@code key} does not exist. */ - Single lpop(K key); + Mono lpop(K key); /** * Prepend one or multiple values to a list. @@ -99,7 +98,7 @@ public interface RedisListReactiveCommands { * @param values the value * @return Long integer-reply the length of the list after the push operations. */ - Single lpush(K key, V... values); + Mono lpush(K key, V... values); /** * Prepend values to a list, only if the list exists. @@ -108,7 +107,7 @@ public interface RedisListReactiveCommands { * @param values the values * @return Long integer-reply the length of the list after the push operation. */ - Single lpushx(K key, V... values); + Mono lpushx(K key, V... values); /** * Get a range of elements from a list. @@ -118,7 +117,7 @@ public interface RedisListReactiveCommands { * @param stop the stop type: long * @return V array-reply list of elements in the specified range. */ - Observable lrange(K key, long start, long stop); + Flux lrange(K key, long start, long stop); /** * Get a range of elements from a list. @@ -129,7 +128,7 @@ public interface RedisListReactiveCommands { * @param stop the stop type: long * @return Long count of elements in the specified range. */ - Single lrange(ValueStreamingChannel channel, K key, long start, long stop); + Mono lrange(ValueStreamingChannel channel, K key, long start, long stop); /** * Remove elements from a list. @@ -139,7 +138,7 @@ public interface RedisListReactiveCommands { * @param value the value * @return Long integer-reply the number of removed elements. */ - Single lrem(K key, long count, V value); + Mono lrem(K key, long count, V value); /** * Set the value of an element in a list by its index. @@ -149,7 +148,7 @@ public interface RedisListReactiveCommands { * @param value the value * @return String simple-string-reply */ - Single lset(K key, long index, V value); + Mono lset(K key, long index, V value); /** * Trim a list to the specified range. @@ -159,7 +158,7 @@ public interface RedisListReactiveCommands { * @param stop the stop type: long * @return String simple-string-reply */ - Single ltrim(K key, long start, long stop); + Mono ltrim(K key, long start, long stop); /** * Remove and get the last element in a list. @@ -167,7 +166,7 @@ public interface RedisListReactiveCommands { * @param key the key * @return V bulk-string-reply the value of the last element, or {@literal null} when {@code key} does not exist. */ - Single rpop(K key); + Mono rpop(K key); /** * Remove the last element in a list, append it to another list and return it. @@ -176,7 +175,7 @@ public interface RedisListReactiveCommands { * @param destination the destination type: key * @return V bulk-string-reply the element being popped and pushed. */ - Single rpoplpush(K source, K destination); + Mono rpoplpush(K source, K destination); /** * Append one or multiple values to a list. @@ -185,7 +184,7 @@ public interface RedisListReactiveCommands { * @param values the value * @return Long integer-reply the length of the list after the push operation. */ - Single rpush(K key, V... values); + Mono rpush(K key, V... values); /** * Append values to a list, only if the list exists. @@ -194,5 +193,5 @@ public interface RedisListReactiveCommands { * @param values the values * @return Long integer-reply the length of the list after the push operation. */ - Single rpushx(K key, V... values); + Mono rpushx(K key, V... values); } diff --git a/src/main/java/com/lambdaworks/redis/api/rx/RedisReactiveCommands.java b/src/main/java/com/lambdaworks/redis/api/reactive/RedisReactiveCommands.java similarity index 85% rename from src/main/java/com/lambdaworks/redis/api/rx/RedisReactiveCommands.java rename to src/main/java/com/lambdaworks/redis/api/reactive/RedisReactiveCommands.java index 1c3901423a..cc8a08962c 100644 --- a/src/main/java/com/lambdaworks/redis/api/rx/RedisReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/reactive/RedisReactiveCommands.java @@ -1,12 +1,11 @@ -package com.lambdaworks.redis.api.rx; +package com.lambdaworks.redis.api.reactive; import java.util.concurrent.TimeUnit; -import rx.Observable; - import com.lambdaworks.redis.api.StatefulRedisConnection; -import com.lambdaworks.redis.cluster.api.rx.RedisClusterReactiveCommands; -import rx.Single; +import com.lambdaworks.redis.cluster.api.reactive.RedisClusterReactiveCommands; + +import reactor.core.publisher.Mono; /** * A complete reactive and thread-safe Redis API with 400+ Methods. @@ -14,7 +13,7 @@ * @param Key type. * @param Value type. * @author Mark Paluch - * @since 4.0 + * @since 5.0 */ public interface RedisReactiveCommands extends RedisHashReactiveCommands, RedisKeyReactiveCommands, RedisStringReactiveCommands, RedisListReactiveCommands, RedisSetReactiveCommands, @@ -36,7 +35,7 @@ public interface RedisReactiveCommands extends RedisHashReactiveCommands auth(String password); + Mono auth(String password); /** * Change the selected database for the current connection. @@ -44,7 +43,7 @@ public interface RedisReactiveCommands extends RedisHashReactiveCommands select(int db); + Mono select(int db); /** * @return the underlying connection. diff --git a/src/main/java/com/lambdaworks/redis/api/rx/RedisScriptingReactiveCommands.java b/src/main/java/com/lambdaworks/redis/api/reactive/RedisScriptingReactiveCommands.java similarity index 78% rename from src/main/java/com/lambdaworks/redis/api/rx/RedisScriptingReactiveCommands.java rename to src/main/java/com/lambdaworks/redis/api/reactive/RedisScriptingReactiveCommands.java index ceb47dee70..56e3a2ed3a 100644 --- a/src/main/java/com/lambdaworks/redis/api/rx/RedisScriptingReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/reactive/RedisScriptingReactiveCommands.java @@ -1,13 +1,12 @@ -package com.lambdaworks.redis.api.rx; +package com.lambdaworks.redis.api.reactive; import java.util.List; import com.lambdaworks.redis.ScriptOutputType; -import rx.Observable; -import rx.Single; -import rx.Completable; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; /** - * Observable commands for Scripting. + * Reactive executed commands for Scripting. * * @param Key type. * @param Value type. @@ -26,7 +25,7 @@ public interface RedisScriptingReactiveCommands { * @param expected return type * @return script result */ - Observable eval(String script, ScriptOutputType type, K... keys); + Flux eval(String script, ScriptOutputType type, K... keys); /** * Execute a Lua script server side. @@ -38,7 +37,7 @@ public interface RedisScriptingReactiveCommands { * @param expected return type * @return script result */ - Observable eval(String script, ScriptOutputType type, K[] keys, V... values); + Flux eval(String script, ScriptOutputType type, K[] keys, V... values); /** * Evaluates a script cached on the server side by its SHA1 digest @@ -49,7 +48,7 @@ public interface RedisScriptingReactiveCommands { * @param expected return type * @return script result */ - Observable evalsha(String digest, ScriptOutputType type, K... keys); + Flux evalsha(String digest, ScriptOutputType type, K... keys); /** * Execute a Lua script server side. @@ -61,7 +60,7 @@ public interface RedisScriptingReactiveCommands { * @param expected return type * @return script result */ - Observable evalsha(String digest, ScriptOutputType type, K[] keys, V... values); + Flux evalsha(String digest, ScriptOutputType type, K[] keys, V... values); /** * Check existence of scripts in the script cache. @@ -71,21 +70,21 @@ public interface RedisScriptingReactiveCommands { * digest arguments. For every corresponding SHA1 digest of a script that actually exists in the script cache, an 1 * is returned, otherwise 0 is returned. */ - Observable scriptExists(String... digests); + Flux scriptExists(String... digests); /** * Remove all the scripts from the script cache. * * @return String simple-string-reply */ - Single scriptFlush(); + Mono scriptFlush(); /** * Kill the script currently in execution. * * @return String simple-string-reply */ - Single scriptKill(); + Mono scriptKill(); /** * Load the specified Lua script into the script cache. @@ -93,7 +92,7 @@ public interface RedisScriptingReactiveCommands { * @param script script content * @return String bulk-string-reply This command returns the SHA1 digest of the script added into the script cache. */ - Single scriptLoad(V script); + Mono scriptLoad(V script); /** * Create a SHA1 digest from a Lua script. diff --git a/src/main/java/com/lambdaworks/redis/api/rx/RedisServerReactiveCommands.java b/src/main/java/com/lambdaworks/redis/api/reactive/RedisServerReactiveCommands.java similarity index 80% rename from src/main/java/com/lambdaworks/redis/api/rx/RedisServerReactiveCommands.java rename to src/main/java/com/lambdaworks/redis/api/reactive/RedisServerReactiveCommands.java index 883904d090..788b88b074 100644 --- a/src/main/java/com/lambdaworks/redis/api/rx/RedisServerReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/reactive/RedisServerReactiveCommands.java @@ -1,15 +1,14 @@ -package com.lambdaworks.redis.api.rx; +package com.lambdaworks.redis.api.reactive; import java.util.Date; import java.util.List; import com.lambdaworks.redis.KillArgs; import com.lambdaworks.redis.protocol.CommandType; -import rx.Observable; -import rx.Single; -import rx.Completable; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; /** - * Observable commands for Server Control. + * Reactive executed commands for Server Control. * * @param Key type. * @param Value type. @@ -24,21 +23,21 @@ public interface RedisServerReactiveCommands { * * @return String simple-string-reply always {@code OK}. */ - Single bgrewriteaof(); + Mono bgrewriteaof(); /** * Asynchronously save the dataset to disk. * * @return String simple-string-reply */ - Single bgsave(); + Mono bgsave(); /** * Get the current connection name. * * @return K bulk-string-reply The connection name, or a null bulk reply if no name is set. */ - Single clientGetname(); + Mono clientGetname(); /** * Set the current connection name. @@ -46,7 +45,7 @@ public interface RedisServerReactiveCommands { * @param name the client name * @return simple-string-reply {@code OK} if the connection name was successfully set. */ - Single clientSetname(K name); + Mono clientSetname(K name); /** * Kill the connection of a client identified by ip:port. @@ -54,7 +53,7 @@ public interface RedisServerReactiveCommands { * @param addr ip:port * @return String simple-string-reply {@code OK} if the connection exists and has been closed */ - Single clientKill(String addr); + Mono clientKill(String addr); /** * Kill connections of clients which are filtered by {@code killArgs} @@ -62,7 +61,7 @@ public interface RedisServerReactiveCommands { * @param killArgs args for the kill operation * @return Long integer-reply number of killed connections */ - Single clientKill(KillArgs killArgs); + Mono clientKill(KillArgs killArgs); /** * Stop processing commands from clients for some time. @@ -70,7 +69,7 @@ public interface RedisServerReactiveCommands { * @param timeout the timeout value in milliseconds * @return String simple-string-reply The command returns OK or an error if the timeout is invalid. */ - Single clientPause(long timeout); + Mono clientPause(long timeout); /** * Get the list of client connections. @@ -78,14 +77,14 @@ public interface RedisServerReactiveCommands { * @return String bulk-string-reply a unique string, formatted as follows: One client connection per line (separated by LF), * each line is composed of a succession of property=value fields separated by a space character. */ - Single clientList(); + Mono clientList(); /** * Returns an array reply of details about all Redis commands. * * @return Object array-reply */ - Observable command(); + Flux command(); /** * Returns an array reply of details about the requested commands. @@ -93,7 +92,7 @@ public interface RedisServerReactiveCommands { * @param commands the commands to query for * @return Object array-reply */ - Observable commandInfo(String... commands); + Flux commandInfo(String... commands); /** * Returns an array reply of details about the requested commands. @@ -101,14 +100,14 @@ public interface RedisServerReactiveCommands { * @param commands the commands to query for * @return Object array-reply */ - Observable commandInfo(CommandType... commands); + Flux commandInfo(CommandType... commands); /** * Get total number of Redis commands. * * @return Long integer-reply of number of total commands in this Redis server. */ - Single commandCount(); + Mono commandCount(); /** * Get the value of a configuration parameter. @@ -116,14 +115,14 @@ public interface RedisServerReactiveCommands { * @param parameter name of the parameter * @return String bulk-string-reply */ - Observable configGet(String parameter); + Flux configGet(String parameter); /** * Reset the stats returned by INFO. * * @return String simple-string-reply always {@code OK}. */ - Single configResetstat(); + Mono configResetstat(); /** * Rewrite the configuration file with the in memory configuration. @@ -131,7 +130,7 @@ public interface RedisServerReactiveCommands { * @return String simple-string-reply {@code OK} when the configuration was rewritten properly. Otherwise an error is * returned. */ - Single configRewrite(); + Mono configRewrite(); /** * Set a configuration parameter to the given value. @@ -140,21 +139,21 @@ public interface RedisServerReactiveCommands { * @param value the parameter value * @return String simple-string-reply: {@code OK} when the configuration was set properly. Otherwise an error is returned. */ - Single configSet(String parameter, String value); + Mono configSet(String parameter, String value); /** * Return the number of keys in the selected database. * * @return Long integer-reply */ - Single dbsize(); + Mono dbsize(); /** * Crash and recover * @param delay optional delay in milliseconds * @return String simple-string-reply */ - Single debugCrashAndRecover(Long delay); + Mono debugCrashAndRecover(Long delay); /** * Get debugging information about the internal hash-table state. @@ -162,7 +161,7 @@ public interface RedisServerReactiveCommands { * @param db the database number * @return String simple-string-reply */ - Single debugHtstats(int db); + Mono debugHtstats(int db); /** * Get debugging information about a key. @@ -170,35 +169,35 @@ public interface RedisServerReactiveCommands { * @param key the key * @return String simple-string-reply */ - Single debugObject(K key); + Mono debugObject(K key); /** * Make the server crash: Out of memory. * * @return nothing, because the server crashes before returning. */ - Completable debugOom(); + Mono debugOom(); /** * Make the server crash: Invalid pointer access. * * @return nothing, because the server crashes before returning. */ - Completable debugSegfault(); + Mono debugSegfault(); /** * Save RDB, clear the database and reload RDB. * * @return String simple-string-reply The commands returns OK on success. */ - Single debugReload(); + Mono debugReload(); /** * Restart the server gracefully. * @param delay optional delay in milliseconds * @return String simple-string-reply */ - Single debugRestart(Long delay); + Mono debugRestart(Long delay); /** * Get debugging information about the internal SDS length. @@ -206,42 +205,42 @@ public interface RedisServerReactiveCommands { * @param key the key * @return String simple-string-reply */ - Single debugSdslen(K key); + Mono debugSdslen(K key); /** * Remove all keys from all databases. * * @return String simple-string-reply */ - Single flushall(); + Mono flushall(); /** * Remove all keys asynchronously from all databases. * * @return String simple-string-reply */ - Single flushallAsync(); + Mono flushallAsync(); /** * Remove all keys from the current database. * * @return String simple-string-reply */ - Single flushdb(); + Mono flushdb(); /** * Remove all keys asynchronously from the current database. * * @return String simple-string-reply */ - Single flushdbAsync(); + Mono flushdbAsync(); /** * Get information and statistics about the server. * * @return String bulk-string-reply as a collection of text lines. */ - Single info(); + Mono info(); /** * Get information and statistics about the server. @@ -249,28 +248,28 @@ public interface RedisServerReactiveCommands { * @param section the section type: string * @return String bulk-string-reply as a collection of text lines. */ - Single info(String section); + Mono info(String section); /** * Get the UNIX time stamp of the last successful save to disk. * * @return Date integer-reply an UNIX time stamp. */ - Single lastsave(); + Mono lastsave(); /** * Synchronously save the dataset to disk. * * @return String simple-string-reply The commands returns OK on success. */ - Single save(); + Mono save(); /** * Synchronously save the dataset to disk and then shut down the server. * * @param save {@literal true} force save operation */ - Completable shutdown(boolean save); + Mono shutdown(boolean save); /** * Make the server a slave of another instance, or promote it as master. @@ -279,21 +278,21 @@ public interface RedisServerReactiveCommands { * @param port the port type: string * @return String simple-string-reply */ - Single slaveof(String host, int port); + Mono slaveof(String host, int port); /** * Promote server as master. * * @return String simple-string-reply */ - Single slaveofNoOne(); + Mono slaveofNoOne(); /** * Read the slow log. * * @return Object deeply nested multi bulk replies */ - Observable slowlogGet(); + Flux slowlogGet(); /** * Read the slow log. @@ -301,21 +300,21 @@ public interface RedisServerReactiveCommands { * @param count the count * @return Object deeply nested multi bulk replies */ - Observable slowlogGet(int count); + Flux slowlogGet(int count); /** * Obtaining the current length of the slow log. * * @return Long length of the slow log. */ - Single slowlogLen(); + Mono slowlogLen(); /** * Resetting the slow log. * * @return String simple-string-reply The commands returns OK on success. */ - Single slowlogReset(); + Mono slowlogReset(); /** * Return the current server time. @@ -326,5 +325,5 @@ public interface RedisServerReactiveCommands { * * unix time in seconds. microseconds. */ - Observable time(); + Flux time(); } diff --git a/src/main/java/com/lambdaworks/redis/api/rx/RedisSetReactiveCommands.java b/src/main/java/com/lambdaworks/redis/api/reactive/RedisSetReactiveCommands.java similarity index 80% rename from src/main/java/com/lambdaworks/redis/api/rx/RedisSetReactiveCommands.java rename to src/main/java/com/lambdaworks/redis/api/reactive/RedisSetReactiveCommands.java index 15bce1cc47..23fbbf65a3 100644 --- a/src/main/java/com/lambdaworks/redis/api/rx/RedisSetReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/reactive/RedisSetReactiveCommands.java @@ -1,4 +1,4 @@ -package com.lambdaworks.redis.api.rx; +package com.lambdaworks.redis.api.reactive; import java.util.Set; import com.lambdaworks.redis.ScanArgs; @@ -6,12 +6,11 @@ import com.lambdaworks.redis.StreamScanCursor; import com.lambdaworks.redis.ValueScanCursor; import com.lambdaworks.redis.output.ValueStreamingChannel; -import rx.Observable; -import rx.Single; -import rx.Completable; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; /** - * Observable commands for Sets. + * Reactive executed commands for Sets. * * @param Key type. * @param Value type. @@ -29,7 +28,7 @@ public interface RedisSetReactiveCommands { * @return Long integer-reply the number of elements that were added to the set, not including all the elements already * present into the set. */ - Single sadd(K key, V... members); + Mono sadd(K key, V... members); /** * Get the number of members in a set. @@ -38,7 +37,7 @@ public interface RedisSetReactiveCommands { * @return Long integer-reply the cardinality (number of elements) of the set, or {@literal false} if {@code key} does not * exist. */ - Single scard(K key); + Mono scard(K key); /** * Subtract multiple sets. @@ -46,7 +45,7 @@ public interface RedisSetReactiveCommands { * @param keys the key * @return V array-reply list with members of the resulting set. */ - Observable sdiff(K... keys); + Flux sdiff(K... keys); /** * Subtract multiple sets. @@ -55,7 +54,7 @@ public interface RedisSetReactiveCommands { * @param keys the keys * @return Long count of members of the resulting set. */ - Single sdiff(ValueStreamingChannel channel, K... keys); + Mono sdiff(ValueStreamingChannel channel, K... keys); /** * Subtract multiple sets and store the resulting set in a key. @@ -64,7 +63,7 @@ public interface RedisSetReactiveCommands { * @param keys the key * @return Long integer-reply the number of elements in the resulting set. */ - Single sdiffstore(K destination, K... keys); + Mono sdiffstore(K destination, K... keys); /** * Intersect multiple sets. @@ -72,7 +71,7 @@ public interface RedisSetReactiveCommands { * @param keys the key * @return V array-reply list with members of the resulting set. */ - Observable sinter(K... keys); + Flux sinter(K... keys); /** * Intersect multiple sets. @@ -81,7 +80,7 @@ public interface RedisSetReactiveCommands { * @param keys the keys * @return Long count of members of the resulting set. */ - Single sinter(ValueStreamingChannel channel, K... keys); + Mono sinter(ValueStreamingChannel channel, K... keys); /** * Intersect multiple sets and store the resulting set in a key. @@ -90,7 +89,7 @@ public interface RedisSetReactiveCommands { * @param keys the key * @return Long integer-reply the number of elements in the resulting set. */ - Single sinterstore(K destination, K... keys); + Mono sinterstore(K destination, K... keys); /** * Determine if a given value is a member of a set. @@ -102,7 +101,7 @@ public interface RedisSetReactiveCommands { * {@literal true} if the element is a member of the set. {@literal false} if the element is not a member of the * set, or if {@code key} does not exist. */ - Single sismember(K key, V member); + Mono sismember(K key, V member); /** * Move a member from one set to another. @@ -115,7 +114,7 @@ public interface RedisSetReactiveCommands { * {@literal true} if the element is moved. {@literal false} if the element is not a member of {@code source} and no * operation was performed. */ - Single smove(K source, K destination, V member); + Mono smove(K source, K destination, V member); /** * Get all the members in a set. @@ -123,7 +122,7 @@ public interface RedisSetReactiveCommands { * @param key the key * @return V array-reply all elements of the set. */ - Observable smembers(K key); + Flux smembers(K key); /** * Get all the members in a set. @@ -132,7 +131,7 @@ public interface RedisSetReactiveCommands { * @param key the keys * @return Long count of members of the resulting set. */ - Single smembers(ValueStreamingChannel channel, K key); + Mono smembers(ValueStreamingChannel channel, K key); /** * Remove and return a random member from a set. @@ -140,7 +139,7 @@ public interface RedisSetReactiveCommands { * @param key the key * @return V bulk-string-reply the removed element, or {@literal null} when {@code key} does not exist. */ - Single spop(K key); + Mono spop(K key); /** * Remove and return one or multiple random members from a set. @@ -149,7 +148,7 @@ public interface RedisSetReactiveCommands { * @param count number of members to pop * @return V bulk-string-reply the removed element, or {@literal null} when {@code key} does not exist. */ - Observable spop(K key, long count); + Flux spop(K key, long count); /** * Get one random member from a set. @@ -159,7 +158,7 @@ public interface RedisSetReactiveCommands { * @return V bulk-string-reply without the additional {@code count} argument the command returns a Bulk Reply with the * randomly selected element, or {@literal null} when {@code key} does not exist. */ - Single srandmember(K key); + Mono srandmember(K key); /** * Get one or multiple random members from a set. @@ -169,7 +168,7 @@ public interface RedisSetReactiveCommands { * @return V bulk-string-reply without the additional {@code count} argument the command returns a Bulk Reply * with the randomly selected element, or {@literal null} when {@code key} does not exist. */ - Observable srandmember(K key, long count); + Flux srandmember(K key, long count); /** * Get one or multiple random members from a set. @@ -179,7 +178,7 @@ public interface RedisSetReactiveCommands { * @param count the count * @return Long count of members of the resulting set. */ - Single srandmember(ValueStreamingChannel channel, K key, long count); + Mono srandmember(ValueStreamingChannel channel, K key, long count); /** * Remove one or more members from a set. @@ -188,7 +187,7 @@ public interface RedisSetReactiveCommands { * @param members the member type: value * @return Long integer-reply the number of members that were removed from the set, not including non existing members. */ - Single srem(K key, V... members); + Mono srem(K key, V... members); /** * Add multiple sets. @@ -196,7 +195,7 @@ public interface RedisSetReactiveCommands { * @param keys the key * @return V array-reply list with members of the resulting set. */ - Observable sunion(K... keys); + Flux sunion(K... keys); /** * Add multiple sets. @@ -205,7 +204,7 @@ public interface RedisSetReactiveCommands { * @param keys the keys * @return Long count of members of the resulting set. */ - Single sunion(ValueStreamingChannel channel, K... keys); + Mono sunion(ValueStreamingChannel channel, K... keys); /** * Add multiple sets and store the resulting set in a key. @@ -214,7 +213,7 @@ public interface RedisSetReactiveCommands { * @param keys the key * @return Long integer-reply the number of elements in the resulting set. */ - Single sunionstore(K destination, K... keys); + Mono sunionstore(K destination, K... keys); /** * Incrementally iterate Set elements. @@ -222,7 +221,7 @@ public interface RedisSetReactiveCommands { * @param key the key * @return ValueScanCursor<V> scan cursor. */ - Single> sscan(K key); + Mono> sscan(K key); /** * Incrementally iterate Set elements. @@ -231,7 +230,7 @@ public interface RedisSetReactiveCommands { * @param scanArgs scan arguments * @return ValueScanCursor<V> scan cursor. */ - Single> sscan(K key, ScanArgs scanArgs); + Mono> sscan(K key, ScanArgs scanArgs); /** * Incrementally iterate Set elements. @@ -241,7 +240,7 @@ public interface RedisSetReactiveCommands { * @param scanArgs scan arguments * @return ValueScanCursor<V> scan cursor. */ - Single> sscan(K key, ScanCursor scanCursor, ScanArgs scanArgs); + Mono> sscan(K key, ScanCursor scanCursor, ScanArgs scanArgs); /** * Incrementally iterate Set elements. @@ -250,7 +249,7 @@ public interface RedisSetReactiveCommands { * @param scanCursor cursor to resume from a previous scan, must not be {@literal null} * @return ValueScanCursor<V> scan cursor. */ - Single> sscan(K key, ScanCursor scanCursor); + Mono> sscan(K key, ScanCursor scanCursor); /** * Incrementally iterate Set elements. @@ -259,7 +258,7 @@ public interface RedisSetReactiveCommands { * @param key the key * @return StreamScanCursor scan cursor. */ - Single sscan(ValueStreamingChannel channel, K key); + Mono sscan(ValueStreamingChannel channel, K key); /** * Incrementally iterate Set elements. @@ -269,7 +268,7 @@ public interface RedisSetReactiveCommands { * @param scanArgs scan arguments * @return StreamScanCursor scan cursor. */ - Single sscan(ValueStreamingChannel channel, K key, ScanArgs scanArgs); + Mono sscan(ValueStreamingChannel channel, K key, ScanArgs scanArgs); /** * Incrementally iterate Set elements. @@ -280,7 +279,7 @@ public interface RedisSetReactiveCommands { * @param scanArgs scan arguments * @return StreamScanCursor scan cursor. */ - Single sscan(ValueStreamingChannel channel, K key, ScanCursor scanCursor, ScanArgs scanArgs); + Mono sscan(ValueStreamingChannel channel, K key, ScanCursor scanCursor, ScanArgs scanArgs); /** * Incrementally iterate Set elements. @@ -290,5 +289,5 @@ public interface RedisSetReactiveCommands { * @param scanCursor cursor to resume from a previous scan, must not be {@literal null} * @return StreamScanCursor scan cursor. */ - Single sscan(ValueStreamingChannel channel, K key, ScanCursor scanCursor); + Mono sscan(ValueStreamingChannel channel, K key, ScanCursor scanCursor); } diff --git a/src/main/java/com/lambdaworks/redis/api/rx/RedisSortedSetReactiveCommands.java b/src/main/java/com/lambdaworks/redis/api/reactive/RedisSortedSetReactiveCommands.java similarity index 79% rename from src/main/java/com/lambdaworks/redis/api/rx/RedisSortedSetReactiveCommands.java rename to src/main/java/com/lambdaworks/redis/api/reactive/RedisSortedSetReactiveCommands.java index 0da8841703..ca9c6ca24c 100644 --- a/src/main/java/com/lambdaworks/redis/api/rx/RedisSortedSetReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/reactive/RedisSortedSetReactiveCommands.java @@ -1,4 +1,4 @@ -package com.lambdaworks.redis.api.rx; +package com.lambdaworks.redis.api.reactive; import java.util.List; import com.lambdaworks.redis.ScanArgs; @@ -10,12 +10,11 @@ import com.lambdaworks.redis.ZStoreArgs; import com.lambdaworks.redis.output.ScoredValueStreamingChannel; import com.lambdaworks.redis.output.ValueStreamingChannel; -import rx.Observable; -import rx.Single; -import rx.Completable; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; /** - * Observable commands for Sorted Sets. + * Reactive executed commands for Sorted Sets. * * @param Key type. * @param Value type. @@ -37,7 +36,7 @@ public interface RedisSortedSetReactiveCommands { * The number of elements added to the sorted sets, not including elements already existing for which the score was * updated. */ - Single zadd(K key, double score, V member); + Mono zadd(K key, double score, V member); /** * Add one or more members to a sorted set, or update its score if it already exists. @@ -49,7 +48,7 @@ public interface RedisSortedSetReactiveCommands { * The number of elements added to the sorted sets, not including elements already existing for which the score was * updated. */ - Single zadd(K key, Object... scoresAndValues); + Mono zadd(K key, Object... scoresAndValues); /** * Add one or more members to a sorted set, or update its score if it already exists. @@ -61,7 +60,7 @@ public interface RedisSortedSetReactiveCommands { * The number of elements added to the sorted sets, not including elements already existing for which the score was * updated. */ - Single zadd(K key, ScoredValue... scoredValues); + Mono zadd(K key, ScoredValue... scoredValues); /** * Add one or more members to a sorted set, or update its score if it already exists. @@ -76,7 +75,7 @@ public interface RedisSortedSetReactiveCommands { * The number of elements added to the sorted sets, not including elements already existing for which the score was * updated. */ - Single zadd(K key, ZAddArgs zAddArgs, double score, V member); + Mono zadd(K key, ZAddArgs zAddArgs, double score, V member); /** * Add one or more members to a sorted set, or update its score if it already exists. @@ -89,7 +88,7 @@ public interface RedisSortedSetReactiveCommands { * The number of elements added to the sorted sets, not including elements already existing for which the score was * updated. */ - Single zadd(K key, ZAddArgs zAddArgs, Object... scoresAndValues); + Mono zadd(K key, ZAddArgs zAddArgs, Object... scoresAndValues); /** * Add one or more members to a sorted set, or update its score if it already exists. @@ -102,7 +101,7 @@ public interface RedisSortedSetReactiveCommands { * The number of elements added to the sorted sets, not including elements already existing for which the score was * updated. */ - Single zadd(K key, ZAddArgs zAddArgs, ScoredValue... scoredValues); + Mono zadd(K key, ZAddArgs zAddArgs, ScoredValue... scoredValues); /** * ZADD acts like ZINCRBY @@ -115,7 +114,7 @@ public interface RedisSortedSetReactiveCommands { * * The total number of elements changed */ - Single zaddincr(K key, double score, V member); + Mono zaddincr(K key, double score, V member); /** * Get the number of members in a sorted set. @@ -124,7 +123,7 @@ public interface RedisSortedSetReactiveCommands { * @return Long integer-reply the cardinality (number of elements) of the sorted set, or {@literal false} if {@code key} * does not exist. */ - Single zcard(K key); + Mono zcard(K key); /** * Count the members in a sorted set with scores within the given values. @@ -134,7 +133,7 @@ public interface RedisSortedSetReactiveCommands { * @param max max score * @return Long integer-reply the number of elements in the specified score range. */ - Single zcount(K key, double min, double max); + Mono zcount(K key, double min, double max); /** * Count the members in a sorted set with scores within the given values. @@ -144,7 +143,7 @@ public interface RedisSortedSetReactiveCommands { * @param max max score * @return Long integer-reply the number of elements in the specified score range. */ - Single zcount(K key, String min, String max); + Mono zcount(K key, String min, String max); /** * Increment the score of a member in a sorted set. @@ -155,7 +154,7 @@ public interface RedisSortedSetReactiveCommands { * @return Double bulk-string-reply the new score of {@code member} (a double precision floating point number), represented * as string. */ - Single zincrby(K key, double amount, K member); + Mono zincrby(K key, double amount, K member); /** * Intersect multiple sorted sets and store the resulting sorted set in a new key. @@ -164,7 +163,7 @@ public interface RedisSortedSetReactiveCommands { * @param keys the keys * @return Long integer-reply the number of elements in the resulting sorted set at {@code destination}. */ - Single zinterstore(K destination, K... keys); + Mono zinterstore(K destination, K... keys); /** * Intersect multiple sorted sets and store the resulting sorted set in a new key. @@ -174,7 +173,7 @@ public interface RedisSortedSetReactiveCommands { * @param keys the keys * @return Long integer-reply the number of elements in the resulting sorted set at {@code destination}. */ - Single zinterstore(K destination, ZStoreArgs storeArgs, K... keys); + Mono zinterstore(K destination, ZStoreArgs storeArgs, K... keys); /** * Return a range of members in a sorted set, by index. @@ -184,7 +183,7 @@ public interface RedisSortedSetReactiveCommands { * @param stop the stop * @return V array-reply list of elements in the specified range. */ - Observable zrange(K key, long start, long stop); + Flux zrange(K key, long start, long stop); /** * Return a range of members with scores in a sorted set, by index. @@ -194,7 +193,7 @@ public interface RedisSortedSetReactiveCommands { * @param stop the stop * @return V array-reply list of elements in the specified range. */ - Observable> zrangeWithScores(K key, long start, long stop); + Flux> zrangeWithScores(K key, long start, long stop); /** * Return a range of members in a sorted set, by score. @@ -204,7 +203,7 @@ public interface RedisSortedSetReactiveCommands { * @param max max score * @return V array-reply list of elements in the specified score range. */ - Observable zrangebyscore(K key, double min, double max); + Flux zrangebyscore(K key, double min, double max); /** * Return a range of members in a sorted set, by score. @@ -214,7 +213,7 @@ public interface RedisSortedSetReactiveCommands { * @param max max score * @return V array-reply list of elements in the specified score range. */ - Observable zrangebyscore(K key, String min, String max); + Flux zrangebyscore(K key, String min, String max); /** * Return a range of members in a sorted set, by score. @@ -226,7 +225,7 @@ public interface RedisSortedSetReactiveCommands { * @param count the count * @return V array-reply list of elements in the specified score range. */ - Observable zrangebyscore(K key, double min, double max, long offset, long count); + Flux zrangebyscore(K key, double min, double max, long offset, long count); /** * Return a range of members in a sorted set, by score. @@ -238,7 +237,7 @@ public interface RedisSortedSetReactiveCommands { * @param count the count * @return V array-reply list of elements in the specified score range. */ - Observable zrangebyscore(K key, String min, String max, long offset, long count); + Flux zrangebyscore(K key, String min, String max, long offset, long count); /** * Return a range of members with score in a sorted set, by score. @@ -248,7 +247,7 @@ public interface RedisSortedSetReactiveCommands { * @param max max score * @return ScoredValue<V> array-reply list of elements in the specified score range. */ - Observable> zrangebyscoreWithScores(K key, double min, double max); + Flux> zrangebyscoreWithScores(K key, double min, double max); /** * Return a range of members with score in a sorted set, by score. @@ -258,7 +257,7 @@ public interface RedisSortedSetReactiveCommands { * @param max max score * @return ScoredValue<V> array-reply list of elements in the specified score range. */ - Observable> zrangebyscoreWithScores(K key, String min, String max); + Flux> zrangebyscoreWithScores(K key, String min, String max); /** * Return a range of members with score in a sorted set, by score. @@ -270,7 +269,7 @@ public interface RedisSortedSetReactiveCommands { * @param count the count * @return ScoredValue<V> array-reply list of elements in the specified score range. */ - Observable> zrangebyscoreWithScores(K key, double min, double max, long offset, long count); + Flux> zrangebyscoreWithScores(K key, double min, double max, long offset, long count); /** * Return a range of members with score in a sorted set, by score. @@ -282,7 +281,7 @@ public interface RedisSortedSetReactiveCommands { * @param count the count * @return ScoredValue<V> array-reply list of elements in the specified score range. */ - Observable> zrangebyscoreWithScores(K key, String min, String max, long offset, long count); + Flux> zrangebyscoreWithScores(K key, String min, String max, long offset, long count); /** * Return a range of members in a sorted set, by index. @@ -293,7 +292,7 @@ public interface RedisSortedSetReactiveCommands { * @param stop the stop * @return Long count of elements in the specified range. */ - Single zrange(ValueStreamingChannel channel, K key, long start, long stop); + Mono zrange(ValueStreamingChannel channel, K key, long start, long stop); /** * Stream over a range of members with scores in a sorted set, by index. @@ -304,7 +303,7 @@ public interface RedisSortedSetReactiveCommands { * @param stop the stop * @return Long count of elements in the specified range. */ - Single zrangeWithScores(ScoredValueStreamingChannel channel, K key, long start, long stop); + Mono zrangeWithScores(ScoredValueStreamingChannel channel, K key, long start, long stop); /** * Stream over a range of members in a sorted set, by score. @@ -315,7 +314,7 @@ public interface RedisSortedSetReactiveCommands { * @param max max score * @return Long count of elements in the specified score range. */ - Single zrangebyscore(ValueStreamingChannel channel, K key, double min, double max); + Mono zrangebyscore(ValueStreamingChannel channel, K key, double min, double max); /** * Stream over a range of members in a sorted set, by score. @@ -326,7 +325,7 @@ public interface RedisSortedSetReactiveCommands { * @param max max score * @return Long count of elements in the specified score range. */ - Single zrangebyscore(ValueStreamingChannel channel, K key, String min, String max); + Mono zrangebyscore(ValueStreamingChannel channel, K key, String min, String max); /** * Stream over range of members in a sorted set, by score. @@ -339,7 +338,7 @@ public interface RedisSortedSetReactiveCommands { * @param count the count * @return Long count of elements in the specified score range. */ - Single zrangebyscore(ValueStreamingChannel channel, K key, double min, double max, long offset, long count); + Mono zrangebyscore(ValueStreamingChannel channel, K key, double min, double max, long offset, long count); /** * Stream over a range of members in a sorted set, by score. @@ -352,7 +351,7 @@ public interface RedisSortedSetReactiveCommands { * @param count the count * @return Long count of elements in the specified score range. */ - Single zrangebyscore(ValueStreamingChannel channel, K key, String min, String max, long offset, long count); + Mono zrangebyscore(ValueStreamingChannel channel, K key, String min, String max, long offset, long count); /** * Stream over a range of members with scores in a sorted set, by score. @@ -363,7 +362,7 @@ public interface RedisSortedSetReactiveCommands { * @param max max score * @return Long count of elements in the specified score range. */ - Single zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, double min, double max); + Mono zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, double min, double max); /** * Stream over a range of members with scores in a sorted set, by score. @@ -374,7 +373,7 @@ public interface RedisSortedSetReactiveCommands { * @param max max score * @return Long count of elements in the specified score range. */ - Single zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, String min, String max); + Mono zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, String min, String max); /** * Stream over a range of members with scores in a sorted set, by score. @@ -387,7 +386,7 @@ public interface RedisSortedSetReactiveCommands { * @param count the count * @return Long count of elements in the specified score range. */ - Single zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, double min, double max, long offset, long count); + Mono zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, double min, double max, long offset, long count); /** * Stream over a range of members with scores in a sorted set, by score. @@ -400,7 +399,7 @@ public interface RedisSortedSetReactiveCommands { * @param count the count * @return Long count of elements in the specified score range. */ - Single zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, String min, String max, long offset, long count); + Mono zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, String min, String max, long offset, long count); /** * Determine the index of a member in a sorted set. @@ -410,7 +409,7 @@ public interface RedisSortedSetReactiveCommands { * @return Long integer-reply the rank of {@code member}. If {@code member} does not exist in the sorted set or {@code key} * does not exist, */ - Single zrank(K key, V member); + Mono zrank(K key, V member); /** * Remove one or more members from a sorted set. @@ -421,7 +420,7 @@ public interface RedisSortedSetReactiveCommands { * * The number of members removed from the sorted set, not including non existing members. */ - Single zrem(K key, V... members); + Mono zrem(K key, V... members); /** * Remove all members in a sorted set within the given indexes. @@ -431,7 +430,7 @@ public interface RedisSortedSetReactiveCommands { * @param stop the stop type: long * @return Long integer-reply the number of elements removed. */ - Single zremrangebyrank(K key, long start, long stop); + Mono zremrangebyrank(K key, long start, long stop); /** * Remove all members in a sorted set within the given scores. @@ -441,7 +440,7 @@ public interface RedisSortedSetReactiveCommands { * @param max max score * @return Long integer-reply the number of elements removed. */ - Single zremrangebyscore(K key, double min, double max); + Mono zremrangebyscore(K key, double min, double max); /** * Remove all members in a sorted set within the given scores. @@ -451,7 +450,7 @@ public interface RedisSortedSetReactiveCommands { * @param max max score * @return Long integer-reply the number of elements removed. */ - Single zremrangebyscore(K key, String min, String max); + Mono zremrangebyscore(K key, String min, String max); /** * Return a range of members in a sorted set, by index, with scores ordered from high to low. @@ -461,7 +460,7 @@ public interface RedisSortedSetReactiveCommands { * @param stop the stop * @return V array-reply list of elements in the specified range. */ - Observable zrevrange(K key, long start, long stop); + Flux zrevrange(K key, long start, long stop); /** * Return a range of members with scores in a sorted set, by index, with scores ordered from high to low. @@ -471,7 +470,7 @@ public interface RedisSortedSetReactiveCommands { * @param stop the stop * @return V array-reply list of elements in the specified range. */ - Observable> zrevrangeWithScores(K key, long start, long stop); + Flux> zrevrangeWithScores(K key, long start, long stop); /** * Return a range of members in a sorted set, by score, with scores ordered from high to low. @@ -481,7 +480,7 @@ public interface RedisSortedSetReactiveCommands { * @param max max score * @return V array-reply list of elements in the specified score range. */ - Observable zrevrangebyscore(K key, double max, double min); + Flux zrevrangebyscore(K key, double max, double min); /** * Return a range of members in a sorted set, by score, with scores ordered from high to low. @@ -491,7 +490,7 @@ public interface RedisSortedSetReactiveCommands { * @param max max score * @return V array-reply list of elements in the specified score range. */ - Observable zrevrangebyscore(K key, String max, String min); + Flux zrevrangebyscore(K key, String max, String min); /** * Return a range of members in a sorted set, by score, with scores ordered from high to low. @@ -503,7 +502,7 @@ public interface RedisSortedSetReactiveCommands { * @param count the null * @return V array-reply list of elements in the specified score range. */ - Observable zrevrangebyscore(K key, double max, double min, long offset, long count); + Flux zrevrangebyscore(K key, double max, double min, long offset, long count); /** * Return a range of members in a sorted set, by score, with scores ordered from high to low. @@ -515,7 +514,7 @@ public interface RedisSortedSetReactiveCommands { * @param count the count * @return V array-reply list of elements in the specified score range. */ - Observable zrevrangebyscore(K key, String max, String min, long offset, long count); + Flux zrevrangebyscore(K key, String max, String min, long offset, long count); /** * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. @@ -525,7 +524,7 @@ public interface RedisSortedSetReactiveCommands { * @param min min score * @return V array-reply list of elements in the specified score range. */ - Observable> zrevrangebyscoreWithScores(K key, double max, double min); + Flux> zrevrangebyscoreWithScores(K key, double max, double min); /** * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. @@ -535,7 +534,7 @@ public interface RedisSortedSetReactiveCommands { * @param min min score * @return ScoredValue<V> array-reply list of elements in the specified score range. */ - Observable> zrevrangebyscoreWithScores(K key, String max, String min); + Flux> zrevrangebyscoreWithScores(K key, String max, String min); /** * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. @@ -547,7 +546,7 @@ public interface RedisSortedSetReactiveCommands { * @param count the count * @return ScoredValue<V> array-reply list of elements in the specified score range. */ - Observable> zrevrangebyscoreWithScores(K key, double max, double min, long offset, long count); + Flux> zrevrangebyscoreWithScores(K key, double max, double min, long offset, long count); /** * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. @@ -559,7 +558,7 @@ public interface RedisSortedSetReactiveCommands { * @param count the count * @return V array-reply list of elements in the specified score range. */ - Observable> zrevrangebyscoreWithScores(K key, String max, String min, long offset, long count); + Flux> zrevrangebyscoreWithScores(K key, String max, String min, long offset, long count); /** * Stream over a range of members in a sorted set, by index, with scores ordered from high to low. @@ -570,7 +569,7 @@ public interface RedisSortedSetReactiveCommands { * @param stop the stop * @return Long count of elements in the specified range. */ - Single zrevrange(ValueStreamingChannel channel, K key, long start, long stop); + Mono zrevrange(ValueStreamingChannel channel, K key, long start, long stop); /** * Stream over a range of members with scores in a sorted set, by index, with scores ordered from high to low. @@ -581,7 +580,7 @@ public interface RedisSortedSetReactiveCommands { * @param stop the stop * @return Long count of elements in the specified range. */ - Single zrevrangeWithScores(ScoredValueStreamingChannel channel, K key, long start, long stop); + Mono zrevrangeWithScores(ScoredValueStreamingChannel channel, K key, long start, long stop); /** * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. @@ -592,7 +591,7 @@ public interface RedisSortedSetReactiveCommands { * @param min min score * @return Long count of elements in the specified range. */ - Single zrevrangebyscore(ValueStreamingChannel channel, K key, double max, double min); + Mono zrevrangebyscore(ValueStreamingChannel channel, K key, double max, double min); /** * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. @@ -603,7 +602,7 @@ public interface RedisSortedSetReactiveCommands { * @param max max score * @return Long count of elements in the specified range. */ - Single zrevrangebyscore(ValueStreamingChannel channel, K key, String max, String min); + Mono zrevrangebyscore(ValueStreamingChannel channel, K key, String max, String min); /** * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. @@ -616,7 +615,7 @@ public interface RedisSortedSetReactiveCommands { * @param count the count * @return Long count of elements in the specified range. */ - Single zrevrangebyscore(ValueStreamingChannel channel, K key, double max, double min, long offset, long count); + Mono zrevrangebyscore(ValueStreamingChannel channel, K key, double max, double min, long offset, long count); /** * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. @@ -629,7 +628,7 @@ public interface RedisSortedSetReactiveCommands { * @param count the count * @return Long count of elements in the specified range. */ - Single zrevrangebyscore(ValueStreamingChannel channel, K key, String max, String min, long offset, long count); + Mono zrevrangebyscore(ValueStreamingChannel channel, K key, String max, String min, long offset, long count); /** * Stream over a range of members with scores in a sorted set, by score, with scores ordered from high to low. @@ -640,7 +639,7 @@ public interface RedisSortedSetReactiveCommands { * @param max max score * @return Long count of elements in the specified range. */ - Single zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, double max, double min); + Mono zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, double max, double min); /** * Stream over a range of members with scores in a sorted set, by score, with scores ordered from high to low. @@ -651,7 +650,7 @@ public interface RedisSortedSetReactiveCommands { * @param max max score * @return Long count of elements in the specified range. */ - Single zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, String max, String min); + Mono zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, String max, String min); /** * Stream over a range of members with scores in a sorted set, by score, with scores ordered from high to low. @@ -664,7 +663,7 @@ public interface RedisSortedSetReactiveCommands { * @param count the count * @return Long count of elements in the specified range. */ - Single zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, double max, double min, long offset, long count); + Mono zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, double max, double min, long offset, long count); /** * Stream over a range of members with scores in a sorted set, by score, with scores ordered from high to low. @@ -677,7 +676,7 @@ public interface RedisSortedSetReactiveCommands { * @param count the count * @return Long count of elements in the specified range. */ - Single zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, String max, String min, long offset, long count); + Mono zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, String max, String min, long offset, long count); /** * Determine the index of a member in a sorted set, with scores ordered from high to low. @@ -687,7 +686,7 @@ public interface RedisSortedSetReactiveCommands { * @return Long integer-reply the rank of {@code member}. If {@code member} does not exist in the sorted set or {@code key} * does not exist, */ - Single zrevrank(K key, V member); + Mono zrevrank(K key, V member); /** * Get the score associated with the given member in a sorted set. @@ -697,7 +696,7 @@ public interface RedisSortedSetReactiveCommands { * @return Double bulk-string-reply the score of {@code member} (a double precision floating point number), represented as * string. */ - Single zscore(K key, V member); + Mono zscore(K key, V member); /** * Add multiple sorted sets and store the resulting sorted set in a new key. @@ -706,7 +705,7 @@ public interface RedisSortedSetReactiveCommands { * @param keys source keys * @return Long integer-reply the number of elements in the resulting sorted set at {@code destination}. */ - Single zunionstore(K destination, K... keys); + Mono zunionstore(K destination, K... keys); /** * Add multiple sorted sets and store the resulting sorted set in a new key. @@ -716,7 +715,7 @@ public interface RedisSortedSetReactiveCommands { * @param keys the keys * @return Long integer-reply the number of elements in the resulting sorted set at {@code destination}. */ - Single zunionstore(K destination, ZStoreArgs storeArgs, K... keys); + Mono zunionstore(K destination, ZStoreArgs storeArgs, K... keys); /** * Incrementally iterate sorted sets elements and associated scores. @@ -724,7 +723,7 @@ public interface RedisSortedSetReactiveCommands { * @param key the key * @return ScoredValueScanCursor<V> scan cursor. */ - Single> zscan(K key); + Mono> zscan(K key); /** * Incrementally iterate sorted sets elements and associated scores. @@ -733,7 +732,7 @@ public interface RedisSortedSetReactiveCommands { * @param scanArgs scan arguments * @return ScoredValueScanCursor<V> scan cursor. */ - Single> zscan(K key, ScanArgs scanArgs); + Mono> zscan(K key, ScanArgs scanArgs); /** * Incrementally iterate sorted sets elements and associated scores. @@ -743,7 +742,7 @@ public interface RedisSortedSetReactiveCommands { * @param scanArgs scan arguments * @return ScoredValueScanCursor<V> scan cursor. */ - Single> zscan(K key, ScanCursor scanCursor, ScanArgs scanArgs); + Mono> zscan(K key, ScanCursor scanCursor, ScanArgs scanArgs); /** * Incrementally iterate sorted sets elements and associated scores. @@ -752,7 +751,7 @@ public interface RedisSortedSetReactiveCommands { * @param scanCursor cursor to resume from a previous scan, must not be {@literal null} * @return ScoredValueScanCursor<V> scan cursor. */ - Single> zscan(K key, ScanCursor scanCursor); + Mono> zscan(K key, ScanCursor scanCursor); /** * Incrementally iterate sorted sets elements and associated scores. @@ -761,7 +760,7 @@ public interface RedisSortedSetReactiveCommands { * @param key the key * @return StreamScanCursor scan cursor. */ - Single zscan(ScoredValueStreamingChannel channel, K key); + Mono zscan(ScoredValueStreamingChannel channel, K key); /** * Incrementally iterate sorted sets elements and associated scores. @@ -771,7 +770,7 @@ public interface RedisSortedSetReactiveCommands { * @param scanArgs scan arguments * @return StreamScanCursor scan cursor. */ - Single zscan(ScoredValueStreamingChannel channel, K key, ScanArgs scanArgs); + Mono zscan(ScoredValueStreamingChannel channel, K key, ScanArgs scanArgs); /** * Incrementally iterate sorted sets elements and associated scores. @@ -782,7 +781,7 @@ public interface RedisSortedSetReactiveCommands { * @param scanArgs scan arguments * @return StreamScanCursor scan cursor. */ - Single zscan(ScoredValueStreamingChannel channel, K key, ScanCursor scanCursor, ScanArgs scanArgs); + Mono zscan(ScoredValueStreamingChannel channel, K key, ScanCursor scanCursor, ScanArgs scanArgs); /** * Incrementally iterate sorted sets elements and associated scores. @@ -792,7 +791,7 @@ public interface RedisSortedSetReactiveCommands { * @param scanCursor cursor to resume from a previous scan, must not be {@literal null} * @return StreamScanCursor scan cursor. */ - Single zscan(ScoredValueStreamingChannel channel, K key, ScanCursor scanCursor); + Mono zscan(ScoredValueStreamingChannel channel, K key, ScanCursor scanCursor); /** * Count the number of members in a sorted set between a given lexicographical range. @@ -802,7 +801,7 @@ public interface RedisSortedSetReactiveCommands { * @param max max score * @return Long integer-reply the number of elements in the specified score range. */ - Single zlexcount(K key, String min, String max); + Mono zlexcount(K key, String min, String max); /** * Remove all members in a sorted set between the given lexicographical range. @@ -812,7 +811,7 @@ public interface RedisSortedSetReactiveCommands { * @param max max score * @return Long integer-reply the number of elements removed. */ - Single zremrangebylex(K key, String min, String max); + Mono zremrangebylex(K key, String min, String max); /** * Return a range of members in a sorted set, by lexicographical range. @@ -822,7 +821,7 @@ public interface RedisSortedSetReactiveCommands { * @param max max score * @return V array-reply list of elements in the specified score range. */ - Observable zrangebylex(K key, String min, String max); + Flux zrangebylex(K key, String min, String max); /** * Return a range of members in a sorted set, by lexicographical range. @@ -834,5 +833,5 @@ public interface RedisSortedSetReactiveCommands { * @param count the count * @return V array-reply list of elements in the specified score range. */ - Observable zrangebylex(K key, String min, String max, long offset, long count); + Flux zrangebylex(K key, String min, String max, long offset, long count); } diff --git a/src/main/java/com/lambdaworks/redis/api/rx/RedisStringReactiveCommands.java b/src/main/java/com/lambdaworks/redis/api/reactive/RedisStringReactiveCommands.java similarity index 86% rename from src/main/java/com/lambdaworks/redis/api/rx/RedisStringReactiveCommands.java rename to src/main/java/com/lambdaworks/redis/api/reactive/RedisStringReactiveCommands.java index 5abf9b1b9f..b6934b126f 100644 --- a/src/main/java/com/lambdaworks/redis/api/rx/RedisStringReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/reactive/RedisStringReactiveCommands.java @@ -1,4 +1,4 @@ -package com.lambdaworks.redis.api.rx; +package com.lambdaworks.redis.api.reactive; import java.util.List; import java.util.Map; @@ -8,12 +8,11 @@ import com.lambdaworks.redis.KeyValue; import com.lambdaworks.redis.SetArgs; import com.lambdaworks.redis.Value; -import rx.Observable; -import rx.Single; -import rx.Completable; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; /** - * Observable commands for Strings. + * Reactive executed commands for Strings. * * @param Key type. * @param Value type. @@ -30,7 +29,7 @@ public interface RedisStringReactiveCommands { * @param value the value * @return Long integer-reply the length of the string after the append operation. */ - Single append(K key, V value); + Mono append(K key, V value); /** * Count set bits in a string. @@ -39,7 +38,7 @@ public interface RedisStringReactiveCommands { * * @return Long integer-reply The number of bits set to 1. */ - Single bitcount(K key); + Mono bitcount(K key); /** * Count set bits in a string. @@ -50,7 +49,7 @@ public interface RedisStringReactiveCommands { * * @return Long integer-reply The number of bits set to 1. */ - Single bitcount(K key, long start, long end); + Mono bitcount(K key, long start, long end); /** * Execute {@code BITFIELD} with its subcommands. @@ -60,7 +59,7 @@ public interface RedisStringReactiveCommands { * * @return Long bulk-reply the results from the bitfield commands. */ - Observable bitfield(K key, BitFieldArgs bitFieldArgs); + Flux bitfield(K key, BitFieldArgs bitFieldArgs); /** * Find first bit set or clear in a string. @@ -84,7 +83,7 @@ public interface RedisStringReactiveCommands { * start and end. If no clear bit is found in the specified range, the function * returns -1 as the user specified a clear range and there are no 0 bits in that range. */ - Single bitpos(K key, boolean state); + Mono bitpos(K key, boolean state); /** * Find first bit set or clear in a string. @@ -109,7 +108,7 @@ public interface RedisStringReactiveCommands { * start and end. If no clear bit is found in the specified range, the function * returns -1 as the user specified a clear range and there are no 0 bits in that range. */ - Single bitpos(K key, boolean state, long start, long end); + Mono bitpos(K key, boolean state, long start, long end); /** * Perform bitwise AND between strings. @@ -119,7 +118,7 @@ public interface RedisStringReactiveCommands { * @return Long integer-reply The size of the string stored in the destination key, that is equal to the size of the longest * input string. */ - Single bitopAnd(K destination, K... keys); + Mono bitopAnd(K destination, K... keys); /** * Perform bitwise NOT between strings. @@ -129,7 +128,7 @@ public interface RedisStringReactiveCommands { * @return Long integer-reply The size of the string stored in the destination key, that is equal to the size of the longest * input string. */ - Single bitopNot(K destination, K source); + Mono bitopNot(K destination, K source); /** * Perform bitwise OR between strings. @@ -139,7 +138,7 @@ public interface RedisStringReactiveCommands { * @return Long integer-reply The size of the string stored in the destination key, that is equal to the size of the longest * input string. */ - Single bitopOr(K destination, K... keys); + Mono bitopOr(K destination, K... keys); /** * Perform bitwise XOR between strings. @@ -149,7 +148,7 @@ public interface RedisStringReactiveCommands { * @return Long integer-reply The size of the string stored in the destination key, that is equal to the size of the longest * input string. */ - Single bitopXor(K destination, K... keys); + Mono bitopXor(K destination, K... keys); /** * Decrement the integer value of a key by one. @@ -157,7 +156,7 @@ public interface RedisStringReactiveCommands { * @param key the key * @return Long integer-reply the value of {@code key} after the decrement */ - Single decr(K key); + Mono decr(K key); /** * Decrement the integer value of a key by the given number. @@ -166,7 +165,7 @@ public interface RedisStringReactiveCommands { * @param amount the decrement type: long * @return Long integer-reply the value of {@code key} after the decrement */ - Single decrby(K key, long amount); + Mono decrby(K key, long amount); /** * Get the value of a key. @@ -174,7 +173,7 @@ public interface RedisStringReactiveCommands { * @param key the key * @return V bulk-string-reply the value of {@code key}, or {@literal null} when {@code key} does not exist. */ - Single get(K key); + Mono get(K key); /** * Returns the bit value at offset in the string value stored at key. @@ -183,7 +182,7 @@ public interface RedisStringReactiveCommands { * @param offset the offset type: long * @return Long integer-reply the bit value stored at offset. */ - Single getbit(K key, long offset); + Mono getbit(K key, long offset); /** * Get a substring of the string stored at a key. @@ -193,7 +192,7 @@ public interface RedisStringReactiveCommands { * @param end the end type: long * @return V bulk-string-reply */ - Single getrange(K key, long start, long end); + Mono getrange(K key, long start, long end); /** * Set the string value of a key and return its old value. @@ -202,7 +201,7 @@ public interface RedisStringReactiveCommands { * @param value the value * @return V bulk-string-reply the old value stored at {@code key}, or {@literal null} when {@code key} did not exist. */ - Single getset(K key, V value); + Mono getset(K key, V value); /** * Increment the integer value of a key by one. @@ -210,7 +209,7 @@ public interface RedisStringReactiveCommands { * @param key the key * @return Long integer-reply the value of {@code key} after the increment */ - Single incr(K key); + Mono incr(K key); /** * Increment the integer value of a key by the given amount. @@ -219,7 +218,7 @@ public interface RedisStringReactiveCommands { * @param amount the increment type: long * @return Long integer-reply the value of {@code key} after the increment */ - Single incrby(K key, long amount); + Mono incrby(K key, long amount); /** * Increment the float value of a key by the given amount. @@ -228,7 +227,7 @@ public interface RedisStringReactiveCommands { * @param amount the increment type: double * @return Double bulk-string-reply the value of {@code key} after the increment. */ - Single incrbyfloat(K key, double amount); + Mono incrbyfloat(K key, double amount); /** * Get the values of all the given keys. @@ -236,7 +235,7 @@ public interface RedisStringReactiveCommands { * @param keys the key * @return V array-reply list of values at the specified keys. */ - Observable> mget(K... keys); + Flux> mget(K... keys); /** * Stream over the values of all the given keys. @@ -246,7 +245,7 @@ public interface RedisStringReactiveCommands { * * @return Long array-reply list of values at the specified keys. */ - Single mget(KeyValueStreamingChannel channel, K... keys); + Mono mget(KeyValueStreamingChannel channel, K... keys); /** * Set multiple keys to multiple values. @@ -254,7 +253,7 @@ public interface RedisStringReactiveCommands { * @param map the null * @return String simple-string-reply always {@code OK} since {@code MSET} can't fail. */ - Single mset(Map map); + Mono mset(Map map); /** * Set multiple keys to multiple values, only if none of the keys exist. @@ -264,7 +263,7 @@ public interface RedisStringReactiveCommands { * * {@code 1} if the all the keys were set. {@code 0} if no key was set (at least one key already existed). */ - Single msetnx(Map map); + Mono msetnx(Map map); /** * Set the string value of a key. @@ -274,7 +273,7 @@ public interface RedisStringReactiveCommands { * * @return String simple-string-reply {@code OK} if {@code SET} was executed correctly. */ - Single set(K key, V value); + Mono set(K key, V value); /** * Set the string value of a key. @@ -285,7 +284,7 @@ public interface RedisStringReactiveCommands { * * @return String simple-string-reply {@code OK} if {@code SET} was executed correctly. */ - Single set(K key, V value, SetArgs setArgs); + Mono set(K key, V value, SetArgs setArgs); /** * Sets or clears the bit at offset in the string value stored at key. @@ -295,7 +294,7 @@ public interface RedisStringReactiveCommands { * @param value the value type: string * @return Long integer-reply the original bit value stored at offset. */ - Single setbit(K key, long offset, int value); + Mono setbit(K key, long offset, int value); /** * Set the value and expiration of a key. @@ -305,7 +304,7 @@ public interface RedisStringReactiveCommands { * @param value the value * @return String simple-string-reply */ - Single setex(K key, long seconds, V value); + Mono setex(K key, long seconds, V value); /** * Set the value and expiration in milliseconds of a key. @@ -315,7 +314,7 @@ public interface RedisStringReactiveCommands { * @param value the value * @return String simple-string-reply */ - Single psetex(K key, long milliseconds, V value); + Mono psetex(K key, long milliseconds, V value); /** * Set the value of a key, only if the key does not exist. @@ -326,7 +325,7 @@ public interface RedisStringReactiveCommands { * * {@code 1} if the key was set {@code 0} if the key was not set */ - Single setnx(K key, V value); + Mono setnx(K key, V value); /** * Overwrite part of a string at key starting at the specified offset. @@ -336,7 +335,7 @@ public interface RedisStringReactiveCommands { * @param value the value * @return Long integer-reply the length of the string after it was modified by the command. */ - Single setrange(K key, long offset, V value); + Mono setrange(K key, long offset, V value); /** * Get the length of the value stored in a key. @@ -344,5 +343,5 @@ public interface RedisStringReactiveCommands { * @param key the key * @return Long integer-reply the length of the string at {@code key}, or {@code 0} when {@code key} does not exist. */ - Single strlen(K key); + Mono strlen(K key); } diff --git a/src/main/java/com/lambdaworks/redis/api/rx/RedisTransactionalReactiveCommands.java b/src/main/java/com/lambdaworks/redis/api/reactive/RedisTransactionalReactiveCommands.java similarity index 78% rename from src/main/java/com/lambdaworks/redis/api/rx/RedisTransactionalReactiveCommands.java rename to src/main/java/com/lambdaworks/redis/api/reactive/RedisTransactionalReactiveCommands.java index aa8b83033c..561816b98f 100644 --- a/src/main/java/com/lambdaworks/redis/api/rx/RedisTransactionalReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/reactive/RedisTransactionalReactiveCommands.java @@ -1,14 +1,12 @@ -package com.lambdaworks.redis.api.rx; +package com.lambdaworks.redis.api.reactive; import java.util.List; - import com.lambdaworks.redis.TransactionResult; -import rx.Observable; -import rx.Single; -import rx.Completable; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; /** - * Observable commands for Transactions. + * Reactive executed commands for Transactions. * * @param Key type. * @param Value type. @@ -23,7 +21,7 @@ public interface RedisTransactionalReactiveCommands { * * @return String simple-string-reply always {@code OK}. */ - Single discard(); + Mono discard(); /** * Execute all commands issued after MULTI. @@ -32,14 +30,14 @@ public interface RedisTransactionalReactiveCommands { * * When using {@code WATCH}, {@code EXEC} can return a */ - Single exec(); + Mono exec(); /** * Mark the start of a transaction block. * * @return String simple-string-reply always {@code OK}. */ - Single multi(); + Mono multi(); /** * Watch the given keys to determine execution of the MULTI/EXEC block. @@ -47,12 +45,12 @@ public interface RedisTransactionalReactiveCommands { * @param keys the key * @return String simple-string-reply always {@code OK}. */ - Single watch(K... keys); + Mono watch(K... keys); /** * Forget about all watched keys. * * @return String simple-string-reply always {@code OK}. */ - Single unwatch(); + Mono unwatch(); } diff --git a/src/main/java/com/lambdaworks/redis/api/rx/package-info.java b/src/main/java/com/lambdaworks/redis/api/reactive/package-info.java similarity index 56% rename from src/main/java/com/lambdaworks/redis/api/rx/package-info.java rename to src/main/java/com/lambdaworks/redis/api/reactive/package-info.java index 36be73a34f..70d9f046c8 100644 --- a/src/main/java/com/lambdaworks/redis/api/rx/package-info.java +++ b/src/main/java/com/lambdaworks/redis/api/reactive/package-info.java @@ -1,4 +1,4 @@ /** * Standalone Redis API for reactive commands. */ -package com.lambdaworks.redis.api.rx; \ No newline at end of file +package com.lambdaworks.redis.api.reactive; \ No newline at end of file diff --git a/src/main/java/com/lambdaworks/redis/api/rx/Success.java b/src/main/java/com/lambdaworks/redis/api/rx/Success.java deleted file mode 100644 index 37e1c6906f..0000000000 --- a/src/main/java/com/lambdaworks/redis/api/rx/Success.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.lambdaworks.redis.api.rx; - -/** - * An enum representing a successful operation. - * @author Mark Paluch - * @since 4.0 - */ -public enum Success { - Success; -} diff --git a/src/main/java/com/lambdaworks/redis/api/sync/RedisGeoCommands.java b/src/main/java/com/lambdaworks/redis/api/sync/RedisGeoCommands.java index b7c5ba2100..1f5dff8cf5 100644 --- a/src/main/java/com/lambdaworks/redis/api/sync/RedisGeoCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/sync/RedisGeoCommands.java @@ -1,9 +1,7 @@ package com.lambdaworks.redis.api.sync; -import com.lambdaworks.redis.GeoArgs; -import com.lambdaworks.redis.GeoCoordinates; -import com.lambdaworks.redis.GeoRadiusStoreArgs; -import com.lambdaworks.redis.GeoWithin; +import com.lambdaworks.redis.*; + import java.util.List; import java.util.Set; @@ -43,7 +41,7 @@ public interface RedisGeoCommands { * @param members the members * @return bulk reply Geohash strings in the order of {@code members}. Returns {@literal null} if a member is not found. */ - List geohash(K key, V... members); + List> geohash(K key, V... members); /** * Retrieve members selected by distance with the center of {@code longitude} and {@code latitude}. @@ -71,7 +69,7 @@ public interface RedisGeoCommands { List> georadius(K key, double longitude, double latitude, double distance, GeoArgs.Unit unit, GeoArgs geoArgs); /** - * Perform a {@link #georadius(Object, double, double, double, Unit, GeoArgs)} query and store the results in a sorted set. + * Perform a {@link #georadius(Object, double, double, double, GeoArgs.Unit, GeoArgs)} query and store the results in a sorted set. * * @param key the key of the geo set * @param longitude the longitude coordinate according to WGS84 @@ -132,7 +130,7 @@ public interface RedisGeoCommands { * @return a list of {@link GeoCoordinates}s representing the x,y position of each element specified in the arguments. For * missing elements {@literal null} is returned. */ - List geopos(K key, V... members); + List> geopos(K key, V... members); /** * diff --git a/src/main/java/com/lambdaworks/redis/api/sync/RedisStringCommands.java b/src/main/java/com/lambdaworks/redis/api/sync/RedisStringCommands.java index d965a8194d..6b689e6f2f 100644 --- a/src/main/java/com/lambdaworks/redis/api/sync/RedisStringCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/sync/RedisStringCommands.java @@ -2,8 +2,6 @@ import java.util.List; import java.util.Map; - -import com.lambdaworks.redis.KeyValue; import com.lambdaworks.redis.output.KeyValueStreamingChannel; import com.lambdaworks.redis.output.ValueStreamingChannel; import com.lambdaworks.redis.BitFieldArgs; diff --git a/src/main/java/com/lambdaworks/redis/api/sync/RedisTransactionalCommands.java b/src/main/java/com/lambdaworks/redis/api/sync/RedisTransactionalCommands.java index 0c2add2174..197c205807 100644 --- a/src/main/java/com/lambdaworks/redis/api/sync/RedisTransactionalCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/sync/RedisTransactionalCommands.java @@ -1,5 +1,6 @@ package com.lambdaworks.redis.api.sync; +import java.util.List; import com.lambdaworks.redis.TransactionResult; /** diff --git a/src/main/java/com/lambdaworks/redis/cluster/ClusterScanSupport.java b/src/main/java/com/lambdaworks/redis/cluster/ClusterScanSupport.java index 2151558aac..9838f51779 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/ClusterScanSupport.java +++ b/src/main/java/com/lambdaworks/redis/cluster/ClusterScanSupport.java @@ -10,9 +10,7 @@ import com.lambdaworks.redis.cluster.models.partitions.RedisClusterNode; import com.lambdaworks.redis.models.role.RedisNodeDescription; -import rx.Observable; -import rx.Single; -import rx.functions.Func1; +import reactor.core.publisher.Mono; /** * Methods to support a Cluster-wide SCAN operation over multiple hosts. @@ -54,18 +52,18 @@ public StreamScanCursor apply(StreamScanCursor result) { }; /** - * Map a {@link Single} of {@link KeyScanCursor} to a {@link Observable} of {@link ClusterKeyScanCursor}. + * Map a {@link Mono} of {@link KeyScanCursor} to a {@link Mono} of {@link ClusterKeyScanCursor}. */ - final static ScanCursorMapper>> reactiveKeyScanCursorMapper = (nodeIds, currentNodeId, + final static ScanCursorMapper>> reactiveKeyScanCursorMapper = (nodeIds, currentNodeId, cursor) -> cursor.map(keyScanCursor -> new ClusterKeyScanCursor<>(nodeIds, currentNodeId, keyScanCursor)); /** - * Map a {@link Single} of {@link StreamScanCursor} to a {@link Observable} of {@link ClusterStreamScanCursor}. + * Map a {@link Mono} of {@link StreamScanCursor} to a {@link Mono} of {@link ClusterStreamScanCursor}. */ - final static ScanCursorMapper> reactiveStreamScanCursorMapper = (nodeIds, currentNodeId, - cursor) -> cursor.map(new Func1() { + final static ScanCursorMapper> reactiveStreamScanCursorMapper = (nodeIds, currentNodeId, + cursor) -> cursor.map(new Function() { @Override - public StreamScanCursor call(StreamScanCursor streamScanCursor) { + public StreamScanCursor apply(StreamScanCursor streamScanCursor) { return new ClusterStreamScanCursor(nodeIds, currentNodeId, streamScanCursor); } }); @@ -190,11 +188,11 @@ static ScanCursorMapper> asyncClusterStreamScanCur return futureStreamScanCursorMapper; } - static ScanCursorMapper>> reactiveClusterKeyScanCursorMapper() { + static ScanCursorMapper>> reactiveClusterKeyScanCursorMapper() { return (ScanCursorMapper) reactiveKeyScanCursorMapper; } - static ScanCursorMapper> reactiveClusterStreamScanCursorMapper() { + static ScanCursorMapper> reactiveClusterStreamScanCursorMapper() { return reactiveStreamScanCursorMapper; } diff --git a/src/main/java/com/lambdaworks/redis/cluster/RedisAdvancedClusterReactiveCommandsImpl.java b/src/main/java/com/lambdaworks/redis/cluster/RedisAdvancedClusterReactiveCommandsImpl.java index 1127e06056..f2eb5c4cc0 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/RedisAdvancedClusterReactiveCommandsImpl.java +++ b/src/main/java/com/lambdaworks/redis/cluster/RedisAdvancedClusterReactiveCommandsImpl.java @@ -9,25 +9,23 @@ import java.util.function.Function; import java.util.stream.Collectors; -import com.lambdaworks.redis.internal.LettuceLists; -import rx.Observable; +import org.reactivestreams.Publisher; import com.lambdaworks.redis.*; import com.lambdaworks.redis.api.StatefulRedisConnection; -import com.lambdaworks.redis.api.rx.RedisKeyReactiveCommands; +import com.lambdaworks.redis.api.reactive.RedisKeyReactiveCommands; import com.lambdaworks.redis.cluster.api.StatefulRedisClusterConnection; -import com.lambdaworks.redis.cluster.api.rx.RedisAdvancedClusterReactiveCommands; -import com.lambdaworks.redis.cluster.api.rx.RedisClusterReactiveCommands; +import com.lambdaworks.redis.cluster.api.reactive.RedisAdvancedClusterReactiveCommands; +import com.lambdaworks.redis.cluster.api.reactive.RedisClusterReactiveCommands; import com.lambdaworks.redis.cluster.models.partitions.Partitions; import com.lambdaworks.redis.cluster.models.partitions.RedisClusterNode; import com.lambdaworks.redis.codec.RedisCodec; +import com.lambdaworks.redis.internal.LettuceLists; import com.lambdaworks.redis.output.KeyStreamingChannel; import com.lambdaworks.redis.output.KeyValueStreamingChannel; -import com.lambdaworks.redis.output.ValueStreamingChannel; -import rx.Completable; -import rx.Observable; -import rx.Single; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; /** * An advanced reactive and thread-safe API to a Redis Cluster connection. @@ -52,12 +50,12 @@ public RedisAdvancedClusterReactiveCommandsImpl(StatefulRedisClusterConnectionIm } @Override - public Single del(K... keys) { + public Mono del(K... keys) { return del(Arrays.asList(keys)); } @Override - public Single del(Iterable keys) { + public Mono del(Iterable keys) { Map> partitioned = SlotHash.partition(codec, keys); @@ -65,22 +63,22 @@ public Single del(Iterable keys) { return super.del(keys); } - List> observables = new ArrayList<>(); + List> publishers = new ArrayList<>(); for (Map.Entry> entry : partitioned.entrySet()) { - observables.add(super.del(entry.getValue()).toObservable()); + publishers.add(super.del(entry.getValue())); } - return Observable.merge(observables).reduce((accu, next) -> accu + next).last().toSingle(); + return Flux.merge(publishers).reduce((accu, next) -> accu + next); } @Override - public Single unlink(K... keys) { + public Mono unlink(K... keys) { return unlink(Arrays.asList(keys)); } @Override - public Single unlink(Iterable keys) { + public Mono unlink(Iterable keys) { Map> partitioned = SlotHash.partition(codec, keys); @@ -88,21 +86,21 @@ public Single unlink(Iterable keys) { return super.unlink(keys); } - List> observables = new ArrayList<>(); + List> publishers = new ArrayList<>(); for (Map.Entry> entry : partitioned.entrySet()) { - observables.add(super.unlink(entry.getValue()).toObservable()); + publishers.add(super.unlink(entry.getValue())); } - return Observable.merge(observables).reduce((accu, next) -> accu + next).last().toSingle(); + return Flux.merge(publishers).reduce((accu, next) -> accu + next); } @Override - public Single exists(K... keys) { + public Mono exists(K... keys) { return exists(Arrays.asList(keys)); } - public Single exists(Iterable keys) { + public Mono exists(Iterable keys) { List keyList = LettuceLists.newList(keys); @@ -112,21 +110,21 @@ public Single exists(Iterable keys) { return super.exists(keyList); } - List> observables = new ArrayList<>(); + List> publishers = new ArrayList<>(); for (Map.Entry> entry : partitioned.entrySet()) { - observables.add(super.exists(entry.getValue()).toObservable()); + publishers.add(super.exists(entry.getValue())); } - return Observable.merge(observables).reduce((accu, next) -> accu + next).toSingle(); + return Flux.merge(publishers).reduce((accu, next) -> accu + next); } @Override - public Observable> mget(K... keys) { + public Flux> mget(K... keys) { return mget(Arrays.asList(keys)); } - public Observable> mget(Iterable keys) { + public Flux> mget(Iterable keys) { List keyList = LettuceLists.newList(keys); Map> partitioned = SlotHash.partition(codec, keyList); @@ -135,14 +133,15 @@ public Observable> mget(Iterable keys) { return super.mget(keyList); } - List>> observables = new ArrayList<>(); + List>> publishers = new ArrayList<>(); for (Map.Entry> entry : partitioned.entrySet()) { - observables.add(super.mget(entry.getValue())); + publishers.add(super.mget(entry.getValue())); } - Observable> observable = Observable.concat(Observable.from(observables)); - Observable>> map = observable.toList().map(vs -> { + Flux> fluxes = Flux.concat(publishers); + + Mono>> map = fluxes.collectList().map(vs -> { KeyValue[] values = new KeyValue[vs.size()]; int offset = 0; @@ -165,16 +164,16 @@ public Observable> mget(Iterable keys) { return objects; }); - return map.compose(new FlattenTransform<>()); + return map.flatMap(Flux::fromIterable); } @Override - public Single mget(KeyValueStreamingChannel channel, K... keys) { + public Mono mget(KeyValueStreamingChannel channel, K... keys) { return mget(channel, Arrays.asList(keys)); } @Override - public Single mget(KeyValueStreamingChannel channel, Iterable keys) { + public Mono mget(KeyValueStreamingChannel channel, Iterable keys) { List keyList = LettuceLists.newList(keys); @@ -184,29 +183,30 @@ public Single mget(KeyValueStreamingChannel channel, Iterable key return super.mget(channel, keyList); } - List> observables = new ArrayList<>(); + List> publishers = new ArrayList<>(); for (Map.Entry> entry : partitioned.entrySet()) { - observables.add(super.mget(channel, entry.getValue()).toObservable()); + publishers.add(super.mget(channel, entry.getValue())); } - return Observable.merge(observables).reduce((accu, next) -> accu + next).last().toSingle(); + return Flux.merge(publishers).reduce((accu, next) -> accu + next); } @Override - public Single msetnx(Map map) { + public Mono msetnx(Map map) { - return pipeliningWithMap(map, kvMap -> super.msetnx(kvMap).toObservable(), - booleanObservable -> booleanObservable.reduce((accu, next) -> accu || next)).last().toSingle(); + return pipeliningWithMap(map, kvMap -> RedisAdvancedClusterReactiveCommandsImpl.super.msetnx(kvMap).flux(), + booleanFlux -> booleanFlux).reduce((accu, next) -> accu || next); } @Override - public Single mset(Map map) { - return pipeliningWithMap(map, kvMap -> super.mset(kvMap).toObservable(), Observable::last).last().toSingle(); + public Mono mset(Map map) { + return pipeliningWithMap(map, kvMap -> RedisAdvancedClusterReactiveCommandsImpl.super.mset(kvMap).flux(), + booleanFlux -> booleanFlux).last(); } @Override - public Observable clusterGetKeysInSlot(int slot, int count) { + public Flux clusterGetKeysInSlot(int slot, int count) { RedisClusterReactiveCommands connectionBySlot = findConnectionBySlot(slot); if (connectionBySlot != null) { @@ -217,7 +217,7 @@ public Observable clusterGetKeysInSlot(int slot, int count) { } @Override - public Single clusterCountKeysInSlot(int slot) { + public Mono clusterCountKeysInSlot(int slot) { RedisClusterReactiveCommands connectionBySlot = findConnectionBySlot(slot); if (connectionBySlot != null) { @@ -228,59 +228,58 @@ public Single clusterCountKeysInSlot(int slot) { } @Override - public Single clientSetname(K name) { - List> observables = new ArrayList<>(); + public Mono clientSetname(K name) { + List> publishers = new ArrayList<>(); for (RedisClusterNode redisClusterNode : getStatefulConnection().getPartitions()) { StatefulRedisConnection byNodeId = getStatefulConnection().getConnection(redisClusterNode.getNodeId()); if (byNodeId.isOpen()) { - observables.add(byNodeId.reactive().clientSetname(name).toObservable()); + publishers.add(byNodeId.reactive().clientSetname(name)); } StatefulRedisConnection byHost = getStatefulConnection().getConnection(redisClusterNode.getUri().getHost(), redisClusterNode.getUri().getPort()); if (byHost.isOpen()) { - observables.add(byHost.reactive().clientSetname(name).toObservable()); + publishers.add(byHost.reactive().clientSetname(name)); } } - return Observable.merge(observables).last().last().toSingle(); + return Flux.merge(publishers).last(); } @Override - public Single dbsize() { - Map> observables = executeOnMasters((commands) -> commands.dbsize().toObservable()); - return Observable.merge(observables.values()).reduce((accu, next) -> accu + next).toSingle(); + public Mono dbsize() { + Map> publishers = executeOnMasters((commands) -> commands.dbsize().flux()); + return Flux.merge(publishers.values()).reduce((accu, next) -> accu + next); } @Override - public Single flushall() { - Map> observables = executeOnMasters( - (kvRedisClusterReactiveCommancommandss) -> kvRedisClusterReactiveCommancommandss.flushall().toObservable()); - return Observable.merge(observables.values()).last().last().toSingle(); + public Mono flushall() { + Map> publishers = executeOnMasters( + (kvRedisClusterReactiveCommancommandss) -> kvRedisClusterReactiveCommancommandss.flushall().flux()); + return Flux.merge(publishers.values()).last(); } @Override - public Single flushdb() { - Map> observables = executeOnMasters((commands) -> commands.flushdb().toObservable()); - return Observable.merge(observables.values()).last().last().toSingle(); + public Mono flushdb() { + Map> publishers = executeOnMasters((commands) -> commands.flushdb().flux()); + return Flux.merge(publishers.values()).last(); } @Override - public Observable keys(K pattern) { - Map> observables = executeOnMasters(commands -> commands.keys(pattern)); - return Observable.merge(observables.values()); + public Flux keys(K pattern) { + Map> publishers = executeOnMasters(commands -> commands.keys(pattern)); + return Flux.merge(publishers.values()); } @Override - public Single keys(KeyStreamingChannel channel, K pattern) { - Map> observables = executeOnMasters( - commands -> commands.keys(channel, pattern).toObservable()); - return Observable.merge(observables.values()).reduce((accu, next) -> accu + next).last().toSingle(); + public Mono keys(KeyStreamingChannel channel, K pattern) { + Map> publishers = executeOnMasters(commands -> commands.keys(channel, pattern).flux()); + return Flux.merge(publishers.values()).reduce((accu, next) -> accu + next); } @Override - public Single randomkey() { + public Mono randomkey() { Partitions partitions = getStatefulConnection().getPartitions(); int index = random.nextInt(partitions.size()); @@ -290,32 +289,32 @@ public Single randomkey() { } @Override - public Single scriptFlush() { - Map> observables = executeOnNodes((commands) -> commands.scriptFlush().toObservable(), + public Mono scriptFlush() { + Map> publishers = executeOnNodes((commands) -> commands.scriptFlush().flux(), redisClusterNode -> true); - return Observable.merge(observables.values()).last().last().toSingle(); + return Flux.merge(publishers.values()).last(); } @Override - public Single scriptKill() { - Map> observables = executeOnNodes((commands) -> commands.scriptFlush().toObservable(), + public Mono scriptKill() { + Map> publishers = executeOnNodes((commands) -> commands.scriptFlush().flux(), redisClusterNode -> true); - return Observable.merge(observables.values()).onErrorReturn(throwable -> "OK").last().toSingle(); + return Flux.merge(publishers.values()).onErrorReturn("OK").last(); } @Override - public Completable shutdown(boolean save) { - Map> observables = executeOnNodes(commands -> commands.shutdown(save).toObservable(), + public Mono shutdown(boolean save) { + Map> publishers = executeOnNodes(commands -> commands.shutdown(save).flux(), redisClusterNode -> true); - return Completable.fromObservable(Observable.merge(observables.values()).onErrorReturn(throwable -> null).last()); + return Flux.merge(publishers.values()).then(); } @Override - public Single touch(K... keys) { + public Mono touch(K... keys) { return touch(Arrays.asList(keys)); } - public Single touch(Iterable keys) { + public Mono touch(Iterable keys) { List keyList = LettuceLists.newList(keys); Map> partitioned = SlotHash.partition(codec, keyList); @@ -324,13 +323,13 @@ public Single touch(Iterable keys) { return super.touch(keyList); } - List> observables = new ArrayList<>(); + List> publishers = new ArrayList<>(); for (Map.Entry> entry : partitioned.entrySet()) { - observables.add(super.touch(entry.getValue()).toObservable()); + publishers.add(super.touch(entry.getValue()).flux()); } - return Observable.merge(observables).reduce((accu, next) -> accu + next).toSingle(); + return Flux.merge(publishers).reduce((accu, next) -> accu + next); } /** @@ -340,8 +339,7 @@ public Single touch(Iterable keys) { * @param result type * @return map of a key (counter) and commands. */ - protected Map> executeOnMasters( - Function, Observable> function) { + protected Map> executeOnMasters(Function, Flux> function) { return executeOnNodes(function, redisClusterNode -> redisClusterNode.is(MASTER)); } @@ -353,9 +351,9 @@ protected Map> executeOnMasters( * @param result type * @return map of a key (counter) and commands. */ - protected Map> executeOnNodes( - Function, Observable> function, Function filter) { - Map> executions = new HashMap<>(); + protected Map> executeOnNodes(Function, Flux> function, + Function filter) { + Map> executions = new HashMap<>(); for (RedisClusterNode redisClusterNode : getStatefulConnection().getPartitions()) { @@ -397,54 +395,54 @@ public RedisClusterReactiveCommands getConnection(String host, int port) { } @Override - public Single> scan() { + public Mono> scan() { return clusterScan(ScanCursor.INITIAL, (connection, cursor) -> connection.scan(), reactiveClusterKeyScanCursorMapper()); } @Override - public Single> scan(ScanArgs scanArgs) { + public Mono> scan(ScanArgs scanArgs) { return clusterScan(ScanCursor.INITIAL, (connection, cursor) -> connection.scan(scanArgs), reactiveClusterKeyScanCursorMapper()); } @Override - public Single> scan(ScanCursor scanCursor, ScanArgs scanArgs) { + public Mono> scan(ScanCursor scanCursor, ScanArgs scanArgs) { return clusterScan(scanCursor, (connection, cursor) -> connection.scan(cursor, scanArgs), reactiveClusterKeyScanCursorMapper()); } @Override - public Single> scan(ScanCursor scanCursor) { + public Mono> scan(ScanCursor scanCursor) { return clusterScan(scanCursor, (connection, cursor) -> connection.scan(cursor), reactiveClusterKeyScanCursorMapper()); } @Override - public Single scan(KeyStreamingChannel channel) { + public Mono scan(KeyStreamingChannel channel) { return clusterScan(ScanCursor.INITIAL, (connection, cursor) -> connection.scan(channel), reactiveClusterStreamScanCursorMapper()); } @Override - public Single scan(KeyStreamingChannel channel, ScanArgs scanArgs) { + public Mono scan(KeyStreamingChannel channel, ScanArgs scanArgs) { return clusterScan(ScanCursor.INITIAL, (connection, cursor) -> connection.scan(channel, scanArgs), reactiveClusterStreamScanCursorMapper()); } @Override - public Single scan(KeyStreamingChannel channel, ScanCursor scanCursor, ScanArgs scanArgs) { + public Mono scan(KeyStreamingChannel channel, ScanCursor scanCursor, ScanArgs scanArgs) { return clusterScan(scanCursor, (connection, cursor) -> connection.scan(channel, cursor, scanArgs), reactiveClusterStreamScanCursorMapper()); } @Override - public Single scan(KeyStreamingChannel channel, ScanCursor scanCursor) { + public Mono scan(KeyStreamingChannel channel, ScanCursor scanCursor) { return clusterScan(scanCursor, (connection, cursor) -> connection.scan(channel, cursor), reactiveClusterStreamScanCursorMapper()); } - private Single clusterScan(ScanCursor cursor, - BiFunction, ScanCursor, Single> scanFunction, - ClusterScanSupport.ScanCursorMapper> resultMapper) { + private Mono clusterScan(ScanCursor cursor, + BiFunction, ScanCursor, Mono> scanFunction, + ClusterScanSupport.ScanCursorMapper> resultMapper) { return clusterScan(getStatefulConnection(), cursor, scanFunction, (ClusterScanSupport.ScanCursorMapper) resultMapper); } @@ -453,20 +451,20 @@ private Single clusterScan(ScanCursor cursor, * Perform a SCAN in the cluster. * */ - static Single clusterScan(StatefulRedisClusterConnection connection, - ScanCursor cursor, BiFunction, ScanCursor, Single> scanFunction, - ClusterScanSupport.ScanCursorMapper> mapper) { + static Mono clusterScan(StatefulRedisClusterConnection connection, ScanCursor cursor, + BiFunction, ScanCursor, Mono> scanFunction, + ClusterScanSupport.ScanCursorMapper> mapper) { List nodeIds = ClusterScanSupport.getNodeIds(connection, cursor); String currentNodeId = ClusterScanSupport.getCurrentNodeId(cursor, nodeIds); ScanCursor continuationCursor = ClusterScanSupport.getContinuationCursor(cursor); - Single scanCursor = scanFunction.apply(connection.getConnection(currentNodeId).reactive(), continuationCursor); + Mono scanCursor = scanFunction.apply(connection.getConnection(currentNodeId).reactive(), continuationCursor); return mapper.map(nodeIds, currentNodeId, scanCursor); } - private Observable pipeliningWithMap(Map map, Function, Observable> function, - Function, Observable> resultFunction) { + private Flux pipeliningWithMap(Map map, Function, Flux> function, + Function, Flux> resultFunction) { Map> partitioned = SlotHash.partition(codec, map.keySet()); @@ -474,21 +472,13 @@ private Observable pipeliningWithMap(Map map, Function, O return function.apply(map); } - List> observables = partitioned.values().stream().map(ks -> { + List> publishers = partitioned.values().stream().map(ks -> { Map op = new HashMap<>(); ks.forEach(k -> op.put(k, map.get(k))); return function.apply(op); }).collect(Collectors.toList()); - return resultFunction.apply(Observable.merge(observables)); - } - - static class FlattenTransform implements Observable.Transformer, T> { - - @Override - public Observable call(Observable> source) { - return source.flatMap(values -> Observable.from(values)); - } + return resultFunction.apply(Flux.merge(publishers)); } } diff --git a/src/main/java/com/lambdaworks/redis/cluster/StatefulRedisClusterConnectionImpl.java b/src/main/java/com/lambdaworks/redis/cluster/StatefulRedisClusterConnectionImpl.java index 2503df6dbe..c352a4b069 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/StatefulRedisClusterConnectionImpl.java +++ b/src/main/java/com/lambdaworks/redis/cluster/StatefulRedisClusterConnectionImpl.java @@ -19,7 +19,7 @@ import com.lambdaworks.redis.cluster.api.NodeSelectionSupport; import com.lambdaworks.redis.cluster.api.StatefulRedisClusterConnection; import com.lambdaworks.redis.cluster.api.async.RedisAdvancedClusterAsyncCommands; -import com.lambdaworks.redis.cluster.api.rx.RedisAdvancedClusterReactiveCommands; +import com.lambdaworks.redis.cluster.api.reactive.RedisAdvancedClusterReactiveCommands; import com.lambdaworks.redis.cluster.api.sync.NodeSelection; import com.lambdaworks.redis.cluster.api.sync.NodeSelectionCommands; import com.lambdaworks.redis.cluster.api.sync.RedisAdvancedClusterCommands; diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/StatefulRedisClusterConnection.java b/src/main/java/com/lambdaworks/redis/cluster/api/StatefulRedisClusterConnection.java index b6a4502f18..b1dea48a96 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/StatefulRedisClusterConnection.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/StatefulRedisClusterConnection.java @@ -6,7 +6,7 @@ import com.lambdaworks.redis.api.StatefulRedisConnection; import com.lambdaworks.redis.cluster.ClusterClientOptions; import com.lambdaworks.redis.cluster.api.async.RedisAdvancedClusterAsyncCommands; -import com.lambdaworks.redis.cluster.api.rx.RedisAdvancedClusterReactiveCommands; +import com.lambdaworks.redis.cluster.api.reactive.RedisAdvancedClusterReactiveCommands; import com.lambdaworks.redis.cluster.api.sync.RedisAdvancedClusterCommands; import com.lambdaworks.redis.cluster.models.partitions.Partitions; diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionGeoAsyncCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionGeoAsyncCommands.java index e303c012df..3f923c0bcb 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionGeoAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionGeoAsyncCommands.java @@ -1,12 +1,9 @@ package com.lambdaworks.redis.cluster.api.async; -import com.lambdaworks.redis.GeoArgs; -import com.lambdaworks.redis.GeoCoordinates; -import com.lambdaworks.redis.GeoRadiusStoreArgs; -import com.lambdaworks.redis.GeoWithin; +import com.lambdaworks.redis.*; + import java.util.List; import java.util.Set; -import com.lambdaworks.redis.RedisFuture; /** * Asynchronous executed commands on a node selection for the Geo-API. @@ -44,7 +41,7 @@ public interface NodeSelectionGeoAsyncCommands { * @param members the members * @return bulk reply Geohash strings in the order of {@code members}. Returns {@literal null} if a member is not found. */ - AsyncExecutions> geohash(K key, V... members); + AsyncExecutions>> geohash(K key, V... members); /** * Retrieve members selected by distance with the center of {@code longitude} and {@code latitude}. @@ -133,7 +130,7 @@ public interface NodeSelectionGeoAsyncCommands { * @return a list of {@link GeoCoordinates}s representing the x,y position of each element specified in the arguments. For * missing elements {@literal null} is returned. */ - AsyncExecutions> geopos(K key, V... members); + AsyncExecutions>> geopos(K key, V... members); /** * diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionSetAsyncCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionSetAsyncCommands.java index 6e9d1c6337..e12c0d5207 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionSetAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionSetAsyncCommands.java @@ -7,7 +7,6 @@ import com.lambdaworks.redis.StreamScanCursor; import com.lambdaworks.redis.ValueScanCursor; import com.lambdaworks.redis.output.ValueStreamingChannel; -import com.lambdaworks.redis.RedisFuture; /** * Asynchronous executed commands on a node selection for Sets. diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionStringAsyncCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionStringAsyncCommands.java index 25d70d1654..ef554b017f 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionStringAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionStringAsyncCommands.java @@ -2,10 +2,13 @@ import java.util.List; import java.util.Map; - -import com.lambdaworks.redis.*; import com.lambdaworks.redis.output.KeyValueStreamingChannel; import com.lambdaworks.redis.output.ValueStreamingChannel; +import com.lambdaworks.redis.BitFieldArgs; +import com.lambdaworks.redis.KeyValue; +import com.lambdaworks.redis.SetArgs; +import com.lambdaworks.redis.Value; +import com.lambdaworks.redis.RedisFuture; /** * Asynchronous executed commands on a node selection for Strings. diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/rx/RedisAdvancedClusterReactiveCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/reactive/RedisAdvancedClusterReactiveCommands.java similarity index 84% rename from src/main/java/com/lambdaworks/redis/cluster/api/rx/RedisAdvancedClusterReactiveCommands.java rename to src/main/java/com/lambdaworks/redis/cluster/api/reactive/RedisAdvancedClusterReactiveCommands.java index 8afbd0e3ca..1987f1d6a0 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/rx/RedisAdvancedClusterReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/reactive/RedisAdvancedClusterReactiveCommands.java @@ -1,22 +1,24 @@ -package com.lambdaworks.redis.cluster.api.rx; +package com.lambdaworks.redis.cluster.api.reactive; import java.util.Map; import com.lambdaworks.redis.*; -import com.lambdaworks.redis.api.rx.*; +import com.lambdaworks.redis.api.reactive.RedisKeyReactiveCommands; +import com.lambdaworks.redis.api.reactive.RedisScriptingReactiveCommands; +import com.lambdaworks.redis.api.reactive.RedisServerReactiveCommands; +import com.lambdaworks.redis.api.reactive.RedisStringReactiveCommands; import com.lambdaworks.redis.cluster.ClusterClientOptions; import com.lambdaworks.redis.cluster.api.StatefulRedisClusterConnection; import com.lambdaworks.redis.output.KeyStreamingChannel; -import rx.Completable; -import rx.Observable; -import rx.Single; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; /** * Advanced reactive and thread-safe Redis Cluster API. * * @author Mark Paluch - * @since 4.0 + * @since 5.0 */ public interface RedisAdvancedClusterReactiveCommands extends RedisClusterReactiveCommands { @@ -54,7 +56,7 @@ public interface RedisAdvancedClusterReactiveCommands extends RedisCluster * @return Long integer-reply The number of keys that were removed. * @see RedisKeyReactiveCommands#del(Object[]) */ - Single del(K... keys); + Mono del(K... keys); /** * Unlink one or more keys with pipelining. Cross-slot keys will result in multiple calls to the particular cluster nodes. @@ -63,15 +65,16 @@ public interface RedisAdvancedClusterReactiveCommands extends RedisCluster * @return Long integer-reply The number of keys that were removed. * @see RedisKeyReactiveCommands#unlink(Object[]) */ - Single unlink(K... keys); + Mono unlink(K... keys); /** - * Determine how many keys exist with pipelining. Cross-slot keys will result in multiple calls to the particular cluster nodes. + * Determine how many keys exist with pipelining. Cross-slot keys will result in multiple calls to the particular cluster + * nodes. * * @param keys the keys * @return Long integer-reply specifically: Number of existing keys */ - Single exists(K... keys); + Mono exists(K... keys); /** * Get the values of all the given keys with pipelining. Cross-slot keys will result in multiple calls to the particular @@ -81,7 +84,7 @@ public interface RedisAdvancedClusterReactiveCommands extends RedisCluster * @return V array-reply list of values at the specified keys. * @see RedisStringReactiveCommands#mget(Object[]) */ - Observable> mget(K... keys); + Flux> mget(K... keys); /** * Set multiple keys to multiple values with pipelining. Cross-slot keys will result in multiple calls to the particular @@ -91,7 +94,7 @@ public interface RedisAdvancedClusterReactiveCommands extends RedisCluster * @return String simple-string-reply always {@code OK} since {@code MSET} can't fail. * @see RedisStringReactiveCommands#mset(Map) */ - Single mset(Map map); + Mono mset(Map map); /** * Set multiple keys to multiple values, only if none of the keys exist with pipelining. Cross-slot keys will result in @@ -104,7 +107,7 @@ public interface RedisAdvancedClusterReactiveCommands extends RedisCluster * * @see RedisStringReactiveCommands#msetnx(Map) */ - Single msetnx(Map map); + Mono msetnx(Map map); /** * Set the current connection name on all cluster nodes with pipelining. @@ -113,7 +116,7 @@ public interface RedisAdvancedClusterReactiveCommands extends RedisCluster * @return simple-string-reply {@code OK} if the connection name was successfully set. * @see RedisServerReactiveCommands#clientSetname(Object) */ - Single clientSetname(K name); + Mono clientSetname(K name); /** * Remove all keys from all databases on all cluster masters with pipelining. @@ -121,7 +124,7 @@ public interface RedisAdvancedClusterReactiveCommands extends RedisCluster * @return String simple-string-reply * @see RedisServerReactiveCommands#flushall() */ - Single flushall(); + Mono flushall(); /** * Remove all keys from the current database on all cluster masters with pipelining. @@ -129,7 +132,7 @@ public interface RedisAdvancedClusterReactiveCommands extends RedisCluster * @return String simple-string-reply * @see RedisServerReactiveCommands#flushdb() */ - Single flushdb(); + Mono flushdb(); /** * Return the number of keys in the selected database on all cluster masters. @@ -137,7 +140,7 @@ public interface RedisAdvancedClusterReactiveCommands extends RedisCluster * @return Long integer-reply * @see RedisServerReactiveCommands#dbsize() */ - Single dbsize(); + Mono dbsize(); /** * Find all keys matching the given pattern on all cluster masters. @@ -146,7 +149,7 @@ public interface RedisAdvancedClusterReactiveCommands extends RedisCluster * @return List<K> array-reply list of keys matching {@code pattern}. * @see RedisKeyReactiveCommands#keys(Object) */ - Observable keys(K pattern); + Flux keys(K pattern); /** * Find all keys matching the given pattern on all cluster masters. @@ -156,7 +159,7 @@ public interface RedisAdvancedClusterReactiveCommands extends RedisCluster * @return Long array-reply list of keys matching {@code pattern}. * @see RedisKeyReactiveCommands#keys(KeyStreamingChannel, Object) */ - Single keys(KeyStreamingChannel channel, K pattern); + Mono keys(KeyStreamingChannel channel, K pattern); /** * Return a random key from the keyspace on a random master. @@ -164,7 +167,7 @@ public interface RedisAdvancedClusterReactiveCommands extends RedisCluster * @return V bulk-string-reply the random key, or {@literal null} when the database is empty. * @see RedisKeyReactiveCommands#randomkey() */ - Single randomkey(); + Mono randomkey(); /** * Remove all the scripts from the script cache on all cluster nodes. @@ -172,7 +175,7 @@ public interface RedisAdvancedClusterReactiveCommands extends RedisCluster * @return String simple-string-reply * @see RedisScriptingReactiveCommands#scriptFlush() */ - Single scriptFlush(); + Mono scriptFlush(); /** * Kill the script currently in execution on all cluster nodes. This call does not fail even if no scripts are running. @@ -180,7 +183,7 @@ public interface RedisAdvancedClusterReactiveCommands extends RedisCluster * @return String simple-string-reply, always {@literal OK}. * @see RedisScriptingReactiveCommands#scriptKill() */ - Single scriptKill(); + Mono scriptKill(); /** * Synchronously save the dataset to disk and then shut down all nodes of the cluster. @@ -188,7 +191,7 @@ public interface RedisAdvancedClusterReactiveCommands extends RedisCluster * @param save {@literal true} force save operation * @see RedisServerReactiveCommands#shutdown(boolean) */ - Completable shutdown(boolean save); + Mono shutdown(boolean save); /** * Incrementally iterate the keys space over the whole Cluster. @@ -196,7 +199,7 @@ public interface RedisAdvancedClusterReactiveCommands extends RedisCluster * @return KeyScanCursor<K> scan cursor. * @see RedisKeyReactiveCommands#scan(ScanArgs) */ - Single> scan(); + Mono> scan(); /** * Incrementally iterate the keys space over the whole Cluster. @@ -205,7 +208,7 @@ public interface RedisAdvancedClusterReactiveCommands extends RedisCluster * @return KeyScanCursor<K> scan cursor. * @see RedisKeyReactiveCommands#scan(ScanArgs) */ - Single> scan(ScanArgs scanArgs); + Mono> scan(ScanArgs scanArgs); /** * Incrementally iterate the keys space over the whole Cluster. @@ -216,7 +219,7 @@ public interface RedisAdvancedClusterReactiveCommands extends RedisCluster * @return KeyScanCursor<K> scan cursor. * @see RedisKeyReactiveCommands#scan(ScanCursor, ScanArgs) */ - Single> scan(ScanCursor scanCursor, ScanArgs scanArgs); + Mono> scan(ScanCursor scanCursor, ScanArgs scanArgs); /** * Incrementally iterate the keys space over the whole Cluster. @@ -226,7 +229,7 @@ public interface RedisAdvancedClusterReactiveCommands extends RedisCluster * @return KeyScanCursor<K> scan cursor. * @see RedisKeyReactiveCommands#scan(ScanCursor) */ - Single> scan(ScanCursor scanCursor); + Mono> scan(ScanCursor scanCursor); /** * Incrementally iterate the keys space over the whole Cluster. @@ -235,7 +238,7 @@ public interface RedisAdvancedClusterReactiveCommands extends RedisCluster * @return StreamScanCursor scan cursor. * @see RedisKeyReactiveCommands#scan(KeyStreamingChannel) */ - Single scan(KeyStreamingChannel channel); + Mono scan(KeyStreamingChannel channel); /** * Incrementally iterate the keys space over the whole Cluster. @@ -245,7 +248,7 @@ public interface RedisAdvancedClusterReactiveCommands extends RedisCluster * @return StreamScanCursor scan cursor. * @see RedisKeyReactiveCommands#scan(KeyStreamingChannel, ScanArgs) */ - Single scan(KeyStreamingChannel channel, ScanArgs scanArgs); + Mono scan(KeyStreamingChannel channel, ScanArgs scanArgs); /** * Incrementally iterate the keys space over the whole Cluster. @@ -257,7 +260,7 @@ public interface RedisAdvancedClusterReactiveCommands extends RedisCluster * @return StreamScanCursor scan cursor. * @see RedisKeyReactiveCommands#scan(KeyStreamingChannel, ScanCursor, ScanArgs) */ - Single scan(KeyStreamingChannel channel, ScanCursor scanCursor, ScanArgs scanArgs); + Mono scan(KeyStreamingChannel channel, ScanCursor scanCursor, ScanArgs scanArgs); /** * Incrementally iterate the keys space over the whole Cluster. @@ -268,7 +271,7 @@ public interface RedisAdvancedClusterReactiveCommands extends RedisCluster * @return StreamScanCursor scan cursor. * @see RedisKeyReactiveCommands#scan(ScanCursor, ScanArgs) */ - Single scan(KeyStreamingChannel channel, ScanCursor scanCursor); + Mono scan(KeyStreamingChannel channel, ScanCursor scanCursor); /** * Touch one or more keys with pipelining. Touch sets the last accessed time for a key. Non-exsitent keys wont get created. @@ -277,6 +280,6 @@ public interface RedisAdvancedClusterReactiveCommands extends RedisCluster * @param keys the keys * @return Long integer-reply the number of found keys. */ - Single touch(K... keys); + Mono touch(K... keys); -} +} \ No newline at end of file diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/rx/RedisClusterReactiveCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/reactive/RedisClusterReactiveCommands.java similarity index 82% rename from src/main/java/com/lambdaworks/redis/cluster/api/rx/RedisClusterReactiveCommands.java rename to src/main/java/com/lambdaworks/redis/cluster/api/reactive/RedisClusterReactiveCommands.java index f3365643a3..97f4289a34 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/rx/RedisClusterReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/reactive/RedisClusterReactiveCommands.java @@ -1,13 +1,13 @@ -package com.lambdaworks.redis.cluster.api.rx; +package com.lambdaworks.redis.cluster.api.reactive; import java.util.Map; import java.util.concurrent.TimeUnit; import com.lambdaworks.redis.KeyValue; -import rx.Observable; +import com.lambdaworks.redis.api.reactive.*; -import com.lambdaworks.redis.api.rx.*; -import rx.Single; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; /** * A complete reactive and thread-safe cluster Redis API with 400+ Methods. @@ -15,7 +15,7 @@ * @param Key type. * @param Value type. * @author Mark Paluch - * @since 4.0 + * @since 5.0 */ public interface RedisClusterReactiveCommands extends RedisHashReactiveCommands, RedisKeyReactiveCommands, RedisStringReactiveCommands, RedisListReactiveCommands, RedisSetReactiveCommands, @@ -36,7 +36,7 @@ public interface RedisClusterReactiveCommands extends RedisHashReactiveCom * @param password the password * @return String simple-string-reply */ - Single auth(String password); + Mono auth(String password); /** * Generate a new config epoch, incrementing the current epoch, assign the new epoch to this node, WITHOUT any consensus and @@ -45,7 +45,7 @@ public interface RedisClusterReactiveCommands extends RedisHashReactiveCom * @return String simple-string-reply If the new config epoch is generated and assigned either BUMPED (epoch) or STILL * (epoch) are returned. */ - Single clusterBumpepoch(); + Mono clusterBumpepoch(); /** * Meet another cluster node to include the node into the cluster. The command starts the cluster handshake and returns with @@ -55,7 +55,7 @@ public interface RedisClusterReactiveCommands extends RedisHashReactiveCom * @param port port number. * @return String simple-string-reply */ - Single clusterMeet(String ip, int port); + Mono clusterMeet(String ip, int port); /** * Blacklist and remove the cluster node from the cluster. @@ -63,7 +63,7 @@ public interface RedisClusterReactiveCommands extends RedisHashReactiveCom * @param nodeId the node Id * @return String simple-string-reply */ - Single clusterForget(String nodeId); + Mono clusterForget(String nodeId); /** * Adds slots to the cluster node. The current node will become the master for the specified slots. @@ -71,7 +71,7 @@ public interface RedisClusterReactiveCommands extends RedisHashReactiveCom * @param slots one or more slots from {@literal 0} to {@literal 16384} * @return String simple-string-reply */ - Single clusterAddSlots(int... slots); + Mono clusterAddSlots(int... slots); /** * Removes slots from the cluster node. @@ -79,7 +79,7 @@ public interface RedisClusterReactiveCommands extends RedisHashReactiveCom * @param slots one or more slots from {@literal 0} to {@literal 16384} * @return String simple-string-reply */ - Single clusterDelSlots(int... slots); + Mono clusterDelSlots(int... slots); /** * Assign a slot to a node. The command migrates the specified slot from the current node to the specified node in @@ -89,7 +89,7 @@ public interface RedisClusterReactiveCommands extends RedisHashReactiveCom * @param nodeId the id of the node that will become the master for the slot * @return String simple-string-reply */ - Single clusterSetSlotNode(int slot, String nodeId); + Mono clusterSetSlotNode(int slot, String nodeId); /** * Clears migrating / importing state from the slot. @@ -97,7 +97,7 @@ public interface RedisClusterReactiveCommands extends RedisHashReactiveCom * @param slot the slot * @return String simple-string-reply */ - Single clusterSetSlotStable(int slot); + Mono clusterSetSlotStable(int slot); /** * Flag a slot as {@literal MIGRATING} (outgoing) towards the node specified in {@code nodeId}. The slot must be handled by @@ -107,7 +107,7 @@ public interface RedisClusterReactiveCommands extends RedisHashReactiveCom * @param nodeId the id of the node is targeted to become the master for the slot * @return String simple-string-reply */ - Single clusterSetSlotMigrating(int slot, String nodeId); + Mono clusterSetSlotMigrating(int slot, String nodeId); /** * Flag a slot as {@literal IMPORTING} (incoming) from the node specified in {@code nodeId}. @@ -116,21 +116,21 @@ public interface RedisClusterReactiveCommands extends RedisHashReactiveCom * @param nodeId the id of the node is the master of the slot * @return String simple-string-reply */ - Single clusterSetSlotImporting(int slot, String nodeId); + Mono clusterSetSlotImporting(int slot, String nodeId); /** * Get information and statistics about the cluster viewed by the current node. * * @return String bulk-string-reply as a collection of text lines. */ - Single clusterInfo(); + Mono clusterInfo(); /** * Obtain the nodeId for the currently connected node. * * @return String simple-string-reply */ - Single clusterMyId(); + Mono clusterMyId(); /** * Obtain details about all cluster nodes. Can be parsed using @@ -138,7 +138,7 @@ public interface RedisClusterReactiveCommands extends RedisHashReactiveCom * * @return String bulk-string-reply as a collection of text lines */ - Single clusterNodes(); + Mono clusterNodes(); /** * List slaves for a certain node identified by its {@code nodeId}. Can be parsed using @@ -148,7 +148,7 @@ public interface RedisClusterReactiveCommands extends RedisHashReactiveCom * @return List<String> array-reply list of slaves. The command returns data in the same format as * {@link #clusterNodes()} but one line per slave. */ - Observable clusterSlaves(String nodeId); + Flux clusterSlaves(String nodeId); /** * Retrieve the list of keys within the {@code slot}. @@ -157,7 +157,7 @@ public interface RedisClusterReactiveCommands extends RedisHashReactiveCom * @param count maximal number of keys * @return List<K> array-reply list of keys */ - Observable clusterGetKeysInSlot(int slot, int count); + Flux clusterGetKeysInSlot(int slot, int count); /** * Returns the number of keys in the specified Redis Cluster hash {@code slot}. @@ -165,7 +165,7 @@ public interface RedisClusterReactiveCommands extends RedisHashReactiveCom * @param slot the slot * @return Integer reply: The number of keys in the specified hash slot, or an error if the hash slot is invalid. */ - Single clusterCountKeysInSlot(int slot); + Mono clusterCountKeysInSlot(int slot); /** * Returns the number of failure reports for the specified node. Failure reports are the way Redis Cluster uses in order to @@ -175,7 +175,7 @@ public interface RedisClusterReactiveCommands extends RedisHashReactiveCom * @param nodeId the node id * @return Integer reply: The number of active failure reports for the node. */ - Single clusterCountFailureReports(String nodeId); + Mono clusterCountFailureReports(String nodeId); /** * Returns an integer identifying the hash slot the specified key hashes to. This command is mainly useful for debugging and @@ -185,14 +185,14 @@ public interface RedisClusterReactiveCommands extends RedisHashReactiveCom * @param key the key. * @return Integer reply: The hash slot number. */ - Single clusterKeyslot(K key); + Mono clusterKeyslot(K key); /** * Forces a node to save the nodes.conf configuration on disk. * * @return String simple-string-reply: {@code OK} or an error if the operation fails. */ - Single clusterSaveconfig(); + Mono clusterSaveconfig(); /** * This command sets a specific config epoch in a fresh node. It only works when: @@ -204,14 +204,14 @@ public interface RedisClusterReactiveCommands extends RedisHashReactiveCom * @param configEpoch the config epoch * @return String simple-string-reply: {@code OK} or an error if the operation fails. */ - Single clusterSetConfigEpoch(long configEpoch); + Mono clusterSetConfigEpoch(long configEpoch); /** * Get array of cluster slots to node mappings. * * @return List<Object> array-reply nested list of slot ranges with IP/Port mappings. */ - Observable clusterSlots(); + Flux clusterSlots(); /** * The asking command is required after a {@code -ASK} redirection. The client should issue {@code ASKING} before to @@ -219,7 +219,7 @@ public interface RedisClusterReactiveCommands extends RedisHashReactiveCom * * @return String simple-string-reply */ - Single asking(); + Mono asking(); /** * Turn this node into a slave of the node with the id {@code nodeId}. @@ -227,7 +227,7 @@ public interface RedisClusterReactiveCommands extends RedisHashReactiveCom * @param nodeId master node id * @return String simple-string-reply */ - Single clusterReplicate(String nodeId); + Mono clusterReplicate(String nodeId); /** * Failover a cluster node. Turns the currently connected node into a master and the master into its slave. @@ -235,7 +235,7 @@ public interface RedisClusterReactiveCommands extends RedisHashReactiveCom * @param force do not coordinate with master if {@literal true} * @return String simple-string-reply */ - Single clusterFailover(boolean force); + Mono clusterFailover(boolean force); /** * Reset a node performing a soft or hard reset: @@ -252,14 +252,14 @@ public interface RedisClusterReactiveCommands extends RedisHashReactiveCom * @param hard {@literal true} for hard reset. Generates a new nodeId and currentEpoch/configEpoch are set to 0 * @return String simple-string-reply */ - Single clusterReset(boolean hard); + Mono clusterReset(boolean hard); /** * Delete all the slots associated with the specified node. The number of deleted slots is returned. * * @return String simple-string-reply */ - Single clusterFlushslots(); + Mono clusterFlushslots(); /** * Tells a Redis cluster slave node that the client is ok reading possibly stale data and is not interested in running write @@ -267,49 +267,49 @@ public interface RedisClusterReactiveCommands extends RedisHashReactiveCom * * @return String simple-string-reply */ - Single readOnly(); + Mono readOnly(); /** * Resets readOnly flag. * * @return String simple-string-reply */ - Single readWrite(); + Mono readWrite(); /** * Delete a key with pipelining. Cross-slot keys will result in multiple calls to the particular cluster nodes. * * @param keys the key - * @return Observable<Long> integer-reply The number of keys that were removed. + * @return Flux<Long> integer-reply The number of keys that were removed. */ - Single del(K... keys); + Mono del(K... keys); /** * Get the values of all the given keys with pipelining. Cross-slot keys will result in multiple calls to the particular * cluster nodes. * * @param keys the key - * @return Observable<List<V>> array-reply list of values at the specified keys. + * @return Flux<List<V>> array-reply list of values at the specified keys. */ - Observable> mget(K... keys); + Flux> mget(K... keys); /** * Set multiple keys to multiple values with pipelining. Cross-slot keys will result in multiple calls to the particular * cluster nodes. * * @param map the null - * @return Observable<String> simple-string-reply always {@code OK} since {@code MSET} can't fail. + * @return Flux<String> simple-string-reply always {@code OK} since {@code MSET} can't fail. */ - Single mset(Map map); + Mono mset(Map map); /** * Set multiple keys to multiple values, only if none of the keys exist with pipelining. Cross-slot keys will result in * multiple calls to the particular cluster nodes. * * @param map the null - * @return Observable<Boolean> integer-reply specifically: + * @return Flux<Boolean> integer-reply specifically: * * {@code 1} if the all the keys were set. {@code 0} if no key was set (at least one key already existed). */ - Single msetnx(Map map); -} + Mono msetnx(Map map); +} \ No newline at end of file diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/rx/package-info.java b/src/main/java/com/lambdaworks/redis/cluster/api/reactive/package-info.java similarity index 50% rename from src/main/java/com/lambdaworks/redis/cluster/api/rx/package-info.java rename to src/main/java/com/lambdaworks/redis/cluster/api/reactive/package-info.java index 240604692c..1477849c97 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/rx/package-info.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/reactive/package-info.java @@ -1,4 +1,4 @@ /** * Redis Cluster API for reactive commands. */ -package com.lambdaworks.redis.cluster.api.rx; \ No newline at end of file +package com.lambdaworks.redis.cluster.api.reactive; \ No newline at end of file diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionGeoCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionGeoCommands.java index 950ef1d1fb..d502ba9011 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionGeoCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionGeoCommands.java @@ -1,9 +1,7 @@ package com.lambdaworks.redis.cluster.api.sync; -import com.lambdaworks.redis.GeoArgs; -import com.lambdaworks.redis.GeoCoordinates; -import com.lambdaworks.redis.GeoRadiusStoreArgs; -import com.lambdaworks.redis.GeoWithin; +import com.lambdaworks.redis.*; + import java.util.List; import java.util.Set; @@ -43,7 +41,7 @@ public interface NodeSelectionGeoCommands { * @param members the members * @return bulk reply Geohash strings in the order of {@code members}. Returns {@literal null} if a member is not found. */ - Executions> geohash(K key, V... members); + Executions>> geohash(K key, V... members); /** * Retrieve members selected by distance with the center of {@code longitude} and {@code latitude}. @@ -132,7 +130,7 @@ public interface NodeSelectionGeoCommands { * @return a list of {@link GeoCoordinates}s representing the x,y position of each element specified in the arguments. For * missing elements {@literal null} is returned. */ - Executions> geopos(K key, V... members); + Executions>> geopos(K key, V... members); /** * diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionStringCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionStringCommands.java index 041140dd53..98fecb27e7 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionStringCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionStringCommands.java @@ -2,11 +2,10 @@ import java.util.List; import java.util.Map; - -import com.lambdaworks.redis.KeyValue; import com.lambdaworks.redis.output.KeyValueStreamingChannel; import com.lambdaworks.redis.output.ValueStreamingChannel; import com.lambdaworks.redis.BitFieldArgs; +import com.lambdaworks.redis.KeyValue; import com.lambdaworks.redis.SetArgs; import com.lambdaworks.redis.Value; diff --git a/src/main/java/com/lambdaworks/redis/event/DefaultEventBus.java b/src/main/java/com/lambdaworks/redis/event/DefaultEventBus.java index 1d16240069..08dea5b637 100644 --- a/src/main/java/com/lambdaworks/redis/event/DefaultEventBus.java +++ b/src/main/java/com/lambdaworks/redis/event/DefaultEventBus.java @@ -1,9 +1,8 @@ package com.lambdaworks.redis.event; -import rx.Observable; -import rx.Scheduler; -import rx.subjects.PublishSubject; -import rx.subjects.Subject; +import reactor.core.publisher.Flux; +import reactor.core.publisher.TopicProcessor; +import reactor.core.scheduler.Scheduler; /** * Default implementation for an {@link EventBus}. Events are published using a {@link Scheduler}. @@ -13,23 +12,21 @@ */ public class DefaultEventBus implements EventBus { - private final Subject bus; + private final TopicProcessor bus; private final Scheduler scheduler; public DefaultEventBus(Scheduler scheduler) { - this.bus = PublishSubject. create().toSerialized(); + this.bus = TopicProcessor.create(); this.scheduler = scheduler; } @Override - public Observable get() { - return bus.onBackpressureDrop().observeOn(scheduler); + public Flux get() { + return bus.onBackpressureDrop().publishOn(scheduler); } @Override public void publish(Event event) { - if (bus.hasObservers()) { - bus.onNext(event); - } + bus.onNext(event); } } diff --git a/src/main/java/com/lambdaworks/redis/event/EventBus.java b/src/main/java/com/lambdaworks/redis/event/EventBus.java index e5475fc6d5..7f65d7d0e4 100644 --- a/src/main/java/com/lambdaworks/redis/event/EventBus.java +++ b/src/main/java/com/lambdaworks/redis/event/EventBus.java @@ -1,6 +1,6 @@ package com.lambdaworks.redis.event; -import rx.Observable; +import reactor.core.publisher.Flux; /** * Interface for an EventBus. Events can be published over the bus that are delivered to the subscribers. @@ -11,11 +11,11 @@ public interface EventBus { /** - * Subscribe to the event bus and {@link Event}s. The {@link Observable} drops events on backpressure to avoid contention. + * Subscribe to the event bus and {@link Event}s. The {@link Flux} drops events on backpressure to avoid contention. * * @return the observable to obtain events. */ - Observable get(); + Flux get(); /** * Publish a {@link Event} to the bus. diff --git a/src/main/java/com/lambdaworks/redis/output/GeoCoordinatesListOutput.java b/src/main/java/com/lambdaworks/redis/output/GeoCoordinatesListOutput.java index 191b4e7e6c..e348611f2d 100644 --- a/src/main/java/com/lambdaworks/redis/output/GeoCoordinatesListOutput.java +++ b/src/main/java/com/lambdaworks/redis/output/GeoCoordinatesListOutput.java @@ -7,6 +7,7 @@ import java.util.List; import com.lambdaworks.redis.GeoCoordinates; +import com.lambdaworks.redis.Value; import com.lambdaworks.redis.codec.RedisCodec; import com.lambdaworks.redis.internal.LettuceAssert; @@ -15,10 +16,10 @@ * * @author Mark Paluch */ -public class GeoCoordinatesListOutput extends CommandOutput> implements StreamingOutput { +public class GeoCoordinatesListOutput extends CommandOutput>> implements StreamingOutput> { private Double x; - private Subscriber subscriber; + private Subscriber> subscriber; public GeoCoordinatesListOutput(RedisCodec codec) { super(codec, new ArrayList<>()); @@ -35,25 +36,25 @@ public void set(ByteBuffer bytes) { return; } - subscriber.onNext(new GeoCoordinates(x, value)); + subscriber.onNext(Value.fromNullable(new GeoCoordinates(x, value))); x = null; } @Override public void multi(int count) { if (count == -1) { - subscriber.onNext(null); + subscriber.onNext(Value.empty()); } } @Override - public void setSubscriber(Subscriber subscriber) { + public void setSubscriber(Subscriber> subscriber) { LettuceAssert.notNull(subscriber, "Subscriber must not be null"); this.subscriber = subscriber; } @Override - public Subscriber getSubscriber() { + public Subscriber> getSubscriber() { return subscriber; } } diff --git a/src/main/java/com/lambdaworks/redis/output/StringValueListOutput.java b/src/main/java/com/lambdaworks/redis/output/StringValueListOutput.java new file mode 100644 index 0000000000..14b18755f0 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/output/StringValueListOutput.java @@ -0,0 +1,46 @@ +// Copyright (C) 2011 - Will Glozer. All rights reserved. + +package com.lambdaworks.redis.output; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; + +import com.lambdaworks.redis.Value; +import com.lambdaworks.redis.codec.RedisCodec; +import com.lambdaworks.redis.internal.LettuceAssert; + +/** + * {@link List} of {@link com.lambdaworks.redis.Value} output. + * + * @param Key type. + * @param Value type. + * @author Mark Paluch + * @since 5.0 + */ +public class StringValueListOutput extends CommandOutput>> + implements StreamingOutput> { + + private Subscriber> subscriber; + + public StringValueListOutput(RedisCodec codec) { + super(codec, new ArrayList<>()); + setSubscriber(ListSubscriber.of(output)); + } + + @Override + public void set(ByteBuffer bytes) { + subscriber.onNext(bytes == null ? Value.empty() : Value.fromNullable(decodeAscii(bytes))); + } + + @Override + public void setSubscriber(Subscriber> subscriber) { + LettuceAssert.notNull(subscriber, "Subscriber must not be null"); + this.subscriber = subscriber; + } + + @Override + public Subscriber> getSubscriber() { + return subscriber; + } +} diff --git a/src/main/java/com/lambdaworks/redis/pubsub/RedisPubSubReactiveCommandsImpl.java b/src/main/java/com/lambdaworks/redis/pubsub/RedisPubSubReactiveCommandsImpl.java index afc9b50b5b..6677f6cbdc 100644 --- a/src/main/java/com/lambdaworks/redis/pubsub/RedisPubSubReactiveCommandsImpl.java +++ b/src/main/java/com/lambdaworks/redis/pubsub/RedisPubSubReactiveCommandsImpl.java @@ -1,22 +1,16 @@ package com.lambdaworks.redis.pubsub; -import static com.lambdaworks.redis.protocol.CommandType.*; - -import com.lambdaworks.redis.protocol.Command; -import rx.Completable; -import rx.Observable; -import rx.Single; -import rx.Subscriber; +import java.util.Map; import com.lambdaworks.redis.RedisReactiveCommandsImpl; -import com.lambdaworks.redis.api.rx.Success; import com.lambdaworks.redis.codec.RedisCodec; -import com.lambdaworks.redis.protocol.CommandArgs; -import com.lambdaworks.redis.pubsub.api.rx.ChannelMessage; -import com.lambdaworks.redis.pubsub.api.rx.PatternMessage; -import com.lambdaworks.redis.pubsub.api.rx.RedisPubSubReactiveCommands; +import com.lambdaworks.redis.pubsub.api.reactive.ChannelMessage; +import com.lambdaworks.redis.pubsub.api.reactive.PatternMessage; +import com.lambdaworks.redis.pubsub.api.reactive.RedisPubSubReactiveCommands; -import java.util.Map; +import reactor.core.publisher.Flux; +import reactor.core.publisher.FluxSink; +import reactor.core.publisher.Mono; /** * A reactive and thread-safe API for a Redis pub/sub connection. @@ -25,8 +19,8 @@ * @param Value type. * @author Mark Paluch */ -public class RedisPubSubReactiveCommandsImpl extends RedisReactiveCommandsImpl implements - RedisPubSubReactiveCommands { +public class RedisPubSubReactiveCommandsImpl extends RedisReactiveCommandsImpl + implements RedisPubSubReactiveCommands { private PubSubCommandBuilder commandBuilder; @@ -53,51 +47,55 @@ public void addListener(RedisPubSubListener listener) { } @Override - public Observable> observePatterns() { + public Flux> observePatterns() { + return observePatterns(FluxSink.OverflowStrategy.BUFFER); + } - SubscriptionPubSubListener> listener = new SubscriptionPubSubListener>() { - @Override - public void message(K pattern, K channel, V message) { - if (subscriber == null) { - return; - } + @Override + public Flux> observePatterns(FluxSink.OverflowStrategy overflowStrategy) { + return Flux.create(sink -> { + + RedisPubSubAdapter listener = new RedisPubSubAdapter() { - if (subscriber.isUnsubscribed()) { - subscriber.onCompleted(); - removeListener(this); - subscriber = null; - return; + @Override + public void message(K pattern, K channel, V message) { + sink.next(new PatternMessage<>(pattern, channel, message)); } + }; - subscriber.onNext(new PatternMessage<>(pattern, channel, message)); - } - }; + addListener(listener); + sink.setCancellation(() -> { + removeListener(listener); + }); - return Observable.create(new PubSubObservable<>(listener)); + }, overflowStrategy); } @Override - public Observable> observeChannels() { + public Flux> observeChannels() { + return observeChannels(FluxSink.OverflowStrategy.BUFFER); + } - SubscriptionPubSubListener> listener = new SubscriptionPubSubListener>() { - @Override - public void message(K channel, V message) { - if (subscriber == null) { - return; - } + @Override + public Flux> observeChannels(FluxSink.OverflowStrategy overflowStrategy) { + + return Flux.create(sink -> { + + RedisPubSubAdapter listener = new RedisPubSubAdapter() { - if (subscriber.isUnsubscribed()) { - subscriber.onCompleted(); - removeListener(this); - subscriber = null; - return; + @Override + public void message(K channel, V message) { + sink.next(new ChannelMessage<>(channel, message)); } + }; - subscriber.onNext(new ChannelMessage<>(channel, message)); - } - }; + addListener(listener); + + sink.setCancellation(() -> { + removeListener(listener); + }); - return Observable.create(new PubSubObservable<>(listener)); + }, overflowStrategy); } /** @@ -111,38 +109,38 @@ public void removeListener(RedisPubSubListener listener) { } @Override - public Completable psubscribe(K... patterns) { - return Completable.fromObservable(createObservable(() -> commandBuilder.psubscribe(patterns))); + public Mono psubscribe(K... patterns) { + return createMono(() -> commandBuilder.psubscribe(patterns)).then(); } @Override - public Completable punsubscribe(K... patterns) { - return Completable.fromObservable(createObservable(() -> commandBuilder.punsubscribe(patterns))); + public Mono punsubscribe(K... patterns) { + return createFlux(() -> commandBuilder.punsubscribe(patterns)).then(); } @Override - public Completable subscribe(K... channels) { - return Completable.fromObservable(createObservable(() -> commandBuilder.subscribe(channels))); + public Mono subscribe(K... channels) { + return createFlux(() -> commandBuilder.subscribe(channels)).then(); } @Override - public Completable unsubscribe(K... channels) { - return Completable.fromObservable(createObservable(() -> commandBuilder.unsubscribe(channels))); + public Mono unsubscribe(K... channels) { + return createFlux(() -> commandBuilder.unsubscribe(channels)).then(); } @Override - public Single publish(K channel, V message) { - return createSingle(() -> commandBuilder.publish(channel, message)); + public Mono publish(K channel, V message) { + return createMono(() -> commandBuilder.publish(channel, message)); } @Override - public Observable pubsubChannels(K channel) { - return createDissolvingObservable(() -> commandBuilder.pubsubChannels(channel)); + public Flux pubsubChannels(K channel) { + return createDissolvingFlux(() -> commandBuilder.pubsubChannels(channel)); } @Override - public Single> pubsubNumsub(K... channels) { - return createSingle(() -> commandBuilder.pubsubNumsub(channels)); + public Mono> pubsubNumsub(K... channels) { + return createMono(() -> commandBuilder.pubsubNumsub(channels)); } @Override @@ -151,29 +149,4 @@ public StatefulRedisPubSubConnection getStatefulConnection() { return (StatefulRedisPubSubConnection) super.getStatefulConnection(); } - private class PubSubObservable implements Observable.OnSubscribe { - - private SubscriptionPubSubListener listener; - - public PubSubObservable(SubscriptionPubSubListener listener) { - this.listener = listener; - } - - @Override - public void call(Subscriber subscriber) { - - listener.activate(subscriber); - subscriber.onStart(); - addListener(listener); - - } - } - - private static class SubscriptionPubSubListener extends RedisPubSubAdapter { - protected Subscriber subscriber; - - public void activate(Subscriber subscriber) { - this.subscriber = subscriber; - } - } } diff --git a/src/main/java/com/lambdaworks/redis/pubsub/StatefulRedisPubSubConnection.java b/src/main/java/com/lambdaworks/redis/pubsub/StatefulRedisPubSubConnection.java index 92e42ff701..f71b755729 100644 --- a/src/main/java/com/lambdaworks/redis/pubsub/StatefulRedisPubSubConnection.java +++ b/src/main/java/com/lambdaworks/redis/pubsub/StatefulRedisPubSubConnection.java @@ -2,7 +2,7 @@ import com.lambdaworks.redis.api.StatefulRedisConnection; import com.lambdaworks.redis.pubsub.api.async.RedisPubSubAsyncCommands; -import com.lambdaworks.redis.pubsub.api.rx.RedisPubSubReactiveCommands; +import com.lambdaworks.redis.pubsub.api.reactive.RedisPubSubReactiveCommands; import com.lambdaworks.redis.pubsub.api.sync.RedisPubSubCommands; /** diff --git a/src/main/java/com/lambdaworks/redis/pubsub/StatefulRedisPubSubConnectionImpl.java b/src/main/java/com/lambdaworks/redis/pubsub/StatefulRedisPubSubConnectionImpl.java index 6652c69577..123ebcf193 100644 --- a/src/main/java/com/lambdaworks/redis/pubsub/StatefulRedisPubSubConnectionImpl.java +++ b/src/main/java/com/lambdaworks/redis/pubsub/StatefulRedisPubSubConnectionImpl.java @@ -14,7 +14,7 @@ import com.lambdaworks.redis.codec.RedisCodec; import com.lambdaworks.redis.protocol.ConnectionWatchdog; import com.lambdaworks.redis.pubsub.api.async.RedisPubSubAsyncCommands; -import com.lambdaworks.redis.pubsub.api.rx.RedisPubSubReactiveCommands; +import com.lambdaworks.redis.pubsub.api.reactive.RedisPubSubReactiveCommands; import com.lambdaworks.redis.pubsub.api.sync.RedisPubSubCommands; import io.netty.channel.ChannelHandler; diff --git a/src/main/java/com/lambdaworks/redis/pubsub/api/rx/ChannelMessage.java b/src/main/java/com/lambdaworks/redis/pubsub/api/reactive/ChannelMessage.java similarity index 92% rename from src/main/java/com/lambdaworks/redis/pubsub/api/rx/ChannelMessage.java rename to src/main/java/com/lambdaworks/redis/pubsub/api/reactive/ChannelMessage.java index d1b8d49071..ee2e2f3e37 100644 --- a/src/main/java/com/lambdaworks/redis/pubsub/api/rx/ChannelMessage.java +++ b/src/main/java/com/lambdaworks/redis/pubsub/api/reactive/ChannelMessage.java @@ -1,4 +1,4 @@ -package com.lambdaworks.redis.pubsub.api.rx; +package com.lambdaworks.redis.pubsub.api.reactive; /** * Message payload for a subscription to a channel. diff --git a/src/main/java/com/lambdaworks/redis/pubsub/api/rx/PatternMessage.java b/src/main/java/com/lambdaworks/redis/pubsub/api/reactive/PatternMessage.java similarity index 94% rename from src/main/java/com/lambdaworks/redis/pubsub/api/rx/PatternMessage.java rename to src/main/java/com/lambdaworks/redis/pubsub/api/reactive/PatternMessage.java index 019c6b4bee..d210c5b7d7 100644 --- a/src/main/java/com/lambdaworks/redis/pubsub/api/rx/PatternMessage.java +++ b/src/main/java/com/lambdaworks/redis/pubsub/api/reactive/PatternMessage.java @@ -1,4 +1,4 @@ -package com.lambdaworks.redis.pubsub.api.rx; +package com.lambdaworks.redis.pubsub.api.reactive; /** * Message payload for a subscription to a pattern. diff --git a/src/main/java/com/lambdaworks/redis/pubsub/api/reactive/RedisPubSubReactiveCommands.java b/src/main/java/com/lambdaworks/redis/pubsub/api/reactive/RedisPubSubReactiveCommands.java new file mode 100644 index 0000000000..d4dc4d613d --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/pubsub/api/reactive/RedisPubSubReactiveCommands.java @@ -0,0 +1,116 @@ +package com.lambdaworks.redis.pubsub.api.reactive; + +import com.lambdaworks.redis.api.reactive.RedisReactiveCommands; +import com.lambdaworks.redis.pubsub.RedisPubSubListener; +import com.lambdaworks.redis.pubsub.StatefulRedisPubSubConnection; + +import reactor.core.publisher.Flux; +import reactor.core.publisher.FluxSink; +import reactor.core.publisher.Mono; + +/** + * Asynchronous and thread-safe Redis PubSub API. + * + * @param Key type. + * @param Value type. + * @author Mark Paluch + * @since 5.0 + */ +public interface RedisPubSubReactiveCommands extends RedisReactiveCommands { + + /** + * Add a new listener. + * + * @param listener Listener. + */ + void addListener(RedisPubSubListener listener); + + /** + * Remove an existing listener. + * + * @param listener Listener. + */ + void removeListener(RedisPubSubListener listener); + + /** + * Flux for messages ({@literal pmessage}) received though pattern subscriptions. The connection needs to be subscribed to + * one or more patterns using {@link #psubscribe(Object[])}. + *

+ * Warning! This method uses {@link reactor.core.publisher.FluxSink.OverflowStrategy#BUFFER} This does unbounded buffering + * and may lead to {@link OutOfMemoryError}. Use {@link #observePatterns(FluxSink.OverflowStrategy)} to specify a different + * strategy. + *

+ * + * @return hot Flux for subscriptions to {@literal pmessage}'s. + */ + Flux> observePatterns(); + + /** + * Flux for messages ({@literal pmessage}) received though pattern subscriptions. The connection needs to be subscribed to + * one or more patterns using {@link #psubscribe(Object[])}. + * + * @param overflowStrategy the overflow strategy to use. + * @return hot Flux for subscriptions to {@literal pmessage}'s. + */ + Flux> observePatterns(FluxSink.OverflowStrategy overflowStrategy); + + /** + * Flux for messages ({@literal message}) received though channel subscriptions. The connection needs to be subscribed to + * one or more channels using {@link #subscribe(Object[])}. + * + *

+ * Warning! This method uses {@link reactor.core.publisher.FluxSink.OverflowStrategy#BUFFER} This does unbounded buffering + * and may lead to {@link OutOfMemoryError}. Use {@link #observeChannels(FluxSink.OverflowStrategy)} to specify a different + * strategy. + *

+ * + * @return hot Flux for subscriptions to {@literal message}'s. + */ + Flux> observeChannels(); + + /** + * Flux for messages ({@literal message}) received though channel subscriptions. The connection needs to be subscribed to + * one or more channels using {@link #subscribe(Object[])}. + * + * @param overflowStrategy the overflow strategy to use. + * @return hot Flux for subscriptions to {@literal message}'s. + */ + Flux> observeChannels(FluxSink.OverflowStrategy overflowStrategy); + + /** + * Listen for messages published to channels matching the given patterns. + * + * @param patterns the patterns + * @return Flux<Success> Flux for {@code psubscribe} command + */ + Mono psubscribe(K... patterns); + + /** + * Stop listening for messages posted to channels matching the given patterns. + * + * @param patterns the patterns + * @return Flux<Success> Flux for {@code punsubscribe} command + */ + Mono punsubscribe(K... patterns); + + /** + * Listen for messages published to the given channels. + * + * @param channels the channels + * @return Flux<Success> Flux for {@code subscribe} command + */ + Mono subscribe(K... channels); + + /** + * Stop listening for messages posted to the given channels. + * + * @param channels the channels + * @return Flux<Success> Flux for {@code unsubscribe} command. + */ + Mono unsubscribe(K... channels); + + /** + * @return the underlying connection. + */ + StatefulRedisPubSubConnection getStatefulConnection(); +} diff --git a/src/main/java/com/lambdaworks/redis/pubsub/api/rx/package-info.java b/src/main/java/com/lambdaworks/redis/pubsub/api/reactive/package-info.java similarity index 50% rename from src/main/java/com/lambdaworks/redis/pubsub/api/rx/package-info.java rename to src/main/java/com/lambdaworks/redis/pubsub/api/reactive/package-info.java index 96ad27db25..8e45ee225b 100644 --- a/src/main/java/com/lambdaworks/redis/pubsub/api/rx/package-info.java +++ b/src/main/java/com/lambdaworks/redis/pubsub/api/reactive/package-info.java @@ -1,4 +1,4 @@ /** * Pub/Sub Redis API for reactive commands. */ -package com.lambdaworks.redis.pubsub.api.rx; \ No newline at end of file +package com.lambdaworks.redis.pubsub.api.reactive; \ No newline at end of file diff --git a/src/main/java/com/lambdaworks/redis/pubsub/api/rx/RedisPubSubReactiveCommands.java b/src/main/java/com/lambdaworks/redis/pubsub/api/rx/RedisPubSubReactiveCommands.java deleted file mode 100644 index 1d67dee71a..0000000000 --- a/src/main/java/com/lambdaworks/redis/pubsub/api/rx/RedisPubSubReactiveCommands.java +++ /dev/null @@ -1,87 +0,0 @@ -package com.lambdaworks.redis.pubsub.api.rx; - -import com.lambdaworks.redis.api.rx.Success; -import rx.Completable; -import rx.Observable; - -import com.lambdaworks.redis.api.rx.RedisReactiveCommands; -import com.lambdaworks.redis.pubsub.RedisPubSubListener; -import com.lambdaworks.redis.pubsub.StatefulRedisPubSubConnection; - -/** - * Asynchronous and thread-safe Redis PubSub API. - * - * @param Key type. - * @param Value type. - * @author Mark Paluch - * @since 3.0 - */ -public interface RedisPubSubReactiveCommands extends RedisReactiveCommands { - - /** - * Add a new listener. - * - * @param listener Listener. - */ - void addListener(RedisPubSubListener listener); - - /** - * Remove an existing listener. - * - * @param listener Listener. - */ - void removeListener(RedisPubSubListener listener); - - /** - * Observable for messages ({@literal pmessage}) received though pattern subscriptions. The connection needs to be - * subscribed to one or more patterns using {@link #psubscribe(Object[])}. - * - * @return hot observable for subscriptions to {@literal pmessage}'s. - */ - Observable> observePatterns(); - - /** - * Observable for messages ({@literal message}) received though channel subscriptions. The connection needs to be subscribed - * to one or more channels using {@link #subscribe(Object[])}. - * - * @return hot observable for subscriptions to {@literal message}'s. - */ - Observable> observeChannels(); - - /** - * Listen for messages published to channels matching the given patterns. - * - * @param patterns the patterns - * @return Observable<Success> Observable for {@code psubscribe} command - */ - Completable psubscribe(K... patterns); - - /** - * Stop listening for messages posted to channels matching the given patterns. - * - * @param patterns the patterns - * @return Observable<Success> Observable for {@code punsubscribe} command - */ - Completable punsubscribe(K... patterns); - - /** - * Listen for messages published to the given channels. - * - * @param channels the channels - * @return Observable<Success> Observable for {@code subscribe} command - */ - Completable subscribe(K... channels); - - /** - * Stop listening for messages posted to the given channels. - * - * @param channels the channels - * @return Observable<Success> Observable for {@code unsubscribe} command. - */ - Completable unsubscribe(K... channels); - - /** - * @return the underlying connection. - */ - StatefulRedisPubSubConnection getStatefulConnection(); -} diff --git a/src/main/java/com/lambdaworks/redis/resource/DefaultClientResources.java b/src/main/java/com/lambdaworks/redis/resource/DefaultClientResources.java index b39290f882..cd193c49f4 100644 --- a/src/main/java/com/lambdaworks/redis/resource/DefaultClientResources.java +++ b/src/main/java/com/lambdaworks/redis/resource/DefaultClientResources.java @@ -21,6 +21,7 @@ import io.netty.util.internal.SystemPropertyUtil; import io.netty.util.internal.logging.InternalLogger; import io.netty.util.internal.logging.InternalLoggerFactory; +import reactor.core.scheduler.Schedulers; /** * Default instance of the client resources. @@ -118,7 +119,7 @@ protected DefaultClientResources(Builder builder) { } if (builder.eventBus == null) { - eventBus = new DefaultEventBus(new RxJavaEventExecutorGroupScheduler(eventExecutorGroup)); + eventBus = new DefaultEventBus(Schedulers.fromExecutor(eventExecutorGroup)); } else { eventBus = builder.eventBus; } diff --git a/src/main/java/com/lambdaworks/redis/resource/RxJavaEventExecutorGroupScheduler.java b/src/main/java/com/lambdaworks/redis/resource/RxJavaEventExecutorGroupScheduler.java deleted file mode 100644 index 581a7b68e3..0000000000 --- a/src/main/java/com/lambdaworks/redis/resource/RxJavaEventExecutorGroupScheduler.java +++ /dev/null @@ -1,106 +0,0 @@ -package com.lambdaworks.redis.resource; - -import java.util.concurrent.Future; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; - -import rx.Scheduler; -import rx.Subscription; -import rx.functions.Action0; -import rx.internal.schedulers.ScheduledAction; -import rx.internal.util.SubscriptionList; -import rx.subscriptions.CompositeSubscription; -import rx.subscriptions.Subscriptions; -import io.netty.util.concurrent.EventExecutor; -import io.netty.util.concurrent.EventExecutorGroup; - -/** - * A scheduler that uses a provided {@link EventExecutorGroup} instance to schedule tasks. This should typically be used as a - * computation scheduler or any other scheduler that do not schedule blocking tasks. See also - * https://github.com/ReactiveX/RxNetty - * /blob/0.5.x/rxnetty-common/src/main/java/io/reactivex/netty/threads/RxJavaEventloopScheduler.java - */ -public class RxJavaEventExecutorGroupScheduler extends Scheduler { - - private final EventExecutorGroup eventLoopGroup; - - public RxJavaEventExecutorGroupScheduler(EventExecutorGroup eventLoopGroup) { - this.eventLoopGroup = eventLoopGroup; - } - - @Override - public Worker createWorker() { - final EventExecutor eventLoop = eventLoopGroup.next(); - return new ScheduledExecutorServiceWorker(eventLoop); - } - - /** - * This code is more or less copied from rx-netty's EventloopWorker worker code. - **/ - private static class ScheduledExecutorServiceWorker extends Worker { - - /** - * Why are there two subscription holders? - * - * The serial subscriptions are used for non-delayed schedules which are always executed (and hence removed) in order. - * Since SubscriptionList holds the subs as a linked list, removals are optimal for serial removes. OTOH, delayed - * schedules are executed (and hence removed) out of order and hence a CompositeSubscription, that stores the subs in a - * hash structure is more optimal for removals. - */ - private final SubscriptionList serial; - private final CompositeSubscription timed; - private final SubscriptionList both; - private final ScheduledExecutorService scheduledExecutor; - - public ScheduledExecutorServiceWorker(EventExecutor scheduledExecutor) { - this.scheduledExecutor = scheduledExecutor; - serial = new SubscriptionList(); - timed = new CompositeSubscription(); - both = new SubscriptionList(serial, timed); - } - - @Override - public Subscription schedule(final Action0 action) { - return schedule(action, 0, TimeUnit.DAYS); - } - - @Override - public Subscription schedule(final Action0 action, long delayTime, TimeUnit unit) { - - if (isUnsubscribed()) { - return Subscriptions.unsubscribed(); - } - - final ScheduledAction sa; - - if (delayTime <= 0) { - sa = new ScheduledAction(action, serial); - serial.add(sa); - } else { - sa = new ScheduledAction(action, timed); - timed.add(sa); - } - - final Future result = scheduledExecutor.schedule(sa, delayTime, unit); - Subscription cancelFuture = Subscriptions.create(new Action0() { - @Override - public void call() { - result.cancel(false); - } - }); - sa.add(cancelFuture); /* An unsubscribe of the returned sub should cancel the future */ - return sa; - } - - @Override - public void unsubscribe() { - both.unsubscribe(); - } - - @Override - public boolean isUnsubscribed() { - return both.isUnsubscribed(); - } - - } -} diff --git a/src/main/java/com/lambdaworks/redis/sentinel/RedisSentinelReactiveCommandsImpl.java b/src/main/java/com/lambdaworks/redis/sentinel/RedisSentinelReactiveCommandsImpl.java index fc1335f4b0..2a168de5f4 100644 --- a/src/main/java/com/lambdaworks/redis/sentinel/RedisSentinelReactiveCommandsImpl.java +++ b/src/main/java/com/lambdaworks/redis/sentinel/RedisSentinelReactiveCommandsImpl.java @@ -3,18 +3,16 @@ import java.net.InetSocketAddress; import java.net.SocketAddress; import java.util.Map; -import java.util.function.Supplier; -import com.lambdaworks.redis.ReactiveCommandDispatcher; +import com.lambdaworks.redis.AbstractRedisReactiveCommands; import com.lambdaworks.redis.api.StatefulConnection; import com.lambdaworks.redis.codec.RedisCodec; import com.lambdaworks.redis.internal.LettuceAssert; -import com.lambdaworks.redis.protocol.RedisCommand; import com.lambdaworks.redis.sentinel.api.StatefulRedisSentinelConnection; -import com.lambdaworks.redis.sentinel.api.rx.RedisSentinelReactiveCommands; +import com.lambdaworks.redis.sentinel.api.reactive.RedisSentinelReactiveCommands; -import rx.Observable; -import rx.Single; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; /** * A reactive and thread-safe API for a Redis Sentinel connection. @@ -24,75 +22,79 @@ * @author Mark Paluch * @since 3.0 */ -public class RedisSentinelReactiveCommandsImpl implements RedisSentinelReactiveCommands { +public class RedisSentinelReactiveCommandsImpl extends AbstractRedisReactiveCommands + implements RedisSentinelReactiveCommands { private final SentinelCommandBuilder commandBuilder; private final StatefulConnection connection; public RedisSentinelReactiveCommandsImpl(StatefulConnection connection, RedisCodec codec) { + super(connection, codec); this.connection = connection; commandBuilder = new SentinelCommandBuilder(codec); } @Override - public Single getMasterAddrByName(K key) { + public Mono getMasterAddrByName(K key) { + + Flux flux = createDissolvingFlux(() -> commandBuilder.getMasterAddrByKey(key)); + + return flux.collectList().flatMap(list -> { - Observable observable = createDissolvingObservable(() -> commandBuilder.getMasterAddrByKey(key)); - return observable.buffer(2).map(list -> { if (list.isEmpty()) { - return null; + return Flux.empty(); } LettuceAssert.isTrue(list.size() == 2, "List must contain exact 2 entries (Hostname, Port)"); String hostname = (String) list.get(0); String port = (String) list.get(1); - return new InetSocketAddress(hostname, Integer.parseInt(port)); - }).lastOrDefault(null).cast(SocketAddress.class).toSingle(); + return Mono.just(new InetSocketAddress(hostname, Integer.parseInt(port))); + }).cast(SocketAddress.class).next(); } @Override - public Observable> masters() { - return createDissolvingObservable(() -> commandBuilder.masters()); + public Flux> masters() { + return createDissolvingFlux(commandBuilder::masters); } @Override - public Single> master(K key) { - return createSingle(() -> commandBuilder.master(key)); + public Mono> master(K key) { + return createMono(() -> commandBuilder.master(key)); } @Override - public Observable> slaves(K key) { - return createDissolvingObservable(() -> commandBuilder.slaves(key)); + public Flux> slaves(K key) { + return createDissolvingFlux(() -> commandBuilder.slaves(key)); } @Override - public Single reset(K key) { - return createSingle(() -> commandBuilder.reset(key)); + public Mono reset(K key) { + return createMono(() -> commandBuilder.reset(key)); } @Override - public Single failover(K key) { - return createSingle(() -> commandBuilder.failover(key)); + public Mono failover(K key) { + return createMono(() -> commandBuilder.failover(key)); } @Override - public Single monitor(K key, String ip, int port, int quorum) { - return createSingle(() -> commandBuilder.monitor(key, ip, port, quorum)); + public Mono monitor(K key, String ip, int port, int quorum) { + return createMono(() -> commandBuilder.monitor(key, ip, port, quorum)); } @Override - public Single set(K key, String option, V value) { - return createSingle(() -> commandBuilder.set(key, option, value)); + public Mono set(K key, String option, V value) { + return createMono(() -> commandBuilder.set(key, option, value)); } @Override - public Single remove(K key) { - return createSingle(() -> commandBuilder.remove(key)); + public Mono remove(K key) { + return createMono(() -> commandBuilder.remove(key)); } @Override - public Single ping() { - return createSingle(() -> commandBuilder.ping()); + public Mono ping() { + return createMono(commandBuilder::ping); } // @Override @@ -109,19 +111,4 @@ public boolean isOpen() { public StatefulRedisSentinelConnection getStatefulConnection() { return (StatefulRedisSentinelConnection) connection; } - - public Observable createObservable(Supplier> commandSupplier) { - return Observable - .create(new ReactiveCommandDispatcher(commandSupplier, connection, false).getObservableSubscriber()); - } - - public Single createSingle(Supplier> commandSupplier) { - return Single.create(new ReactiveCommandDispatcher(commandSupplier, connection, false).getSingleSubscriber()); - } - - @SuppressWarnings("unchecked") - public R createDissolvingObservable(Supplier> commandSupplier) { - return (R) Observable - .create(new ReactiveCommandDispatcher<>(commandSupplier, connection, true).getObservableSubscriber()); - } } diff --git a/src/main/java/com/lambdaworks/redis/sentinel/StatefulRedisSentinelConnectionImpl.java b/src/main/java/com/lambdaworks/redis/sentinel/StatefulRedisSentinelConnectionImpl.java index feea14bb95..9f852dc829 100644 --- a/src/main/java/com/lambdaworks/redis/sentinel/StatefulRedisSentinelConnectionImpl.java +++ b/src/main/java/com/lambdaworks/redis/sentinel/StatefulRedisSentinelConnectionImpl.java @@ -8,7 +8,7 @@ import com.lambdaworks.redis.protocol.RedisCommand; import com.lambdaworks.redis.sentinel.api.StatefulRedisSentinelConnection; import com.lambdaworks.redis.sentinel.api.async.RedisSentinelAsyncCommands; -import com.lambdaworks.redis.sentinel.api.rx.RedisSentinelReactiveCommands; +import com.lambdaworks.redis.sentinel.api.reactive.RedisSentinelReactiveCommands; import com.lambdaworks.redis.sentinel.api.sync.RedisSentinelCommands; import io.netty.channel.ChannelHandler; diff --git a/src/main/java/com/lambdaworks/redis/sentinel/api/StatefulRedisSentinelConnection.java b/src/main/java/com/lambdaworks/redis/sentinel/api/StatefulRedisSentinelConnection.java index c09f00f444..034ba3396e 100644 --- a/src/main/java/com/lambdaworks/redis/sentinel/api/StatefulRedisSentinelConnection.java +++ b/src/main/java/com/lambdaworks/redis/sentinel/api/StatefulRedisSentinelConnection.java @@ -3,7 +3,7 @@ import com.lambdaworks.redis.api.StatefulConnection; import com.lambdaworks.redis.protocol.ConnectionWatchdog; import com.lambdaworks.redis.sentinel.api.async.RedisSentinelAsyncCommands; -import com.lambdaworks.redis.sentinel.api.rx.RedisSentinelReactiveCommands; +import com.lambdaworks.redis.sentinel.api.reactive.RedisSentinelReactiveCommands; import com.lambdaworks.redis.sentinel.api.sync.RedisSentinelCommands; /** @@ -27,14 +27,14 @@ public interface StatefulRedisSentinelConnection extends StatefulConnectio RedisSentinelCommands sync(); /** - * Returns the {@link RedisSentinelAsyncCommands} API for the current connection. Does not create a new connection. * + * Returns the {@link RedisSentinelAsyncCommands} API for the current connection. Does not create a new connection. * * @return the asynchronous API for the underlying connection. */ RedisSentinelAsyncCommands async(); /** - * Returns the {@link RedisSentinelReactiveCommands} API for the current connection. Does not create a new connection. * + * Returns the {@link RedisSentinelReactiveCommands} API for the current connection. Does not create a new connection. * * @return the reactive API for the underlying connection. */ diff --git a/src/main/java/com/lambdaworks/redis/sentinel/api/rx/RedisSentinelReactiveCommands.java b/src/main/java/com/lambdaworks/redis/sentinel/api/reactive/RedisSentinelReactiveCommands.java similarity index 79% rename from src/main/java/com/lambdaworks/redis/sentinel/api/rx/RedisSentinelReactiveCommands.java rename to src/main/java/com/lambdaworks/redis/sentinel/api/reactive/RedisSentinelReactiveCommands.java index 2bfc480db9..ab430d1d4d 100644 --- a/src/main/java/com/lambdaworks/redis/sentinel/api/rx/RedisSentinelReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/sentinel/api/reactive/RedisSentinelReactiveCommands.java @@ -1,15 +1,14 @@ -package com.lambdaworks.redis.sentinel.api.rx; +package com.lambdaworks.redis.sentinel.api.reactive; import java.net.SocketAddress; import java.util.List; import java.util.Map; import com.lambdaworks.redis.sentinel.api.StatefulRedisSentinelConnection; -import rx.Observable; -import rx.Single; -import rx.Completable; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; /** - * Observable commands for Redis Sentinel. + * Reactive executed commands for Redis Sentinel. * * @param Key type. * @param Value type. @@ -25,14 +24,14 @@ public interface RedisSentinelReactiveCommands { * @param key the key * @return SocketAddress; */ - Single getMasterAddrByName(K key); + Mono getMasterAddrByName(K key); /** * Enumerates all the monitored masters and their states. * * @return Map<K, V>> */ - Observable> masters(); + Flux> masters(); /** * Show the state and info of the specified master. @@ -40,7 +39,7 @@ public interface RedisSentinelReactiveCommands { * @param key the key * @return Map<K, V> */ - Single> master(K key); + Mono> master(K key); /** * Provides a list of slaves for the master with the specified name. @@ -48,7 +47,7 @@ public interface RedisSentinelReactiveCommands { * @param key the key * @return Map<K, V> */ - Observable> slaves(K key); + Flux> slaves(K key); /** * This command will reset all the masters with matching name. @@ -56,7 +55,7 @@ public interface RedisSentinelReactiveCommands { * @param key the key * @return Long */ - Single reset(K key); + Mono reset(K key); /** * Perform a failover. @@ -64,7 +63,7 @@ public interface RedisSentinelReactiveCommands { * @param key the master id * @return String */ - Single failover(K key); + Mono failover(K key); /** * This command tells the Sentinel to start monitoring a new master with the specified name, ip, port, and quorum. @@ -75,7 +74,7 @@ public interface RedisSentinelReactiveCommands { * @param quorum the quorum count * @return String */ - Single monitor(K key, String ip, int port, int quorum); + Mono monitor(K key, String ip, int port, int quorum); /** * Multiple option / value pairs can be specified (or none at all). @@ -86,7 +85,7 @@ public interface RedisSentinelReactiveCommands { * * @return String simple-string-reply {@code OK} if {@code SET} was executed correctly. */ - Single set(K key, String option, V value); + Mono set(K key, String option, V value); /** * remove the specified master. @@ -94,14 +93,14 @@ public interface RedisSentinelReactiveCommands { * @param key the key * @return String */ - Single remove(K key); + Mono remove(K key); /** * Ping the server. * * @return String simple-string-reply */ - Single ping(); + Mono ping(); /** * close the underlying connection. diff --git a/src/main/java/com/lambdaworks/redis/sentinel/api/rx/package-info.java b/src/main/java/com/lambdaworks/redis/sentinel/api/rx/package-info.java deleted file mode 100644 index e126b5d5ab..0000000000 --- a/src/main/java/com/lambdaworks/redis/sentinel/api/rx/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * Redis Sentinel API for reactive commands. - */ -package com.lambdaworks.redis.sentinel.api.rx; \ No newline at end of file diff --git a/src/main/templates/com/lambdaworks/redis/api/RedisGeoCommands.java b/src/main/templates/com/lambdaworks/redis/api/RedisGeoCommands.java index 583599f7af..765b7a0ae4 100644 --- a/src/main/templates/com/lambdaworks/redis/api/RedisGeoCommands.java +++ b/src/main/templates/com/lambdaworks/redis/api/RedisGeoCommands.java @@ -4,6 +4,7 @@ import com.lambdaworks.redis.GeoCoordinates; import com.lambdaworks.redis.GeoRadiusStoreArgs; import com.lambdaworks.redis.GeoWithin; +import com.lambdaworks.redis.Value; import java.util.List; import java.util.Set; @@ -42,7 +43,7 @@ public interface RedisGeoCommands { * @param members the members * @return bulk reply Geohash strings in the order of {@code members}. Returns {@literal null} if a member is not found. */ - List geohash(K key, V... members); + List> geohash(K key, V... members); /** * Retrieve members selected by distance with the center of {@code longitude} and {@code latitude}. @@ -70,7 +71,7 @@ public interface RedisGeoCommands { List> georadius(K key, double longitude, double latitude, double distance, GeoArgs.Unit unit, GeoArgs geoArgs); /** - * Perform a {@link #georadius(Object, double, double, double, Unit, GeoArgs)} query and store the results in a sorted set. + * Perform a {@link #georadius(Object, double, double, double, GeoArgs.Unit, GeoArgs)} query and store the results in a sorted set. * * @param key the key of the geo set * @param longitude the longitude coordinate according to WGS84 @@ -110,7 +111,7 @@ public interface RedisGeoCommands { List> georadiusbymember(K key, V member, double distance, GeoArgs.Unit unit, GeoArgs geoArgs); /** - * Perform a {@link #georadiusbymember(Object, Object, double, Unit, GeoArgs)} query and store the results in a sorted set. + * Perform a {@link #georadiusbymember(Object, Object, double, GeoArgs.Unit, GeoArgs)} query and store the results in a sorted set. * * @param key the key of the geo set * @param member reference member @@ -131,7 +132,7 @@ public interface RedisGeoCommands { * @return a list of {@link GeoCoordinates}s representing the x,y position of each element specified in the arguments. For * missing elements {@literal null} is returned. */ - List geopos(K key, V... members); + List> geopos(K key, V... members); /** * diff --git a/src/main/templates/com/lambdaworks/redis/api/RedisSetCommands.java b/src/main/templates/com/lambdaworks/redis/api/RedisSetCommands.java index 56efcb1a10..17025aa0f2 100644 --- a/src/main/templates/com/lambdaworks/redis/api/RedisSetCommands.java +++ b/src/main/templates/com/lambdaworks/redis/api/RedisSetCommands.java @@ -1,5 +1,6 @@ package com.lambdaworks.redis.api; +import java.util.List; import java.util.Set; import com.lambdaworks.redis.ScanArgs; diff --git a/src/site/markdown/download.md.vm b/src/site/markdown/download.md.vm index 250140c85a..eeee9ca6a8 100644 --- a/src/site/markdown/download.md.vm +++ b/src/site/markdown/download.md.vm @@ -66,8 +66,7 @@ Using lettuce on your classpath netty-transport-${netty-version}.jar netty-transport-native-epoll-${netty-version}.jar netty-handler-${netty-version}.jar - guava-17.0.jar - rxjava-1.1.9.jar + reactor-3.0.0.RELEASE.jar LatencyUtils-2.0.3.jar HdrHistogram-2.1.8.jar commons-pool2-2.4.2.jar diff --git a/src/site/markdown/index.md.vm b/src/site/markdown/index.md.vm index 25a4d5792f..8ec6b81d05 100644 --- a/src/site/markdown/index.md.vm +++ b/src/site/markdown/index.md.vm @@ -72,8 +72,8 @@ Shaded JAR-File (packaged dependencies and relocated to the `com.lambdaworks` p - io.reactivex - rxjava + io.projectreactor + reactor-core org.latencyutils @@ -95,10 +95,6 @@ Shaded JAR-File (packaged dependencies and relocated to the `com.lambdaworks` p io.netty netty-codec - - com.google.guava - guava - io.netty netty-transport-native-epoll diff --git a/src/test/java/biz/paluch/redis/extensibility/LettuceGeoDemo.java b/src/test/java/biz/paluch/redis/extensibility/LettuceGeoDemo.java index 770b244fd8..0c61a3e500 100644 --- a/src/test/java/biz/paluch/redis/extensibility/LettuceGeoDemo.java +++ b/src/test/java/biz/paluch/redis/extensibility/LettuceGeoDemo.java @@ -40,8 +40,8 @@ public static void main(String[] args) { System.out.println("Distance: " + weinheim.distance); System.out.println("Coordinates: " + weinheim.coordinates.x + "/" + weinheim.coordinates.y); - List geopos = redis.geopos(key, "Weinheim", "Train station"); - GeoCoordinates weinheimGeopos = geopos.get(0); + List> geopos = redis.geopos(key, "Weinheim", "Train station"); + GeoCoordinates weinheimGeopos = geopos.get(0).getValue(); System.out.println("Coordinates: " + weinheimGeopos.x + "/" + weinheimGeopos.y); redis.getStatefulConnection().close(); diff --git a/src/test/java/com/lambdaworks/apigenerator/CreateReactiveApi.java b/src/test/java/com/lambdaworks/apigenerator/CreateReactiveApi.java index 1dbf8a61ad..8ab4f7bcac 100644 --- a/src/test/java/com/lambdaworks/apigenerator/CreateReactiveApi.java +++ b/src/test/java/com/lambdaworks/apigenerator/CreateReactiveApi.java @@ -28,7 +28,7 @@ public class CreateReactiveApi { private static Set KEEP_METHOD_RESULT_TYPE = LettuceSets.unmodifiableSet("digest", "close", "isOpen", "BaseRedisCommands.reset", "getStatefulConnection", "setAutoFlushCommands", "flushCommands"); - private static Set FORCE_OBSERVABLE_RESULT = LettuceSets.unmodifiableSet("eval", "evalsha", "dispatch"); + private static Set FORCE_FLUX_RESULT = LettuceSets.unmodifiableSet("eval", "evalsha", "dispatch"); private CompilationUnitFactory factory; @@ -54,9 +54,9 @@ public CreateReactiveApi(String templateName) { String targetPackage; if (templateName.contains("RedisSentinel")) { - targetPackage = "com.lambdaworks.redis.sentinel.api.rx"; + targetPackage = "com.lambdaworks.redis.sentinel.api.reactive"; } else { - targetPackage = "com.lambdaworks.redis.api.rx"; + targetPackage = "com.lambdaworks.redis.api.reactive"; } factory = new CompilationUnitFactory(templateFile, Constants.SOURCES, targetPackage, targetName, commentMutator(), @@ -69,7 +69,7 @@ public CreateReactiveApi(String templateName) { * @return */ protected Function commentMutator() { - return s -> s.replaceAll("\\$\\{intent\\}", "Observable commands").replaceAll("@since 3.0", "@since 4.0") + return s -> s.replaceAll("\\$\\{intent\\}", "Reactive executed commands").replaceAll("@since 3.0", "@since 4.0") + "* @generated by " + getClass().getName() + "\r\n "; } @@ -102,16 +102,16 @@ protected Function methodTypeMutator() { String typeAsString = method.getType().toStringWithoutComments().trim(); - if (methodMatch(FORCE_OBSERVABLE_RESULT, method, classOfMethod)) { - typeAsString = "Observable<" + typeAsString + ">"; + if (methodMatch(FORCE_FLUX_RESULT, method, classOfMethod)) { + typeAsString = "Flux<" + typeAsString + ">"; } else if (typeAsString.equals("void")) { - typeAsString = "Completable"; + typeAsString = "Mono"; } else if (typeAsString.startsWith("List<")) { - typeAsString = "Observable<" + typeAsString.substring(5, typeAsString.length() - 1) + ">"; + typeAsString = "Flux<" + typeAsString.substring(5, typeAsString.length() - 1) + ">"; } else if (typeAsString.startsWith("Set<")) { - typeAsString = "Observable<" + typeAsString.substring(4, typeAsString.length() - 1) + ">"; + typeAsString = "Flux<" + typeAsString.substring(4, typeAsString.length() - 1) + ">"; } else { - typeAsString = "Single<" + typeAsString + ">"; + typeAsString = "Mono<" + typeAsString + ">"; } return new ReferenceType(new ClassOrInterfaceType(typeAsString)); @@ -129,7 +129,7 @@ private boolean methodMatch(Collection methodNames, MethodDeclaration me * @return */ protected Supplier> importSupplier() { - return () -> Arrays.asList("rx.Observable", "rx.Single", "rx.Completable"); + return () -> Arrays.asList("reactor.core.publisher.Flux", "reactor.core.publisher.Mono"); } @Test diff --git a/src/test/java/com/lambdaworks/redis/ClientMetricsTest.java b/src/test/java/com/lambdaworks/redis/ClientMetricsTest.java index ca3a9443ad..647ec54f77 100644 --- a/src/test/java/com/lambdaworks/redis/ClientMetricsTest.java +++ b/src/test/java/com/lambdaworks/redis/ClientMetricsTest.java @@ -1,31 +1,29 @@ package com.lambdaworks.redis; -import static com.google.code.tempusfugit.temporal.Duration.seconds; -import static com.google.code.tempusfugit.temporal.Timeout.timeout; import static com.lambdaworks.redis.AbstractRedisClientTest.client; import static org.assertj.core.api.Assertions.assertThat; -import com.lambdaworks.TestClientResources; -import com.lambdaworks.redis.api.sync.RedisCommands; -import com.lambdaworks.redis.metrics.CommandLatencyId; -import com.lambdaworks.redis.metrics.CommandMetrics; -import org.junit.*; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +import com.lambdaworks.Wait; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; import org.springframework.test.util.ReflectionTestUtils; -import com.google.code.tempusfugit.temporal.Condition; -import com.google.code.tempusfugit.temporal.WaitFor; -import com.lambdaworks.redis.api.StatefulRedisConnection; -import com.lambdaworks.redis.event.Event; +import com.lambdaworks.TestClientResources; +import com.lambdaworks.redis.api.sync.RedisCommands; import com.lambdaworks.redis.event.EventBus; import com.lambdaworks.redis.event.metrics.CommandLatencyEvent; import com.lambdaworks.redis.event.metrics.MetricEventPublisher; +import com.lambdaworks.redis.metrics.CommandLatencyId; +import com.lambdaworks.redis.metrics.CommandMetrics; -import rx.Subscription; -import rx.functions.Func1; -import rx.observers.TestSubscriber; - -import java.util.Set; -import java.util.concurrent.TimeUnit; +import reactor.test.TestSubscriber; /** * @author Mark Paluch @@ -52,22 +50,26 @@ public static void afterClass() { @Test public void testMetricsEvent() throws Exception { + List events = new ArrayList<>(); EventBus eventBus = client.getResources().eventBus(); MetricEventPublisher publisher = (MetricEventPublisher) ReflectionTestUtils.getField(client.getResources(), "metricEventPublisher"); publisher.emitMetricsEvent(); - TestSubscriber subscriber = new TestSubscriber(); - Subscription subscription = eventBus.get().filter(redisEvent -> redisEvent instanceof CommandLatencyEvent).cast(CommandLatencyEvent.class).subscribe(subscriber); + TestSubscriber subscriber = TestSubscriber.create(); + eventBus.get().filter(redisEvent -> redisEvent instanceof CommandLatencyEvent).cast(CommandLatencyEvent.class) + .doOnNext(events::add).subscribe(subscriber); generateTestData(); publisher.emitMetricsEvent(); - WaitFor.waitOrTimeout(() -> !subscriber.getOnNextEvents().isEmpty(), timeout(seconds(5))); + subscriber.request(1); + Wait.untilTrue(() -> !events.isEmpty()).waitOrTimeout(); - subscription.unsubscribe(); + assertThat(events).isNotEmpty(); - subscriber.assertValueCount(1); + subscriber.assertNotComplete(); + subscriber.cancel(); } @Test @@ -78,26 +80,24 @@ public void testMetrics() throws Exception { "metricEventPublisher"); publisher.emitMetricsEvent(); - TestSubscriber subscriber = new TestSubscriber(); - Subscription subscription = eventBus.get().filter(redisEvent -> redisEvent instanceof CommandLatencyEvent).cast(CommandLatencyEvent.class).subscribe(subscriber); + TestSubscriber subscriber = TestSubscriber.create(); + eventBus.get().filter(redisEvent -> redisEvent instanceof CommandLatencyEvent).cast(CommandLatencyEvent.class) + .subscribe(subscriber); generateTestData(); publisher.emitMetricsEvent(); - WaitFor.waitOrTimeout(() -> !subscriber.getOnNextEvents().isEmpty(), timeout(seconds(5))); - subscription.unsubscribe(); - - subscriber.assertValueCount(1); + subscriber.awaitAndAssertNextValuesWith(event -> { - CommandLatencyEvent event = subscriber.getOnNextEvents().get(0); + Set ids = event.getLatencies().keySet(); + CommandMetrics commandMetrics = event.getLatencies().get(ids.iterator().next()); + assertThat(commandMetrics.getCompletion().getMin()).isBetween(0L, TimeUnit.MILLISECONDS.toMicros(100)); + assertThat(commandMetrics.getCompletion().getMax()).isBetween(0L, TimeUnit.MILLISECONDS.toMicros(200)); - Set ids = event.getLatencies().keySet(); - CommandMetrics commandMetrics = event.getLatencies().get(ids.iterator().next()); - assertThat(commandMetrics.getCompletion().getMin()).isBetween(0L, TimeUnit.MILLISECONDS.toMicros(100)); - assertThat(commandMetrics.getCompletion().getMax()).isBetween(0L, TimeUnit.MILLISECONDS.toMicros(200)); + assertThat(commandMetrics.getFirstResponse().getMin()).isBetween(0L, TimeUnit.MILLISECONDS.toMicros(100)); + assertThat(commandMetrics.getFirstResponse().getMax()).isBetween(0L, TimeUnit.MILLISECONDS.toMicros(200)); + }); - assertThat(commandMetrics.getFirstResponse().getMin()).isBetween(0L, TimeUnit.MILLISECONDS.toMicros(100)); - assertThat(commandMetrics.getFirstResponse().getMax()).isBetween(0L, TimeUnit.MILLISECONDS.toMicros(200)); } private void generateTestData() { diff --git a/src/test/java/com/lambdaworks/redis/CustomCodecTest.java b/src/test/java/com/lambdaworks/redis/CustomCodecTest.java index 693959379f..29463bc4f2 100644 --- a/src/test/java/com/lambdaworks/redis/CustomCodecTest.java +++ b/src/test/java/com/lambdaworks/redis/CustomCodecTest.java @@ -22,7 +22,7 @@ import com.lambdaworks.redis.codec.ByteArrayCodec; import com.lambdaworks.redis.codec.CompressionCodec; import com.lambdaworks.redis.codec.RedisCodec; -import rx.observers.TestSubscriber; +import reactor.test.TestSubscriber; public class CustomCodecTest extends AbstractRedisClientTest { @@ -41,16 +41,14 @@ public void testJavaSerializer() throws Exception { } @Test - public void testJavaSerializerRx() throws Exception { + public void testJavaSerializerReactive() throws Exception { StatefulRedisConnection redisConnection = client.connect(new SerializedObjectCodec()); List list = list("one", "two"); TestSubscriber subscriber = TestSubscriber.create(); redisConnection.reactive().set(key, list, SetArgs.Builder.ex(1)).subscribe(subscriber); - subscriber.awaitTerminalEvent(1, TimeUnit.SECONDS); - subscriber.assertCompleted(); - subscriber.assertValue("OK"); + subscriber.awaitAndAssertNextValues("OK").assertComplete().assertNoError(); redisConnection.close(); } diff --git a/src/test/java/com/lambdaworks/redis/LettucePerformanceTest.java b/src/test/java/com/lambdaworks/redis/LettucePerformanceTest.java index 7df56f4634..5c1de4cd35 100644 --- a/src/test/java/com/lambdaworks/redis/LettucePerformanceTest.java +++ b/src/test/java/com/lambdaworks/redis/LettucePerformanceTest.java @@ -12,12 +12,10 @@ import com.lambdaworks.redis.api.StatefulRedisConnection; import com.lambdaworks.redis.api.async.RedisAsyncCommands; -import com.lambdaworks.redis.api.rx.RedisReactiveCommands; +import com.lambdaworks.redis.api.reactive.RedisReactiveCommands; -import rx.Observable; -import rx.Single; - -import javax.annotation.Resources; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; /** * @author Mark Paluch @@ -149,7 +147,7 @@ protected void submitExecutionTasks(int threads, List(totalCalls)); - List>>> futurama = new ArrayList<>(); + List>>> futurama = new ArrayList<>(); preheat(threads); final int callsPerThread = totalCalls / threads; - submitObservableTasks(threads, futurama, callsPerThread, connectionPerThread); + submitFluxTasks(threads, futurama, callsPerThread, connectionPerThread); Thread.sleep(800); long start = System.currentTimeMillis(); latch.countDown(); - for (Future>> listFuture : futurama) { - for (Single future : listFuture.get()) { - if (waitForCompletion) { - future.toBlocking().value(); - } else { - future.subscribe(); + for (Future>> listFuture : futurama) { + + if (waitForCompletion) { + Flux.concat(listFuture.get()).last().subscribe().request(Long.MAX_VALUE); + + } else + for (Mono mono : listFuture.get()) { + mono.subscribe().request(Long.MAX_VALUE); } - } } long end = System.currentTimeMillis(); @@ -193,7 +192,7 @@ public void testObservablePerformance() throws Exception { } - protected void submitObservableTasks(int threads, List>>> futurama, final int callsPerThread, + protected void submitFluxTasks(int threads, List>>> futurama, final int callsPerThread, final boolean connectionPerThread) { final StatefulRedisConnection sharedConnection; if (!connectionPerThread) { @@ -203,7 +202,7 @@ protected void submitObservableTasks(int threads, List>> submit = executor.submit(() -> { + Future>> submit = executor.submit(() -> { StatefulRedisConnection connection = sharedConnection; if (connectionPerThread) { @@ -213,13 +212,13 @@ protected void submitObservableTasks(int threads, List> observables = new ArrayList<>(callsPerThread); + List> monos = new ArrayList<>(callsPerThread); latch.await(); for (int i1 = 0; i1 < callsPerThread; i1++) { - observables.add(reactive.ping()); + monos.add(reactive.ping()); } - return observables; + return monos; }); futurama.add(submit); diff --git a/src/test/java/com/lambdaworks/redis/ReactiveConnectionTest.java b/src/test/java/com/lambdaworks/redis/ReactiveConnectionTest.java index 409d702bb4..395de86637 100644 --- a/src/test/java/com/lambdaworks/redis/ReactiveConnectionTest.java +++ b/src/test/java/com/lambdaworks/redis/ReactiveConnectionTest.java @@ -16,21 +16,18 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; - -import rx.Observable; -import rx.Single; -import rx.Subscriber; +import org.reactivestreams.Subscriber; +import org.reactivestreams.Subscription; import com.lambdaworks.Delay; import com.lambdaworks.Wait; import com.lambdaworks.redis.api.StatefulRedisConnection; -import com.lambdaworks.redis.api.rx.RedisReactiveCommands; -import rx.observers.TestSubscriber; +import com.lambdaworks.redis.api.reactive.RedisReactiveCommands; -import rx.Observable; -import rx.Subscriber; -import rx.observers.TestSubscriber; -import rx.schedulers.Schedulers; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import reactor.core.scheduler.Schedulers; +import reactor.test.TestSubscriber; public class ReactiveConnectionTest extends AbstractRedisClientTest { @@ -53,7 +50,7 @@ public void closeReactiveConnection() throws Exception { @Test public void doNotFireCommandUntilObservation() throws Exception { - Single set = reactive.set(key, value); + Mono set = reactive.set(key, value); Delay.delay(millis(200)); assertThat(redis.get(key)).isNull(); set.subscribe(); @@ -64,7 +61,7 @@ public void doNotFireCommandUntilObservation() throws Exception { @Test public void fireCommandAfterObserve() throws Exception { - assertThat(reactive.set(key, value).toBlocking().value()).isEqualTo("OK"); + assertThat(reactive.set(key, value).block()).isEqualTo("OK"); assertThat(redis.get(key)).isEqualTo(value); } @@ -89,53 +86,53 @@ public void testCancelCommand() throws Exception { Delay.delay(millis(100)); reactive.reset(); - assertThat(result).hasSize(1).hasOnlyElementsOfType(CancellationException.class); + assertThat(result).isEmpty(); } @Test public void testEcho() throws Exception { - String result = reactive.echo("echo").toBlocking().value(); + String result = reactive.echo("echo").block(); assertThat(result).isEqualTo("echo"); } @Test - public void testSingleMultiCancel() throws Exception { + public void testMonoMultiCancel() throws Exception { List result = new ArrayList<>(); reactive.clientPause(1000).subscribe(); Delay.delay(millis(100)); - Single set = reactive.set(key, value); + Mono set = reactive.set(key, value); set.subscribe(new CompletionSubscriber(result)); set.subscribe(new CompletionSubscriber(result)); set.subscribe(new CompletionSubscriber(result)); Delay.delay(millis(100)); reactive.reset(); - assertThat(result).hasSize(3); + assertThat(result).isEmpty(); } @Test - public void testObservableMultiCancel() throws Exception { + public void testFluxCancel() throws Exception { List result = new ArrayList<>(); reactive.clientPause(1000).subscribe(); Delay.delay(millis(100)); - Observable> set = reactive.mget(key, value); + Flux> set = reactive.mget(key, value); set.subscribe(new CompletionSubscriber(result)); set.subscribe(new CompletionSubscriber(result)); set.subscribe(new CompletionSubscriber(result)); Delay.delay(millis(100)); reactive.reset(); - assertThat(result).hasSize(3); + assertThat(result).isEmpty(); } @Test public void multiSubscribe() throws Exception { reactive.set(key, "1").subscribe(); - Single incr = reactive.incr(key); + Mono incr = reactive.incr(key); incr.subscribe(); incr.subscribe(); incr.subscribe(); @@ -173,10 +170,10 @@ public void reactiveChain() throws Exception { map.put(key, value); map.put("key1", "value1"); - reactive.mset(map).toBlocking().value(); + reactive.mset(map).block(); - List values = reactive.keys("*").flatMap(s -> reactive.get(s).toObservable()).toList().subscribeOn(Schedulers.immediate()) - .toBlocking().first(); + List values = reactive.keys("*").flatMap(s -> reactive.get(s)).collectList().subscribeOn(Schedulers.immediate()) + .block(); assertThat(values).hasSize(2).contains(value, "value1"); } @@ -184,7 +181,7 @@ public void reactiveChain() throws Exception { @Test public void auth() throws Exception { List errors = new ArrayList<>(); - reactive.auth("error").doOnError(errors::add).subscribe(new TestSubscriber<>()); + reactive.auth("error").doOnError(errors::add).subscribe(TestSubscriber.create()); Delay.delay(millis(50)); assertThat(errors).hasSize(1); } @@ -192,19 +189,25 @@ public void auth() throws Exception { @Test public void subscriberCompletingWithExceptionShouldBeHandledSafely() throws Exception { - Single.concat(reactive.set("keyA", "valueA"), reactive.set("keyB", "valueB")).toBlocking().last(); + Flux.concat(reactive.set("keyA", "valueA"), reactive.set("keyB", "valueB")).collectList().block(); reactive.get("keyA").subscribe(createSubscriberWithExceptionOnComplete()); reactive.get("keyA").subscribe(createSubscriberWithExceptionOnComplete()); - String valueB = reactive.get("keyB").toBlocking().toFuture().get(); + String valueB = reactive.get("keyB").block(); assertThat(valueB).isEqualTo("valueB"); } private static Subscriber createSubscriberWithExceptionOnComplete() { return new Subscriber() { + + @Override + public void onSubscribe(Subscription s) { + s.request(1000); + } + @Override - public void onCompleted() { + public void onComplete() { throw new RuntimeException("throwing something"); } @@ -218,7 +221,7 @@ public void onNext(String s) { }; } - private static class CompletionSubscriber extends Subscriber { + private static class CompletionSubscriber implements Subscriber { private final List result; @@ -227,7 +230,12 @@ public CompletionSubscriber(List result) { } @Override - public void onCompleted() { + public void onSubscribe(Subscription s) { + s.request(1000); + } + + @Override + public void onComplete() { result.add("completed"); } diff --git a/src/test/java/com/lambdaworks/redis/ReactiveStreamingOutputTest.java b/src/test/java/com/lambdaworks/redis/ReactiveStreamingOutputTest.java index f0809a4641..d528f58d51 100644 --- a/src/test/java/com/lambdaworks/redis/ReactiveStreamingOutputTest.java +++ b/src/test/java/com/lambdaworks/redis/ReactiveStreamingOutputTest.java @@ -1,6 +1,7 @@ package com.lambdaworks.redis; +import java.util.List; import java.util.stream.Collectors; import org.junit.After; @@ -12,9 +13,9 @@ import com.lambdaworks.RandomKeys; import com.lambdaworks.redis.GeoArgs.Unit; import com.lambdaworks.redis.api.StatefulRedisConnection; -import com.lambdaworks.redis.api.rx.RedisReactiveCommands; - -import rx.observers.TestSubscriber; +import com.lambdaworks.redis.api.reactive.RedisReactiveCommands; +import org.springframework.test.util.ReflectionTestUtils; +import reactor.test.TestSubscriber; import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; @@ -44,9 +45,17 @@ public void keyListCommandShouldReturnAllElements() throws Exception { redis.mset(RandomKeys.MAP); reactive.keys("*").subscribe(subscriber); - subscriber.awaitTerminalEvent(); + subscriber.await(); + + assertThat(getValues()).containsAll(RandomKeys.KEYS); + } + + public List getValues() { + return (List) ReflectionTestUtils.getField(subscriber, "values"); + } - assertThat(subscriber.getOnNextEvents()).containsAll(RandomKeys.KEYS); + public List getValues(TestSubscriber subscriber) { + return (List) ReflectionTestUtils.getField(subscriber, "values"); } @Test @@ -57,11 +66,11 @@ public void valueListCommandShouldReturnAllElements() throws Exception { TestSubscriber> subscriber = TestSubscriber.create(); reactive.mget(RandomKeys.KEYS.toArray(new String[RandomKeys.COUNT])).subscribe(subscriber); - subscriber.awaitTerminalEvent(); + subscriber.await(); - assertThat(subscriber.getOnNextEvents().stream().map(KeyValue::getValue).collect(Collectors.toList())) + assertThat(getValues(subscriber).stream().map(KeyValue::getValue).collect(Collectors.toList())) .containsAll(RandomKeys.VALUES); - assertThat(subscriber.getOnNextEvents().stream().map(KeyValue::getKey).collect(Collectors.toList())) + assertThat(getValues(subscriber).stream().map(KeyValue::getKey).collect(Collectors.toList())) .containsAll(RandomKeys.KEYS); } @@ -69,9 +78,9 @@ public void valueListCommandShouldReturnAllElements() throws Exception { public void stringListCommandShouldReturnAllElements() throws Exception { reactive.configGet("*").subscribe(subscriber); - subscriber.awaitTerminalEvent(); + subscriber.await(); - assertThat(subscriber.getOnNextEvents().size()).isGreaterThan(120); + assertThat(getValues().size()).isGreaterThan(120); } @Test @@ -80,22 +89,20 @@ public void booleanListCommandShouldReturnAllElements() throws Exception { TestSubscriber subscriber = TestSubscriber.create(); reactive.scriptExists("a", "b", "c").subscribe(subscriber); - subscriber.awaitTerminalEvent(); - - assertThat(subscriber.getOnNextEvents()).hasSize(3).doesNotContainNull(); + subscriber.awaitAndAssertNextValueCount(3); } @Test public void scoredValueListCommandShouldReturnAllElements() throws Exception { - TestSubscriber> subscriber = TestSubscriber.create(); + TestSubscriber>> subscriber = TestSubscriber.create(); redis.zadd(key, 1d, "v1", 2d, "v2", 3d, "v3"); - reactive.zrangeWithScores(key, 0, -1).subscribe(subscriber); - subscriber.awaitTerminalEvent(); - - assertThat(subscriber.getOnNextEvents()).hasSize(3).contains(sv(1, "v1"), sv(2, "v2"), sv(3, "v3")); + reactive.zrangeWithScores(key, 0, -1).collectList().subscribe(subscriber); + subscriber.awaitAndAssertNextValuesWith(scoredValues -> { + assertThat(scoredValues).hasSize(3).contains(sv(1, "v1"), sv(2, "v2"), sv(3, "v3")); + }); } @Test @@ -107,9 +114,9 @@ public void geoWithinListCommandShouldReturnAllElements() throws Exception { redis.geoadd(key, 50, 21, "value2"); reactive.georadius(key, 50, 20, 1000, Unit.km, new GeoArgs().withHash()).subscribe(subscriber); - subscriber.awaitTerminalEvent(); + subscriber.await(); - assertThat(subscriber.getOnNextEvents()).hasSize(2).contains( + assertThat(getValues(subscriber)).hasSize(2).contains( new GeoWithin("value1", null, 3542523898362974L, null), new GeoWithin<>("value2", null, 3542609801095198L, null)); } @@ -117,15 +124,13 @@ public void geoWithinListCommandShouldReturnAllElements() throws Exception { @Test public void geoCoordinatesListCommandShouldReturnAllElements() throws Exception { - TestSubscriber subscriber = TestSubscriber.create(); + TestSubscriber> subscriber = TestSubscriber.create(); redis.geoadd(key, 50, 20, "value1"); redis.geoadd(key, 50, 21, "value2"); reactive.geopos(key, "value1", "value2").subscribe(subscriber); - subscriber.awaitTerminalEvent(); - - assertThat(subscriber.getOnNextEvents()).hasSize(2).doesNotContainNull(); + subscriber.awaitAndAssertNextValueCount(2); } } diff --git a/src/test/java/com/lambdaworks/redis/cluster/AdvancedClusterClientTest.java b/src/test/java/com/lambdaworks/redis/cluster/AdvancedClusterClientTest.java index a9f1f643b6..341be73b36 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/AdvancedClusterClientTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/AdvancedClusterClientTest.java @@ -17,8 +17,8 @@ import com.lambdaworks.redis.cluster.api.StatefulRedisClusterConnection; import com.lambdaworks.redis.cluster.api.async.RedisAdvancedClusterAsyncCommands; import com.lambdaworks.redis.cluster.api.async.RedisClusterAsyncCommands; -import com.lambdaworks.redis.cluster.api.rx.RedisAdvancedClusterReactiveCommands; -import com.lambdaworks.redis.cluster.api.rx.RedisClusterReactiveCommands; +import com.lambdaworks.redis.cluster.api.reactive.RedisAdvancedClusterReactiveCommands; +import com.lambdaworks.redis.cluster.api.reactive.RedisClusterReactiveCommands; import com.lambdaworks.redis.cluster.api.sync.RedisAdvancedClusterCommands; import com.lambdaworks.redis.cluster.api.sync.RedisClusterCommands; import com.lambdaworks.redis.cluster.models.partitions.Partitions; diff --git a/src/test/java/com/lambdaworks/redis/cluster/AdvancedClusterReactiveTest.java b/src/test/java/com/lambdaworks/redis/cluster/AdvancedClusterReactiveTest.java index f6608daf4c..34b248f439 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/AdvancedClusterReactiveTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/AdvancedClusterReactiveTest.java @@ -18,16 +18,16 @@ import com.lambdaworks.RandomKeys; import com.lambdaworks.redis.*; import com.lambdaworks.redis.api.sync.RedisCommands; -import com.lambdaworks.redis.cluster.api.rx.RedisAdvancedClusterReactiveCommands; -import com.lambdaworks.redis.cluster.api.rx.RedisClusterReactiveCommands; +import com.lambdaworks.redis.cluster.api.reactive.RedisAdvancedClusterReactiveCommands; +import com.lambdaworks.redis.cluster.api.reactive.RedisClusterReactiveCommands; import com.lambdaworks.redis.cluster.api.sync.RedisAdvancedClusterCommands; import com.lambdaworks.redis.cluster.api.sync.RedisClusterCommands; import com.lambdaworks.redis.cluster.models.partitions.RedisClusterNode; import com.lambdaworks.redis.codec.Utf8StringCodec; -import com.lambdaworks.util.RxSyncInvocationHandler; +import com.lambdaworks.util.ReactiveSyncInvocationHandler; -import rx.Observable; -import rx.Single; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; /** * @author Mark Paluch @@ -43,7 +43,7 @@ public class AdvancedClusterReactiveTest extends AbstractClusterTest { @Before public void before() throws Exception { commands = clusterClient.connect().reactive(); - syncCommands = RxSyncInvocationHandler.sync(commands.getStatefulConnection()); + syncCommands = ReactiveSyncInvocationHandler.sync(commands.getStatefulConnection()); } @After @@ -65,7 +65,7 @@ public void invalidHost() throws Exception { @Test public void msetCrossSlot() throws Exception { - Single mset = commands.mset(RandomKeys.MAP); + Mono mset = commands.mset(RandomKeys.MAP); assertThat(block(mset)).isEqualTo("OK"); for (String mykey : RandomKeys.KEYS) { @@ -93,8 +93,8 @@ public void mgetCrossSlot() throws Exception { Map> partitioned = SlotHash.partition(new Utf8StringCodec(), RandomKeys.KEYS); assertThat(partitioned.size()).isGreaterThan(100); - Observable> observable = commands.mget(RandomKeys.KEYS.toArray(new String[RandomKeys.COUNT])); - List> result = observable.toList().toBlocking().single(); + Flux> flux = commands.mget(RandomKeys.KEYS.toArray(new String[RandomKeys.COUNT])); + List> result = flux.collectList().block(); assertThat(result).hasSize(RandomKeys.COUNT); assertThat(result.stream().map(Value::getValue).collect(Collectors.toList())).isEqualTo(RandomKeys.VALUES); @@ -107,8 +107,8 @@ public void mgetCrossSlotStreaming() throws Exception { KeyValueStreamingAdapter result = new KeyValueStreamingAdapter<>(); - Single single = commands.mget(result, RandomKeys.KEYS.toArray(new String[RandomKeys.COUNT])); - Long count = block(single); + Mono mono = commands.mget(result, RandomKeys.KEYS.toArray(new String[RandomKeys.COUNT])); + Long count = block(mono); assertThat(result.getMap()).hasSize(RandomKeys.COUNT); assertThat(count).isEqualTo(RandomKeys.COUNT); @@ -119,8 +119,8 @@ public void delCrossSlot() throws Exception { msetCrossSlot(); - Single single = commands.del(RandomKeys.KEYS.toArray(new String[RandomKeys.COUNT])); - Long result = block(single); + Mono mono = commands.del(RandomKeys.KEYS.toArray(new String[RandomKeys.COUNT])); + Long result = block(mono); assertThat(result).isEqualTo(RandomKeys.COUNT); @@ -135,8 +135,8 @@ public void unlinkCrossSlot() throws Exception { msetCrossSlot(); - Single single = commands.unlink(RandomKeys.KEYS.toArray(new String[RandomKeys.COUNT])); - Long result = block(single); + Mono mono = commands.unlink(RandomKeys.KEYS.toArray(new String[RandomKeys.COUNT])); + Long result = block(mono); assertThat(result).isEqualTo(RandomKeys.COUNT); @@ -203,7 +203,7 @@ public void keys() throws Exception { writeKeysToTwoNodes(); - List result = commands.keys("*").toList().toBlocking().single(); + List result = commands.keys("*").collectList().block(); assertThat(result).contains(KEY_ON_NODE_1, KEY_ON_NODE_2); } @@ -251,7 +251,7 @@ public void readFromSlaves() throws Exception { NodeSelectionAsyncTest.waitForReplication(commands.getStatefulConnection().async(), key, port4); AtomicBoolean error = new AtomicBoolean(); - connection.get(key).doOnError(throwable -> error.set(true)).toBlocking().toFuture().get(); + connection.get(key).doOnError(throwable -> error.set(true)).block(); assertThat(error.get()).isFalse(); @@ -356,8 +356,8 @@ public void clusterScanStreamingWithArgs() throws Exception { } - private T block(Single single) { - return single.toBlocking().value(); + private T block(Mono mono) { + return mono.block(); } diff --git a/src/test/java/com/lambdaworks/redis/cluster/ClusterReactiveCommandTest.java b/src/test/java/com/lambdaworks/redis/cluster/ClusterReactiveCommandTest.java index dba6a999ff..c0f5d2a81a 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/ClusterReactiveCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/ClusterReactiveCommandTest.java @@ -13,12 +13,12 @@ import com.lambdaworks.redis.RedisClient; import com.lambdaworks.redis.RedisURI; import com.lambdaworks.redis.api.async.RedisAsyncCommands; -import com.lambdaworks.redis.cluster.api.rx.RedisClusterReactiveCommands; +import com.lambdaworks.redis.cluster.api.reactive.RedisClusterReactiveCommands; import com.lambdaworks.redis.cluster.models.slots.ClusterSlotRange; import com.lambdaworks.redis.cluster.models.slots.ClusterSlotsParser; import com.lambdaworks.redis.internal.LettuceLists; -import rx.Single; +import reactor.core.publisher.Mono; @FixMethodOrder(MethodSorters.NAME_ASCENDING) @SuppressWarnings("unchecked") @@ -111,7 +111,7 @@ public void testAsking() throws Exception { @Test public void testClusterSlots() throws Exception { - List reply = reactive.clusterSlots().toList().toBlocking().first(); + List reply = reactive.clusterSlots().collectList().block(); assertThat(reply.size()).isGreaterThan(1); List parse = ClusterSlotsParser.parse(reply); @@ -128,13 +128,13 @@ public void testClusterSlots() throws Exception { public void clusterSlaves() throws Exception { String nodeId = getNodeId(async.getStatefulConnection().sync()); - List result = reactive.clusterSlaves(nodeId).toList().toBlocking().first(); + List result = reactive.clusterSlaves(nodeId).collectList().block(); assertThat(result.size()).isGreaterThan(0); } - private T block(Single single) { - return single.toBlocking().value(); + private T block(Mono mono) { + return mono.block(); } } diff --git a/src/test/java/com/lambdaworks/redis/cluster/RedisRxClusterClientTest.java b/src/test/java/com/lambdaworks/redis/cluster/RedisReactiveClusterClientTest.java similarity index 68% rename from src/test/java/com/lambdaworks/redis/cluster/RedisRxClusterClientTest.java rename to src/test/java/com/lambdaworks/redis/cluster/RedisReactiveClusterClientTest.java index 0981e4b517..f194e990d9 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/RedisRxClusterClientTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/RedisReactiveClusterClientTest.java @@ -6,42 +6,37 @@ import java.util.Collections; import java.util.List; -import com.lambdaworks.TestClientResources; -import org.junit.After; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.FixMethodOrder; -import org.junit.Test; +import org.junit.*; import org.junit.runners.MethodSorters; -import rx.Observable; - +import com.lambdaworks.TestClientResources; import com.lambdaworks.redis.FastShutdown; import com.lambdaworks.redis.RedisClient; import com.lambdaworks.redis.RedisException; import com.lambdaworks.redis.RedisURI; import com.lambdaworks.redis.cluster.api.StatefulRedisClusterConnection; -import com.lambdaworks.redis.cluster.api.rx.RedisAdvancedClusterReactiveCommands; +import com.lambdaworks.redis.cluster.api.reactive.RedisAdvancedClusterReactiveCommands; import com.lambdaworks.redis.cluster.api.sync.RedisAdvancedClusterCommands; import com.lambdaworks.redis.cluster.models.partitions.RedisClusterNode; -import rx.Single; + +import reactor.core.publisher.Mono; @FixMethodOrder(MethodSorters.NAME_ASCENDING) @SuppressWarnings("unchecked") -public class RedisRxClusterClientTest extends AbstractClusterTest { +public class RedisReactiveClusterClientTest extends AbstractClusterTest { protected static RedisClient client; protected StatefulRedisClusterConnection connection; protected RedisAdvancedClusterCommands sync; - protected RedisAdvancedClusterReactiveCommands rx; + protected RedisAdvancedClusterReactiveCommands reactive; @BeforeClass public static void setupClient() throws Exception { setupClusterClient(); client = RedisClient.create(TestClientResources.get(), RedisURI.Builder.redis(host, port1).build()); - clusterClient = RedisClusterClient.create(TestClientResources.get(), Collections.singletonList(RedisURI.Builder.redis(host, port1).build())); + clusterClient = RedisClusterClient.create(TestClientResources.get(), + Collections.singletonList(RedisURI.Builder.redis(host, port1).build())); } @AfterClass @@ -59,7 +54,7 @@ public void before() throws Exception { clusterClient.reloadPartitions(); connection = clusterClient.connect(); sync = connection.sync(); - rx = connection.reactive(); + reactive = connection.reactive(); } @After @@ -70,10 +65,10 @@ public void after() throws Exception { @Test public void testClusterCommandRedirection() throws Exception { // Command on node within the default connection - assertThat(block(rx.set(KEY_B, "myValue1"))).isEqualTo("OK"); + assertThat(block(reactive.set(KEY_B, "myValue1"))).isEqualTo("OK"); // gets redirection to node 3 - assertThat(block(rx.set(KEY_A, "myValue1"))).isEqualTo("OK"); + assertThat(block(reactive.set(KEY_A, "myValue1"))).isEqualTo("OK"); } @Test @@ -82,10 +77,10 @@ public void getKeysInSlot() throws Exception { sync.set(KEY_A, value); sync.set(KEY_B, value); - List keysA = block(rx.clusterGetKeysInSlot(SLOT_A, 10).toList()); + List keysA = block(reactive.clusterGetKeysInSlot(SLOT_A, 10).collectList()); assertThat(keysA).isEqualTo(Collections.singletonList(KEY_A)); - List keysB = block(rx.clusterGetKeysInSlot(SLOT_B, 10).toList()); + List keysB = block(reactive.clusterGetKeysInSlot(SLOT_B, 10).collectList()); assertThat(keysB).isEqualTo(Collections.singletonList(KEY_B)); } @@ -95,49 +90,45 @@ public void countKeysInSlot() throws Exception { sync.set(KEY_A, value); sync.set(KEY_B, value); - Long result = block(rx.clusterCountKeysInSlot(SLOT_A)); + Long result = block(reactive.clusterCountKeysInSlot(SLOT_A)); assertThat(result).isEqualTo(1L); - result = block(rx.clusterCountKeysInSlot(SLOT_B)); + result = block(reactive.clusterCountKeysInSlot(SLOT_B)); assertThat(result).isEqualTo(1L); int slotZZZ = SlotHash.getSlot("ZZZ".getBytes()); - result = block(rx.clusterCountKeysInSlot(slotZZZ)); + result = block(reactive.clusterCountKeysInSlot(slotZZZ)); assertThat(result).isEqualTo(0L); } @Test public void testClusterCountFailureReports() throws Exception { RedisClusterNode ownPartition = getOwnPartition(sync); - assertThat(block(rx.clusterCountFailureReports(ownPartition.getNodeId()))).isGreaterThanOrEqualTo(0); + assertThat(block(reactive.clusterCountFailureReports(ownPartition.getNodeId()))).isGreaterThanOrEqualTo(0); } @Test public void testClusterKeyslot() throws Exception { - assertThat(block(rx.clusterKeyslot(KEY_A))).isEqualTo(SLOT_A); + assertThat(block(reactive.clusterKeyslot(KEY_A))).isEqualTo(SLOT_A); assertThat(SlotHash.getSlot(KEY_A)).isEqualTo(SLOT_A); } @Test public void testClusterSaveconfig() throws Exception { - assertThat(block(rx.clusterSaveconfig())).isEqualTo("OK"); + assertThat(block(reactive.clusterSaveconfig())).isEqualTo("OK"); } @Test public void testClusterSetConfigEpoch() throws Exception { try { - block(rx.clusterSetConfigEpoch(1L)); + block(reactive.clusterSetConfigEpoch(1L)); } catch (RedisException e) { assertThat(e).hasMessageContaining("ERR The user can assign a config epoch only"); } } - private T block(Observable observable) { - return observable.toBlocking().single(); - } - - private T block(Single observable) { - return observable.toBlocking().value(); + private T block(Mono mono) { + return mono.block(); } } diff --git a/src/test/java/com/lambdaworks/redis/cluster/commands/CustomClusterCommandTest.java b/src/test/java/com/lambdaworks/redis/cluster/commands/CustomClusterCommandTest.java index d0da760ad7..aa1283f099 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/commands/CustomClusterCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/commands/CustomClusterCommandTest.java @@ -19,9 +19,6 @@ import com.lambdaworks.redis.output.StatusOutput; import com.lambdaworks.redis.protocol.*; -import rx.Observable; -import rx.Single; - /** * @author Mark Paluch */ @@ -96,19 +93,6 @@ public void standaloneFireAndForget() throws Exception { } - @Test - public void standaloneReactivePing() throws Exception { - - RedisCommand command = new Command<>(CustomCommandTest.MyCommands.PING, - new StatusOutput<>(new Utf8StringCodec()), null); - ReactiveCommandDispatcher dispatcher = new ReactiveCommandDispatcher<>(command, - redisClusterConnection, false); - - String result = Single.create(dispatcher.getSingleSubscriber()).toBlocking().value(); - - assertThat(result).isEqualTo("PONG"); - } - public enum MyCommands implements ProtocolKeyword { PING, SET, INFO; diff --git a/src/test/java/com/lambdaworks/redis/cluster/commands/rx/HashClusterRxCommandTest.java b/src/test/java/com/lambdaworks/redis/cluster/commands/reactive/HashClusterReactiveCommandTest.java similarity index 82% rename from src/test/java/com/lambdaworks/redis/cluster/commands/rx/HashClusterRxCommandTest.java rename to src/test/java/com/lambdaworks/redis/cluster/commands/reactive/HashClusterReactiveCommandTest.java index bdbcd39d3e..d6f2d98be3 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/commands/rx/HashClusterRxCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/commands/reactive/HashClusterReactiveCommandTest.java @@ -1,4 +1,4 @@ -package com.lambdaworks.redis.cluster.commands.rx; +package com.lambdaworks.redis.cluster.commands.reactive; import org.junit.AfterClass; import org.junit.Before; @@ -12,12 +12,12 @@ import com.lambdaworks.redis.cluster.RedisClusterClient; import com.lambdaworks.redis.cluster.api.StatefulRedisClusterConnection; import com.lambdaworks.redis.commands.HashCommandTest; -import com.lambdaworks.util.RxSyncInvocationHandler; +import com.lambdaworks.util.ReactiveSyncInvocationHandler; /** * @author Mark Paluch */ -public class HashClusterRxCommandTest extends HashCommandTest { +public class HashClusterReactiveCommandTest extends HashCommandTest { private static RedisClusterClient redisClusterClient; private StatefulRedisClusterConnection clusterConnection; @@ -41,6 +41,6 @@ public void openConnection() throws Exception { @Override protected RedisCommands connect() { clusterConnection = redisClusterClient.connect(); - return RxSyncInvocationHandler.sync(redisClusterClient.connect()); + return ReactiveSyncInvocationHandler.sync(redisClusterClient.connect()); } } diff --git a/src/test/java/com/lambdaworks/redis/cluster/commands/rx/KeyClusterRxCommandTest.java b/src/test/java/com/lambdaworks/redis/cluster/commands/reactive/KeyClusterReativeCommandTest.java similarity index 83% rename from src/test/java/com/lambdaworks/redis/cluster/commands/rx/KeyClusterRxCommandTest.java rename to src/test/java/com/lambdaworks/redis/cluster/commands/reactive/KeyClusterReativeCommandTest.java index dc89c09554..aa3f4c15b1 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/commands/rx/KeyClusterRxCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/commands/reactive/KeyClusterReativeCommandTest.java @@ -1,7 +1,7 @@ -package com.lambdaworks.redis.cluster.commands.rx; +package com.lambdaworks.redis.cluster.commands.reactive; import com.lambdaworks.TestClientResources; -import com.lambdaworks.util.RxSyncInvocationHandler; +import com.lambdaworks.util.ReactiveSyncInvocationHandler; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; @@ -18,7 +18,7 @@ /** * @author Mark Paluch */ -public class KeyClusterRxCommandTest extends KeyClusterCommandTest { +public class KeyClusterReativeCommandTest extends KeyClusterCommandTest { private static RedisClusterClient redisClusterClient; private StatefulRedisClusterConnection clusterConnection; @@ -41,7 +41,7 @@ public void openConnection() throws Exception { protected RedisCommands connect() { clusterConnection = redisClusterClient.connect(); - return RxSyncInvocationHandler.sync(redisClusterClient.connect()); + return ReactiveSyncInvocationHandler.sync(redisClusterClient.connect()); } } diff --git a/src/test/java/com/lambdaworks/redis/cluster/commands/rx/ListClusterRxCommandTest.java b/src/test/java/com/lambdaworks/redis/cluster/commands/reactive/ListClusterRxCommandTest.java similarity index 93% rename from src/test/java/com/lambdaworks/redis/cluster/commands/rx/ListClusterRxCommandTest.java rename to src/test/java/com/lambdaworks/redis/cluster/commands/reactive/ListClusterRxCommandTest.java index 340526ec1a..a1d265693a 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/commands/rx/ListClusterRxCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/commands/reactive/ListClusterRxCommandTest.java @@ -1,6 +1,5 @@ -package com.lambdaworks.redis.cluster.commands.rx; +package com.lambdaworks.redis.cluster.commands.reactive; -import org.assertj.core.api.Assertions; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; @@ -14,7 +13,7 @@ import com.lambdaworks.redis.cluster.RedisClusterClient; import com.lambdaworks.redis.cluster.api.StatefulRedisClusterConnection; import com.lambdaworks.redis.commands.ListCommandTest; -import com.lambdaworks.util.RxSyncInvocationHandler; +import com.lambdaworks.util.ReactiveSyncInvocationHandler; import static org.assertj.core.api.Assertions.assertThat; @@ -44,7 +43,7 @@ public void openConnection() throws Exception { @Override protected RedisCommands connect() { clusterConnection = redisClusterClient.connect(); - return RxSyncInvocationHandler.sync(redisClusterClient.connect()); + return ReactiveSyncInvocationHandler.sync(redisClusterClient.connect()); } // re-implementation because keys have to be on the same slot diff --git a/src/test/java/com/lambdaworks/redis/cluster/commands/rx/StringClusterRxCommandTest.java b/src/test/java/com/lambdaworks/redis/cluster/commands/reactive/StringClusterReactiveCommandTest.java similarity index 80% rename from src/test/java/com/lambdaworks/redis/cluster/commands/rx/StringClusterRxCommandTest.java rename to src/test/java/com/lambdaworks/redis/cluster/commands/reactive/StringClusterReactiveCommandTest.java index 127a8938a7..e44abe0626 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/commands/rx/StringClusterRxCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/commands/reactive/StringClusterReactiveCommandTest.java @@ -1,4 +1,4 @@ -package com.lambdaworks.redis.cluster.commands.rx; +package com.lambdaworks.redis.cluster.commands.reactive; import static org.assertj.core.api.Assertions.assertThat; @@ -18,16 +18,16 @@ import com.lambdaworks.redis.cluster.ClusterTestUtil; import com.lambdaworks.redis.cluster.RedisClusterClient; import com.lambdaworks.redis.cluster.api.StatefulRedisClusterConnection; -import com.lambdaworks.redis.cluster.api.rx.RedisAdvancedClusterReactiveCommands; +import com.lambdaworks.redis.cluster.api.reactive.RedisAdvancedClusterReactiveCommands; import com.lambdaworks.redis.commands.StringCommandTest; -import com.lambdaworks.util.RxSyncInvocationHandler; +import com.lambdaworks.util.ReactiveSyncInvocationHandler; -import rx.Observable; +import reactor.core.publisher.Flux; /** * @author Mark Paluch */ -public class StringClusterRxCommandTest extends StringCommandTest { +public class StringClusterReactiveCommandTest extends StringCommandTest { private static RedisClusterClient redisClusterClient; private StatefulRedisClusterConnection clusterConnection; @@ -50,7 +50,7 @@ public void openConnection() throws Exception { @Override protected RedisCommands connect() { clusterConnection = redisClusterClient.connect(); - return RxSyncInvocationHandler.sync(redisClusterClient.connect()); + return ReactiveSyncInvocationHandler.sync(redisClusterClient.connect()); } @Test @@ -74,8 +74,8 @@ public void mget() throws Exception { RedisAdvancedClusterReactiveCommands reactive = clusterConnection.reactive(); - Observable> mget = reactive.mget(key, "key1", "key2"); - KeyValue first = mget.toBlocking().first(); + Flux> mget = reactive.mget(key, "key1", "key2"); + KeyValue first = mget.next().block(); assertThat(first).isEqualTo(KeyValue.just(key, value)); } diff --git a/src/test/java/com/lambdaworks/redis/commands/CustomCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/CustomCommandTest.java index 6299f62558..e92e3c5a3c 100644 --- a/src/test/java/com/lambdaworks/redis/commands/CustomCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/CustomCommandTest.java @@ -3,22 +3,16 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assume.assumeTrue; -import java.util.List; - -import com.lambdaworks.redis.TransactionResult; import org.junit.Test; import com.lambdaworks.redis.AbstractRedisClientTest; -import com.lambdaworks.redis.ReactiveCommandDispatcher; import com.lambdaworks.redis.RedisCommandExecutionException; +import com.lambdaworks.redis.TransactionResult; import com.lambdaworks.redis.api.StatefulRedisConnection; -import com.lambdaworks.redis.cluster.api.StatefulRedisClusterConnection; import com.lambdaworks.redis.codec.Utf8StringCodec; import com.lambdaworks.redis.output.StatusOutput; import com.lambdaworks.redis.protocol.*; -import rx.Observable; - /** * @author Mark Paluch */ @@ -85,19 +79,6 @@ public void standaloneFireAndForget() throws Exception { } - @Test - public void standaloneReactivePing() throws Exception { - - RedisCommand command = new Command<>(MyCommands.PING, new StatusOutput<>(new Utf8StringCodec()), - null); - ReactiveCommandDispatcher dispatcher = new ReactiveCommandDispatcher<>(command, - getStandaloneConnection(), false); - - String result = Observable.create(dispatcher.getObservableSubscriber()).toBlocking().first(); - - assertThat(result).isEqualTo("PONG"); - } - private StatefulRedisConnection getStandaloneConnection() { assumeTrue(redis.getStatefulConnection() instanceof StatefulRedisConnection); diff --git a/src/test/java/com/lambdaworks/redis/commands/GeoCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/GeoCommandTest.java index 43b2c813fa..c79cbe8f38 100644 --- a/src/test/java/com/lambdaworks/redis/commands/GeoCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/GeoCommandTest.java @@ -122,12 +122,12 @@ public void geopos() throws Exception { prepareGeo(); - List geopos = redis.geopos(key, "Weinheim", "foobar", "Bahn"); + List> geopos = redis.geopos(key, "Weinheim", "foobar", "Bahn"); assertThat(geopos).hasSize(3); - assertThat(geopos.get(0).x.doubleValue()).isEqualTo(8.6638, offset(0.001)); - assertThat(geopos.get(1)).isNull(); - assertThat(geopos.get(2)).isNotNull(); + assertThat(geopos.get(0).getValue().x.doubleValue()).isEqualTo(8.6638, offset(0.001)); + assertThat(geopos.get(1).hasValue()).isFalse(); + assertThat(geopos.get(2).hasValue()).isTrue(); } @Test @@ -138,12 +138,12 @@ public void geoposWithTransaction() throws Exception { redis.multi(); redis.geopos(key, "Weinheim", "foobar", "Bahn"); redis.geopos(key, "Weinheim", "foobar", "Bahn"); - List geopos = (List) redis.exec().get(1); + List> geopos = redis.exec().get(1); assertThat(geopos).hasSize(3); - assertThat(geopos.get(0).x.doubleValue()).isEqualTo(8.6638, offset(0.001)); - assertThat(geopos.get(1)).isNull(); - assertThat(geopos.get(2)).isNotNull(); + assertThat(geopos.get(0).getValue().x.doubleValue()).isEqualTo(8.6638, offset(0.001)); + assertThat(geopos.get(1).hasValue()).isFalse(); + assertThat(geopos.get(2).hasValue()).isTrue(); } @Test @@ -219,9 +219,9 @@ public void geohash() throws Exception { prepareGeo(); - List geohash = redis.geohash(key, "Weinheim", "Bahn", "dunno"); + List> geohash = redis.geohash(key, "Weinheim", "Bahn", "dunno"); - assertThat(geohash).containsSequence("u0y1v0kffz0", "u0y1vhvuvm0", null); + assertThat(geohash).containsSequence(Value.just("u0y1v0kffz0"), Value.just("u0y1vhvuvm0"), Value.empty()); } @Test @@ -229,7 +229,7 @@ public void geohashUnknownKey() throws Exception { prepareGeo(); - List geohash = redis.geohash("dunno", "member"); + List> geohash = redis.geohash("dunno", "member"); assertThat(geohash).isEmpty(); } @@ -244,9 +244,9 @@ public void geohashWithTransaction() throws Exception { redis.geohash(key, "Weinheim", "Bahn", "dunno"); TransactionResult exec = redis.exec(); - List geohash = exec.get(1); + List> geohash = exec.get(1); - assertThat(geohash).containsSequence("u0y1v0kffz0", "u0y1vhvuvm0", null); + assertThat(geohash).containsSequence(Value.just("u0y1v0kffz0"), Value.just("u0y1vhvuvm0"), Value.empty()); } @Test diff --git a/src/test/java/com/lambdaworks/redis/commands/reactive/BitReactiveCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/reactive/BitReactiveCommandTest.java new file mode 100644 index 0000000000..8a17a22feb --- /dev/null +++ b/src/test/java/com/lambdaworks/redis/commands/reactive/BitReactiveCommandTest.java @@ -0,0 +1,17 @@ +package com.lambdaworks.redis.commands.reactive; + +import com.lambdaworks.redis.api.sync.RedisCommands; +import com.lambdaworks.redis.commands.BitCommandTest; +import com.lambdaworks.util.ReactiveSyncInvocationHandler; + +/** + * @author Mark Paluch + */ +public class BitReactiveCommandTest extends BitCommandTest { + @Override + protected RedisCommands connect() { + bitstring = ReactiveSyncInvocationHandler.sync(client.connect(new BitStringCodec())); + return ReactiveSyncInvocationHandler.sync(client.connect()); + } + +} diff --git a/src/test/java/com/lambdaworks/redis/commands/reactive/CustomReactiveCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/reactive/CustomReactiveCommandTest.java new file mode 100644 index 0000000000..4dcb02ab84 --- /dev/null +++ b/src/test/java/com/lambdaworks/redis/commands/reactive/CustomReactiveCommandTest.java @@ -0,0 +1,57 @@ +package com.lambdaworks.redis.commands.reactive; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.List; + +import org.junit.Test; + +import com.lambdaworks.redis.api.reactive.RedisReactiveCommands; +import com.lambdaworks.redis.api.sync.RedisCommands; +import com.lambdaworks.redis.commands.CustomCommandTest; +import com.lambdaworks.redis.output.ValueListOutput; +import com.lambdaworks.redis.output.ValueOutput; +import com.lambdaworks.redis.protocol.CommandArgs; +import com.lambdaworks.redis.protocol.CommandType; +import com.lambdaworks.util.ReactiveSyncInvocationHandler; + +import reactor.core.publisher.Flux; +import reactor.test.TestSubscriber; + +/** + * @author Mark Paluch + */ +public class CustomReactiveCommandTest extends CustomCommandTest { + + @Override + protected RedisCommands connect() { + return ReactiveSyncInvocationHandler.sync(client.connect()); + } + + @Test + public void dispatchGetAndSet() throws Exception { + + redis.set(key, value); + RedisReactiveCommands reactive = redis.getStatefulConnection().reactive(); + + Flux flux = reactive.dispatch(CommandType.GET, new ValueOutput<>(utf8StringCodec), + new CommandArgs<>(utf8StringCodec).addKey(key)); + + TestSubscriber testSubscriber = TestSubscriber.subscribe(flux); + testSubscriber.awaitAndAssertNextValues(value).assertComplete().assertNoError(); + } + + @Test + public void dispatchList() throws Exception { + + redis.rpush(key, "a", "b", "c"); + RedisReactiveCommands reactive = redis.getStatefulConnection().reactive(); + + Flux flux = reactive.dispatch(CommandType.LRANGE, new ValueListOutput<>(utf8StringCodec), + new CommandArgs<>(utf8StringCodec).addKey(key).add(0).add(-1)); + + TestSubscriber testSubscriber = TestSubscriber.subscribe(flux); + testSubscriber.awaitAndAssertNextValues("a", "b", "c").assertComplete().assertNoError(); + } + +} diff --git a/src/test/java/com/lambdaworks/redis/commands/reactive/GeoReactiveCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/reactive/GeoReactiveCommandTest.java new file mode 100644 index 0000000000..2ddbdbbc66 --- /dev/null +++ b/src/test/java/com/lambdaworks/redis/commands/reactive/GeoReactiveCommandTest.java @@ -0,0 +1,13 @@ +package com.lambdaworks.redis.commands.reactive; + +import com.lambdaworks.redis.api.sync.RedisCommands; +import com.lambdaworks.redis.commands.GeoCommandTest; +import com.lambdaworks.util.ReactiveSyncInvocationHandler; + +public class GeoReactiveCommandTest extends GeoCommandTest { + + @Override + protected RedisCommands connect() { + return ReactiveSyncInvocationHandler.sync(client.connect()); + } +} diff --git a/src/test/java/com/lambdaworks/redis/commands/reactive/HLLReactiveCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/reactive/HLLReactiveCommandTest.java new file mode 100644 index 0000000000..cb54b23aee --- /dev/null +++ b/src/test/java/com/lambdaworks/redis/commands/reactive/HLLReactiveCommandTest.java @@ -0,0 +1,13 @@ +package com.lambdaworks.redis.commands.reactive; + +import com.lambdaworks.redis.api.sync.RedisCommands; +import com.lambdaworks.redis.commands.HLLCommandTest; +import com.lambdaworks.util.ReactiveSyncInvocationHandler; + +public class HLLReactiveCommandTest extends HLLCommandTest { + + @Override + protected RedisCommands connect() { + return ReactiveSyncInvocationHandler.sync(client.connect()); + } +} diff --git a/src/test/java/com/lambdaworks/redis/commands/reactive/HashReactiveCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/reactive/HashReactiveCommandTest.java new file mode 100644 index 0000000000..492f7cf1b8 --- /dev/null +++ b/src/test/java/com/lambdaworks/redis/commands/reactive/HashReactiveCommandTest.java @@ -0,0 +1,14 @@ +package com.lambdaworks.redis.commands.reactive; + +import com.lambdaworks.redis.api.sync.RedisCommands; +import com.lambdaworks.redis.commands.HashCommandTest; +import com.lambdaworks.util.ReactiveSyncInvocationHandler; + +public class HashReactiveCommandTest extends HashCommandTest { + + @Override + protected RedisCommands connect() { + return ReactiveSyncInvocationHandler.sync(client.connect()); + } + +} diff --git a/src/test/java/com/lambdaworks/redis/commands/reactive/KeyReactiveCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/reactive/KeyReactiveCommandTest.java new file mode 100644 index 0000000000..5258ccc205 --- /dev/null +++ b/src/test/java/com/lambdaworks/redis/commands/reactive/KeyReactiveCommandTest.java @@ -0,0 +1,12 @@ +package com.lambdaworks.redis.commands.reactive; + +import com.lambdaworks.redis.api.sync.RedisCommands; +import com.lambdaworks.redis.commands.KeyCommandTest; +import com.lambdaworks.util.ReactiveSyncInvocationHandler; + +public class KeyReactiveCommandTest extends KeyCommandTest { + @Override + protected RedisCommands connect() { + return ReactiveSyncInvocationHandler.sync(client.connect()); + } +} diff --git a/src/test/java/com/lambdaworks/redis/commands/reactive/ListReactiveCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/reactive/ListReactiveCommandTest.java new file mode 100644 index 0000000000..08aace213c --- /dev/null +++ b/src/test/java/com/lambdaworks/redis/commands/reactive/ListReactiveCommandTest.java @@ -0,0 +1,12 @@ +package com.lambdaworks.redis.commands.reactive; + +import com.lambdaworks.redis.api.sync.RedisCommands; +import com.lambdaworks.redis.commands.ListCommandTest; +import com.lambdaworks.util.ReactiveSyncInvocationHandler; + +public class ListReactiveCommandTest extends ListCommandTest { + @Override + protected RedisCommands connect() { + return ReactiveSyncInvocationHandler.sync(client.connect()); + } +} diff --git a/src/test/java/com/lambdaworks/redis/commands/reactive/NumericReactiveCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/reactive/NumericReactiveCommandTest.java new file mode 100644 index 0000000000..93b4f43c7f --- /dev/null +++ b/src/test/java/com/lambdaworks/redis/commands/reactive/NumericReactiveCommandTest.java @@ -0,0 +1,12 @@ +package com.lambdaworks.redis.commands.reactive; + +import com.lambdaworks.redis.api.sync.RedisCommands; +import com.lambdaworks.redis.commands.NumericCommandTest; +import com.lambdaworks.util.ReactiveSyncInvocationHandler; + +public class NumericReactiveCommandTest extends NumericCommandTest { + @Override + protected RedisCommands connect() { + return ReactiveSyncInvocationHandler.sync(client.connect()); + } +} diff --git a/src/test/java/com/lambdaworks/redis/commands/reactive/ScriptingReactiveCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/reactive/ScriptingReactiveCommandTest.java new file mode 100644 index 0000000000..92546430af --- /dev/null +++ b/src/test/java/com/lambdaworks/redis/commands/reactive/ScriptingReactiveCommandTest.java @@ -0,0 +1,14 @@ +package com.lambdaworks.redis.commands.reactive; + +import com.lambdaworks.redis.api.sync.RedisCommands; +import com.lambdaworks.redis.commands.ScriptingCommandTest; +import com.lambdaworks.util.ReactiveSyncInvocationHandler; + +public class ScriptingReactiveCommandTest extends ScriptingCommandTest { + + + @Override + protected RedisCommands connect() { + return ReactiveSyncInvocationHandler.sync(client.connect()); + } +} diff --git a/src/test/java/com/lambdaworks/redis/commands/rx/ServerRxCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/reactive/ServerReactiveCommandTest.java similarity index 82% rename from src/test/java/com/lambdaworks/redis/commands/rx/ServerRxCommandTest.java rename to src/test/java/com/lambdaworks/redis/commands/reactive/ServerReactiveCommandTest.java index f90eef80ca..150d40a2b6 100644 --- a/src/test/java/com/lambdaworks/redis/commands/rx/ServerRxCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/reactive/ServerReactiveCommandTest.java @@ -1,16 +1,16 @@ -package com.lambdaworks.redis.commands.rx; +package com.lambdaworks.redis.commands.reactive; import static org.assertj.core.api.Assertions.assertThat; -import com.lambdaworks.util.RxSyncInvocationHandler; +import com.lambdaworks.util.ReactiveSyncInvocationHandler; import org.junit.Before; import org.junit.Test; -import com.lambdaworks.redis.api.rx.RedisReactiveCommands; +import com.lambdaworks.redis.api.reactive.RedisReactiveCommands; import com.lambdaworks.redis.api.sync.RedisCommands; import com.lambdaworks.redis.commands.ServerCommandTest; -public class ServerRxCommandTest extends ServerCommandTest { +public class ServerReactiveCommandTest extends ServerCommandTest { private RedisReactiveCommands reactive; @@ -22,7 +22,7 @@ public void openConnection() throws Exception { @Override protected RedisCommands connect() { - return RxSyncInvocationHandler.sync(client.connect()); + return ReactiveSyncInvocationHandler.sync(client.connect()); } /** diff --git a/src/test/java/com/lambdaworks/redis/commands/reactive/SetReactiveCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/reactive/SetReactiveCommandTest.java new file mode 100644 index 0000000000..5b588e81f7 --- /dev/null +++ b/src/test/java/com/lambdaworks/redis/commands/reactive/SetReactiveCommandTest.java @@ -0,0 +1,14 @@ +package com.lambdaworks.redis.commands.reactive; + +import com.lambdaworks.redis.api.sync.RedisCommands; +import com.lambdaworks.redis.commands.SetCommandTest; +import com.lambdaworks.util.ReactiveSyncInvocationHandler; + +public class SetReactiveCommandTest extends SetCommandTest { + + @Override + protected RedisCommands connect() { + return ReactiveSyncInvocationHandler.sync(client.connect()); + } + +} diff --git a/src/test/java/com/lambdaworks/redis/commands/reactive/SortReactiveCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/reactive/SortReactiveCommandTest.java new file mode 100644 index 0000000000..87127a1f49 --- /dev/null +++ b/src/test/java/com/lambdaworks/redis/commands/reactive/SortReactiveCommandTest.java @@ -0,0 +1,12 @@ +package com.lambdaworks.redis.commands.reactive; + +import com.lambdaworks.redis.api.sync.RedisCommands; +import com.lambdaworks.redis.commands.SortCommandTest; +import com.lambdaworks.util.ReactiveSyncInvocationHandler; + +public class SortReactiveCommandTest extends SortCommandTest { + @Override + protected RedisCommands connect() { + return ReactiveSyncInvocationHandler.sync(client.connect()); + } +} diff --git a/src/test/java/com/lambdaworks/redis/commands/reactive/SortedSetReactiveCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/reactive/SortedSetReactiveCommandTest.java new file mode 100644 index 0000000000..68b190e01a --- /dev/null +++ b/src/test/java/com/lambdaworks/redis/commands/reactive/SortedSetReactiveCommandTest.java @@ -0,0 +1,12 @@ +package com.lambdaworks.redis.commands.reactive; + +import com.lambdaworks.redis.api.sync.RedisCommands; +import com.lambdaworks.redis.commands.SortedSetCommandTest; +import com.lambdaworks.util.ReactiveSyncInvocationHandler; + +public class SortedSetReactiveCommandTest extends SortedSetCommandTest { + @Override + protected RedisCommands connect() { + return ReactiveSyncInvocationHandler.sync(client.connect()); + } +} diff --git a/src/test/java/com/lambdaworks/redis/commands/rx/StringRxCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/reactive/StringReactiveCommandTest.java similarity index 63% rename from src/test/java/com/lambdaworks/redis/commands/rx/StringRxCommandTest.java rename to src/test/java/com/lambdaworks/redis/commands/reactive/StringReactiveCommandTest.java index 0392f10e40..e3c69eed09 100644 --- a/src/test/java/com/lambdaworks/redis/commands/rx/StringRxCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/reactive/StringReactiveCommandTest.java @@ -1,21 +1,20 @@ -package com.lambdaworks.redis.commands.rx; +package com.lambdaworks.redis.commands.reactive; import static org.assertj.core.api.Assertions.assertThat; import com.lambdaworks.redis.KeyValue; -import com.lambdaworks.util.RxSyncInvocationHandler; +import com.lambdaworks.util.ReactiveSyncInvocationHandler; import org.junit.Test; import com.lambdaworks.redis.api.StatefulRedisConnection; import com.lambdaworks.redis.api.sync.RedisCommands; import com.lambdaworks.redis.commands.StringCommandTest; +import reactor.core.publisher.Flux; -import rx.Observable; - -public class StringRxCommandTest extends StringCommandTest { +public class StringReactiveCommandTest extends StringCommandTest { @Override protected RedisCommands connect() { - return RxSyncInvocationHandler.sync(client.connect()); + return ReactiveSyncInvocationHandler.sync(client.connect()); } @Test @@ -27,8 +26,8 @@ public void mget() throws Exception { connection.sync().set("key1", value); connection.sync().set("key2", value); - Observable> mget = connection.reactive().mget(key, "key1", "key2"); - KeyValue first = mget.toBlocking().first(); + Flux> mget = connection.reactive().mget(key, "key1", "key2"); + KeyValue first = mget.next().block(); assertThat(first).isEqualTo(KeyValue.just(key, value)); connection.close(); @@ -41,8 +40,8 @@ public void mgetEmpty() throws Exception { connection.sync().set(key, value); - Observable> mget = connection.reactive().mget("unknown"); - KeyValue first = mget.toBlocking().first(); + Flux> mget = connection.reactive().mget("unknown"); + KeyValue first = mget.next().block(); assertThat(first).isEqualTo(KeyValue.empty("unknown")); connection.close(); diff --git a/src/test/java/com/lambdaworks/redis/commands/rx/TransactionRxCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/reactive/TransactionReactiveCommandTest.java similarity index 66% rename from src/test/java/com/lambdaworks/redis/commands/rx/TransactionRxCommandTest.java rename to src/test/java/com/lambdaworks/redis/commands/reactive/TransactionReactiveCommandTest.java index 6eebbd37e7..a949512c4d 100644 --- a/src/test/java/com/lambdaworks/redis/commands/rx/TransactionRxCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/reactive/TransactionReactiveCommandTest.java @@ -1,11 +1,9 @@ -package com.lambdaworks.redis.commands.rx; +package com.lambdaworks.redis.commands.reactive; import static org.assertj.core.api.Assertions.assertThat; -import java.util.Iterator; import java.util.List; -import com.lambdaworks.redis.TransactionResult; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -13,24 +11,24 @@ import com.lambdaworks.redis.ClientOptions; import com.lambdaworks.redis.KeyValue; import com.lambdaworks.redis.RedisException; -import com.lambdaworks.redis.api.rx.RedisReactiveCommands; +import com.lambdaworks.redis.TransactionResult; +import com.lambdaworks.redis.api.StatefulRedisConnection; +import com.lambdaworks.redis.api.reactive.RedisReactiveCommands; import com.lambdaworks.redis.api.sync.RedisCommands; import com.lambdaworks.redis.commands.TransactionCommandTest; -import com.lambdaworks.redis.internal.LettuceLists; -import com.lambdaworks.util.RxSyncInvocationHandler; +import com.lambdaworks.util.ReactiveSyncInvocationHandler; -import rx.Observable; -import rx.Single; -import rx.observables.BlockingObservable; -import rx.observers.TestSubscriber; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import reactor.test.TestSubscriber; -public class TransactionRxCommandTest extends TransactionCommandTest { +public class TransactionReactiveCommandTest extends TransactionCommandTest { private RedisReactiveCommands commands; @Override protected RedisCommands connect() { - return RxSyncInvocationHandler.sync(client.connect()); + return ReactiveSyncInvocationHandler.sync(client.connect()); } @Before @@ -58,6 +56,25 @@ public void discard() throws Exception { assertThat(block(commands.get(key))).isNull(); } + @Test + public void watchRollback() throws Exception { + + StatefulRedisConnection otherConnection = client.connect(); + + otherConnection.sync().set(key, value); + + assertThat(block(commands.watch(key))).isEqualTo("OK"); + assertThat(block(commands.multi())).isEqualTo("OK"); + + commands.set(key, value); + + otherConnection.sync().del(key); + + TransactionResult transactionResult = block(commands.exec()); + assertThat(transactionResult).isNotNull(); + assertThat(transactionResult.wasRolledBack()).isTrue(); + } + @Test public void execSingular() throws Exception { @@ -83,7 +100,7 @@ public void errorInMulti() throws Exception { } @Test - public void resultOfMultiIsContainedInCommandObservables() throws Exception { + public void resultOfMultiIsContainedInCommandFlux() throws Exception { TestSubscriber set1 = TestSubscriber.create(); TestSubscriber set2 = TestSubscriber.create(); @@ -98,12 +115,12 @@ public void resultOfMultiIsContainedInCommandObservables() throws Exception { commands.llen("something").subscribe(llen); commands.exec().subscribe(exec); - exec.awaitTerminalEvent(); + exec.await(); - set1.assertValue("OK"); - set2.assertValue("OK"); + set1.awaitAndAssertNextValues("OK"); + set2.awaitAndAssertNextValues("OK"); mget.assertValues(KeyValue.just("key1", "value1"), KeyValue.just("key2", "value2")); - llen.assertValue(0L); + llen.awaitAndAssertNextValues(0L); } @Test @@ -118,28 +135,16 @@ public void resultOfMultiIsContainedInExecObservable() throws Exception { commands.llen("something").subscribe(); commands.exec().subscribe(exec); - exec.awaitTerminalEvent(); - - assertThat(exec.getOnNextEvents().get(0)).hasSize(4).containsExactly("OK", "OK", - list(kv("key1", "value1"), kv("key2", "value2")), 0L); - } - - protected T first(Observable observable) { - BlockingObservable blocking = observable.toBlocking(); - Iterator iterator = blocking.getIterator(); - if (iterator.hasNext()) { - return iterator.next(); - } - return null; + exec.awaitAndAssertNextValuesWith(object -> { + assertThat(object).hasSize(4).containsExactly("OK", "OK", list(kv("key1", "value1"), kv("key2", "value2")), 0L); + }).assertNoError(); } - protected T block(Single single) { - return single.toBlocking().value(); + protected T block(Mono mono) { + return mono.block(); } - protected List all(Observable observable) { - BlockingObservable blocking = observable.toBlocking(); - Iterator iterator = blocking.getIterator(); - return LettuceLists.newList(iterator); + protected List all(Flux flux) { + return flux.collectList().block(); } } diff --git a/src/test/java/com/lambdaworks/redis/commands/rx/BitRxCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/rx/BitRxCommandTest.java deleted file mode 100644 index 4bcf9c148d..0000000000 --- a/src/test/java/com/lambdaworks/redis/commands/rx/BitRxCommandTest.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.lambdaworks.redis.commands.rx; - -import com.lambdaworks.redis.api.sync.RedisCommands; -import com.lambdaworks.redis.commands.BitCommandTest; -import com.lambdaworks.util.RxSyncInvocationHandler; - -/** - * @author Mark Paluch - */ -public class BitRxCommandTest extends BitCommandTest { - @Override - protected RedisCommands connect() { - bitstring = RxSyncInvocationHandler.sync(client.connect(new BitStringCodec())); - return RxSyncInvocationHandler.sync(client.connect()); - } - -} diff --git a/src/test/java/com/lambdaworks/redis/commands/rx/CustomRxCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/rx/CustomRxCommandTest.java deleted file mode 100644 index 5ccbe933c9..0000000000 --- a/src/test/java/com/lambdaworks/redis/commands/rx/CustomRxCommandTest.java +++ /dev/null @@ -1,61 +0,0 @@ -package com.lambdaworks.redis.commands.rx; - -import com.lambdaworks.util.RxSyncInvocationHandler; -import org.junit.Test; - -import com.lambdaworks.redis.api.rx.RedisReactiveCommands; -import com.lambdaworks.redis.api.sync.RedisCommands; -import com.lambdaworks.redis.commands.CustomCommandTest; -import com.lambdaworks.redis.output.ValueListOutput; -import com.lambdaworks.redis.output.ValueOutput; -import com.lambdaworks.redis.protocol.CommandArgs; -import com.lambdaworks.redis.protocol.CommandType; - -import rx.Observable; -import rx.observers.TestSubscriber; - -/** - * @author Mark Paluch - */ -public class CustomRxCommandTest extends CustomCommandTest { - - @Override - protected RedisCommands connect() { - return RxSyncInvocationHandler.sync(client.connect()); - } - - @Test - public void dispatchGetAndSet() throws Exception { - - redis.set(key, value); - RedisReactiveCommands reactive = redis.getStatefulConnection().reactive(); - - Observable observable = reactive.dispatch(CommandType.GET, new ValueOutput<>(utf8StringCodec), - new CommandArgs<>(utf8StringCodec).addKey(key)); - - TestSubscriber testSubscriber = TestSubscriber.create(); - observable.subscribe(testSubscriber); - - testSubscriber.awaitTerminalEvent(); - testSubscriber.assertCompleted(); - testSubscriber.assertValue(value); - } - - @Test - public void dispatchList() throws Exception { - - redis.rpush(key, "a", "b", "c"); - RedisReactiveCommands reactive = redis.getStatefulConnection().reactive(); - - Observable observable = reactive.dispatch(CommandType.LRANGE, new ValueListOutput<>(utf8StringCodec), - new CommandArgs<>(utf8StringCodec).addKey(key).add(0).add(-1)); - - TestSubscriber testSubscriber = TestSubscriber.create(); - observable.subscribe(testSubscriber); - - testSubscriber.awaitTerminalEvent(); - testSubscriber.assertCompleted(); - testSubscriber.assertValues("a", "b", "c"); - } - -} diff --git a/src/test/java/com/lambdaworks/redis/commands/rx/GeoRxCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/rx/GeoRxCommandTest.java deleted file mode 100644 index 685ade80c4..0000000000 --- a/src/test/java/com/lambdaworks/redis/commands/rx/GeoRxCommandTest.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.lambdaworks.redis.commands.rx; - -import com.lambdaworks.redis.api.sync.RedisCommands; -import com.lambdaworks.redis.commands.GeoCommandTest; -import com.lambdaworks.util.RxSyncInvocationHandler; - -public class GeoRxCommandTest extends GeoCommandTest { - - @Override - protected RedisCommands connect() { - return RxSyncInvocationHandler.sync(client.connect()); - } -} diff --git a/src/test/java/com/lambdaworks/redis/commands/rx/HLLRxCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/rx/HLLRxCommandTest.java deleted file mode 100644 index 2b26e3fea9..0000000000 --- a/src/test/java/com/lambdaworks/redis/commands/rx/HLLRxCommandTest.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.lambdaworks.redis.commands.rx; - -import com.lambdaworks.redis.api.sync.RedisCommands; -import com.lambdaworks.redis.commands.HLLCommandTest; -import com.lambdaworks.util.RxSyncInvocationHandler; - -public class HLLRxCommandTest extends HLLCommandTest { - - @Override - protected RedisCommands connect() { - return RxSyncInvocationHandler.sync(client.connect()); - } -} diff --git a/src/test/java/com/lambdaworks/redis/commands/rx/HashRxCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/rx/HashRxCommandTest.java deleted file mode 100644 index a6786af741..0000000000 --- a/src/test/java/com/lambdaworks/redis/commands/rx/HashRxCommandTest.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.lambdaworks.redis.commands.rx; - -import com.lambdaworks.redis.api.sync.RedisCommands; -import com.lambdaworks.redis.commands.HashCommandTest; -import com.lambdaworks.util.RxSyncInvocationHandler; - -public class HashRxCommandTest extends HashCommandTest { - - @Override - protected RedisCommands connect() { - return RxSyncInvocationHandler.sync(client.connect()); - } - -} diff --git a/src/test/java/com/lambdaworks/redis/commands/rx/KeyRxCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/rx/KeyRxCommandTest.java deleted file mode 100644 index 92c51ed297..0000000000 --- a/src/test/java/com/lambdaworks/redis/commands/rx/KeyRxCommandTest.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.lambdaworks.redis.commands.rx; - -import com.lambdaworks.redis.api.sync.RedisCommands; -import com.lambdaworks.redis.commands.KeyCommandTest; -import com.lambdaworks.util.RxSyncInvocationHandler; - -public class KeyRxCommandTest extends KeyCommandTest { - @Override - protected RedisCommands connect() { - return RxSyncInvocationHandler.sync(client.connect()); - } -} diff --git a/src/test/java/com/lambdaworks/redis/commands/rx/ListRxCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/rx/ListRxCommandTest.java deleted file mode 100644 index 7c25c7ce56..0000000000 --- a/src/test/java/com/lambdaworks/redis/commands/rx/ListRxCommandTest.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.lambdaworks.redis.commands.rx; - -import com.lambdaworks.redis.api.sync.RedisCommands; -import com.lambdaworks.redis.commands.ListCommandTest; -import com.lambdaworks.util.RxSyncInvocationHandler; - -public class ListRxCommandTest extends ListCommandTest { - @Override - protected RedisCommands connect() { - return RxSyncInvocationHandler.sync(client.connect()); - } -} diff --git a/src/test/java/com/lambdaworks/redis/commands/rx/NumericRxCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/rx/NumericRxCommandTest.java deleted file mode 100644 index e93c0496c9..0000000000 --- a/src/test/java/com/lambdaworks/redis/commands/rx/NumericRxCommandTest.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.lambdaworks.redis.commands.rx; - -import com.lambdaworks.redis.api.sync.RedisCommands; -import com.lambdaworks.redis.commands.NumericCommandTest; -import com.lambdaworks.util.RxSyncInvocationHandler; - -public class NumericRxCommandTest extends NumericCommandTest { - @Override - protected RedisCommands connect() { - return RxSyncInvocationHandler.sync(client.connect()); - } -} diff --git a/src/test/java/com/lambdaworks/redis/commands/rx/ScriptingRxCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/rx/ScriptingRxCommandTest.java deleted file mode 100644 index 33f4c9225e..0000000000 --- a/src/test/java/com/lambdaworks/redis/commands/rx/ScriptingRxCommandTest.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.lambdaworks.redis.commands.rx; - -import com.lambdaworks.redis.api.sync.RedisCommands; -import com.lambdaworks.redis.commands.ScriptingCommandTest; -import com.lambdaworks.util.RxSyncInvocationHandler; - -public class ScriptingRxCommandTest extends ScriptingCommandTest { - - - @Override - protected RedisCommands connect() { - return RxSyncInvocationHandler.sync(client.connect()); - } -} diff --git a/src/test/java/com/lambdaworks/redis/commands/rx/SetRxCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/rx/SetRxCommandTest.java deleted file mode 100644 index 091520bfb1..0000000000 --- a/src/test/java/com/lambdaworks/redis/commands/rx/SetRxCommandTest.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.lambdaworks.redis.commands.rx; - -import com.lambdaworks.redis.api.sync.RedisCommands; -import com.lambdaworks.redis.commands.SetCommandTest; -import com.lambdaworks.util.RxSyncInvocationHandler; - -public class SetRxCommandTest extends SetCommandTest { - - @Override - protected RedisCommands connect() { - return RxSyncInvocationHandler.sync(client.connect()); - } - -} diff --git a/src/test/java/com/lambdaworks/redis/commands/rx/SortRxCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/rx/SortRxCommandTest.java deleted file mode 100644 index 37d1d05719..0000000000 --- a/src/test/java/com/lambdaworks/redis/commands/rx/SortRxCommandTest.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.lambdaworks.redis.commands.rx; - -import com.lambdaworks.redis.api.sync.RedisCommands; -import com.lambdaworks.redis.commands.SortCommandTest; -import com.lambdaworks.util.RxSyncInvocationHandler; - -public class SortRxCommandTest extends SortCommandTest { - @Override - protected RedisCommands connect() { - return RxSyncInvocationHandler.sync(client.connect()); - } -} diff --git a/src/test/java/com/lambdaworks/redis/commands/rx/SortedSetRxCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/rx/SortedSetRxCommandTest.java deleted file mode 100644 index 2e5a153e1d..0000000000 --- a/src/test/java/com/lambdaworks/redis/commands/rx/SortedSetRxCommandTest.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.lambdaworks.redis.commands.rx; - -import com.lambdaworks.redis.api.sync.RedisCommands; -import com.lambdaworks.redis.commands.SortedSetCommandTest; -import com.lambdaworks.util.RxSyncInvocationHandler; - -public class SortedSetRxCommandTest extends SortedSetCommandTest { - @Override - protected RedisCommands connect() { - return RxSyncInvocationHandler.sync(client.connect()); - } -} diff --git a/src/test/java/com/lambdaworks/redis/event/ConnectionEventsTriggeredTest.java b/src/test/java/com/lambdaworks/redis/event/ConnectionEventsTriggeredTest.java index a6ba8c04ae..0b385d117d 100644 --- a/src/test/java/com/lambdaworks/redis/event/ConnectionEventsTriggeredTest.java +++ b/src/test/java/com/lambdaworks/redis/event/ConnectionEventsTriggeredTest.java @@ -2,18 +2,18 @@ import static org.assertj.core.api.Assertions.assertThat; +import java.util.ArrayList; import java.util.List; import org.assertj.core.api.Condition; import org.junit.Test; -import rx.Subscription; -import rx.observers.TestSubscriber; - import com.lambdaworks.Wait; import com.lambdaworks.redis.AbstractRedisClientTest; import com.lambdaworks.redis.event.connection.*; +import reactor.test.TestSubscriber; + /** * @author Mark Paluch */ @@ -23,19 +23,19 @@ public class ConnectionEventsTriggeredTest extends AbstractRedisClientTest { public void testConnectionEvents() throws Exception { TestSubscriber subscriber = TestSubscriber.create(); + List events = new ArrayList<>(); - Subscription subscription = client.getResources().eventBus().get().filter( - event -> event instanceof ConnectionEvent) + client.getResources().eventBus().get().filter(event -> event instanceof ConnectionEvent).doOnNext(events::add) .subscribe(subscriber); try { + subscriber.request(10); client.connect().close(); - Wait.untilTrue(() -> subscriber.getOnNextEvents().size() > 3).waitOrTimeout(); + Wait.untilTrue(() -> events.size() > 4).waitOrTimeout(); } finally { - subscription.unsubscribe(); + subscriber.cancel(); } - List events = subscriber.getOnNextEvents(); assertThat(events).areAtLeast(1, new ExpectedClassCondition(ConnectedEvent.class)); assertThat(events).areAtLeast(1, new ExpectedClassCondition(ConnectionActivatedEvent.class)); assertThat(events).areAtLeast(1, new ExpectedClassCondition(DisconnectedEvent.class)); diff --git a/src/test/java/com/lambdaworks/redis/event/DefaultEventBusTest.java b/src/test/java/com/lambdaworks/redis/event/DefaultEventBusTest.java index b344aef133..f97d331f08 100644 --- a/src/test/java/com/lambdaworks/redis/event/DefaultEventBusTest.java +++ b/src/test/java/com/lambdaworks/redis/event/DefaultEventBusTest.java @@ -8,10 +8,8 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; - -import rx.observers.TestSubscriber; -import rx.schedulers.Schedulers; -import rx.schedulers.TestScheduler; +import reactor.core.scheduler.Schedulers; +import reactor.test.TestSubscriber; /** * @author Mark Paluch @@ -24,16 +22,30 @@ public class DefaultEventBusTest { @Test public void publishToSubscriber() throws Exception { - TestScheduler testScheduler = Schedulers.test(); - EventBus sut = new DefaultEventBus(testScheduler); - TestSubscriber subscriber = new TestSubscriber(); + EventBus sut = new DefaultEventBus(Schedulers.immediate()); + + TestSubscriber subscriber = TestSubscriber.create(); sut.get().subscribe(subscriber); sut.publish(event); - testScheduler.advanceTimeBy(1, TimeUnit.SECONDS); + subscriber.awaitAndAssertNextValues(event); + } + + @Test + public void publishToMultipleSubscribers() throws Exception { + + EventBus sut = new DefaultEventBus(Schedulers.immediate()); + + TestSubscriber subscriber1 = TestSubscriber.create(); + TestSubscriber subscriber2 = TestSubscriber.create(); + sut.get().subscribe(subscriber1); + sut.get().subscribe(subscriber2); + + sut.publish(event); - assertThat(subscriber.getOnNextEvents()).hasSize(1).contains(event); + subscriber1.awaitAndAssertNextValues(event); + subscriber2.awaitAndAssertNextValues(event); } } diff --git a/src/test/java/com/lambdaworks/redis/output/GeoCoordinatesListOutputTest.java b/src/test/java/com/lambdaworks/redis/output/GeoCoordinatesListOutputTest.java index 4b250a1f2a..e0831df2cb 100644 --- a/src/test/java/com/lambdaworks/redis/output/GeoCoordinatesListOutputTest.java +++ b/src/test/java/com/lambdaworks/redis/output/GeoCoordinatesListOutputTest.java @@ -4,6 +4,7 @@ import java.nio.ByteBuffer; +import com.lambdaworks.redis.Value; import org.junit.Test; import com.lambdaworks.redis.GeoCoordinates; @@ -33,6 +34,6 @@ public void commandOutputCorrectlyDecoded() throws Exception { sut.set(ByteBuffer.wrap("4.567".getBytes())); sut.multi(-1); - assertThat(sut.get()).contains(new GeoCoordinates(1.234, 4.567)); + assertThat(sut.get()).contains(Value.just(new GeoCoordinates(1.234, 4.567))); } } \ No newline at end of file diff --git a/src/test/java/com/lambdaworks/redis/pubsub/PubSubRxTest.java b/src/test/java/com/lambdaworks/redis/pubsub/PubSubReactiveTest.java similarity index 87% rename from src/test/java/com/lambdaworks/redis/pubsub/PubSubRxTest.java rename to src/test/java/com/lambdaworks/redis/pubsub/PubSubReactiveTest.java index 636aa3c57b..656213477a 100644 --- a/src/test/java/com/lambdaworks/redis/pubsub/PubSubRxTest.java +++ b/src/test/java/com/lambdaworks/redis/pubsub/PubSubReactiveTest.java @@ -4,41 +4,37 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Fail.fail; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.concurrent.BlockingQueue; import java.util.concurrent.TimeUnit; -import com.lambdaworks.TestClientResources; import org.junit.After; import org.junit.Before; import org.junit.Test; import com.lambdaworks.Delay; +import com.lambdaworks.TestClientResources; import com.lambdaworks.Wait; import com.lambdaworks.redis.AbstractRedisClientTest; import com.lambdaworks.redis.FastShutdown; import com.lambdaworks.redis.RedisClient; import com.lambdaworks.redis.RedisURI; -import com.lambdaworks.redis.api.rx.Success; import com.lambdaworks.redis.internal.LettuceFactories; -import com.lambdaworks.redis.internal.LettuceLists; -import com.lambdaworks.redis.pubsub.api.rx.ChannelMessage; -import com.lambdaworks.redis.pubsub.api.rx.PatternMessage; -import com.lambdaworks.redis.pubsub.api.rx.RedisPubSubReactiveCommands; +import com.lambdaworks.redis.pubsub.api.reactive.ChannelMessage; +import com.lambdaworks.redis.pubsub.api.reactive.PatternMessage; +import com.lambdaworks.redis.pubsub.api.reactive.RedisPubSubReactiveCommands; import com.lambdaworks.redis.pubsub.api.sync.RedisPubSubCommands; -import rx.Completable; -import rx.Observable; -import rx.Single; -import rx.Subscription; -import rx.observables.BlockingObservable; +import reactor.core.Cancellation; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import reactor.test.TestSubscriber; /** * @author Mark Paluch */ -public class PubSubRxTest extends AbstractRedisClientTest implements RedisPubSubListener { +public class PubSubReactiveTest extends AbstractRedisClientTest implements RedisPubSubListener { private RedisPubSubReactiveCommands pubsub; private RedisPubSubReactiveCommands pubsub2; @@ -76,17 +72,19 @@ public void observeChannels() throws Exception { block(pubsub.subscribe(channel)); BlockingQueue> channelMessages = LettuceFactories.newBlockingQueue(); + TestSubscriber> testSubscriber = TestSubscriber.create(); - Subscription subscription = pubsub.observeChannels().doOnNext(channelMessages::add).subscribe(); + pubsub.observeChannels().doOnNext(channelMessages::add).subscribe(testSubscriber); redis.publish(channel, message); redis.publish(channel, message); redis.publish(channel, message); + testSubscriber.awaitAndAssertNextValueCount(3); Wait.untilEquals(3, () -> channelMessages.size()).waitOrTimeout(); assertThat(channelMessages).hasSize(3); - subscription.unsubscribe(); + testSubscriber.cancel(); redis.publish(channel, message); Delay.delay(millis(500)); assertThat(channelMessages).hasSize(3); @@ -103,7 +101,7 @@ public void observeChannelsUnsubscribe() throws Exception { BlockingQueue> channelMessages = LettuceFactories.newBlockingQueue(); - pubsub.observeChannels().doOnNext(channelMessages::add).subscribe().unsubscribe(); + pubsub.observeChannels().doOnNext(channelMessages::add).subscribe().dispose(); block(redis.getStatefulConnection().reactive().publish(channel, message)); block(redis.getStatefulConnection().reactive().publish(channel, message)); @@ -141,7 +139,7 @@ public void observePatternsWithUnsubscribe() throws Exception { BlockingQueue> patternMessages = LettuceFactories.newBlockingQueue(); - Subscription subscription = pubsub.observePatterns().doOnNext(patternMessages::add).subscribe(); + Cancellation subscription = pubsub.observePatterns().doOnNext(patternMessages::add).subscribe(); redis.publish(channel, message); redis.publish(channel, message); @@ -149,7 +147,7 @@ public void observePatternsWithUnsubscribe() throws Exception { Wait.untilTrue(() -> patternMessages.size() == 3).waitOrTimeout(); assertThat(patternMessages).hasSize(3); - subscription.unsubscribe(); + subscription.dispose(); redis.publish(channel, message); redis.publish(channel, message); @@ -208,7 +206,7 @@ public void pubsubEmptyChannels() throws Exception { public void pubsubChannels() throws Exception { block(pubsub.subscribe(channel)); - List result = single(pubsub2.pubsubChannels().toList()); + List result = block(pubsub2.pubsubChannels().collectList()); assertThat(result).contains(channel); } @@ -217,7 +215,7 @@ public void pubsubMultipleChannels() throws Exception { block(pubsub.subscribe(channel, "channel1", "channel3")); - List result = single(pubsub2.pubsubChannels().toList()); + List result = all(pubsub2.pubsubChannels()); assertThat(result).contains(channel, "channel1", "channel3"); } @@ -225,9 +223,9 @@ public void pubsubMultipleChannels() throws Exception { public void pubsubChannelsWithArg() throws Exception { pubsub.subscribe(channel).subscribe(); - Wait.untilTrue(() -> single(pubsub2.pubsubChannels(pattern).filter(s -> channel.equals(s))) != null).waitOrTimeout(); + Wait.untilTrue(() -> mono(pubsub2.pubsubChannels(pattern).filter(s -> channel.equals(s))) != null).waitOrTimeout(); - String result = single(pubsub2.pubsubChannels(pattern).filter(s -> channel.equals(s))); + String result = mono(pubsub2.pubsubChannels(pattern).filter(s -> channel.equals(s))); assertThat(result).isEqualToIgnoringCase(channel); } @@ -435,28 +433,15 @@ public void punsubscribed(String pattern, long count) { counts.add(count); } - protected T block(Single single) { - return single.toBlocking().value(); - } - - protected void block(Completable completable) { - completable.get(); + protected T block(Mono mono) { + return mono.block(); } - protected T single(Observable observable) { - - BlockingObservable blocking = observable.toBlocking(); - Iterator iterator = blocking.getIterator(); - if (iterator.hasNext()) { - return iterator.next(); - } - return null; + protected T mono(Flux flux) { + return flux.next().block(); } - protected List all(Observable observable) { - - BlockingObservable blocking = observable.toBlocking(); - Iterator iterator = blocking.getIterator(); - return LettuceLists.newList(iterator); + protected List all(Flux flux) { + return flux.collectList().block(); } } diff --git a/src/test/java/com/lambdaworks/redis/resource/DefaultClientResourcesTest.java b/src/test/java/com/lambdaworks/redis/resource/DefaultClientResourcesTest.java index 3a3035226c..a6fbeb5d76 100644 --- a/src/test/java/com/lambdaworks/redis/resource/DefaultClientResourcesTest.java +++ b/src/test/java/com/lambdaworks/redis/resource/DefaultClientResourcesTest.java @@ -1,7 +1,5 @@ package com.lambdaworks.redis.resource; -import static com.google.code.tempusfugit.temporal.Duration.seconds; -import static com.google.code.tempusfugit.temporal.Timeout.timeout; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; @@ -12,8 +10,6 @@ import org.junit.Test; -import com.google.code.tempusfugit.temporal.Condition; -import com.google.code.tempusfugit.temporal.WaitFor; import com.lambdaworks.redis.event.Event; import com.lambdaworks.redis.event.EventBus; import com.lambdaworks.redis.metrics.CommandLatencyCollector; @@ -22,7 +18,7 @@ import io.netty.channel.nio.NioEventLoopGroup; import io.netty.util.concurrent.EventExecutorGroup; import io.netty.util.concurrent.Future; -import rx.observers.TestSubscriber; +import reactor.test.TestSubscriber; /** * @author Mark Paluch @@ -128,21 +124,17 @@ public void testEventBus() throws Exception { EventBus eventBus = sut.eventBus(); - final TestSubscriber subject = new TestSubscriber(); + final TestSubscriber testSubscriber = TestSubscriber.create(); - eventBus.get().subscribe(subject); + eventBus.get().subscribe(testSubscriber); Event event = mock(Event.class); eventBus.publish(event); - WaitFor.waitOrTimeout(new Condition() { - @Override - public boolean isSatisfied() { - return !subject.getOnNextEvents().isEmpty(); - } - }, timeout(seconds(2))); + testSubscriber.awaitAndAssertNextValuesWith(receivedEvent -> { + assertThat(receivedEvent).isEqualTo(event); + }); - assertThat(subject.getOnNextEvents()).contains(event); assertThat(sut.shutdown(0, 0, TimeUnit.MILLISECONDS).get()).isTrue(); } diff --git a/src/test/java/com/lambdaworks/redis/sentinel/rx/SentinelRxCommandTest.java b/src/test/java/com/lambdaworks/redis/sentinel/reactive/SentinelRxCommandTest.java similarity index 78% rename from src/test/java/com/lambdaworks/redis/sentinel/rx/SentinelRxCommandTest.java rename to src/test/java/com/lambdaworks/redis/sentinel/reactive/SentinelRxCommandTest.java index 6d0e139289..489a004747 100644 --- a/src/test/java/com/lambdaworks/redis/sentinel/rx/SentinelRxCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/sentinel/reactive/SentinelRxCommandTest.java @@ -1,13 +1,13 @@ -package com.lambdaworks.redis.sentinel.rx; +package com.lambdaworks.redis.sentinel.reactive; import static com.lambdaworks.redis.TestSettings.hostAddr; import static org.assertj.core.api.Assertions.assertThat; import com.lambdaworks.redis.TestSettings; -import com.lambdaworks.util.RxSyncInvocationHandler; +import com.lambdaworks.util.ReactiveSyncInvocationHandler; import com.lambdaworks.redis.sentinel.SentinelCommandTest; import com.lambdaworks.redis.sentinel.api.async.RedisSentinelAsyncCommands; -import com.lambdaworks.redis.sentinel.api.rx.RedisSentinelReactiveCommands; +import com.lambdaworks.redis.sentinel.api.reactive.RedisSentinelReactiveCommands; /** * @author Mark Paluch @@ -19,7 +19,7 @@ public void openConnection() throws Exception { RedisSentinelAsyncCommands async = sentinelClient.connectSentinel().async(); RedisSentinelReactiveCommands reactive = async.getStatefulConnection().reactive(); - sentinel = RxSyncInvocationHandler.sync(async.getStatefulConnection()); + sentinel = ReactiveSyncInvocationHandler.sync(async.getStatefulConnection()); try { sentinel.master(MASTER_ID); diff --git a/src/test/java/com/lambdaworks/util/RxSyncInvocationHandler.java b/src/test/java/com/lambdaworks/util/ReactiveSyncInvocationHandler.java similarity index 68% rename from src/test/java/com/lambdaworks/util/RxSyncInvocationHandler.java rename to src/test/java/com/lambdaworks/util/ReactiveSyncInvocationHandler.java index 1b93cc6f4e..3eec42fb0e 100644 --- a/src/test/java/com/lambdaworks/util/RxSyncInvocationHandler.java +++ b/src/test/java/com/lambdaworks/util/ReactiveSyncInvocationHandler.java @@ -3,24 +3,19 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Proxy; -import java.util.Iterator; import java.util.List; import java.util.Set; -import java.util.concurrent.TimeUnit; import com.lambdaworks.redis.api.StatefulConnection; import com.lambdaworks.redis.api.StatefulRedisConnection; import com.lambdaworks.redis.api.sync.RedisCommands; import com.lambdaworks.redis.cluster.api.StatefulRedisClusterConnection; -import com.lambdaworks.redis.internal.AbstractInvocationHandler; -import com.lambdaworks.redis.internal.LettuceLists; import com.lambdaworks.redis.internal.LettuceSets; import com.lambdaworks.redis.sentinel.api.StatefulRedisSentinelConnection; import com.lambdaworks.redis.sentinel.api.sync.RedisSentinelCommands; -import rx.Completable; -import rx.Observable; -import rx.Single; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; /** * Invocation handler for testing purposes. @@ -28,11 +23,11 @@ * @param * @param */ -public class RxSyncInvocationHandler extends ConnectionDecoratingInvocationHandler { +public class ReactiveSyncInvocationHandler extends ConnectionDecoratingInvocationHandler { private final StatefulConnection connection; - public RxSyncInvocationHandler(StatefulConnection connection, Object rxApi) { + public ReactiveSyncInvocationHandler(StatefulConnection connection, Object rxApi) { super(rxApi); this.connection = connection; } @@ -53,18 +48,18 @@ protected Object handleInvocation(Object proxy, Method method, Object[] args) th return result; } - if (result instanceof Observable) { - Observable observable = (Observable) result; + if (result instanceof Flux) { + Flux flux = (Flux) result; if (!method.getName().equals("exec") && !method.getName().equals("multi")) { if (connection instanceof StatefulRedisConnection && ((StatefulRedisConnection) connection) .isMulti()) { - observable.subscribe(); + flux.subscribe(); return null; } } - List value = observable.toList().toBlocking().first(); + List value = flux.collectList().block(); if (method.getReturnType().equals(List.class)) { return value; @@ -79,25 +74,17 @@ protected Object handleInvocation(Object proxy, Method method, Object[] args) th } } - if (result instanceof Single) { - Single single = (Single) result; + if (result instanceof Mono) { + Mono mono = (Mono) result; if (!method.getName().equals("exec") && !method.getName().equals("multi")) { if (connection instanceof StatefulRedisConnection && ((StatefulRedisConnection) connection).isMulti()) { - single.subscribe(); + mono.subscribe(); return null; } } - return single.toBlocking().value(); - } - - if (result instanceof Completable) { - Completable completable = (Completable) result; - completable.await(5, TimeUnit.SECONDS); - if (completable.get() != null) { - throw completable.get(); - } + return mono.block(); } return result; @@ -109,21 +96,21 @@ protected Object handleInvocation(Object proxy, Method method, Object[] args) th public static RedisCommands sync(StatefulRedisConnection connection) { - RxSyncInvocationHandler handler = new RxSyncInvocationHandler<>(connection, connection.reactive()); + ReactiveSyncInvocationHandler handler = new ReactiveSyncInvocationHandler<>(connection, connection.reactive()); return (RedisCommands) Proxy.newProxyInstance(handler.getClass().getClassLoader(), new Class[] { RedisCommands.class }, handler); } public static RedisCommands sync(StatefulRedisClusterConnection connection) { - RxSyncInvocationHandler handler = new RxSyncInvocationHandler<>(connection, connection.reactive()); + ReactiveSyncInvocationHandler handler = new ReactiveSyncInvocationHandler<>(connection, connection.reactive()); return (RedisCommands) Proxy.newProxyInstance(handler.getClass().getClassLoader(), new Class[] { RedisCommands.class }, handler); } public static RedisSentinelCommands sync(StatefulRedisSentinelConnection connection) { - RxSyncInvocationHandler handler = new RxSyncInvocationHandler<>(connection, connection.reactive()); + ReactiveSyncInvocationHandler handler = new ReactiveSyncInvocationHandler<>(connection, connection.reactive()); return (RedisSentinelCommands) Proxy.newProxyInstance(handler.getClass().getClassLoader(), new Class[] { RedisSentinelCommands.class }, handler); } From 30bbbbdf5884981b7af0687268e4d6c48f885475 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Wed, 10 Aug 2016 09:29:57 +0200 Subject: [PATCH 012/808] Decouple CommandHandler #317 Refactoring of CommandHandler and connection handling. Lettuce now uses the Endpoint concept to represent communication with a server. Endpoints may be in a connected or disconnected state and are used by the stateful connection. Channel handlers are no longer reused but registered per channel pipeline. Each CommandHandler has its own queue instance to keep track of alive command processing. Command buffering (disconnected endpoint) is held on endpoint level. The stateful connection is no longer required to be a command handler but can be notified from endpoints (see PubSubEndpoint). --- .../redis/AbstractRedisClient.java | 41 +- .../redis/ChannelGroupListener.java | 1 - .../lambdaworks/redis/ConnectionBuilder.java | 56 +- .../redis/ConnectionEventTrigger.java | 3 +- .../lambdaworks/redis/ConnectionEvents.java | 13 +- .../redis/PlainChannelInitializer.java | 26 +- .../redis/RedisChannelHandler.java | 35 +- .../lambdaworks/redis/RedisChannelWriter.java | 16 +- .../com/lambdaworks/redis/RedisClient.java | 66 +- .../redis/SslConnectionBuilder.java | 28 +- .../redis/StatefulRedisConnectionImpl.java | 3 +- .../redis/cluster/AbstractNodeSelection.java | 2 +- .../redis/cluster/ClusterCommand.java | 4 +- .../ClusterDistributionChannelWriter.java | 32 +- ...dHandler.java => ClusterNodeEndpoint.java} | 62 +- .../PooledClusterConnectionProvider.java | 14 +- .../redis/cluster/RedisClusterClient.java | 91 +- .../StatefulRedisClusterConnectionImpl.java | 7 +- .../topology/ClusterTopologyRefresh.java | 6 +- .../masterslave/MasterSlaveChannelWriter.java | 10 +- .../redis/output/CommandOutput.java | 7 +- .../redis/protocol/CommandEncoder.java | 3 +- .../redis/protocol/CommandHandler.java | 900 ++++-------------- .../redis/protocol/ConnectionFacade.java | 27 + .../redis/protocol/ConnectionWatchdog.java | 133 +-- .../redis/protocol/DefaultEndpoint.java | 603 ++++++++++++ .../lambdaworks/redis/protocol/Endpoint.java | 64 ++ .../redis/protocol/HasQueuedCommands.java | 19 + .../redis/protocol/QueuedCommands.java | 110 +++ .../redis/protocol/ReconnectionHandler.java | 38 +- .../redis/protocol/RedisStateMachine.java | 18 +- .../redis/protocol/SharedLock.java | 128 +++ .../redis/pubsub/PubSubCommandHandler.java | 46 +- .../redis/pubsub/PubSubEndpoint.java | 117 +++ .../StatefulRedisPubSubConnectionImpl.java | 85 +- .../StatefulRedisSentinelConnectionImpl.java | 3 +- .../extensibility/MyExtendedRedisClient.java | 9 +- .../extensibility/MyPubSubConnection.java | 36 +- ...nnections.java => ConnectionTestUtil.java} | 38 +- .../lambdaworks/redis/ClientOptionsTest.java | 6 +- .../com/lambdaworks/redis/ClientTest.java | 2 +- .../redis/ConnectionCommandTest.java | 3 +- .../redis/LettucePerformanceTest.java | 251 ----- .../cluster/ClusterCommandInternalsTest.java | 2 +- ...Test.java => ClusterNodeEndpointTest.java} | 12 +- .../redis/cluster/ClusterSetup.java | 56 +- .../PooledClusterConnectionProviderTest.java | 2 +- .../redis/cluster/RedisClusterClientTest.java | 3 +- .../redis/cluster/RedisClusterSetupTest.java | 4 +- .../RedisClusterStressScenariosTest.java | 60 +- .../redis/commands/HLLCommandTest.java | 11 + .../redis/protocol/CommandHandlerTest.java | 428 +-------- .../redis/protocol/ConnectionFailureTest.java | 15 +- .../redis/protocol/DefaultEndpointTest.java | 338 +++++++ .../redis/protocol/StateMachineTest.java | 4 +- .../redis/reliability/AtLeastOnceTest.java | 70 +- .../redis/reliability/AtMostOnceTest.java | 44 +- .../cluster/EmptyRedisChannelWriter.java | 6 +- .../cluster/EmptyRedisClusterClient.java | 2 +- .../cluster/EmptyStatefulRedisConnection.java | 13 +- .../redis/protocol/CommandBenchmark.java | 29 +- .../protocol/CommandHandlerBenchmark.java | 62 +- .../redis/protocol/EmptyClientResources.java | 39 +- .../lambdaworks/redis/protocol/JmhMain.java | 3 +- .../protocol/RedisEndpointBenchmark.java | 85 ++ .../protocol/RedisStateMachineBenchmark.java | 2 +- 66 files changed, 2272 insertions(+), 2180 deletions(-) rename src/main/java/com/lambdaworks/redis/cluster/{ClusterNodeCommandHandler.java => ClusterNodeEndpoint.java} (59%) create mode 100644 src/main/java/com/lambdaworks/redis/protocol/ConnectionFacade.java create mode 100644 src/main/java/com/lambdaworks/redis/protocol/DefaultEndpoint.java create mode 100644 src/main/java/com/lambdaworks/redis/protocol/Endpoint.java create mode 100644 src/main/java/com/lambdaworks/redis/protocol/HasQueuedCommands.java create mode 100644 src/main/java/com/lambdaworks/redis/protocol/QueuedCommands.java create mode 100644 src/main/java/com/lambdaworks/redis/protocol/SharedLock.java create mode 100644 src/main/java/com/lambdaworks/redis/pubsub/PubSubEndpoint.java rename src/test/java/com/lambdaworks/{Connections.java => ConnectionTestUtil.java} (60%) delete mode 100644 src/test/java/com/lambdaworks/redis/LettucePerformanceTest.java rename src/test/java/com/lambdaworks/redis/cluster/{ClusterNodeCommandHandlerTest.java => ClusterNodeEndpointTest.java} (91%) create mode 100644 src/test/java/com/lambdaworks/redis/protocol/DefaultEndpointTest.java create mode 100644 src/test/jmh/com/lambdaworks/redis/protocol/RedisEndpointBenchmark.java diff --git a/src/main/java/com/lambdaworks/redis/AbstractRedisClient.java b/src/main/java/com/lambdaworks/redis/AbstractRedisClient.java index 5e98512311..94bf808c27 100644 --- a/src/main/java/com/lambdaworks/redis/AbstractRedisClient.java +++ b/src/main/java/com/lambdaworks/redis/AbstractRedisClient.java @@ -13,8 +13,7 @@ import java.util.function.Supplier; import com.lambdaworks.redis.internal.LettuceAssert; -import com.lambdaworks.redis.protocol.CommandHandler; -import com.lambdaworks.redis.pubsub.PubSubCommandHandler; +import com.lambdaworks.redis.protocol.ConnectionWatchdog; import com.lambdaworks.redis.resource.ClientResources; import com.lambdaworks.redis.resource.DefaultClientResources; @@ -103,29 +102,15 @@ public void setDefaultTimeout(long timeout, TimeUnit unit) { this.unit = unit; } - @SuppressWarnings("unchecked") - protected > T connectAsyncImpl(final CommandHandler handler, - final T connection, final Supplier socketAddressSupplier) { - - ConnectionBuilder connectionBuilder = ConnectionBuilder.connectionBuilder(); - connectionBuilder.clientOptions(clientOptions); - connectionBuilder.clientResources(clientResources); - connectionBuilder(handler, connection, socketAddressSupplier, connectionBuilder, null); - channelType(connectionBuilder, null); - return (T) initializeChannel(connectionBuilder); - } - /** * Populate connection builder with necessary resources. * - * @param handler instance of a CommandHandler for writing redis commands - * @param connection implementation of a RedisConnection * @param socketAddressSupplier address supplier for initial connect and re-connect * @param connectionBuilder connection builder to configure the connection * @param redisURI URI of the redis instance */ - protected void connectionBuilder(CommandHandler handler, RedisChannelHandler connection, - Supplier socketAddressSupplier, ConnectionBuilder connectionBuilder, RedisURI redisURI) { + protected void connectionBuilder(Supplier socketAddressSupplier, ConnectionBuilder connectionBuilder, + RedisURI redisURI) { Bootstrap redisBootstrap = new Bootstrap(); redisBootstrap.option(ChannelOption.WRITE_BUFFER_HIGH_WATER_MARK, 32 * 1024); @@ -148,8 +133,7 @@ protected void connectionBuilder(CommandHandler handler, RedisChannelHandl connectionBuilder.bootstrap(redisBootstrap); connectionBuilder.channelGroup(channels).connectionEvents(connectionEvents).timer(timer); - connectionBuilder.commandHandler(handler).socketAddressSupplier(socketAddressSupplier).connection(connection); - connectionBuilder.workerPool(genericWorkerPool); + connectionBuilder.socketAddressSupplier(socketAddressSupplier); } protected void channelType(ConnectionBuilder connectionBuilder, ConnectionPoint connectionPoint) { @@ -202,7 +186,7 @@ protected > T initializeChannel(Connec RedisChannelHandler connection = connectionBuilder.connection(); SocketAddress redisAddress = connectionBuilder.socketAddress(); - if(connectionBuilder.workerPool().isShuttingDown()){ + if(clientResources.eventExecutorGroup().isShuttingDown()){ throw new IllegalStateException("Cannot connect. Worker pool not running"); } @@ -234,10 +218,10 @@ protected > T initializeChannel(Connec return (T) connection; } catch (RedisException e) { - connectionBuilder.commandHandler().initialState(); + connectionBuilder.endpoint().initialState(); throw e; } catch (Exception e) { - connectionBuilder.commandHandler().initialState(); + connectionBuilder.endpoint().initialState(); throw new RedisConnectionException("Unable to connect to " + redisAddress, e); } } @@ -279,14 +263,9 @@ public void shutdown(long quietPeriod, long timeout, TimeUnit timeUnit) { for (Channel c : channels) { ChannelPipeline pipeline = c.pipeline(); - CommandHandler commandHandler = pipeline.get(CommandHandler.class); - if (commandHandler != null && !commandHandler.isClosed()) { - commandHandler.close(); - } - - PubSubCommandHandler psCommandHandler = pipeline.get(PubSubCommandHandler.class); - if (psCommandHandler != null && !psCommandHandler.isClosed()) { - psCommandHandler.close(); + ConnectionWatchdog commandHandler = pipeline.get(ConnectionWatchdog.class); + if (commandHandler != null) { + commandHandler.setListenOnChannelInactive(false); } } diff --git a/src/main/java/com/lambdaworks/redis/ChannelGroupListener.java b/src/main/java/com/lambdaworks/redis/ChannelGroupListener.java index 2bd4d42a4b..167301a463 100644 --- a/src/main/java/com/lambdaworks/redis/ChannelGroupListener.java +++ b/src/main/java/com/lambdaworks/redis/ChannelGroupListener.java @@ -13,7 +13,6 @@ * * @author Will Glozer */ -@ChannelHandler.Sharable class ChannelGroupListener extends ChannelInboundHandlerAdapter { private ChannelGroup channels; diff --git a/src/main/java/com/lambdaworks/redis/ConnectionBuilder.java b/src/main/java/com/lambdaworks/redis/ConnectionBuilder.java index 13cbeafed2..2f6995d25a 100644 --- a/src/main/java/com/lambdaworks/redis/ConnectionBuilder.java +++ b/src/main/java/com/lambdaworks/redis/ConnectionBuilder.java @@ -3,14 +3,12 @@ import java.net.SocketAddress; import java.util.ArrayList; import java.util.List; +import java.util.Optional; import java.util.concurrent.TimeUnit; import java.util.function.Supplier; import com.lambdaworks.redis.internal.LettuceAssert; -import com.lambdaworks.redis.protocol.CommandEncoder; -import com.lambdaworks.redis.protocol.CommandHandler; -import com.lambdaworks.redis.protocol.ConnectionWatchdog; -import com.lambdaworks.redis.protocol.ReconnectionListener; +import com.lambdaworks.redis.protocol.*; import com.lambdaworks.redis.resource.ClientResources; import io.netty.bootstrap.Bootstrap; @@ -29,17 +27,18 @@ public class ConnectionBuilder { private Supplier socketAddressSupplier; private ConnectionEvents connectionEvents; private RedisChannelHandler connection; - private CommandHandler commandHandler; + private DefaultEndpoint endpoint; + private Supplier commandHandlerSupplier; private ChannelGroup channelGroup; private Timer timer; private Bootstrap bootstrap; private ClientOptions clientOptions; - private EventExecutorGroup workerPool; private long timeout; private TimeUnit timeUnit; private ClientResources clientResources; private char[] password; private ReconnectionListener reconnectionListener = ReconnectionListener.NO_OP; + private ConnectionWatchdog connectionWatchdog; public static ConnectionBuilder connectionBuilder() { return new ConnectionBuilder(); @@ -51,6 +50,7 @@ protected List buildHandlers() { LettuceAssert.assertState(connectionEvents != null, "ConnectionEvents must be set"); LettuceAssert.assertState(connection != null, "Connection must be set"); LettuceAssert.assertState(clientResources != null, "ClientResources must be set"); + LettuceAssert.assertState(endpoint != null, "Endpoint must be set"); List handlers = new ArrayList<>(); @@ -58,8 +58,14 @@ protected List buildHandlers() { handlers.add(new ChannelGroupListener(channelGroup)); handlers.add(new CommandEncoder()); - handlers.add(commandHandler); - handlers.add(connection); + handlers.add(commandHandlerSupplier.get()); + + if (clientOptions.isAutoReconnect()) { + handlers.add(createConnectionWatchdog()); + } else { + endpoint.registerConnectionWatchdog(Optional.empty()); + } + handlers.add(new ConnectionEventTrigger(connectionEvents, connection, clientResources.eventBus())); if (clientOptions.isAutoReconnect()) { @@ -71,19 +77,25 @@ protected List buildHandlers() { protected ConnectionWatchdog createConnectionWatchdog() { + if (connectionWatchdog != null) { + return connectionWatchdog; + } + LettuceAssert.assertState(bootstrap != null, "Bootstrap must be set for autoReconnect=true"); LettuceAssert.assertState(timer != null, "Timer must be set for autoReconnect=true"); LettuceAssert.assertState(socketAddressSupplier != null, "SocketAddressSupplier must be set for autoReconnect=true"); ConnectionWatchdog watchdog = new ConnectionWatchdog(clientResources.reconnectDelay(), clientOptions, bootstrap, timer, - workerPool, socketAddressSupplier, reconnectionListener); + clientResources.eventExecutorGroup(), socketAddressSupplier, reconnectionListener, connection); + + endpoint.registerConnectionWatchdog(Optional.of(watchdog)); - watchdog.setListenOnChannelInactive(true); + connectionWatchdog = watchdog; return watchdog; } public RedisChannelInitializer build() { - return new PlainChannelInitializer(clientOptions.isPingBeforeActivateConnection(), password(), buildHandlers(), + return new PlainChannelInitializer(clientOptions.isPingBeforeActivateConnection(), password(), this::buildHandlers, clientResources.eventBus()); } @@ -123,11 +135,6 @@ public ConnectionBuilder clientOptions(ClientOptions clientOptions) { return this; } - public ConnectionBuilder workerPool(EventExecutorGroup workerPool) { - this.workerPool = workerPool; - return this; - } - public ConnectionBuilder connectionEvents(ConnectionEvents connectionEvents) { this.connectionEvents = connectionEvents; return this; @@ -143,8 +150,8 @@ public ConnectionBuilder channelGroup(ChannelGroup channelGroup) { return this; } - public ConnectionBuilder commandHandler(CommandHandler commandHandler) { - this.commandHandler = commandHandler; + public ConnectionBuilder commandHandler(Supplier supplier) { + this.commandHandlerSupplier = supplier; return this; } @@ -158,6 +165,11 @@ public ConnectionBuilder bootstrap(Bootstrap bootstrap) { return this; } + public ConnectionBuilder endpoint(DefaultEndpoint endpoint) { + this.endpoint = endpoint; + return this; + } + public ConnectionBuilder clientResources(ClientResources clientResources) { this.clientResources = clientResources; return this; @@ -172,10 +184,6 @@ public ConnectionBuilder password(char[] password) { return connection; } - public CommandHandler commandHandler() { - return commandHandler; - } - public Bootstrap bootstrap() { return bootstrap; } @@ -192,7 +200,7 @@ public char[] password() { return password; } - public EventExecutorGroup workerPool() { - return workerPool; + public DefaultEndpoint endpoint() { + return endpoint; } } diff --git a/src/main/java/com/lambdaworks/redis/ConnectionEventTrigger.java b/src/main/java/com/lambdaworks/redis/ConnectionEventTrigger.java index e2cd48469e..81b73625c7 100644 --- a/src/main/java/com/lambdaworks/redis/ConnectionEventTrigger.java +++ b/src/main/java/com/lambdaworks/redis/ConnectionEventTrigger.java @@ -15,13 +15,12 @@ * @author Mark Paluch * @since 3.0 */ -@ChannelHandler.Sharable class ConnectionEventTrigger extends ChannelInboundHandlerAdapter { private final ConnectionEvents connectionEvents; private final RedisChannelHandler connection; private final EventBus eventBus; - public ConnectionEventTrigger(ConnectionEvents connectionEvents, RedisChannelHandler connection, EventBus eventBus) { + ConnectionEventTrigger(ConnectionEvents connectionEvents, RedisChannelHandler connection, EventBus eventBus) { this.connectionEvents = connectionEvents; this.connection = connection; this.eventBus = eventBus; diff --git a/src/main/java/com/lambdaworks/redis/ConnectionEvents.java b/src/main/java/com/lambdaworks/redis/ConnectionEvents.java index 7a470d5183..f4ca0615b5 100644 --- a/src/main/java/com/lambdaworks/redis/ConnectionEvents.java +++ b/src/main/java/com/lambdaworks/redis/ConnectionEvents.java @@ -40,21 +40,10 @@ public void removeListener(RedisConnectionStateListener listener) { listeners.remove(listener); } - /** - * Internal event before a channel is closed. - */ - public static class PrepareClose { - private CompletableFuture prepareCloseFuture = new CompletableFuture<>(); - - public CompletableFuture getPrepareCloseFuture() { - return prepareCloseFuture; - } - } - /** * Internal event when a channel is closed. */ - public static class Close { + public static class Reset { } /** diff --git a/src/main/java/com/lambdaworks/redis/PlainChannelInitializer.java b/src/main/java/com/lambdaworks/redis/PlainChannelInitializer.java index a8db635a0a..d6aa81ef17 100644 --- a/src/main/java/com/lambdaworks/redis/PlainChannelInitializer.java +++ b/src/main/java/com/lambdaworks/redis/PlainChannelInitializer.java @@ -5,6 +5,7 @@ import java.util.List; import java.util.concurrent.CompletableFuture; +import java.util.function.Supplier; import com.lambdaworks.redis.codec.Utf8StringCodec; import com.lambdaworks.redis.event.EventBus; @@ -12,6 +13,7 @@ import com.lambdaworks.redis.event.connection.ConnectionActivatedEvent; import com.lambdaworks.redis.event.connection.DisconnectedEvent; import com.lambdaworks.redis.protocol.AsyncCommand; + import io.netty.channel.Channel; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; @@ -22,16 +24,18 @@ */ class PlainChannelInitializer extends io.netty.channel.ChannelInitializer implements RedisChannelInitializer { - final static RedisCommandBuilder INITIALIZING_CMD_BUILDER = new RedisCommandBuilder<>(new Utf8StringCodec()); + final static RedisCommandBuilder INITIALIZING_CMD_BUILDER = new RedisCommandBuilder<>( + new Utf8StringCodec()); - protected boolean pingBeforeActivate; - protected CompletableFuture initializedFuture = new CompletableFuture<>(); + private boolean pingBeforeActivate; + private CompletableFuture initializedFuture = new CompletableFuture<>(); protected final char[] password; - private final List handlers; + private final Supplier> handlers; private final EventBus eventBus; - public PlainChannelInitializer(boolean pingBeforeActivateConnection, char[] password, List handlers, + PlainChannelInitializer(boolean pingBeforeActivateConnection, char[] password, Supplier> handlers, EventBus eventBus) { + this.pingBeforeActivate = pingBeforeActivateConnection; this.password = password; this.handlers = handlers; @@ -62,11 +66,6 @@ public void channelInactive(ChannelHandlerContext ctx) throws Exception { @Override public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { - if (evt instanceof ConnectionEvents.Close) { - if (ctx.channel().isOpen()) { - ctx.channel().close(); - } - } if (evt instanceof ConnectionEvents.Activated) { if (!initializedFuture.isDone()) { @@ -86,7 +85,7 @@ public void channelActive(final ChannelHandlerContext ctx) throws Exception { } else { pingCommand = new AsyncCommand<>(INITIALIZING_CMD_BUILDER.ping()); } - pingBeforeActivate(pingCommand, initializedFuture, ctx, handlers); + pingBeforeActivate(pingCommand, initializedFuture, ctx); } else { super.channelActive(ctx); } @@ -102,14 +101,13 @@ public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws E }); } - for (ChannelHandler handler : handlers) { - removeIfExists(channel.pipeline(), handler.getClass()); + for (ChannelHandler handler : handlers.get()) { channel.pipeline().addLast(handler); } } static void pingBeforeActivate(final AsyncCommand cmd, final CompletableFuture initializedFuture, - final ChannelHandlerContext ctx, final List handlers) throws Exception { + final ChannelHandlerContext ctx) throws Exception { cmd.handle((o, throwable) -> { if (throwable == null) { initializedFuture.complete(true); diff --git a/src/main/java/com/lambdaworks/redis/RedisChannelHandler.java b/src/main/java/com/lambdaworks/redis/RedisChannelHandler.java index 4d52769182..8be11b9474 100644 --- a/src/main/java/com/lambdaworks/redis/RedisChannelHandler.java +++ b/src/main/java/com/lambdaworks/redis/RedisChannelHandler.java @@ -9,10 +9,9 @@ import com.lambdaworks.redis.api.StatefulConnection; import com.lambdaworks.redis.internal.LettuceAssert; +import com.lambdaworks.redis.protocol.ConnectionFacade; import com.lambdaworks.redis.protocol.RedisCommand; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.util.internal.logging.InternalLogger; import io.netty.util.internal.logging.InternalLoggerFactory; @@ -24,7 +23,7 @@ * @author Mark Paluch * @since 3.0 */ -public abstract class RedisChannelHandler extends ChannelInboundHandlerAdapter implements Closeable { +public abstract class RedisChannelHandler implements Closeable, ConnectionFacade { private static final InternalLogger logger = InternalLoggerFactory.getInstance(RedisChannelHandler.class); @@ -32,7 +31,7 @@ public abstract class RedisChannelHandler extends ChannelInboundHandlerAda protected TimeUnit unit; private CloseEvents closeEvents = new CloseEvents(); - private final RedisChannelWriter channelWriter; + private final RedisChannelWriter channelWriter; private volatile boolean closed; private volatile boolean active = true; private volatile ClientOptions clientOptions; @@ -45,20 +44,15 @@ public abstract class RedisChannelHandler extends ChannelInboundHandlerAda * @param timeout timeout value * @param unit unit of the timeout */ - public RedisChannelHandler(RedisChannelWriter writer, long timeout, TimeUnit unit) { + public RedisChannelHandler(RedisChannelWriter writer, long timeout, TimeUnit unit) { this.channelWriter = writer; debugEnabled = logger.isDebugEnabled(); - writer.setRedisChannelHandler(this); + writer.setConnectionFacade(this); setTimeout(timeout, unit); } - @Override - public void channelRegistered(ChannelHandlerContext ctx) throws Exception { - closed = false; - } - /** * Set the command timeout for this connection. * @@ -92,21 +86,6 @@ public synchronized void close() { closeEvents.fireEventClosed(this); closeEvents = new CloseEvents(); } - - } - - @Override - public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { - channelRead(msg); - } - - /** - * Invoked on a channel read. - * - * @param msg channel message - */ - public void channelRead(Object msg) { - } protected > C dispatch(C cmd) { @@ -115,7 +94,7 @@ protected > C dispatch(C cmd) { logger.debug("dispatching command {}", cmd); } - return channelWriter.write(cmd); + return (C) channelWriter.write(cmd); } /** @@ -177,7 +156,7 @@ public void deactivated() { * * @return the channel writer */ - public RedisChannelWriter getChannelWriter() { + public RedisChannelWriter getChannelWriter() { return channelWriter; } diff --git a/src/main/java/com/lambdaworks/redis/RedisChannelWriter.java b/src/main/java/com/lambdaworks/redis/RedisChannelWriter.java index 214364266a..e9ff98b6c8 100644 --- a/src/main/java/com/lambdaworks/redis/RedisChannelWriter.java +++ b/src/main/java/com/lambdaworks/redis/RedisChannelWriter.java @@ -2,28 +2,28 @@ import java.io.Closeable; +import com.lambdaworks.redis.protocol.ConnectionFacade; import com.lambdaworks.redis.protocol.RedisCommand; /** * Writer for a channel. Writers push commands on to the communication channel and maintain a state for the commands. * - * @param Key type. - * @param Value type. * @author Mark Paluch * @since 3.0 */ -public interface RedisChannelWriter extends Closeable { +public interface RedisChannelWriter extends Closeable { /** * Write a command on the channel. The command may be changed/wrapped during write and the written instance is returned * after the call. * * @param command the redis command + * @param key type + * @param value type * @param result type - * @param command type * @return the written redis command */ - > C write(C command); + RedisCommand write(RedisCommand command); @Override void close(); @@ -35,11 +35,11 @@ public interface RedisChannelWriter extends Closeable { void reset(); /** - * Set the corresponding connection instance in order to notify it about channel active/inactive state. + * Set the corresponding connection facade in order to notify it about channel active/inactive state. * - * @param redisChannelHandler the channel handler (external connection object) + * @param connection the connection facade (external connection object) */ - void setRedisChannelHandler(RedisChannelHandler redisChannelHandler); + void setConnectionFacade(ConnectionFacade connection); /** * Disable or enable auto-flush behavior. Default is {@literal true}. If autoFlushCommands is disabled, multiple commands diff --git a/src/main/java/com/lambdaworks/redis/RedisClient.java b/src/main/java/com/lambdaworks/redis/RedisClient.java index eaf06353d4..a8ecc2e2fe 100644 --- a/src/main/java/com/lambdaworks/redis/RedisClient.java +++ b/src/main/java/com/lambdaworks/redis/RedisClient.java @@ -9,7 +9,6 @@ import java.net.ConnectException; import java.net.SocketAddress; import java.util.List; -import java.util.Queue; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; @@ -19,16 +18,17 @@ import com.lambdaworks.redis.codec.RedisCodec; import com.lambdaworks.redis.codec.StringCodec; import com.lambdaworks.redis.internal.LettuceAssert; -import com.lambdaworks.redis.internal.LettuceFactories; +import com.lambdaworks.redis.protocol.DefaultEndpoint; import com.lambdaworks.redis.protocol.CommandHandler; -import com.lambdaworks.redis.protocol.RedisCommand; import com.lambdaworks.redis.pubsub.PubSubCommandHandler; +import com.lambdaworks.redis.pubsub.PubSubEndpoint; import com.lambdaworks.redis.pubsub.StatefulRedisPubSubConnection; import com.lambdaworks.redis.pubsub.StatefulRedisPubSubConnectionImpl; import com.lambdaworks.redis.resource.ClientResources; import com.lambdaworks.redis.resource.SocketAddressResolver; import com.lambdaworks.redis.sentinel.StatefulRedisSentinelConnectionImpl; import com.lambdaworks.redis.sentinel.api.StatefulRedisSentinelConnection; +import com.lambdaworks.redis.sentinel.api.async.RedisSentinelAsyncCommands; /** * A scalable thread-safe Redis client. Multiple threads may share one connection if they avoid @@ -194,18 +194,16 @@ private StatefulRedisConnection connectStandalone(RedisCodec assertNotNull(codec); checkValidRedisURI(redisURI); - Queue> queue = LettuceFactories.newConcurrentQueue(); + DefaultEndpoint endpoint = new DefaultEndpoint(clientOptions); - CommandHandler handler = new CommandHandler<>(clientOptions, clientResources, queue); - - StatefulRedisConnectionImpl connection = newStatefulRedisConnection(handler, codec, timeout.timeout, - timeout.timeUnit); - connectStateful(handler, connection, redisURI); + StatefulRedisConnectionImpl connection = newStatefulRedisConnection((RedisChannelWriter) endpoint, codec, + timeout.timeout, timeout.timeUnit); + connectStateful(connection, redisURI, endpoint, () -> new CommandHandler(clientResources, endpoint)); return connection; } - private void connectStateful(CommandHandler handler, StatefulRedisConnectionImpl connection, - RedisURI redisURI) { + private void connectStateful(StatefulRedisConnectionImpl connection, RedisURI redisURI, + DefaultEndpoint endpoint, Supplier commandHandlerSupplier) { ConnectionBuilder connectionBuilder; if (redisURI.isSsl()) { @@ -216,9 +214,12 @@ private void connectStateful(CommandHandler handler, StatefulRedisC connectionBuilder = ConnectionBuilder.connectionBuilder(); } + connectionBuilder.connection(connection); connectionBuilder.clientOptions(clientOptions); connectionBuilder.clientResources(clientResources); - connectionBuilder(handler, connection, getSocketAddressSupplier(redisURI), connectionBuilder, redisURI); + connectionBuilder.commandHandler(commandHandlerSupplier).endpoint(endpoint); + + connectionBuilder(getSocketAddressSupplier(redisURI), connectionBuilder, redisURI); channelType(connectionBuilder, redisURI); initializeChannel(connectionBuilder); @@ -286,13 +287,12 @@ private StatefulRedisPubSubConnection connectPubSub(RedisCodec> queue = LettuceFactories.newConcurrentQueue(); + PubSubEndpoint endpoint = new PubSubEndpoint(clientOptions); - PubSubCommandHandler handler = new PubSubCommandHandler<>(clientOptions, clientResources, queue, codec); - StatefulRedisPubSubConnectionImpl connection = newStatefulRedisPubSubConnection(handler, codec, timeout.timeout, - timeout.timeUnit); + StatefulRedisPubSubConnectionImpl connection = newStatefulRedisPubSubConnection(endpoint, + (RedisChannelWriter) endpoint, codec, timeout.timeout, timeout.timeUnit); - connectStateful(handler, connection, redisURI); + connectStateful(connection, redisURI, endpoint, () -> new PubSubCommandHandler(clientResources, codec, endpoint)); return connection; } @@ -350,20 +350,19 @@ private StatefulRedisSentinelConnection connectSentinel(RedisCodec< assertNotNull(codec); checkValidRedisURI(redisURI); - Queue> queue = LettuceFactories.newConcurrentQueue(); - ConnectionBuilder connectionBuilder = ConnectionBuilder.connectionBuilder(); connectionBuilder.clientOptions(ClientOptions.copyOf(getOptions())); connectionBuilder.clientResources(clientResources); - final CommandHandler commandHandler = new CommandHandler<>(clientOptions, clientResources, queue); + DefaultEndpoint endpoint = new DefaultEndpoint(clientOptions); - StatefulRedisSentinelConnectionImpl connection = newStatefulRedisSentinelConnection(commandHandler, codec, - timeout.timeout, timeout.timeUnit); + StatefulRedisSentinelConnectionImpl connection = newStatefulRedisSentinelConnection(endpoint, + codec, timeout.timeout, timeout.timeUnit); logger.debug("Trying to get a Sentinel connection for one of: " + redisURI.getSentinels()); - connectionBuilder(commandHandler, connection, getSocketAddressSupplier(redisURI), connectionBuilder, redisURI); + connectionBuilder.endpoint(endpoint).commandHandler(() -> new CommandHandler(clientResources, endpoint)).connection(connection); + connectionBuilder(getSocketAddressSupplier(redisURI), connectionBuilder, redisURI); if (redisURI.getSentinels().isEmpty() && (isNotEmpty(redisURI.getHost()) || !isEmpty(redisURI.getSocket()))) { channelType(connectionBuilder, redisURI); @@ -408,7 +407,8 @@ private StatefulRedisSentinelConnection connectSentinel(RedisCodec< /** * Create a new instance of {@link StatefulRedisPubSubConnectionImpl} or a subclass. * - * @param commandHandler the command handler + * @param endpoint the endpoint + * @param channelWriter the channel writer * @param codec codec * @param timeout default timeout * @param unit default timeout unit @@ -416,15 +416,15 @@ private StatefulRedisSentinelConnection connectSentinel(RedisCodec< * @param Value Type * @return new instance of StatefulRedisPubSubConnectionImpl */ - protected StatefulRedisPubSubConnectionImpl newStatefulRedisPubSubConnection( - PubSubCommandHandler commandHandler, RedisCodec codec, long timeout, TimeUnit unit) { - return new StatefulRedisPubSubConnectionImpl<>(commandHandler, codec, timeout, unit); + protected StatefulRedisPubSubConnectionImpl newStatefulRedisPubSubConnection(PubSubEndpoint endpoint, + RedisChannelWriter channelWriter, RedisCodec codec, long timeout, TimeUnit unit) { + return new StatefulRedisPubSubConnectionImpl<>(endpoint, channelWriter, codec, timeout, unit); } /** * Create a new instance of {@link StatefulRedisSentinelConnectionImpl} or a subclass. * - * @param commandHandler the command handler + * @param channelWriter the channel writer * @param codec codec * @param timeout default timeout * @param unit default timeout unit @@ -433,14 +433,14 @@ protected StatefulRedisPubSubConnectionImpl newStatefulRedisPubSubC * @return new instance of StatefulRedisSentinelConnectionImpl */ protected StatefulRedisSentinelConnectionImpl newStatefulRedisSentinelConnection( - CommandHandler commandHandler, RedisCodec codec, long timeout, TimeUnit unit) { - return new StatefulRedisSentinelConnectionImpl<>(commandHandler, codec, timeout, unit); + RedisChannelWriter channelWriter, RedisCodec codec, long timeout, TimeUnit unit) { + return new StatefulRedisSentinelConnectionImpl<>(channelWriter, codec, timeout, unit); } /** * Create a new instance of {@link StatefulRedisConnectionImpl} or a subclass. * - * @param commandHandler the command handler + * @param channelWriter the channel writer * @param codec codec * @param timeout default timeout * @param unit default timeout unit @@ -448,9 +448,9 @@ protected StatefulRedisSentinelConnectionImpl newStatefulRedisSenti * @param Value Type * @return new instance of StatefulRedisConnectionImpl */ - protected StatefulRedisConnectionImpl newStatefulRedisConnection(CommandHandler commandHandler, + protected StatefulRedisConnectionImpl newStatefulRedisConnection(RedisChannelWriter channelWriter, RedisCodec codec, long timeout, TimeUnit unit) { - return new StatefulRedisConnectionImpl<>(commandHandler, codec, timeout, unit); + return new StatefulRedisConnectionImpl<>(channelWriter, codec, timeout, unit); } private void validateUrisAreOfSameConnectionType(List redisUris) { diff --git a/src/main/java/com/lambdaworks/redis/SslConnectionBuilder.java b/src/main/java/com/lambdaworks/redis/SslConnectionBuilder.java index 19cd08dd74..1c256cbb8a 100644 --- a/src/main/java/com/lambdaworks/redis/SslConnectionBuilder.java +++ b/src/main/java/com/lambdaworks/redis/SslConnectionBuilder.java @@ -4,7 +4,6 @@ import static com.lambdaworks.redis.ConnectionEventTrigger.remote; import static com.lambdaworks.redis.PlainChannelInitializer.INITIALIZING_CMD_BUILDER; import static com.lambdaworks.redis.PlainChannelInitializer.pingBeforeActivate; -import static com.lambdaworks.redis.PlainChannelInitializer.removeIfExists; import java.io.IOException; import java.io.InputStream; @@ -12,6 +11,7 @@ import java.security.KeyStore; import java.util.List; import java.util.concurrent.CompletableFuture; +import java.util.function.Supplier; import javax.net.ssl.*; @@ -22,7 +22,10 @@ import com.lambdaworks.redis.internal.LettuceAssert; import com.lambdaworks.redis.protocol.AsyncCommand; -import io.netty.channel.*; +import io.netty.channel.Channel; +import io.netty.channel.ChannelDuplexHandler; +import io.netty.channel.ChannelHandler; +import io.netty.channel.ChannelHandlerContext; import io.netty.handler.ssl.SslContext; import io.netty.handler.ssl.SslContextBuilder; import io.netty.handler.ssl.SslHandler; @@ -57,9 +60,7 @@ protected List buildHandlers() { @Override public RedisChannelInitializer build() { - final List channelHandlers = buildHandlers(); - - return new SslChannelInitializer(clientOptions().isPingBeforeActivateConnection(), channelHandlers, redisURI, + return new SslChannelInitializer(clientOptions().isPingBeforeActivateConnection(), this::buildHandlers, redisURI, clientResources().eventBus(), clientOptions().getSslOptions()); } @@ -69,13 +70,13 @@ public RedisChannelInitializer build() { static class SslChannelInitializer extends io.netty.channel.ChannelInitializer implements RedisChannelInitializer { private final boolean pingBeforeActivate; - private final List handlers; + private final Supplier> handlers; private final RedisURI redisURI; private final EventBus eventBus; private final SslOptions sslOptions; private CompletableFuture initializedFuture = new CompletableFuture<>(); - public SslChannelInitializer(boolean pingBeforeActivate, List handlers, RedisURI redisURI, + public SslChannelInitializer(boolean pingBeforeActivate, Supplier> handlers, RedisURI redisURI, EventBus eventBus, SslOptions sslOptions) { this.pingBeforeActivate = pingBeforeActivate; this.handlers = handlers; @@ -108,8 +109,6 @@ protected void initChannel(Channel channel) throws Exception { SSLEngine sslEngine = sslContext.newEngine(channel.alloc(), redisURI.getHost(), redisURI.getPort()); sslEngine.setSSLParameters(sslParams); - removeIfExists(channel.pipeline(), SslHandler.class); - if (channel.pipeline().get("first") == null) { channel.pipeline().addFirst("first", new ChannelDuplexHandler() { @@ -167,7 +166,7 @@ public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exc } else { pingCommand = new AsyncCommand<>(INITIALIZING_CMD_BUILDER.ping()); } - pingBeforeActivate(pingCommand, initializedFuture, ctx, handlers); + pingBeforeActivate(pingCommand, initializedFuture, ctx); } else { ctx.fireChannelActive(); } @@ -176,12 +175,6 @@ public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exc } } - if (evt instanceof ConnectionEvents.Close) { - if (ctx.channel().isOpen()) { - ctx.channel().close(); - } - } - if (evt instanceof ConnectionEvents.Activated) { if (!initializedFuture.isDone()) { initializedFuture.complete(true); @@ -202,8 +195,7 @@ public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws E }); } - for (ChannelHandler handler : handlers) { - removeIfExists(channel.pipeline(), handler.getClass()); + for (ChannelHandler handler : handlers.get()) { channel.pipeline().addLast(handler); } } diff --git a/src/main/java/com/lambdaworks/redis/StatefulRedisConnectionImpl.java b/src/main/java/com/lambdaworks/redis/StatefulRedisConnectionImpl.java index 96fda2aaa3..1db6921758 100644 --- a/src/main/java/com/lambdaworks/redis/StatefulRedisConnectionImpl.java +++ b/src/main/java/com/lambdaworks/redis/StatefulRedisConnectionImpl.java @@ -34,7 +34,6 @@ * @param Value type. * @author Mark Paluch */ -@ChannelHandler.Sharable public class StatefulRedisConnectionImpl extends RedisChannelHandler implements StatefulRedisConnection { protected final RedisCodec codec; @@ -55,7 +54,7 @@ public class StatefulRedisConnectionImpl extends RedisChannelHandler * @param timeout Maximum time to wait for a response. * @param unit Unit of time for the timeout. */ - public StatefulRedisConnectionImpl(RedisChannelWriter writer, RedisCodec codec, long timeout, TimeUnit unit) { + public StatefulRedisConnectionImpl(RedisChannelWriter writer, RedisCodec codec, long timeout, TimeUnit unit) { super(writer, timeout, unit); this.codec = codec; diff --git a/src/main/java/com/lambdaworks/redis/cluster/AbstractNodeSelection.java b/src/main/java/com/lambdaworks/redis/cluster/AbstractNodeSelection.java index 9f83712db3..93625c45fd 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/AbstractNodeSelection.java +++ b/src/main/java/com/lambdaworks/redis/cluster/AbstractNodeSelection.java @@ -24,7 +24,7 @@ abstract class AbstractNodeSelection implements NodeSelectionSup protected StatefulRedisClusterConnection globalConnection; private ClusterConnectionProvider.Intent intent; - protected ClusterDistributionChannelWriter writer; + protected ClusterDistributionChannelWriter writer; public AbstractNodeSelection(StatefulRedisClusterConnection globalConnection, ClusterConnectionProvider.Intent intent) { this.globalConnection = globalConnection; diff --git a/src/main/java/com/lambdaworks/redis/cluster/ClusterCommand.java b/src/main/java/com/lambdaworks/redis/cluster/ClusterCommand.java index ba0bbf59e1..51375b41d6 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/ClusterCommand.java +++ b/src/main/java/com/lambdaworks/redis/cluster/ClusterCommand.java @@ -14,7 +14,7 @@ */ class ClusterCommand extends CommandWrapper implements RedisCommand { - private RedisChannelWriter retry; + private RedisChannelWriter retry; private int redirections; private int maxRedirections; private boolean completed; @@ -25,7 +25,7 @@ class ClusterCommand extends CommandWrapper implements RedisCo * @param retry * @param maxRedirections */ - ClusterCommand(RedisCommand command, RedisChannelWriter retry, int maxRedirections) { + ClusterCommand(RedisCommand command, RedisChannelWriter retry, int maxRedirections) { super(command); this.retry = retry; this.maxRedirections = maxRedirections; diff --git a/src/main/java/com/lambdaworks/redis/cluster/ClusterDistributionChannelWriter.java b/src/main/java/com/lambdaworks/redis/cluster/ClusterDistributionChannelWriter.java index 15415dbee4..cb5c7a77c6 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/ClusterDistributionChannelWriter.java +++ b/src/main/java/com/lambdaworks/redis/cluster/ClusterDistributionChannelWriter.java @@ -7,24 +7,19 @@ import com.lambdaworks.redis.cluster.models.partitions.Partitions; import com.lambdaworks.redis.internal.HostAndPort; import com.lambdaworks.redis.internal.LettuceAssert; -import com.lambdaworks.redis.protocol.CommandArgs; -import com.lambdaworks.redis.protocol.CommandKeyword; -import com.lambdaworks.redis.protocol.ProtocolKeyword; -import com.lambdaworks.redis.protocol.RedisCommand; +import com.lambdaworks.redis.protocol.*; import io.netty.util.concurrent.EventExecutorGroup; /** * Channel writer for cluster operation. This writer looks up the right partition by hash/slot for the operation. - * - * @param Key type. - * @param Value type. + * * @author Mark Paluch * @since 3.0 */ -class ClusterDistributionChannelWriter implements RedisChannelWriter { +class ClusterDistributionChannelWriter implements RedisChannelWriter { - private final RedisChannelWriter defaultWriter; + private final RedisChannelWriter defaultWriter; private final ClusterEventListener clusterEventListener; private final EventExecutorGroup eventExecutors; private final int executionLimit; @@ -34,7 +29,7 @@ class ClusterDistributionChannelWriter implements RedisChannelWriter long p20, p21, p22, p23, p24, p25, p26; long p30, p31, p32, p33, p34, p35, p36, p37; - ClusterDistributionChannelWriter(ClientOptions clientOptions, RedisChannelWriter defaultWriter, + ClusterDistributionChannelWriter(ClientOptions clientOptions, RedisChannelWriter defaultWriter, ClusterEventListener clusterEventListener, EventExecutorGroup eventExecutors) { if (clientOptions instanceof ClusterClientOptions) { @@ -49,8 +44,7 @@ class ClusterDistributionChannelWriter implements RedisChannelWriter } @Override - @SuppressWarnings("unchecked") - public > C write(C command) { + public RedisCommand write(RedisCommand command) { LettuceAssert.notNull(command, "Command must not be null"); @@ -65,7 +59,6 @@ public > C write(C command) { commandToSend = new ClusterCommand<>(command, this, executionLimit); } - if (commandToSend instanceof ClusterCommand && !commandToSend.isDone()) { ClusterCommand clusterCommand = (ClusterCommand) commandToSend; @@ -107,7 +100,7 @@ public > C write(C command) { } } - RedisChannelWriter channelWriter = null; + RedisChannelWriter channelWriter = null; if (args != null && args.getFirstEncodedKey() != null) { int hash = getSlot(args.getFirstEncodedKey()); @@ -120,7 +113,7 @@ public > C write(C command) { } if (channelWriter instanceof ClusterDistributionChannelWriter) { - ClusterDistributionChannelWriter writer = (ClusterDistributionChannelWriter) channelWriter; + ClusterDistributionChannelWriter writer = (ClusterDistributionChannelWriter) channelWriter; channelWriter = writer.defaultWriter; } @@ -129,10 +122,10 @@ public > C write(C command) { } if (channelWriter != null && channelWriter != this && channelWriter != defaultWriter) { - return channelWriter.write((C) commandToSend); + return channelWriter.write(commandToSend); } - defaultWriter.write((C) commandToSend); + defaultWriter.write(commandToSend); return command; } @@ -188,12 +181,11 @@ public void close() { clusterConnectionProvider.close(); clusterConnectionProvider = null; } - } @Override - public void setRedisChannelHandler(RedisChannelHandler redisChannelHandler) { - defaultWriter.setRedisChannelHandler(redisChannelHandler); + public void setConnectionFacade(ConnectionFacade redisChannelHandler) { + defaultWriter.setConnectionFacade(redisChannelHandler); } @Override diff --git a/src/main/java/com/lambdaworks/redis/cluster/ClusterNodeCommandHandler.java b/src/main/java/com/lambdaworks/redis/cluster/ClusterNodeEndpoint.java similarity index 59% rename from src/main/java/com/lambdaworks/redis/cluster/ClusterNodeCommandHandler.java rename to src/main/java/com/lambdaworks/redis/cluster/ClusterNodeEndpoint.java index dc28064f2b..3604b146e2 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/ClusterNodeCommandHandler.java +++ b/src/main/java/com/lambdaworks/redis/cluster/ClusterNodeEndpoint.java @@ -2,19 +2,15 @@ import java.util.ArrayList; import java.util.Collection; -import java.util.Queue; -import java.util.Set; import com.lambdaworks.redis.ClientOptions; import com.lambdaworks.redis.RedisChannelWriter; import com.lambdaworks.redis.RedisException; -import com.lambdaworks.redis.internal.LettuceSets; -import com.lambdaworks.redis.protocol.CommandHandler; import com.lambdaworks.redis.protocol.ConnectionWatchdog; import com.lambdaworks.redis.protocol.RedisCommand; +import com.lambdaworks.redis.protocol.DefaultEndpoint; import com.lambdaworks.redis.resource.ClientResources; -import io.netty.channel.ChannelHandler; import io.netty.util.internal.logging.InternalLogger; import io.netty.util.internal.logging.InternalLoggerFactory; @@ -25,26 +21,22 @@ * * @author Mark Paluch */ -@ChannelHandler.Sharable -class ClusterNodeCommandHandler extends CommandHandler { +class ClusterNodeEndpoint extends DefaultEndpoint { - private static final InternalLogger logger = InternalLoggerFactory.getInstance(ClusterNodeCommandHandler.class); - private static final Set CHANNEL_OPEN_STATES = LettuceSets.unmodifiableSet(LifecycleState.ACTIVATING, - LifecycleState.ACTIVE, LifecycleState.CONNECTED); + private static final InternalLogger logger = InternalLoggerFactory.getInstance(ClusterNodeEndpoint.class); - private final RedisChannelWriter clusterChannelWriter; + private final RedisChannelWriter clusterChannelWriter; /** * Initialize a new instance that handles commands from the supplied queue. * * @param clientOptions client options for this connection * @param clientResources client resources for this connection - * @param queue The command queue * @param clusterChannelWriter top-most channel writer. */ - public ClusterNodeCommandHandler(ClientOptions clientOptions, ClientResources clientResources, - Queue> queue, RedisChannelWriter clusterChannelWriter) { - super(clientOptions, clientResources, queue); + public ClusterNodeEndpoint(ClientOptions clientOptions, ClientResources clientResources, + RedisChannelWriter clusterChannelWriter) { + super(clientOptions); this.clusterChannelWriter = clusterChannelWriter; } @@ -72,28 +64,22 @@ public void close() { logger.debug("{} close()", logPrefix()); if (clusterChannelWriter != null) { - - if (isAutoReconnect() && !CHANNEL_OPEN_STATES.contains(getState())) { - - Collection> commands = shiftCommands(queue); - retriggerCommands(commands); - } - Collection> commands = shiftCommands(commandBuffer); + Collection> commands = shiftCommands(getQueue()); retriggerCommands(commands); } super.close(); } - protected void retriggerCommands(Collection> commands) { - - for (RedisCommand queuedCommand : commands) { - + protected void retriggerCommands(Collection> commands) { + + for (RedisCommand queuedCommand : commands) { + if (queuedCommand == null || queuedCommand.isCancelled()) { continue; } - + try { clusterChannelWriter.write(queuedCommand); } catch (RedisException e) { @@ -105,27 +91,15 @@ protected void retriggerCommands(Collection> commands) { /** * Retrieve commands within a lock to prevent concurrent modification */ - private Collection> shiftCommands(Collection> source) { - - synchronized (stateLock) { + private Collection> shiftCommands(Collection> source) { + return doExclusive(() -> { try { - - lockWritersExclusive(); - - try { - return new ArrayList<>(source); - } finally { - source.clear(); - } - + return new ArrayList<>(source); } finally { - unlockWritersExclusive(); + source.clear(); } - } + }); } - public boolean isAutoReconnect() { - return clientOptions.isAutoReconnect(); - } } diff --git a/src/main/java/com/lambdaworks/redis/cluster/PooledClusterConnectionProvider.java b/src/main/java/com/lambdaworks/redis/cluster/PooledClusterConnectionProvider.java index b6c7f46ecb..a290f96ba2 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/PooledClusterConnectionProvider.java +++ b/src/main/java/com/lambdaworks/redis/cluster/PooledClusterConnectionProvider.java @@ -49,7 +49,7 @@ class PooledClusterConnectionProvider implements ClusterConnectionProvider private boolean autoFlushCommands = true; private ReadFrom readFrom; - public PooledClusterConnectionProvider(RedisClusterClient redisClusterClient, RedisChannelWriter clusterWriter, + public PooledClusterConnectionProvider(RedisClusterClient redisClusterClient, RedisChannelWriter clusterWriter, RedisCodec redisCodec) { this.redisClusterClient = redisClusterClient; this.debugEnabled = logger.isDebugEnabled(); @@ -271,12 +271,12 @@ private void reconfigurePartitions() { for (ConnectionKey key : staleConnections) { StatefulRedisConnection connection = connections.get(key); - RedisChannelHandler redisChannelHandler = (RedisChannelHandler) connection; + RedisChannelHandler endpoint = (RedisChannelHandler) connection; - if (redisChannelHandler.getChannelWriter() instanceof ClusterNodeCommandHandler) { - ClusterNodeCommandHandler clusterNodeCommandHandler = (ClusterNodeCommandHandler) redisChannelHandler + if (endpoint.getChannelWriter() instanceof ClusterNodeEndpoint) { + ClusterNodeEndpoint clusterNodeEndpoint = (ClusterNodeEndpoint) endpoint .getChannelWriter(); - clusterNodeCommandHandler.prepareClose(); + clusterNodeEndpoint.prepareClose(); } } @@ -478,10 +478,10 @@ private class ConnectionFactory implements Function redisCodec; - private final RedisChannelWriter clusterWriter; + private final RedisChannelWriter clusterWriter; public ConnectionFactory(RedisClusterClient redisClusterClient, RedisCodec redisCodec, - RedisChannelWriter clusterWriter) { + RedisChannelWriter clusterWriter) { this.redisClusterClient = redisClusterClient; this.redisCodec = redisCodec; this.clusterWriter = clusterWriter; diff --git a/src/main/java/com/lambdaworks/redis/cluster/RedisClusterClient.java b/src/main/java/com/lambdaworks/redis/cluster/RedisClusterClient.java index 824a0ade39..d2fb069990 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/RedisClusterClient.java +++ b/src/main/java/com/lambdaworks/redis/cluster/RedisClusterClient.java @@ -26,12 +26,12 @@ import com.lambdaworks.redis.codec.RedisCodec; import com.lambdaworks.redis.codec.StringCodec; import com.lambdaworks.redis.internal.LettuceAssert; -import com.lambdaworks.redis.internal.LettuceFactories; import com.lambdaworks.redis.internal.LettuceLists; import com.lambdaworks.redis.output.ValueStreamingChannel; +import com.lambdaworks.redis.protocol.DefaultEndpoint; import com.lambdaworks.redis.protocol.CommandHandler; -import com.lambdaworks.redis.protocol.RedisCommand; import com.lambdaworks.redis.pubsub.PubSubCommandHandler; +import com.lambdaworks.redis.pubsub.PubSubEndpoint; import com.lambdaworks.redis.pubsub.StatefulRedisPubSubConnection; import com.lambdaworks.redis.pubsub.StatefulRedisPubSubConnectionImpl; import com.lambdaworks.redis.resource.ClientResources; @@ -376,8 +376,8 @@ public SocketAddress get() { * @param Value type * @return A new connection */ - StatefulRedisConnection connectToNode(RedisCodec codec, String nodeId, - RedisChannelWriter clusterWriter, final Supplier socketAddressSupplier) { + StatefulRedisConnection connectToNode(RedisCodec codec, String nodeId, RedisChannelWriter clusterWriter, + final Supplier socketAddressSupplier) { assertNotNull(codec); assertNotEmpty(initialUris); @@ -385,14 +385,13 @@ StatefulRedisConnection connectToNode(RedisCodec codec, Strin LettuceAssert.notNull(socketAddressSupplier, "SocketAddressSupplier must not be null"); logger.debug("connectNode(" + nodeId + ")"); - Queue> queue = LettuceFactories.newConcurrentQueue(); - ClusterNodeCommandHandler handler = new ClusterNodeCommandHandler(clientOptions, getResources(), queue, - clusterWriter); - StatefulRedisConnectionImpl connection = new StatefulRedisConnectionImpl(handler, codec, timeout, unit); + ClusterNodeEndpoint endpoint = new ClusterNodeEndpoint(clientOptions, getResources(), clusterWriter); + StatefulRedisConnectionImpl connection = new StatefulRedisConnectionImpl(endpoint, codec, timeout, unit); try { - connectStateful(handler, connection, getFirstUri(), socketAddressSupplier); + connectStateful(connection, endpoint, getFirstUri(), socketAddressSupplier, + () -> new CommandHandler(clientResources, endpoint)); connection.registerCloseables(closeableResources, connection); } catch (RedisException e) { @@ -420,14 +419,13 @@ StatefulRedisClusterConnectionImpl connectClusterImpl(RedisCodec> queue = LettuceFactories.newConcurrentQueue(); Supplier socketAddressSupplier = getSocketAddressSupplier(TopologyComparators::sortByClientCount); - CommandHandler handler = new CommandHandler(clientOptions, clientResources, queue); + DefaultEndpoint endpoint = new DefaultEndpoint(clientOptions); - ClusterDistributionChannelWriter clusterWriter = new ClusterDistributionChannelWriter(clientOptions, - handler, clusterTopologyRefreshScheduler, getResources().eventExecutorGroup()); + ClusterDistributionChannelWriter clusterWriter = new ClusterDistributionChannelWriter(clientOptions, + endpoint, clusterTopologyRefreshScheduler, getResources().eventExecutorGroup()); PooledClusterConnectionProvider pooledClusterConnectionProvider = new PooledClusterConnectionProvider(this, clusterWriter, codec); @@ -445,7 +443,8 @@ StatefulRedisClusterConnectionImpl connectClusterImpl(RedisCodec new CommandHandler(clientResources, endpoint)); connected = true; break; } catch (RedisException e) { @@ -483,21 +482,20 @@ StatefulRedisPubSubConnectionImpl connectClusterPubSubImpl(RedisCod activateTopologyRefreshIfNeeded(); logger.debug("connectClusterPubSub(" + initialUris + ")"); - Queue> queue = LettuceFactories.newConcurrentQueue(); Supplier socketAddressSupplier = getSocketAddressSupplier(TopologyComparators::sortByClientCount); - PubSubCommandHandler handler = new PubSubCommandHandler(clientOptions, clientResources, queue, codec); + PubSubEndpoint endpoint = new PubSubEndpoint(clientOptions); - ClusterDistributionChannelWriter clusterWriter = new ClusterDistributionChannelWriter(clientOptions, - handler, clusterTopologyRefreshScheduler, getResources().eventExecutorGroup()); + ClusterDistributionChannelWriter clusterWriter = new ClusterDistributionChannelWriter(clientOptions, endpoint, + clusterTopologyRefreshScheduler, getResources().eventExecutorGroup()); PooledClusterConnectionProvider pooledClusterConnectionProvider = new PooledClusterConnectionProvider(this, clusterWriter, codec); clusterWriter.setClusterConnectionProvider(pooledClusterConnectionProvider); - StatefulRedisPubSubConnectionImpl connection = new StatefulRedisPubSubConnectionImpl<>(clusterWriter, codec, - timeout, unit); + StatefulRedisPubSubConnectionImpl connection = new StatefulRedisPubSubConnectionImpl<>(endpoint, clusterWriter, + codec, timeout, unit); clusterWriter.setPartitions(partitions); @@ -507,7 +505,8 @@ StatefulRedisPubSubConnectionImpl connectClusterPubSubImpl(RedisCod for (int i = 0; i < connectionAttempts; i++) { try { - connectStateful(handler, connection, getFirstUri(), socketAddressSupplier); + connectStateful(connection, endpoint, getFirstUri(), socketAddressSupplier, + () -> new PubSubCommandHandler(clientResources, codec, endpoint)); connected = true; break; } catch (RedisException e) { @@ -534,17 +533,12 @@ StatefulRedisPubSubConnectionImpl connectClusterPubSubImpl(RedisCod * Connect to a endpoint provided by {@code socketAddressSupplier} using connection settings (authentication, SSL) from * {@code connectionSettings}. * - * @param handler - * @param connection - * @param connectionSettings - * @param socketAddressSupplier - * @param - * @param */ - private void connectStateful(CommandHandler handler, StatefulRedisConnectionImpl connection, - RedisURI connectionSettings, Supplier socketAddressSupplier) { + private void connectStateful(StatefulRedisConnectionImpl connection, DefaultEndpoint endpoint, + RedisURI connectionSettings, Supplier socketAddressSupplier, + Supplier commandHandlerSupplier) { - connectStateful0(handler, connection, connectionSettings, socketAddressSupplier); + connectStateful0(connection, endpoint, connectionSettings, socketAddressSupplier, commandHandlerSupplier); if (connectionSettings.getPassword() != null && connectionSettings.getPassword().length != 0) { connection.async().auth(new String(connectionSettings.getPassword())); @@ -555,17 +549,12 @@ private void connectStateful(CommandHandler handler, StatefulRedisC * Connect to a endpoint provided by {@code socketAddressSupplier} using connection settings (authentication, SSL) from * {@code connectionSettings}. * - * @param handler - * @param connection - * @param connectionSettings - * @param socketAddressSupplier - * @param - * @param */ - private void connectStateful(CommandHandler handler, StatefulRedisClusterConnectionImpl connection, - RedisURI connectionSettings, Supplier socketAddressSupplier) { + private void connectStateful(DefaultEndpoint endpoint, StatefulRedisClusterConnectionImpl connection, + RedisURI connectionSettings, Supplier socketAddressSupplier, + Supplier commandHandlerSupplier) { - connectStateful0(handler, connection, connectionSettings, socketAddressSupplier); + connectStateful0(connection, endpoint, connectionSettings, socketAddressSupplier, commandHandlerSupplier); if (connectionSettings.getPassword() != null && connectionSettings.getPassword().length != 0) { connection.async().auth(new String(connectionSettings.getPassword())); @@ -575,16 +564,10 @@ private void connectStateful(CommandHandler handler, StatefulRedisC /** * Connect to a endpoint provided by {@code socketAddressSupplier} using connection settings (SSL) from {@code * connectionSettings}. - * - * @param handler - * @param connection - * @param connectionSettings - * @param socketAddressSupplier - * @param - * @param */ - private void connectStateful0(CommandHandler handler, RedisChannelHandler connection, - RedisURI connectionSettings, Supplier socketAddressSupplier) { + private void connectStateful0(RedisChannelHandler connection, DefaultEndpoint endpoint, + RedisURI connectionSettings, Supplier socketAddressSupplier, + Supplier commandHandlerSupplier) { ConnectionBuilder connectionBuilder; if (connectionSettings.isSsl()) { @@ -597,8 +580,11 @@ private void connectStateful0(CommandHandler handler, RedisChannelH connectionBuilder.reconnectionListener(new ReconnectEventListener(clusterTopologyRefreshScheduler)); connectionBuilder.clientOptions(clientOptions); + connectionBuilder.connection(connection); connectionBuilder.clientResources(clientResources); - connectionBuilder(handler, connection, socketAddressSupplier, connectionBuilder, connectionSettings); + connectionBuilder.endpoint(endpoint); + connectionBuilder.commandHandler(commandHandlerSupplier); + connectionBuilder(socketAddressSupplier, connectionBuilder, connectionSettings); channelType(connectionBuilder, connectionSettings); initializeChannel(connectionBuilder); @@ -696,9 +682,8 @@ private void activateTopologyRefreshIfNeeded() { } if (clusterTopologyRefreshActivated.compareAndSet(false, true)) { - ScheduledFuture scheduledFuture = genericWorkerPool - .scheduleAtFixedRate(clusterTopologyRefreshScheduler, options.getRefreshPeriod(), - options.getRefreshPeriod(), options.getRefreshPeriodUnit()); + ScheduledFuture scheduledFuture = genericWorkerPool.scheduleAtFixedRate(clusterTopologyRefreshScheduler, + options.getRefreshPeriod(), options.getRefreshPeriod(), options.getRefreshPeriodUnit()); clusterTopologyRefreshFuture.set(scheduledFuture); } } @@ -768,7 +753,7 @@ public ClientResources getResources() { @Override public void shutdown(long quietPeriod, long timeout, TimeUnit timeUnit) { - if(clusterTopologyRefreshActivated.compareAndSet(true, false)){ + if (clusterTopologyRefreshActivated.compareAndSet(true, false)) { ScheduledFuture scheduledFuture = clusterTopologyRefreshFuture.get(); diff --git a/src/main/java/com/lambdaworks/redis/cluster/StatefulRedisClusterConnectionImpl.java b/src/main/java/com/lambdaworks/redis/cluster/StatefulRedisClusterConnectionImpl.java index c352a4b069..995b9813d0 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/StatefulRedisClusterConnectionImpl.java +++ b/src/main/java/com/lambdaworks/redis/cluster/StatefulRedisClusterConnectionImpl.java @@ -44,7 +44,6 @@ * @author Mark Paluch * @since 4.0 */ -@ChannelHandler.Sharable public class StatefulRedisClusterConnectionImpl extends RedisChannelHandler implements StatefulRedisClusterConnection { @@ -66,7 +65,7 @@ public class StatefulRedisClusterConnectionImpl extends RedisChannelHandle * @param timeout Maximum time to wait for a response. * @param unit Unit of time for the timeout. */ - public StatefulRedisClusterConnectionImpl(RedisChannelWriter writer, RedisCodec codec, long timeout, + public StatefulRedisClusterConnectionImpl(RedisChannelWriter writer, RedisCodec codec, long timeout, TimeUnit unit) { super(writer, timeout, unit); this.codec = codec; @@ -126,8 +125,8 @@ public StatefulRedisConnection getConnection(String host, int port) { .getConnection(ClusterConnectionProvider.Intent.WRITE, host, port); } - public ClusterDistributionChannelWriter getClusterDistributionChannelWriter() { - return (ClusterDistributionChannelWriter) super.getChannelWriter(); + public ClusterDistributionChannelWriter getClusterDistributionChannelWriter() { + return (ClusterDistributionChannelWriter) super.getChannelWriter(); } @Override diff --git a/src/main/java/com/lambdaworks/redis/cluster/topology/ClusterTopologyRefresh.java b/src/main/java/com/lambdaworks/redis/cluster/topology/ClusterTopologyRefresh.java index 652d265f00..178bdeebcc 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/topology/ClusterTopologyRefresh.java +++ b/src/main/java/com/lambdaworks/redis/cluster/topology/ClusterTopologyRefresh.java @@ -90,8 +90,8 @@ private Set toSet(Iterable seed) { return StreamSupport.stream(seed.spliterator(), false).collect(Collectors.toCollection(HashSet::new)); } - NodeTopologyViews getNodeSpecificViews(Requests requestedTopology, Requests requestedClients, - long commandTimeoutNs) throws InterruptedException { + NodeTopologyViews getNodeSpecificViews(Requests requestedTopology, Requests requestedClients, long commandTimeoutNs) + throws InterruptedException { List allNodes = new ArrayList<>(); @@ -122,7 +122,7 @@ NodeTopologyViews getNodeSpecificViews(Requests requestedTopology, Requests requ if (partition.getFlags().contains(RedisClusterNode.NodeFlag.MYSELF)) { - if(partition.getUri() == null){ + if (partition.getUri() == null) { partition.setUri(node); } diff --git a/src/main/java/com/lambdaworks/redis/masterslave/MasterSlaveChannelWriter.java b/src/main/java/com/lambdaworks/redis/masterslave/MasterSlaveChannelWriter.java index 6216cebc03..a066bd5c4c 100644 --- a/src/main/java/com/lambdaworks/redis/masterslave/MasterSlaveChannelWriter.java +++ b/src/main/java/com/lambdaworks/redis/masterslave/MasterSlaveChannelWriter.java @@ -1,11 +1,11 @@ package com.lambdaworks.redis.masterslave; import com.lambdaworks.redis.ReadFrom; -import com.lambdaworks.redis.RedisChannelHandler; import com.lambdaworks.redis.RedisChannelWriter; import com.lambdaworks.redis.RedisException; import com.lambdaworks.redis.api.StatefulRedisConnection; import com.lambdaworks.redis.internal.LettuceAssert; +import com.lambdaworks.redis.protocol.ConnectionFacade; import com.lambdaworks.redis.protocol.ProtocolKeyword; import com.lambdaworks.redis.protocol.RedisCommand; @@ -14,7 +14,7 @@ * * @author Mark Paluch */ -class MasterSlaveChannelWriter implements RedisChannelWriter { +class MasterSlaveChannelWriter implements RedisChannelWriter { private MasterSlaveConnectionProvider masterSlaveConnectionProvider; private boolean closed = false; @@ -24,7 +24,7 @@ public MasterSlaveChannelWriter(MasterSlaveConnectionProvider masterSlaveC } @Override - public > C write(C command) { + public RedisCommand write(RedisCommand command) { LettuceAssert.notNull(command, "Command must not be null"); @@ -33,7 +33,7 @@ public > C write(C command) { } MasterSlaveConnectionProvider.Intent intent = getIntent(command.getType()); - StatefulRedisConnection connection = masterSlaveConnectionProvider.getConnection(intent); + StatefulRedisConnection connection = (StatefulRedisConnection) masterSlaveConnectionProvider.getConnection(intent); return connection.dispatch(command); } @@ -68,7 +68,7 @@ public MasterSlaveConnectionProvider getMasterSlaveConnectionProvider() { } @Override - public void setRedisChannelHandler(RedisChannelHandler redisChannelHandler) { + public void setConnectionFacade(ConnectionFacade connection) { } diff --git a/src/main/java/com/lambdaworks/redis/output/CommandOutput.java b/src/main/java/com/lambdaworks/redis/output/CommandOutput.java index 871a775d7c..46902888b0 100644 --- a/src/main/java/com/lambdaworks/redis/output/CommandOutput.java +++ b/src/main/java/com/lambdaworks/redis/output/CommandOutput.java @@ -109,7 +109,7 @@ public void complete(int depth) { } protected String decodeAscii(ByteBuffer bytes) { - if(bytes == null) { + if (bytes == null) { return null; } @@ -130,6 +130,11 @@ public String toString() { return sb.toString(); } + /** + * Mark the beginning of a multi sequence (array). + * + * @param count expected number of elements in this multi sequence. + */ public void multi(int count) { } diff --git a/src/main/java/com/lambdaworks/redis/protocol/CommandEncoder.java b/src/main/java/com/lambdaworks/redis/protocol/CommandEncoder.java index 0b06635aaa..69321f1cef 100644 --- a/src/main/java/com/lambdaworks/redis/protocol/CommandEncoder.java +++ b/src/main/java/com/lambdaworks/redis/protocol/CommandEncoder.java @@ -19,7 +19,6 @@ * * @author Mark Paluch */ -@ChannelHandler.Sharable public class CommandEncoder extends MessageToByteEncoder { private static final InternalLogger logger = InternalLoggerFactory.getInstance(CommandEncoder.class); @@ -101,7 +100,7 @@ private void encode(ChannelHandlerContext ctx, ByteBuf out, RedisCommand Key type. - * @param Value type. * @author Will Glozer * @author Mark Paluch */ -@ChannelHandler.Sharable -public class CommandHandler extends ChannelDuplexHandler implements RedisChannelWriter { - - private static final InternalLogger logger = InternalLoggerFactory.getInstance(CommandHandler.class); - private static final WriteLogListener WRITE_LOG_LISTENER = new WriteLogListener(); - private static final AtomicLong CHANNEL_COUNTER = new AtomicLong(); +public class CommandHandler extends ChannelDuplexHandler implements HasQueuedCommands { /** * When we encounter an unexpected IOException we look for these {@link Throwable#getMessage() messages} (because we have no * better way to distinguish) and log them at DEBUG rather than WARN, since they are generally caused by unclean client * disconnects rather than an actual problem. */ - private static final Set SUPPRESS_IO_EXCEPTION_MESSAGES = LettuceSets.unmodifiableSet("Connection reset by peer", + static final Set SUPPRESS_IO_EXCEPTION_MESSAGES = LettuceSets.unmodifiableSet("Connection reset by peer", "Broken pipe", "Connection timed out"); - protected final long commandHandlerId = CHANNEL_COUNTER.incrementAndGet(); - protected final ClientOptions clientOptions; - protected final ClientResources clientResources; - protected final Queue> queue; - protected final AtomicLong writers = new AtomicLong(); - protected final Object stateLock = new Object(); - - // all access to the commandBuffer is synchronized - protected final Deque> commandBuffer = LettuceFactories.newConcurrentQueue(); - protected final Deque> transportBuffer = LettuceFactories.newConcurrentQueue(); - protected final ByteBuf buffer = ByteBufAllocator.DEFAULT.directBuffer(8192 * 8); - protected final RedisStateMachine rsm = new RedisStateMachine(); - protected volatile Channel channel; - private volatile ConnectionWatchdog connectionWatchdog; + private static final InternalLogger logger = InternalLoggerFactory.getInstance(CommandHandler.class); + private static final AtomicLong COMMAND_HANDLER_COUNTER = new AtomicLong(); + + private final long commandHandlerId = COMMAND_HANDLER_COUNTER.incrementAndGet(); + private final Queue> queue = LettuceFactories.newConcurrentQueue(); + private final RedisStateMachine rsm = new RedisStateMachine(); // If TRACE level logging has been enabled at startup. private final boolean traceEnabled; // If DEBUG level logging has been enabled at startup. private final boolean debugEnabled; - private final Reliability reliability; - private volatile LifecycleState lifecycleState = LifecycleState.NOT_CONNECTED; - private Thread exclusiveLockOwner; - private RedisChannelHandler redisChannelHandler; - private Throwable connectionError; + private final ClientResources clientResources; + private final Endpoint endpoint; + + private Channel channel; + private ByteBuf buffer; + private LifecycleState lifecycleState = LifecycleState.NOT_CONNECTED; private String logPrefix; - private boolean autoFlushCommands = true; /** * Initialize a new instance that handles commands from the supplied queue. * - * @param clientOptions client options for this connection, must not be {@literal null} * @param clientResources client resources for this connection, must not be {@literal null} - * @param queue The command queue, must not be {@literal null} + * @param endpoint */ - public CommandHandler(ClientOptions clientOptions, ClientResources clientResources, Queue> queue) { + public CommandHandler(ClientResources clientResources, Endpoint endpoint) { - LettuceAssert.notNull(clientOptions, "ClientOptions must not be null"); LettuceAssert.notNull(clientResources, "ClientResources must not be null"); - LettuceAssert.notNull(queue, "Queue must not be null"); + LettuceAssert.notNull(endpoint, "RedisEndpoint must not be null"); - this.clientOptions = clientOptions; this.clientResources = clientResources; - this.queue = queue; + this.endpoint = endpoint; + this.traceEnabled = logger.isTraceEnabled(); this.debugEnabled = logger.isDebugEnabled(); - this.reliability = clientOptions.isAutoReconnect() ? Reliability.AT_LEAST_ONCE : Reliability.AT_MOST_ONCE; } /** @@ -109,9 +88,7 @@ public void channelRegistered(ChannelHandlerContext ctx) throws Exception { logger.debug("{} Dropping register for a closed channel", logPrefix()); } - synchronized (stateLock) { - channel = ctx.channel(); - } + channel = ctx.channel(); if (debugEnabled) { logPrefix = null; @@ -120,8 +97,11 @@ public void channelRegistered(ChannelHandlerContext ctx) throws Exception { setState(LifecycleState.REGISTERED); - buffer.clear(); + endpoint.registerQueue(this); + + buffer = ctx.alloc().directBuffer(8192 * 8); ctx.fireChannelRegistered(); + } @Override @@ -137,15 +117,143 @@ public void channelUnregistered(ChannelHandlerContext ctx) throws Exception { return; } - if (isClosed()) { - cancelCommands("Connection closed"); + channel = null; + buffer.release(); + + endpoint.unregisterQueue(this); + + reset(); + + setState(LifecycleState.CLOSED); + rsm.close(); + + ctx.fireChannelUnregistered(); + } + + @Override + public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { + + if (evt instanceof ConnectionEvents.Reset) { + reset(); } - synchronized (stateLock) { - channel = null; + super.userEventTriggered(ctx, evt); + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { + + InternalLogLevel logLevel = InternalLogLevel.WARN; + + if (!queue.isEmpty()) { + RedisCommand command = queue.poll(); + if (debugEnabled) { + logger.debug("{} Storing exception in {}", logPrefix(), command); + } + logLevel = InternalLogLevel.DEBUG; + command.completeExceptionally(cause); } - ctx.fireChannelUnregistered(); + if (channel == null || !channel.isActive() || !isConnected()) { + + if (debugEnabled) { + logger.debug("{} Storing exception in connectionError", logPrefix()); + } + + logLevel = InternalLogLevel.DEBUG; + endpoint.notifyException(cause); + } + + if (cause instanceof IOException && logLevel.ordinal() > InternalLogLevel.INFO.ordinal()) { + logLevel = InternalLogLevel.INFO; + if (SUPPRESS_IO_EXCEPTION_MESSAGES.contains(cause.getMessage())) { + logLevel = InternalLogLevel.DEBUG; + } + } + + logger.log(logLevel, "{} Unexpected exception during request: {}", logPrefix, cause.toString(), cause); + } + + @Override + public void channelActive(ChannelHandlerContext ctx) throws Exception { + + logPrefix = null; + + if (debugEnabled) { + logger.debug("{} channelActive()", logPrefix()); + } + + setState(LifecycleState.CONNECTED); + + endpoint.notifyChannelActive(ctx.channel()); + + super.channelActive(ctx); + if (channel != null) { + channel.eventLoop().submit(new Runnable() { + @Override + public void run() { + channel.pipeline().fireUserEventTriggered(new ConnectionEvents.Activated()); + } + }); + } + + if (debugEnabled) { + logger.debug("{} channelActive() done", logPrefix()); + } + } + + /** + * @see io.netty.channel.ChannelInboundHandlerAdapter#channelInactive(io.netty.channel.ChannelHandlerContext) + */ + @Override + public void channelInactive(ChannelHandlerContext ctx) throws Exception { + + if (debugEnabled) { + logger.debug("{} channelInactive()", logPrefix()); + } + + if (channel != null && ctx.channel() != channel) { + logger.debug("{} My channel and ctx.channel mismatch. Propagating event to other listeners.", logPrefix()); + super.channelInactive(ctx); + return; + } + + setState(LifecycleState.DISCONNECTED); + + setState(LifecycleState.DEACTIVATING); + endpoint.notifyChannelInactive(ctx.channel()); + endpoint.notifyDrainQueuedCommands(this); + + setState(LifecycleState.DEACTIVATED); + + rsm.reset(); + + if (debugEnabled) { + logger.debug("{} channelInactive() done", logPrefix()); + } + super.channelInactive(ctx); + } + + /** + * @see io.netty.channel.ChannelDuplexHandler#write(io.netty.channel.ChannelHandlerContext, java.lang.Object, + * io.netty.channel.ChannelPromise) + */ + @Override + @SuppressWarnings("unchecked") + public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception { + + if (debugEnabled) { + logger.debug("{} write(ctx, {}, promise)", logPrefix(), msg); + } + + if (msg instanceof RedisCommand) { + writeSingleCommand(ctx, (RedisCommand) msg, promise); + return; + } + + if (msg instanceof Collection) { + writeBatch(ctx, (Collection>) msg, promise); + } } /** @@ -192,7 +300,7 @@ protected void decode(ChannelHandlerContext ctx, ByteBuf buffer) throws Interrup while (!queue.isEmpty()) { - RedisCommand command = queue.peek(); + RedisCommand command = queue.peek(); if (debugEnabled) { logger.debug("{} Queue contains: {} commands", logPrefix(), queue.size()); } @@ -219,11 +327,11 @@ protected void decode(ChannelHandlerContext ctx, ByteBuf buffer) throws Interrup } } - private WithLatency getWithLatency(RedisCommand command) { + private WithLatency getWithLatency(RedisCommand command) { WithLatency withLatency = null; if (clientResources.commandLatencyCollector().isEnabled()) { - RedisCommand unwrappedCommand = CommandWrapper.unwrap(command); + RedisCommand unwrappedCommand = CommandWrapper.unwrap(command); if (unwrappedCommand instanceof WithLatency) { withLatency = (WithLatency) unwrappedCommand; if (withLatency.getFirstResponse() == -1) { @@ -231,9 +339,14 @@ private WithLatency getWithLatency(RedisCommand command) { } } } + return withLatency; } + protected boolean decode(ByteBuf buffer, CommandOutput output) { + return rsm.decode(buffer, output); + } + private void recordLatency(WithLatency withLatency, ProtocolKeyword commandType) { if (withLatency != null && clientResources.commandLatencyCollector().isEnabled() && channel != null @@ -258,280 +371,15 @@ private SocketAddress local() { return LocalAddress.ANY; } - @Override - public > C write(C command) { - - LettuceAssert.notNull(command, "Command must not be null"); - - try { - incrementWriters(); - - if (lifecycleState == LifecycleState.CLOSED) { - throw new RedisException("Connection is closed"); - } - - if (clientOptions.getRequestQueueSize() != Integer.MAX_VALUE - && commandBuffer.size() + queue.size() >= clientOptions.getRequestQueueSize()) { - throw new RedisException("Request queue size exceeded: " + clientOptions.getRequestQueueSize() - + ". Commands are not accepted until the queue size drops."); - } - - if ((channel == null || !isConnected()) && isRejectCommand()) { - throw new RedisException("Currently not connected. Commands are rejected."); - } - - /** - * This lock causes safety for connection activation and somehow netty gets more stable and predictable performance - * than without a lock and all threads are hammering towards writeAndFlush. - */ - Channel channel = this.channel; - if (autoFlushCommands) { - - if (channel != null && isConnected() && channel.isActive()) { - writeToChannel(command, channel); - } else { - writeToBuffer(command); - } - - } else { - bufferCommand(command); - } - } finally { - decrementWriters(); - if (debugEnabled) { - logger.debug("{} write() done", logPrefix()); - } - } - - return command; - } - - protected , T> void writeToBuffer(C command) { - - if (commandBuffer.contains(command) || queue.contains(command)) { - return; - } - - if (connectionError != null) { - if (debugEnabled) { - logger.debug("{} writeToBuffer() Completing command {} due to connection error", logPrefix(), command); - } - command.completeExceptionally(connectionError); - - return; - } - - bufferCommand(command); - } - - protected , T> void writeToChannel(C command, Channel channel) { - - if (reliability == Reliability.AT_MOST_ONCE) { - // cancel on exceptions and remove from queue, because there is no housekeeping - writeAndFlush(command).addListener(new AtMostOnceWriteListener(command, queue)); - } - - if (reliability == Reliability.AT_LEAST_ONCE) { - // commands are ok to stay within the queue, reconnect will retrigger them - writeAndFlush(command).addListener(WRITE_LOG_LISTENER); - } - } - - protected void bufferCommand(RedisCommand command) { - - if (debugEnabled) { - logger.debug("{} write() buffering command {}", logPrefix(), command); - } - - commandBuffer.add(command); - } - - /** - * Wait for stateLock and increment writers. Will wait if stateLock is locked and if writer counter is negative. - */ - protected void incrementWriters() { - - if (exclusiveLockOwner == Thread.currentThread()) { - return; - } - - synchronized (stateLock) { - for (;;) { - - if (writers.get() >= 0) { - writers.incrementAndGet(); - return; - } - } - } - } - - /** - * Decrement writers without any wait. - */ - protected void decrementWriters() { - - if (exclusiveLockOwner == Thread.currentThread()) { - return; - } - - writers.decrementAndGet(); - } - - /** - * Wait for stateLock and no writers. Must be used in an outer {@code synchronized} block to prevent interleaving with other - * methods using writers. Sets writers to a negative value to create a lock for {@link #incrementWriters()}. - */ - protected void lockWritersExclusive() { - - if (exclusiveLockOwner == Thread.currentThread()) { - writers.decrementAndGet(); - return; - } - - synchronized (stateLock) { - for (;;) { - - if (writers.compareAndSet(0, -1)) { - exclusiveLockOwner = Thread.currentThread(); - return; - } - } - } - } - - /** - * Unlock writers. - */ - protected void unlockWritersExclusive() { - - if (exclusiveLockOwner == Thread.currentThread()) { - if (writers.incrementAndGet() == 0) { - exclusiveLockOwner = null; - } - } - } - - private boolean isRejectCommand() { - - if (clientOptions == null) { - return false; - } - - switch (clientOptions.getDisconnectedBehavior()) { - case REJECT_COMMANDS: - return true; - - case ACCEPT_COMMANDS: - return false; - - default: - case DEFAULT: - if (!clientOptions.isAutoReconnect()) { - return true; - } - - return false; - } - } - boolean isConnected() { return lifecycleState.ordinal() >= LifecycleState.CONNECTED.ordinal() && lifecycleState.ordinal() < LifecycleState.DISCONNECTED.ordinal(); } - @Override - @SuppressWarnings({ "rawtypes", "unchecked" }) - public void flushCommands() { - - if (debugEnabled) { - logger.debug("{} flushCommands()", logPrefix()); - } - - if (channel != null && isConnected()) { - List> queuedCommands; - - synchronized (stateLock) { - try { - lockWritersExclusive(); - - if (commandBuffer.isEmpty()) { - return; - } - - queuedCommands = new ArrayList<>(commandBuffer.size()); - RedisCommand cmd; - while ((cmd = commandBuffer.poll()) != null) { - queuedCommands.add(cmd); - } - } finally { - unlockWritersExclusive(); - } - } - - if (debugEnabled) { - logger.debug("{} flushCommands() Flushing {} commands", logPrefix(), queuedCommands.size()); - } - - if (reliability == Reliability.AT_MOST_ONCE) { - // cancel on exceptions and remove from queue, because there is no housekeeping - writeAndFlush(queuedCommands).addListener(new AtMostOnceWriteListener(queuedCommands, this.queue)); - } - - if (reliability == Reliability.AT_LEAST_ONCE) { - // commands are ok to stay within the queue, reconnect will retrigger them - writeAndFlush(queuedCommands).addListener(WRITE_LOG_LISTENER); - } - } - } - - private > ChannelFuture writeAndFlush(List commands) { - - if (debugEnabled) { - logger.debug("{} write() writeAndFlush commands {}", logPrefix(), commands); - } - - transportBuffer.addAll(commands); - return channel.writeAndFlush(commands); - } - - private > ChannelFuture writeAndFlush(C command) { - - if (debugEnabled) { - logger.debug("{} write() writeAndFlush command {}", logPrefix(), command); - } - - transportBuffer.add(command); - return channel.writeAndFlush(command); - } - - /** - * @see io.netty.channel.ChannelDuplexHandler#write(io.netty.channel.ChannelHandlerContext, java.lang.Object, - * io.netty.channel.ChannelPromise) - */ - @Override - @SuppressWarnings("unchecked") - public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception { - - if (debugEnabled) { - logger.debug("{} write(ctx, {}, promise)", logPrefix(), msg); - } - - if (msg instanceof RedisCommand) { - writeSingleCommand(ctx, (RedisCommand) msg, promise); - return; - } - - if (msg instanceof Collection) { - writeBatch(ctx, (Collection>) msg, promise); - } - } - - private void writeSingleCommand(ChannelHandlerContext ctx, RedisCommand command, ChannelPromise promise) + private void writeSingleCommand(ChannelHandlerContext ctx, RedisCommand command, ChannelPromise promise) throws Exception { if (command.isCancelled()) { - transportBuffer.remove(command); return; } @@ -539,14 +387,13 @@ private void writeSingleCommand(ChannelHandlerContext ctx, RedisCommand ctx.write(command, promise); } - private void writeBatch(ChannelHandlerContext ctx, Collection> msg, ChannelPromise promise) + private void writeBatch(ChannelHandlerContext ctx, Collection> batch, ChannelPromise promise) throws Exception { - Collection> commands = msg; - Collection> toWrite = commands; + Collection> toWrite = batch; boolean cancelledCommands = false; - for (RedisCommand command : commands) { + for (RedisCommand command : batch) { if (command.isCancelled()) { cancelledCommands = true; break; @@ -555,12 +402,11 @@ private void writeBatch(ChannelHandlerContext ctx, Collection(commands.size()); + toWrite = new ArrayList<>(batch.size()); - for (RedisCommand command : commands) { + for (RedisCommand command : batch) { if (command.isCancelled()) { - transportBuffer.remove(command); continue; } @@ -569,7 +415,7 @@ private void writeBatch(ChannelHandlerContext ctx, Collection command : toWrite) { + for (RedisCommand command : toWrite) { queueCommand(command, promise); } } @@ -579,7 +425,7 @@ private void writeBatch(ChannelHandlerContext ctx, Collection command, ChannelPromise promise) throws Exception { + private void queueCommand(RedisCommand command, ChannelPromise promise) throws Exception { try { @@ -591,7 +437,7 @@ private void queueCommand(RedisCommand command, ChannelPromise promise) queue.add(command); if (clientResources.commandLatencyCollector().isEnabled()) { - RedisCommand unwrappedCommand = CommandWrapper.unwrap(command); + RedisCommand unwrappedCommand = CommandWrapper.unwrap(command); if (unwrappedCommand instanceof WithLatency) { WithLatency withLatency = (WithLatency) unwrappedCommand; withLatency.firstResponse(-1); @@ -599,7 +445,6 @@ private void queueCommand(RedisCommand command, ChannelPromise promise) } } } - transportBuffer.remove(command); } catch (Exception e) { command.completeExceptionally(e); promise.setFailure(e); @@ -611,177 +456,10 @@ private long nanoTime() { return System.nanoTime(); } - @Override - public void channelActive(ChannelHandlerContext ctx) throws Exception { - - logPrefix = null; - connectionWatchdog = null; - - if (debugEnabled) { - logger.debug("{} channelActive()", logPrefix()); - } - - if (ctx != null && ctx.pipeline() != null) { - - Map map = ctx.pipeline().toMap(); - - for (ChannelHandler handler : map.values()) { - if (handler instanceof ConnectionWatchdog) { - connectionWatchdog = (ConnectionWatchdog) handler; - } - } - } - - synchronized (stateLock) { - try { - lockWritersExclusive(); - setState(LifecycleState.CONNECTED); - - try { - // Move queued commands to buffer before issuing any commands because of connection activation. - // That's necessary to prepend queued commands first as some commands might get into the queue - // after the connection was disconnected. They need to be prepended to the command buffer - moveQueuedCommandsToCommandBuffer(); - activateCommandHandlerAndExecuteBufferedCommands(ctx); - } catch (Exception e) { - - if (debugEnabled) { - logger.debug("{} channelActive() ran into an exception", logPrefix()); - } - - if (clientOptions.isCancelCommandsOnReconnectFailure()) { - reset(); - } - - throw e; - } - } finally { - unlockWritersExclusive(); - } - } - - super.channelActive(ctx); - if (channel != null) { - channel.eventLoop().submit(new Runnable() { - @Override - public void run() { - channel.pipeline().fireUserEventTriggered(new ConnectionEvents.Activated()); - } - }); - } - - if (debugEnabled) { - logger.debug("{} channelActive() done", logPrefix()); - } - } - - private void moveQueuedCommandsToCommandBuffer() { - - List> queuedCommands = drainCommands(queue); - Collections.reverse(queuedCommands); - - List> transportBufferCommands = drainCommands(transportBuffer); - Collections.reverse(transportBufferCommands); - - // Queued commands first because they reached the queue before commands that are still in the transport buffer. - queuedCommands.addAll(transportBufferCommands); - - logger.debug("{} moveQueuedCommandsToCommandBuffer {} command(s) added to buffer", logPrefix(), queuedCommands.size()); - for (RedisCommand command : queuedCommands) { - commandBuffer.addFirst(command); - } - } - - private List> drainCommands(Collection> source) { - - List> target = new ArrayList<>(source.size()); - target.addAll(source); - source.removeAll(target); - return target; - } - - protected void activateCommandHandlerAndExecuteBufferedCommands(ChannelHandlerContext ctx) { - - connectionError = null; - - if (debugEnabled) { - logger.debug("{} activateCommandHandlerAndExecuteBufferedCommands {} command(s) buffered", logPrefix(), - commandBuffer.size()); - } - - channel = ctx.channel(); - - if (redisChannelHandler != null) { - - if (debugEnabled) { - logger.debug("{} activating channel handler", logPrefix()); - } - - setState(LifecycleState.ACTIVATING); - redisChannelHandler.activated(); - } - setState(LifecycleState.ACTIVE); - - flushCommands(); - } - - /** - * @see io.netty.channel.ChannelInboundHandlerAdapter#channelInactive(io.netty.channel.ChannelHandlerContext) - */ - @Override - public void channelInactive(ChannelHandlerContext ctx) throws Exception { - - if (debugEnabled) { - logger.debug("{} channelInactive()", logPrefix()); - } - - if (channel != null && ctx.channel() != channel) { - logger.debug("{} My channel and ctx.channel mismatch. Propagating event to other listeners.", logPrefix()); - super.channelInactive(ctx); - return; - } - - synchronized (stateLock) { - try { - lockWritersExclusive(); - setState(LifecycleState.DISCONNECTED); - - if (redisChannelHandler != null) { - - if (debugEnabled) { - logger.debug("{} deactivating channel handler", logPrefix()); - } - - setState(LifecycleState.DEACTIVATING); - redisChannelHandler.deactivated(); - } - - setState(LifecycleState.DEACTIVATED); - - // Shift all commands to the commandBuffer so the queue is empty. - // Allows to run onConnect commands before executing buffered commands - commandBuffer.addAll(queue); - queue.removeAll(commandBuffer); - - } finally { - unlockWritersExclusive(); - } - } - - rsm.reset(); - - if (debugEnabled) { - logger.debug("{} channelInactive() done", logPrefix()); - } - super.channelInactive(ctx); - } - protected void setState(LifecycleState lifecycleState) { if (this.lifecycleState != LifecycleState.CLOSED) { - synchronized (stateLock) { - this.lifecycleState = lifecycleState; - } + this.lifecycleState = lifecycleState; } } @@ -793,235 +471,41 @@ public boolean isClosed() { return lifecycleState == LifecycleState.CLOSED; } - private void cancelCommands(String message) { + private void reset() { - List> toCancel; - synchronized (stateLock) { - try { - lockWritersExclusive(); - toCancel = prepareReset(); - } finally { - unlockWritersExclusive(); - } - } + rsm.reset(); - for (RedisCommand cmd : toCancel) { + RedisCommand cmd; + while ((cmd = queue.poll()) != null) { if (cmd.getOutput() != null) { - cmd.getOutput().setError(message); + cmd.getOutput().setError("Reset"); } cmd.cancel(); } - } - - protected List> prepareReset() { - - int size = 0; - if (queue != null) { - size += queue.size(); - } - - if (commandBuffer != null) { - size += commandBuffer.size(); - } - - List> toCancel = new ArrayList<>(size); - - if (queue != null) { - toCancel.addAll(queue); - queue.clear(); - } - - if (commandBuffer != null) { - toCancel.addAll(commandBuffer); - commandBuffer.clear(); - } - return toCancel; - } - - @Override - public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { - - InternalLogLevel logLevel = InternalLogLevel.WARN; - - if (!queue.isEmpty()) { - RedisCommand command = queue.poll(); - if (debugEnabled) { - logger.debug("{} Storing exception in {}", logPrefix(), command); - } - logLevel = InternalLogLevel.DEBUG; - command.completeExceptionally(cause); - } - - if (channel == null || !channel.isActive() || !isConnected()) { - if (debugEnabled) { - logger.debug("{} Storing exception in connectionError", logPrefix()); - } - logLevel = InternalLogLevel.DEBUG; - connectionError = cause; - } - - if (cause instanceof IOException && logLevel.ordinal() > InternalLogLevel.INFO.ordinal()) { - logLevel = InternalLogLevel.INFO; - if (SUPPRESS_IO_EXCEPTION_MESSAGES.contains(cause.getMessage())) { - logLevel = InternalLogLevel.DEBUG; - } - } - - logger.log(logLevel, "{} Unexpected exception during request: {}", logPrefix, cause.toString(), cause); - } - - /** - * Close the connection. - */ - @Override - public void close() { - - if (debugEnabled) { - logger.debug("{} close()", logPrefix()); - } - - if (isClosed()) { - return; - } - - setState(LifecycleState.CLOSED); - Channel currentChannel = this.channel; - if (currentChannel != null) { - currentChannel.pipeline().fireUserEventTriggered(new ConnectionEvents.PrepareClose()); - currentChannel.pipeline().fireUserEventTriggered(new ConnectionEvents.Close()); - - ChannelFuture close = currentChannel.pipeline().close(); - if (currentChannel.isOpen()) { - close.syncUninterruptibly(); - } - } else if (connectionWatchdog != null) { - connectionWatchdog.prepareClose(new ConnectionEvents.PrepareClose()); - } - - rsm.close(); - - if (buffer.refCnt() > 0) { - buffer.release(); - } - } - - /** - * Reset the writer state. Queued commands will be canceled and the internal state will be reset. This is useful when the - * internal state machine gets out of sync with the connection. - */ - @Override - public void reset() { - - if (debugEnabled) { - logger.debug("{} reset()", logPrefix()); - } - - cancelCommands("Reset"); - - rsm.reset(); if (buffer.refCnt() > 0) { buffer.clear(); } } - /** - * Reset the command-handler to the initial not-connected state. - */ - public void initialState() { - - setState(LifecycleState.NOT_CONNECTED); - queue.clear(); - commandBuffer.clear(); - - Channel currentChannel = this.channel; - if (currentChannel != null) { - currentChannel.pipeline().fireUserEventTriggered(new ConnectionEvents.PrepareClose()); - currentChannel.pipeline().fireUserEventTriggered(new ConnectionEvents.Close()); - currentChannel.pipeline().close(); - } - } - - @Override - public void setRedisChannelHandler(RedisChannelHandler redisChannelHandler) { - this.redisChannelHandler = redisChannelHandler; - } - - @Override - public void setAutoFlushCommands(boolean autoFlush) { - synchronized (stateLock) { - this.autoFlushCommands = autoFlush; - } - } - protected String logPrefix() { if (logPrefix != null) { return logPrefix; } - StringBuffer buffer = new StringBuffer(64); + StringBuilder buffer = new StringBuilder(64); buffer.append('[').append("chid=0x").append(Long.toHexString(commandHandlerId)).append(", ") .append(ChannelLogDescriptor.logDescriptor(channel)).append(']'); return logPrefix = buffer.toString(); } - public enum LifecycleState { - NOT_CONNECTED, REGISTERED, CONNECTED, ACTIVATING, ACTIVE, DISCONNECTED, DEACTIVATING, DEACTIVATED, CLOSED, - } - - private enum Reliability { - AT_MOST_ONCE, AT_LEAST_ONCE; - } - - private static class AtMostOnceWriteListener implements ChannelFutureListener { - - private final Collection> sentCommands; - private final Queue queue; - - @SuppressWarnings({ "unchecked", "rawtypes" }) - public AtMostOnceWriteListener(RedisCommand sentCommand, Queue queue) { - this((Collection) LettuceLists.newList(sentCommand), queue); - } - - public AtMostOnceWriteListener(Collection> sentCommand, Queue queue) { - this.sentCommands = sentCommand; - this.queue = queue; - } - - @Override - public void operationComplete(ChannelFuture future) throws Exception { - future.await(); - if (future.cause() != null) { - - for (RedisCommand sentCommand : sentCommands) { - sentCommand.completeExceptionally(future.cause()); - } - - queue.removeAll(sentCommands); - } - } + @Override + public Queue> getQueue() { + return queue; } - /** - * A generic future listener which logs unsuccessful writes. - */ - static class WriteLogListener implements GenericFutureListener> { - - @Override - public void operationComplete(Future future) throws Exception { - Throwable cause = future.cause(); - if (!future.isSuccess() && !(cause instanceof ClosedChannelException)) { - - String message = "Unexpected exception during request: {}"; - InternalLogLevel logLevel = InternalLogLevel.WARN; - - if (cause instanceof IOException && SUPPRESS_IO_EXCEPTION_MESSAGES.contains(cause.getMessage())) { - logLevel = InternalLogLevel.DEBUG; - } - - logger.log(logLevel, message, cause.toString(), cause); - } - } + public enum LifecycleState { + NOT_CONNECTED, REGISTERED, CONNECTED, ACTIVATING, ACTIVE, DISCONNECTED, DEACTIVATING, DEACTIVATED, CLOSED, } } diff --git a/src/main/java/com/lambdaworks/redis/protocol/ConnectionFacade.java b/src/main/java/com/lambdaworks/redis/protocol/ConnectionFacade.java new file mode 100644 index 0000000000..5040f9622b --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/protocol/ConnectionFacade.java @@ -0,0 +1,27 @@ +package com.lambdaworks.redis.protocol; + +/** + * Represents a stateful connection facade. Connections can be activated and deactivated and particular actions can be executed + * upon connection activation/deactivation. + * + * @author Mark Paluch + */ +public interface ConnectionFacade { + + /** + * Callback for a connection activated event. This method may invoke non-blocking connection operations to prepare the + * connection after the connection was established. + */ + void activated(); + + /** + * Callback for a connection deactivated event. This method may invoke non-blocking operations to cleanup the connection + * after disconnection. + */ + void deactivated(); + + /** + * Reset the connection state. + */ + void reset(); +} diff --git a/src/main/java/com/lambdaworks/redis/protocol/ConnectionWatchdog.java b/src/main/java/com/lambdaworks/redis/protocol/ConnectionWatchdog.java index a9175d42f7..b567e8f608 100644 --- a/src/main/java/com/lambdaworks/redis/protocol/ConnectionWatchdog.java +++ b/src/main/java/com/lambdaworks/redis/protocol/ConnectionWatchdog.java @@ -8,11 +8,9 @@ import com.lambdaworks.redis.ClientOptions; import com.lambdaworks.redis.ConnectionEvents; -import com.lambdaworks.redis.RedisChannelHandler; import com.lambdaworks.redis.internal.LettuceAssert; - -import com.lambdaworks.redis.resource.ClientResources; import com.lambdaworks.redis.resource.Delay; + import io.netty.bootstrap.Bootstrap; import io.netty.channel.*; import io.netty.channel.group.ChannelGroup; @@ -31,9 +29,9 @@ * @author Mark Paluch */ @ChannelHandler.Sharable -public class ConnectionWatchdog extends ChannelInboundHandlerAdapter implements TimerTask { +public class ConnectionWatchdog extends ChannelInboundHandlerAdapter { - public static final long LOGGING_QUIET_TIME_MS = TimeUnit.MILLISECONDS.convert(5, TimeUnit.SECONDS); + private static final long LOGGING_QUIET_TIME_MS = TimeUnit.MILLISECONDS.convert(5, TimeUnit.SECONDS); private static final InternalLogger logger = InternalLoggerFactory.getInstance(ConnectionWatchdog.class); @@ -42,13 +40,12 @@ public class ConnectionWatchdog extends ChannelInboundHandlerAdapter implements private final EventExecutorGroup reconnectWorkers; private final ReconnectionHandler reconnectionHandler; private final ReconnectionListener reconnectionListener; - - private Channel channel; private final Timer timer; + private Channel channel; private SocketAddress remoteAddress; private long lastReconnectionLogging = -1; - private CommandHandler commandHandler; + private String logPrefix; private volatile int attempts; private volatile boolean armed; @@ -66,10 +63,11 @@ public class ConnectionWatchdog extends ChannelInboundHandlerAdapter implements * @param reconnectWorkers executor group for reconnect tasks, must not be {@literal null} * @param socketAddressSupplier the socket address supplier to obtain an address for reconnection, may be {@literal null} * @param reconnectionListener the reconnection listener, must not be {@literal null} + * @param connectionFacade the connection facade, must not be {@literal null} */ public ConnectionWatchdog(Delay reconnectDelay, ClientOptions clientOptions, Bootstrap bootstrap, Timer timer, EventExecutorGroup reconnectWorkers, Supplier socketAddressSupplier, - ReconnectionListener reconnectionListener) { + ReconnectionListener reconnectionListener, ConnectionFacade connectionFacade) { LettuceAssert.notNull(reconnectDelay, "Delay must not be null"); LettuceAssert.notNull(clientOptions, "ClientOptions must not be null"); @@ -77,12 +75,14 @@ public ConnectionWatchdog(Delay reconnectDelay, ClientOptions clientOptions, Boo LettuceAssert.notNull(timer, "Timer must not be null"); LettuceAssert.notNull(reconnectWorkers, "ReconnectWorkers must not be null"); LettuceAssert.notNull(reconnectionListener, "ReconnectionListener must not be null"); + LettuceAssert.notNull(connectionFacade, "ConnectionFacade must not be null"); this.reconnectDelay = reconnectDelay; this.bootstrap = bootstrap; this.timer = timer; this.reconnectWorkers = reconnectWorkers; this.reconnectionListener = reconnectionListener; + Supplier wrappedSocketAddressSupplier = new Supplier() { @Override public SocketAddress get() { @@ -100,19 +100,14 @@ public SocketAddress get() { } }; - this.reconnectionHandler = new ReconnectionHandler(clientOptions, bootstrap, wrappedSocketAddressSupplier); + this.reconnectionHandler = new ReconnectionHandler(clientOptions, bootstrap, wrappedSocketAddressSupplier, + connectionFacade); } @Override public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { - logger.debug("{} userEventTriggered({}, {})", commandHandler.logPrefix(), ctx, evt); - - if (evt instanceof ConnectionEvents.PrepareClose) { - - ConnectionEvents.PrepareClose prepareClose = (ConnectionEvents.PrepareClose) evt; - prepareClose(prepareClose); - } + logger.debug("{} userEventTriggered(ctx, {})", logPrefix(), evt); if (evt instanceof ConnectionEvents.Activated) { attempts = 0; @@ -121,11 +116,10 @@ public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exc super.userEventTriggered(ctx, evt); } - void prepareClose(ConnectionEvents.PrepareClose prepareClose) { + void prepareClose() { setListenOnChannelInactive(false); setReconnectSuspended(true); - prepareClose.getPrepareCloseFuture().complete(true); reconnectionHandler.prepareClose(); } @@ -133,14 +127,11 @@ void prepareClose(ConnectionEvents.PrepareClose prepareClose) { @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { - if(commandHandler == null) { - this.commandHandler = ctx.pipeline().get(CommandHandler.class); - } - - reconnectScheduleTimeout = null; channel = ctx.channel(); - logger.debug("{} channelActive({})", commandHandler.logPrefix(), ctx); + reconnectScheduleTimeout = null; remoteAddress = channel.remoteAddress(); + logPrefix = null; + logger.debug("{} channelActive()", logPrefix()); super.channelActive(ctx); } @@ -148,39 +139,45 @@ public void channelActive(ChannelHandlerContext ctx) throws Exception { @Override public void channelInactive(ChannelHandlerContext ctx) throws Exception { - logger.debug("{} channelInactive({})", commandHandler.logPrefix(), ctx); - channel = null; + logger.debug("{} channelInactive()", logPrefix()); + if (!armed) { + logger.debug("{} ConnectionWatchdog not armed", logPrefix()); + return; + } + channel = null; if (listenOnChannelInactive && !reconnectionHandler.isReconnectSuspended()) { - RedisChannelHandler channelHandler = ctx.pipeline().get(RedisChannelHandler.class); - if (channelHandler != null) { - reconnectionHandler.setTimeout(channelHandler.getTimeout()); - reconnectionHandler.setTimeoutUnit(channelHandler.getTimeoutUnit()); - } - scheduleReconnect(); } else { - logger.debug("{} Reconnect scheduling disabled", commandHandler.logPrefix(), ctx); + logger.debug("{} Reconnect scheduling disabled", logPrefix(), ctx); } super.channelInactive(ctx); } + /** + * Enable {@link ConnectionWatchdog} to listen for disconnected events. + */ + void arm() { + this.armed = true; + setListenOnChannelInactive(true); + } + /** * Schedule reconnect if channel is not available/not active. */ public synchronized void scheduleReconnect() { - logger.debug("{} scheduleReconnect()", commandHandler.logPrefix()); + logger.debug("{} scheduleReconnect()", logPrefix()); if (!isEventLoopGroupActive()) { logger.debug("isEventLoopGroupActive() == false"); return; } - if (commandHandler.isClosed()) { - logger.debug("Skip reconnect scheduling, CommandHandler is closed"); + if (!isListenOnChannelInactive()) { + logger.debug("Skip reconnect scheduling, listener disabled"); return; } @@ -189,7 +186,7 @@ public synchronized void scheduleReconnect() { final int attempt = attempts; int timeout = (int) reconnectDelay.getTimeUnit().toMillis(reconnectDelay.createDelay(attempt)); - logger.debug("Reconnect attempt {}, delay {}ms", attempt, timeout); + logger.debug("{} Reconnect attempt {}, delay {}ms", logPrefix(), attempt, timeout); this.reconnectScheduleTimeout = timer.newTimeout(new TimerTask() { @Override public void run(final Timeout timeout) throws Exception { @@ -200,13 +197,13 @@ public void run(final Timeout timeout) throws Exception { } reconnectWorkers.submit(() -> { - ConnectionWatchdog.this.run(timeout); + ConnectionWatchdog.this.run(attempt); return null; }); } }, timeout, TimeUnit.MILLISECONDS); } else { - logger.debug("{} Skipping scheduleReconnect() because I have an active channel", commandHandler.logPrefix()); + logger.debug("{} Skipping scheduleReconnect() because I have an active channel", logPrefix()); } } @@ -214,12 +211,11 @@ public void run(final Timeout timeout) throws Exception { * Reconnect to the remote address that the closed channel was connected to. This creates a new {@link ChannelPipeline} with * the same handler instances contained in the old channel's pipeline. * - * @param timeout Timer task handle. + * @param attempt attempt counter * * @throws Exception when reconnection fails. */ - @Override - public void run(Timeout timeout) throws Exception { + public void run(int attempt) throws Exception { reconnectScheduleTimeout = null; @@ -228,8 +224,8 @@ public void run(Timeout timeout) throws Exception { return; } - if (commandHandler.isClosed()) { - logger.debug("Skip reconnect scheduling, CommandHandler is closed"); + if (!isListenOnChannelInactive()) { + logger.debug("Skip reconnect scheduling, listener disabled"); return; } @@ -246,7 +242,7 @@ public void run(Timeout timeout) throws Exception { } try { - reconnectionListener.onReconnect(new ConnectionEvents.Reconnect(attempts)); + reconnectionListener.onReconnect(new ConnectionEvents.Reconnect(attempt)); reconnect(infoLevel, warnLevel); } catch (InterruptedException e) { Thread.currentThread().interrupt(); @@ -275,25 +271,20 @@ private boolean isEventLoopGroupActive() { } private boolean isEventLoopGroupActive(EventExecutorGroup executorService) { - - if (executorService.isShutdown() || executorService.isTerminated() || executorService.isShuttingDown()) { - return false; - } - - return true; + return !(executorService.isShutdown() || executorService.isTerminated() || executorService.isShuttingDown()); } private boolean shouldLog() { long quietUntil = lastReconnectionLogging + LOGGING_QUIET_TIME_MS; - - if (quietUntil > System.currentTimeMillis()) { - return false; - } - - return true; + return quietUntil <= System.currentTimeMillis(); } + /** + * Enable event listener for disconnected events. + * + * @param listenOnChannelInactive {@literal true} to listen for disconnected events. + */ public void setListenOnChannelInactive(boolean listenOnChannelInactive) { this.listenOnChannelInactive = listenOnChannelInactive; } @@ -302,15 +293,33 @@ public boolean isListenOnChannelInactive() { return listenOnChannelInactive; } - public boolean isReconnectSuspended() { - return reconnectionHandler.isReconnectSuspended(); + /** + * Suspend reconnection temporarily. Reconnect suspension will interrupt reconnection attempts. + * + * @param reconnectSuspended {@literal true} to suspend reconnection + */ + public void setReconnectSuspended(boolean reconnectSuspended) { + reconnectionHandler.setReconnectSuspended(reconnectSuspended); } - public void setReconnectSuspended(boolean reconnectSuspended) { - reconnectionHandler.setReconnectSuspended(true); + public boolean isReconnectSuspended() { + return reconnectionHandler.isReconnectSuspended(); } ReconnectionHandler getReconnectionHandler() { return reconnectionHandler; } + + private String logPrefix() { + + if (logPrefix != null) { + return logPrefix; + } + + StringBuilder buffer = new StringBuilder(64); + buffer.append('[').append("Last known addr=").append(remoteAddress).append(", ") + .append(ChannelLogDescriptor.logDescriptor(channel)).append(']'); + return logPrefix = buffer.toString(); + } + } diff --git a/src/main/java/com/lambdaworks/redis/protocol/DefaultEndpoint.java b/src/main/java/com/lambdaworks/redis/protocol/DefaultEndpoint.java new file mode 100644 index 0000000000..b2c9b67274 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/protocol/DefaultEndpoint.java @@ -0,0 +1,603 @@ +package com.lambdaworks.redis.protocol; + +import static com.lambdaworks.redis.protocol.CommandHandler.SUPPRESS_IO_EXCEPTION_MESSAGES; + +import java.io.IOException; +import java.nio.channels.ClosedChannelException; +import java.util.*; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicLong; +import java.util.function.Supplier; + +import com.lambdaworks.redis.ClientOptions; +import com.lambdaworks.redis.ConnectionEvents; +import com.lambdaworks.redis.RedisChannelWriter; +import com.lambdaworks.redis.RedisException; +import com.lambdaworks.redis.internal.LettuceAssert; +import com.lambdaworks.redis.internal.LettuceFactories; + +import io.netty.channel.Channel; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelFutureListener; +import io.netty.util.concurrent.Future; +import io.netty.util.concurrent.GenericFutureListener; +import io.netty.util.internal.logging.InternalLogLevel; +import io.netty.util.internal.logging.InternalLogger; +import io.netty.util.internal.logging.InternalLoggerFactory; + +/** + * Default {@link Endpoint} implementation. + * + * @author Mark Paluch + */ +public class DefaultEndpoint implements RedisChannelWriter, Endpoint, HasQueuedCommands { + + private static final InternalLogger logger = InternalLoggerFactory.getInstance(DefaultEndpoint.class); + private static final AtomicLong ENDPOINT_COUNTER = new AtomicLong(); + + private final long endpointId = ENDPOINT_COUNTER.incrementAndGet(); + private final AtomicBoolean closed = new AtomicBoolean(); + private final Deque> commandBuffer = LettuceFactories.newConcurrentQueue(); + + private final SharedLock sharedLock = new SharedLock(); + + private final Reliability reliability; + private final ClientOptions clientOptions; + + private final QueuedCommands queuedCommands = new QueuedCommands(); + + // If TRACE level logging has been enabled at startup. + private final boolean traceEnabled; + + // If DEBUG level logging has been enabled at startup. + private final boolean debugEnabled; + + protected volatile Channel channel; + private String logPrefix; + private boolean autoFlushCommands = true; + + private ConnectionWatchdog connectionWatchdog; + private ConnectionFacade connectionFacade; + + private Throwable connectionError; + + /** + * Create a new {@link DefaultEndpoint}. + * + * @param clientOptions client options for this connection, must not be {@literal null} + */ + public DefaultEndpoint(ClientOptions clientOptions) { + + LettuceAssert.notNull(clientOptions, "ClientOptions must not be null"); + + this.clientOptions = clientOptions; + this.traceEnabled = logger.isTraceEnabled(); + this.debugEnabled = logger.isDebugEnabled(); + this.reliability = clientOptions.isAutoReconnect() ? Reliability.AT_LEAST_ONCE : Reliability.AT_MOST_ONCE; + this.queuedCommands.register(this); + } + + @Override + public RedisCommand write(RedisCommand command) { + + LettuceAssert.notNull(command, "Command must not be null"); + + try { + sharedLock.incrementWriters(); + + if (isClosed()) { + throw new RedisException("Connection is closed"); + } + + if (queuedCommands.exceedsLimit(clientOptions.getRequestQueueSize())) { + throw new RedisException("Request queue size exceeded: " + clientOptions.getRequestQueueSize() + + ". Commands are not accepted until the queue size drops."); + } + + if ((channel == null || !isConnected()) && isRejectCommand()) { + throw new RedisException("Currently not connected. Commands are rejected."); + } + + if (autoFlushCommands) { + + if (isConnected()) { + writeToChannel(command); + } else { + writeToBuffer(command); + } + + } else { + writeToBuffer(command); + } + } finally { + sharedLock.decrementWriters(); + if (debugEnabled) { + logger.debug("{} write() done", logPrefix()); + } + } + + return command; + } + + private , T> void writeToBuffer(C command) { + + if (commandBuffer.contains(command)) { + return; + } + + bufferCommand(command); + } + + private , T> void writeToChannel(C command) { + + if (reliability == Reliability.AT_MOST_ONCE) { + // cancel on exceptions and remove from queue, because there is no housekeeping + writeAndFlush(command).addListener(new AtMostOnceWriteListener(command, queuedCommands)); + } + + if (reliability == Reliability.AT_LEAST_ONCE) { + // commands are ok to stay within the queue, reconnect will retrigger them + writeAndFlush(command).addListener(new RetryListener(command)); + } + } + + protected void bufferCommand(RedisCommand command) { + + if (debugEnabled) { + logger.debug("{} write() buffering command {}", logPrefix(), command); + } + + if (connectionError != null) { + + if (debugEnabled) { + logger.debug("{} writeToBuffer() Completing command {} due to connection error", logPrefix(), command); + } + command.completeExceptionally(connectionError); + + return; + } + + commandBuffer.add(command); + } + + private boolean isRejectCommand() { + + if (clientOptions == null) { + return false; + } + + switch (clientOptions.getDisconnectedBehavior()) { + case REJECT_COMMANDS: + return true; + + case ACCEPT_COMMANDS: + return false; + + default: + case DEFAULT: + if (!clientOptions.isAutoReconnect()) { + return true; + } + + return false; + } + } + + @Override + public void registerQueue(HasQueuedCommands queueHolder) { + queuedCommands.register(queueHolder); + } + + @Override + public void unregisterQueue(HasQueuedCommands queueHolder) { + queuedCommands.unregister(queueHolder); + } + + @Override + public void notifyChannelActive(Channel channel) { + + this.logPrefix = null; + this.channel = channel; + this.connectionError = null; + + if (isClosed()) { + + logger.info("{} Closing channel because endpoint is already closed", logPrefix()); + channel.close(); + return; + } + + if (connectionWatchdog != null) { + connectionWatchdog.arm(); + } + + sharedLock.doExclusive(() -> { + + try { + // Move queued commands to buffer before issuing any commands because of connection activation. + // That's necessary to prepend queued commands first as some commands might get into the queue + // after the connection was disconnected. They need to be prepended to the command buffer + + if (debugEnabled) { + logger.debug("{} activateEndpointAndExecuteBufferedCommands {} command(s) buffered", logPrefix(), + commandBuffer.size()); + } + + if (debugEnabled) { + logger.debug("{} activating endpoint", logPrefix()); + } + + connectionFacade.activated(); + + flushCommands(); + } catch (Exception e) { + + if (debugEnabled) { + logger.debug("{} channelActive() ran into an exception", logPrefix()); + } + + if (clientOptions.isCancelCommandsOnReconnectFailure()) { + reset(); + } + + throw e; + } + }); + + } + + @Override + public void notifyChannelInactive(Channel channel) { + + if (isClosed()) { + cancelBufferedCommands("Connection closed"); + } + + sharedLock.doExclusive(() -> { + + if (debugEnabled) { + logger.debug("{} deactivating endpoint handler", logPrefix()); + } + + connectionFacade.deactivated(); + }); + + if (this.channel == channel) { + this.channel = null; + } + } + + @Override + public void notifyException(Throwable t) { + + if (!isConnected()) { + connectionError = t; + } + } + + @Override + public void registerConnectionWatchdog(Optional connectionWatchdog) { + this.connectionWatchdog = connectionWatchdog.orElse(null); + } + + @Override + public Queue> getQueue() { + return commandBuffer; + } + + @Override + @SuppressWarnings({ "rawtypes", "unchecked" }) + public void flushCommands() { + + if (debugEnabled) { + logger.debug("{} flushCommands()", logPrefix()); + } + + if (isConnected()) { + + List> commands = sharedLock.doExclusive(() -> { + + if (commandBuffer.isEmpty()) { + return Collections.> emptyList(); + } + + return drainCommands(commandBuffer); + }); + + if (debugEnabled) { + logger.debug("{} flushCommands() Flushing {} commands", logPrefix(), commands.size()); + } + + if (!commands.isEmpty()) { + + if (reliability == Reliability.AT_MOST_ONCE) { + // cancel on exceptions and remove from queue, because there is no housekeeping + writeAndFlush(commands).addListener(new AtMostOnceWriteListener(commands, queuedCommands)); + } + + if (reliability == Reliability.AT_LEAST_ONCE) { + // commands are ok to stay within the queue, reconnect will retrigger them + writeAndFlush(commands).addListener(new RetryListener(commands)); + } + } + } + } + + /** + * Close the connection. + */ + @Override + public void close() { + + if (debugEnabled) { + logger.debug("{} close()", logPrefix()); + } + + if (isClosed()) { + return; + } + + if (closed.compareAndSet(false, true)) { + + if (connectionWatchdog != null) { + connectionWatchdog.prepareClose(); + } + + Channel currentChannel = this.channel; + if (currentChannel != null) { + + ChannelFuture close = currentChannel.close(); + if (currentChannel.isOpen()) { + close.syncUninterruptibly(); + } + } + } + } + + /** + * Reset the writer state. Queued commands will be canceled and the internal state will be reset. This is useful when the + * internal state machine gets out of sync with the connection. + */ + @Override + public void reset() { + + if (debugEnabled) { + logger.debug("{} reset()", logPrefix()); + } + + if (channel != null) { + channel.pipeline().fireUserEventTriggered(new ConnectionEvents.Reset()); + } + cancelBufferedCommands("Reset"); + } + + @Override + public void setConnectionFacade(ConnectionFacade connectionFacade) { + this.connectionFacade = connectionFacade; + } + + @Override + public void setAutoFlushCommands(boolean autoFlush) { + this.autoFlushCommands = autoFlush; + } + + /** + * Reset the command-handler to the initial not-connected state. + */ + public void initialState() { + + commandBuffer.clear(); + + Channel currentChannel = this.channel; + if (currentChannel != null) { + + ChannelFuture close = currentChannel.close(); + if (currentChannel.isOpen()) { + close.syncUninterruptibly(); + } + } + } + + @Override + public void notifyDrainQueuedCommands(HasQueuedCommands queuedCommands) { + + if (isClosed()) { + cancelCommands("Connection closed", queuedCommands.getQueue()); + return; + } + + sharedLock.doExclusive(() -> { + + List> commands = drainCommands(queuedCommands.getQueue()); + Collections.reverse(commands); + + logger.debug("{} notifyQueuedCommands {} command(s) added to buffer", logPrefix(), commands.size()); + + for (RedisCommand command : commands) { + if (!commandBuffer.contains(command)) { + commandBuffer.addFirst(command); + } + } + + if (isConnected()) { + flushCommands(); + } + }); + } + + public boolean isClosed() { + return closed.get(); + } + + /** + * Execute a {@link Supplier} callback guarded by an exclusive lock. + * + * @param supplier + * @param + * @return + */ + protected T doExclusive(Supplier supplier) { + return sharedLock.doExclusive(supplier); + } + + private ChannelFuture writeAndFlush(List> commands) { + + if (debugEnabled) { + logger.debug("{} write() writeAndFlush commands {}", logPrefix(), commands); + } + + return channel.writeAndFlush(commands); + } + + private ChannelFuture writeAndFlush(RedisCommand command) { + + if (debugEnabled) { + logger.debug("{} write() writeAndFlush command {}", logPrefix(), command); + } + + return channel.writeAndFlush(command); + } + + private List> drainCommands(Queue> source) { + + List> target = new ArrayList<>(source.size()); + + RedisCommand cmd; + while ((cmd = source.poll()) != null) { + target.add(cmd); + } + + return target; + } + + private void cancelBufferedCommands(String message) { + + List> toCancel = sharedLock.doExclusive(queuedCommands::drainCommands); + cancelCommands(message, toCancel); + } + + private void cancelCommands(String message, Iterable> toCancel) { + + for (RedisCommand cmd : toCancel) { + if (cmd.getOutput() != null) { + cmd.getOutput().setError(message); + } + cmd.cancel(); + } + } + + private boolean isConnected() { + return channel != null && channel.isActive(); + } + + protected String logPrefix() { + + if (logPrefix != null) { + return logPrefix; + } + + StringBuffer buffer = new StringBuffer(64); + buffer.append('[').append("epid=0x").append(Long.toHexString(endpointId)).append(", ") + .append(ChannelLogDescriptor.logDescriptor(channel)).append(']'); + return logPrefix = buffer.toString(); + } + + private static class AtMostOnceWriteListener implements ChannelFutureListener { + + private final Collection> sentCommands; + private final RedisCommand sentCommand; + private final QueuedCommands queuedCommands; + + AtMostOnceWriteListener(RedisCommand sentCommand, QueuedCommands queuedCommands) { + this.sentCommand = sentCommand; + this.sentCommands = null; + this.queuedCommands = queuedCommands; + } + + AtMostOnceWriteListener(Collection> sentCommands, QueuedCommands queuedCommands) { + this.sentCommand = null; + this.sentCommands = sentCommands; + this.queuedCommands = queuedCommands; + } + + @Override + public void operationComplete(ChannelFuture future) throws Exception { + future.await(); + + if (future.cause() != null) { + + if (sentCommand != null) { + + sentCommand.completeExceptionally(future.cause()); + queuedCommands.remove(sentCommand); + } + + if (sentCommands != null) { + + for (RedisCommand sentCommand : sentCommands) { + sentCommand.completeExceptionally(future.cause()); + } + queuedCommands.removeAll(sentCommands); + } + } + } + } + + /** + * A generic future listener which retries unsuccessful writes. + */ + private class RetryListener implements GenericFutureListener> { + + private final Collection> sentCommands; + private final RedisCommand sentCommand; + + RetryListener(Collection> sentCommands) { + this.sentCommands = sentCommands; + this.sentCommand = null; + } + + RetryListener(RedisCommand sentCommand) { + this.sentCommands = null; + this.sentCommand = sentCommand; + } + + @Override + public void operationComplete(Future future) throws Exception { + + Throwable cause = future.cause(); + + if (!future.isSuccess()) { + if (sentCommand != null) { + if (!sentCommand.isCancelled() && !sentCommand.isDone()) { + write(sentCommand); + } + } + + if (sentCommands != null) { + for (RedisCommand command : sentCommands) { + if (!command.isCancelled() && !command.isDone()) { + write(command); + } + } + } + } + + if (!future.isSuccess() && !(cause instanceof ClosedChannelException)) { + + String message = "Unexpected exception during request: {}"; + InternalLogLevel logLevel = InternalLogLevel.WARN; + + if (cause instanceof IOException && SUPPRESS_IO_EXCEPTION_MESSAGES.contains(cause.getMessage())) { + logLevel = InternalLogLevel.DEBUG; + } + + logger.log(logLevel, message, cause.toString(), cause); + } + } + } + + private enum Reliability { + AT_MOST_ONCE, AT_LEAST_ONCE; + } + +} diff --git a/src/main/java/com/lambdaworks/redis/protocol/Endpoint.java b/src/main/java/com/lambdaworks/redis/protocol/Endpoint.java new file mode 100644 index 0000000000..294257fe67 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/protocol/Endpoint.java @@ -0,0 +1,64 @@ +package com.lambdaworks.redis.protocol; + +import java.util.Optional; + +import io.netty.channel.Channel; + +/** + * Wraps a stateful {@link Endpoint} that abstracts the underlying channel. Endpoints may be connected, disconnected and in + * closed states. Endpoints may feature reconnection capabilities with replaying queued commands. + * + * @author Mark Paluch + */ +interface Endpoint { + + /** + * Notify about channel activation. + * + * @param channel the channel + */ + void notifyChannelActive(Channel channel); + + /** + * Notify about channel deactivation. + * + * @param channel the channel + */ + void notifyChannelInactive(Channel channel); + + /** + * Notify about an exception occured in channel/command processing + * + * @param t the Exception + */ + void notifyException(Throwable t); + + /** + * Register a component holding a queue. + * + * @param queueHolder the queue holder. + */ + void registerQueue(HasQueuedCommands queueHolder); + + /** + * Unregister a component holding a queue. + * + * @param queueHolder the queue holder. + */ + void unregisterQueue(HasQueuedCommands queueHolder); + + /** + * Signal the endpoint to drain queued commands from the queue holder. + * + * @param queuedCommands the queue holder. + */ + void notifyDrainQueuedCommands(HasQueuedCommands queuedCommands); + + /** + * Associate a {@link ConnectionWatchdog} with the {@link Endpoint}. + * + * @param connectionWatchdog the connection watchdog, may be empty. + */ + void registerConnectionWatchdog(Optional connectionWatchdog); + +} diff --git a/src/main/java/com/lambdaworks/redis/protocol/HasQueuedCommands.java b/src/main/java/com/lambdaworks/redis/protocol/HasQueuedCommands.java new file mode 100644 index 0000000000..05eb9bcadf --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/protocol/HasQueuedCommands.java @@ -0,0 +1,19 @@ +package com.lambdaworks.redis.protocol; + +import java.util.Queue; + +/** + * Interface to be implemented by classes that queue commands. Implementors of this class need to expose their queue to control + * all queues by maintenance and cleanup processes. + * + * @author Mark Paluch + */ +interface HasQueuedCommands { + + /** + * The queue holding commands. + * + * @return the queue + */ + Queue> getQueue(); +} diff --git a/src/main/java/com/lambdaworks/redis/protocol/QueuedCommands.java b/src/main/java/com/lambdaworks/redis/protocol/QueuedCommands.java new file mode 100644 index 0000000000..6353f740e8 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/protocol/QueuedCommands.java @@ -0,0 +1,110 @@ +package com.lambdaworks.redis.protocol; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Set; + +import io.netty.util.internal.ConcurrentSet; + +/** + * Registry for all queued commands. This class allows to register/unregister {@link HasQueuedCommands queue holders}. It + * provides queue maintenance commands. + * + * @author Mark Paluch + */ +class QueuedCommands { + + private Set queues = new ConcurrentSet<>(); + + /** + * Register queue holder. + * + * @param queueHolder the queue holder, must not be {@literal null}. + */ + void register(HasQueuedCommands queueHolder) { + queues.add(queueHolder); + } + + /** + * Unregister queue holder. + * + * @param queueHolder the queue holder, must not be {@literal null}. + */ + void unregister(HasQueuedCommands queueHolder) { + queues.remove(queueHolder); + } + + /** + * Remove a command from all registered queues. + * + * @param command the command. + */ + public void remove(RedisCommand command) { + + for (HasQueuedCommands queue : queues) { + queue.getQueue().remove(command); + } + } + + /** + * Remove multiple commands from all registered queues. + * + * @param commands the commands. + */ + void removeAll(Collection> commands) { + + for (HasQueuedCommands queue : queues) { + queue.getQueue().removeAll(commands); + } + } + + /** + * Drain commands from all queues. + * + * @return the commands. + */ + List> drainCommands() { + + int size = 0; + + for (HasQueuedCommands queue : queues) { + size += queue.getQueue().size(); + } + + List> target = new ArrayList<>(size); + + RedisCommand cmd; + for (HasQueuedCommands queue : queues) { + while ((cmd = queue.getQueue().poll()) != null) { + target.add(cmd); + } + } + + return target; + } + + /** + * Check whether the registered queues exceed a global sized of the {@code requestQueueSize}. + * + * @param requestQueueSize the queue size limit. + * @return {@literal true} if there are more queued commands than {@code requestQueueSize} + */ + boolean exceedsLimit(int requestQueueSize) { + + if (requestQueueSize == Integer.MAX_VALUE) { + return false; + } + + int current = 0; + + for (HasQueuedCommands queue : queues) { + current += queue.getQueue().size(); + if (current >= requestQueueSize) { + return true; + } + } + + return false; + } +} diff --git a/src/main/java/com/lambdaworks/redis/protocol/ReconnectionHandler.java b/src/main/java/com/lambdaworks/redis/protocol/ReconnectionHandler.java index b48cb7abd4..aac7e43823 100644 --- a/src/main/java/com/lambdaworks/redis/protocol/ReconnectionHandler.java +++ b/src/main/java/com/lambdaworks/redis/protocol/ReconnectionHandler.java @@ -24,25 +24,28 @@ class ReconnectionHandler { private static final InternalLogger logger = InternalLoggerFactory.getInstance(ReconnectionHandler.class); private final Supplier socketAddressSupplier; - private final Bootstrap bootstrap; private final ClientOptions clientOptions; + private final Bootstrap bootstrap; + private final ConnectionFacade connectionFacade; private TimeUnit timeoutUnit = TimeUnit.SECONDS; private long timeout = 60; private volatile ChannelFuture currentFuture; - private boolean reconnectSuspended; + private volatile boolean reconnectSuspended; - ReconnectionHandler(ClientOptions clientOptions, Bootstrap bootstrap, - Supplier socketAddressSupplier) { + ReconnectionHandler(ClientOptions clientOptions, Bootstrap bootstrap, Supplier socketAddressSupplier, + ConnectionFacade connectionFacade) { LettuceAssert.notNull(socketAddressSupplier, "SocketAddressSupplier must not be null"); LettuceAssert.notNull(clientOptions, "ClientOptions must not be null"); LettuceAssert.notNull(bootstrap, "Bootstrap must not be null"); + LettuceAssert.notNull(connectionFacade, "ConnectionFacade must not be null"); this.socketAddressSupplier = socketAddressSupplier; this.bootstrap = bootstrap; this.clientOptions = clientOptions; + this.connectionFacade = connectionFacade; } protected boolean reconnect(InternalLogLevel infoLevel) throws Exception { @@ -68,7 +71,6 @@ protected boolean reconnect(InternalLogLevel infoLevel) throws Exception { Channel channel = currentFuture.channel(); RedisChannelInitializer channelInitializer = channel.pipeline().get(RedisChannelInitializer.class); - CommandHandler commandHandler = channel.pipeline().get(CommandHandler.class); if (channelInitializer == null) { logger.warn("Reconnection attempt without a RedisChannelInitializer in the channel pipeline"); @@ -76,12 +78,6 @@ protected boolean reconnect(InternalLogLevel infoLevel) throws Exception { return false; } - if (commandHandler == null) { - logger.warn("Reconnection attempt without a CommandHandler in the channel pipeline"); - close(channel); - return false; - } - try { timeLeft -= System.nanoTime() - start; channelInitializer.channelInitialized().get(Math.max(0, timeLeft), TimeUnit.NANOSECONDS); @@ -96,7 +92,7 @@ protected boolean reconnect(InternalLogLevel infoLevel) throws Exception { channelInitializer.channelInitialized().cancel(true); } catch (Exception e) { if (clientOptions.isCancelCommandsOnReconnectFailure()) { - commandHandler.reset(); + connectionFacade.reset(); } if (clientOptions.isSuspendReconnectOnProtocolFailure()) { @@ -120,31 +116,23 @@ private void close(Channel channel) { } } - public boolean isReconnectSuspended() { + boolean isReconnectSuspended() { return reconnectSuspended; } - public void setReconnectSuspended(boolean reconnectSuspended) { + void setReconnectSuspended(boolean reconnectSuspended) { this.reconnectSuspended = reconnectSuspended; } - public TimeUnit getTimeoutUnit() { - return timeoutUnit; - } - - public void setTimeoutUnit(TimeUnit timeoutUnit) { - this.timeoutUnit = timeoutUnit; - } - - public long getTimeout() { + long getTimeout() { return timeout; } - public void setTimeout(long timeout) { + void setTimeout(long timeout) { this.timeout = timeout; } - public void prepareClose() { + void prepareClose() { if (currentFuture != null && !currentFuture.isDone()) { currentFuture.cancel(true); diff --git a/src/main/java/com/lambdaworks/redis/protocol/RedisStateMachine.java b/src/main/java/com/lambdaworks/redis/protocol/RedisStateMachine.java index a4677d43e6..ecd0fee04e 100644 --- a/src/main/java/com/lambdaworks/redis/protocol/RedisStateMachine.java +++ b/src/main/java/com/lambdaworks/redis/protocol/RedisStateMachine.java @@ -23,12 +23,10 @@ * State machine that decodes redis server responses encoded according to the Unified * Request Protocol (RESP). * - * @param Key type. - * @param Value type. * @author Will Glozer * @author Mark Paluch */ -public class RedisStateMachine { +public class RedisStateMachine { private static final InternalLogger logger = InternalLoggerFactory.getInstance(RedisStateMachine.class); private static final ByteBuffer QUEUED = buffer("QUEUED"); @@ -87,7 +85,7 @@ public RedisStateMachine() { * @param output Current command output. * @return true if a complete response was read. */ - public boolean decode(ByteBuf buffer, CommandOutput output) { + public boolean decode(ByteBuf buffer, CommandOutput output) { return decode(buffer, null, output); } @@ -99,7 +97,7 @@ public boolean decode(ByteBuf buffer, CommandOutput output) { * @param output Current command output. * @return true if a complete response was read. */ - public boolean decode(ByteBuf buffer, RedisCommand command, CommandOutput output) { + public boolean decode(ByteBuf buffer, RedisCommand command, CommandOutput output) { int length, end; ByteBuffer bytes; @@ -219,7 +217,7 @@ public void reset() { * Close the state machine to free resources. */ public void close() { - if(closed.compareAndSet(false, true)) { + if (closed.compareAndSet(false, true)) { responseElementBuffer.release(); } } @@ -366,7 +364,7 @@ private boolean isEmpty(State[] stack) { * @param integer * @param command */ - protected void safeSet(CommandOutput output, long integer, RedisCommand command) { + protected void safeSet(CommandOutput output, long integer, RedisCommand command) { try { output.set(integer); @@ -382,7 +380,7 @@ protected void safeSet(CommandOutput output, long integer, RedisCommand * @param bytes * @param command */ - protected void safeSet(CommandOutput output, ByteBuffer bytes, RedisCommand command) { + protected void safeSet(CommandOutput output, ByteBuffer bytes, RedisCommand command) { try { output.set(bytes); @@ -398,7 +396,7 @@ protected void safeSet(CommandOutput output, ByteBuffer bytes, RedisCom * @param count * @param command */ - protected void safeMulti(CommandOutput output, int count, RedisCommand command) { + protected void safeMulti(CommandOutput output, int count, RedisCommand command) { try { output.multi(count); @@ -414,7 +412,7 @@ protected void safeMulti(CommandOutput output, int count, RedisCommand< * @param bytes * @param command */ - protected void safeSetError(CommandOutput output, ByteBuffer bytes, RedisCommand command) { + protected void safeSetError(CommandOutput output, ByteBuffer bytes, RedisCommand command) { try { output.setError(bytes); diff --git a/src/main/java/com/lambdaworks/redis/protocol/SharedLock.java b/src/main/java/com/lambdaworks/redis/protocol/SharedLock.java new file mode 100644 index 0000000000..4a3bce3c33 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/protocol/SharedLock.java @@ -0,0 +1,128 @@ +package com.lambdaworks.redis.protocol; + +import java.util.concurrent.atomic.AtomicLong; +import java.util.function.Supplier; + +import com.lambdaworks.redis.internal.LettuceAssert; + +/** + * Shared locking facade that supports shared and exclusive locking. + *

+ * Multiple shared locks (writers) are allowed concurrently to process their work. If an exclusive lock is requested, the + * exclusive lock requestor will wait until all shared locks are released and the exclusive worker is permitted. + *

+ * Exclusive locking is reentrant. An exclusive lock owner is permitted to acquire and release shared locks. Shared/exclusive + * lock requests by other threads than the thread which holds the exclusive lock, are forced to wait until the exclusive lock is + * released. + * + * @author Mark Paluch + */ +class SharedLock { + + private final AtomicLong writers = new AtomicLong(); + private Thread exclusiveLockOwner; + + /** + * Wait for stateLock and increment writers. Will wait if stateLock is locked and if writer counter is negative. + */ + void incrementWriters() { + + if (exclusiveLockOwner == Thread.currentThread()) { + return; + } + + synchronized (this) { + for (;;) { + + if (writers.get() >= 0) { + writers.incrementAndGet(); + return; + } + } + } + } + + /** + * Decrement writers without any wait. + */ + void decrementWriters() { + + if (exclusiveLockOwner == Thread.currentThread()) { + return; + } + + writers.decrementAndGet(); + } + + /** + * Execute a {@link Runnable} guarded by an exclusive lock. + * + * @param runnable the runnable, must not be {@literal null}. + */ + void doExclusive(Runnable runnable) { + + LettuceAssert.notNull(runnable, "Runnable must not be null"); + + doExclusive(() -> { + runnable.run(); + return null; + }); + } + + /** + * Retrieve a value produced by a {@link Supplier} guarded by an exclusive lock. + * + * @param supplier the {@link Supplier}, must not be {@literal null}. + * @param the return type + * @return the return value + */ + T doExclusive(Supplier supplier) { + + LettuceAssert.notNull(supplier, "Supplier must not be null"); + + synchronized (this) { + + try { + + lockWritersExclusive(); + return supplier.get(); + } finally { + unlockWritersExclusive(); + } + } + } + + /** + * Wait for stateLock and no writers. Must be used in an outer {@code synchronized} block to prevent interleaving with other + * methods using writers. Sets writers to a negative value to create a lock for {@link #incrementWriters()}. + */ + private void lockWritersExclusive() { + + if (exclusiveLockOwner == Thread.currentThread()) { + writers.decrementAndGet(); + return; + } + + synchronized (this) { + for (;;) { + + if (writers.compareAndSet(0, -1)) { + exclusiveLockOwner = Thread.currentThread(); + return; + } + } + } + } + + /** + * Unlock writers. + */ + private void unlockWritersExclusive() { + + if (exclusiveLockOwner == Thread.currentThread()) { + if (writers.incrementAndGet() == 0) { + exclusiveLockOwner = null; + } + } + } +} diff --git a/src/main/java/com/lambdaworks/redis/pubsub/PubSubCommandHandler.java b/src/main/java/com/lambdaworks/redis/pubsub/PubSubCommandHandler.java index 2937ce9c61..2877dec55a 100644 --- a/src/main/java/com/lambdaworks/redis/pubsub/PubSubCommandHandler.java +++ b/src/main/java/com/lambdaworks/redis/pubsub/PubSubCommandHandler.java @@ -2,15 +2,11 @@ package com.lambdaworks.redis.pubsub; -import java.util.Queue; - -import com.lambdaworks.redis.ClientOptions; import com.lambdaworks.redis.codec.RedisCodec; import com.lambdaworks.redis.output.CommandOutput; import com.lambdaworks.redis.protocol.CommandHandler; -import com.lambdaworks.redis.protocol.RedisCommand; - import com.lambdaworks.redis.resource.ClientResources; + import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; @@ -24,44 +20,54 @@ * * @author Will Glozer */ -public class PubSubCommandHandler extends CommandHandler { +public class PubSubCommandHandler extends CommandHandler { + + private PubSubEndpoint endpoint; private RedisCodec codec; private PubSubOutput output; /** * Initialize a new instance. * - * @param clientOptions client options for the connection * @param clientResources client resources for this connection - * @param queue Command queue. * @param codec Codec. + * @param endpoint the Pub/Sub endpoint for Pub/Sub callback. */ - public PubSubCommandHandler(ClientOptions clientOptions, ClientResources clientResources, - Queue> queue, RedisCodec codec) { - super(clientOptions, clientResources, queue); + public PubSubCommandHandler(ClientResources clientResources, RedisCodec codec, PubSubEndpoint endpoint) { + + super(clientResources, endpoint); + this.codec = codec; this.output = new PubSubOutput<>(codec); + this.endpoint = endpoint; } + @SuppressWarnings("unchecked") @Override protected void decode(ChannelHandlerContext ctx, ByteBuf buffer) throws InterruptedException { - while (output.type() == null && !queue.isEmpty()) { - CommandOutput currentOutput = queue.peek().getOutput(); - if (!rsm.decode(buffer, currentOutput)) { + + while (output.type() == null && !getQueue().isEmpty()) { + CommandOutput currentOutput = getQueue().peek().getOutput(); + + if (!super.decode(buffer, currentOutput)) { return; } - queue.poll().complete(); + + getQueue().poll().complete(); + buffer.discardReadBytes(); + if (currentOutput instanceof PubSubOutput) { - ctx.fireChannelRead(currentOutput); + endpoint.notifyMessage((PubSubOutput) currentOutput); } } - while (rsm.decode(buffer, output)) { - ctx.fireChannelRead(output); - output = new PubSubOutput(codec); + while (super.decode(buffer, output)) { + + endpoint.notifyMessage(output); + output = new PubSubOutput<>(codec); + buffer.discardReadBytes(); } } - } diff --git a/src/main/java/com/lambdaworks/redis/pubsub/PubSubEndpoint.java b/src/main/java/com/lambdaworks/redis/pubsub/PubSubEndpoint.java new file mode 100644 index 0000000000..a35ed3c8b8 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/pubsub/PubSubEndpoint.java @@ -0,0 +1,117 @@ +package com.lambdaworks.redis.pubsub; + +import java.util.List; +import java.util.Set; +import java.util.concurrent.CopyOnWriteArrayList; + +import com.lambdaworks.redis.ClientOptions; +import com.lambdaworks.redis.protocol.DefaultEndpoint; + +import io.netty.util.internal.ConcurrentSet; + +/** + * @author Mark Paluch + */ +public class PubSubEndpoint extends DefaultEndpoint { + + private final List> listeners = new CopyOnWriteArrayList<>(); + private final Set channels; + private final Set patterns; + + /** + * Initialize a new instance that handles commands from the supplied queue. + * + * @param clientOptions client options for this connection, must not be {@literal null} + */ + public PubSubEndpoint(ClientOptions clientOptions) { + super(clientOptions); + + this.channels = new ConcurrentSet<>(); + this.patterns = new ConcurrentSet<>(); + } + + /** + * Add a new listener. + * + * @param listener Listener. + */ + public void addListener(RedisPubSubListener listener) { + listeners.add(listener); + } + + /** + * Remove an existing listener. + * + * @param listener Listener. + */ + public void removeListener(RedisPubSubListener listener) { + listeners.remove(listener); + } + + public Set getChannels() { + return channels; + } + + public Set getPatterns() { + return patterns; + } + + public void notifyMessage(PubSubOutput output) { + + // drop empty messages + if (output.type() == null || (output.pattern() == null && output.channel() == null && output.get() == null)) { + return; + } + + updateInternalState(output); + notifyListeners(output); + } + + private void notifyListeners(PubSubOutput output) { + // update listeners + for (RedisPubSubListener listener : listeners) { + switch (output.type()) { + case message: + listener.message(output.channel(), output.get()); + break; + case pmessage: + listener.message(output.pattern(), output.channel(), output.get()); + break; + case psubscribe: + listener.psubscribed(output.pattern(), output.count()); + break; + case punsubscribe: + listener.punsubscribed(output.pattern(), output.count()); + break; + case subscribe: + listener.subscribed(output.channel(), output.count()); + break; + case unsubscribe: + listener.unsubscribed(output.channel(), output.count()); + break; + default: + throw new UnsupportedOperationException("Operation " + output.type() + " not supported"); + } + } + } + + private void updateInternalState(PubSubOutput output) { + // update internal state + switch (output.type()) { + case psubscribe: + patterns.add(output.pattern()); + break; + case punsubscribe: + patterns.remove(output.pattern()); + break; + case subscribe: + channels.add(output.channel()); + break; + case unsubscribe: + channels.remove(output.channel()); + break; + default: + break; + } + } +} diff --git a/src/main/java/com/lambdaworks/redis/pubsub/StatefulRedisPubSubConnectionImpl.java b/src/main/java/com/lambdaworks/redis/pubsub/StatefulRedisPubSubConnectionImpl.java index 123ebcf193..fc92f01593 100644 --- a/src/main/java/com/lambdaworks/redis/pubsub/StatefulRedisPubSubConnectionImpl.java +++ b/src/main/java/com/lambdaworks/redis/pubsub/StatefulRedisPubSubConnectionImpl.java @@ -30,13 +30,10 @@ * @param Value type. * @author Mark Paluch */ -@ChannelHandler.Sharable public class StatefulRedisPubSubConnectionImpl extends StatefulRedisConnectionImpl implements StatefulRedisPubSubConnection { - protected final List> listeners; - protected final Set channels; - protected final Set patterns; + private final PubSubEndpoint endpoint; /** * Initialize a new connection. @@ -46,13 +43,11 @@ public class StatefulRedisPubSubConnectionImpl extends StatefulRedisConnec * @param timeout Maximum time to wait for a response. * @param unit Unit of time for the timeout. */ - public StatefulRedisPubSubConnectionImpl(RedisChannelWriter writer, RedisCodec codec, long timeout, + public StatefulRedisPubSubConnectionImpl(PubSubEndpoint endpoint, RedisChannelWriter writer, RedisCodec codec, long timeout, TimeUnit unit) { super(writer, codec, timeout, unit); - listeners = new CopyOnWriteArrayList<>(); - channels = new ConcurrentSet<>(); - patterns = new ConcurrentSet<>(); + this.endpoint = endpoint; } /** @@ -62,7 +57,7 @@ public StatefulRedisPubSubConnectionImpl(RedisChannelWriter writer, RedisC */ @Override public void addListener(RedisPubSubListener listener) { - listeners.add(listener); + endpoint.addListener(listener); } /** @@ -72,7 +67,7 @@ public void addListener(RedisPubSubListener listener) { */ @Override public void removeListener(RedisPubSubListener listener) { - listeners.remove(listener); + endpoint.removeListener(listener); } @Override @@ -105,48 +100,6 @@ protected RedisPubSubReactiveCommandsImpl newRedisReactiveCommandsImpl() { return new RedisPubSubReactiveCommandsImpl<>(this, codec); } - @Override - @SuppressWarnings("unchecked") - public void channelRead(Object msg) { - PubSubOutput output = (PubSubOutput) msg; - - // drop empty messages - if (output.type() == null || (output.pattern() == null && output.channel() == null && output.get() == null)) { - return; - } - - updateInternalState(output); - notifyListeners(output); - } - - private void notifyListeners(PubSubOutput output) { - // update listeners - for (RedisPubSubListener listener : listeners) { - switch (output.type()) { - case message: - listener.message(output.channel(), output.get()); - break; - case pmessage: - listener.message(output.pattern(), output.channel(), output.get()); - break; - case psubscribe: - listener.psubscribed(output.pattern(), output.count()); - break; - case punsubscribe: - listener.punsubscribed(output.pattern(), output.count()); - break; - case subscribe: - listener.subscribed(output.channel(), output.count()); - break; - case unsubscribe: - listener.unsubscribed(output.channel(), output.count()); - break; - default: - throw new UnsupportedOperationException("Operation " + output.type() + " not supported"); - } - } - } - /** * Re-subscribe to all previously subscribed channels and patterns. * @@ -156,12 +109,12 @@ protected List> resubscribe() { List> result = new ArrayList<>(); - if (!channels.isEmpty()) { - result.add(async().subscribe(toArray(channels))); + if (!endpoint.getChannels().isEmpty()) { + result.add(async().subscribe(toArray(endpoint.getChannels()))); } - if (!patterns.isEmpty()) { - result.add(async().psubscribe(toArray(patterns))); + if (!endpoint.getPatterns().isEmpty()) { + result.add(async().psubscribe(toArray(endpoint.getPatterns()))); } return result; @@ -174,25 +127,7 @@ private T[] toArray(Collection c) { return c.toArray(array); } - private void updateInternalState(PubSubOutput output) { - // update internal state - switch (output.type()) { - case psubscribe: - patterns.add(output.pattern()); - break; - case punsubscribe: - patterns.remove(output.pattern()); - break; - case subscribe: - channels.add(output.channel()); - break; - case unsubscribe: - channels.remove(output.channel()); - break; - default: - break; - } - } + @Override public void activated() { diff --git a/src/main/java/com/lambdaworks/redis/sentinel/StatefulRedisSentinelConnectionImpl.java b/src/main/java/com/lambdaworks/redis/sentinel/StatefulRedisSentinelConnectionImpl.java index 9f852dc829..8be3d00d42 100644 --- a/src/main/java/com/lambdaworks/redis/sentinel/StatefulRedisSentinelConnectionImpl.java +++ b/src/main/java/com/lambdaworks/redis/sentinel/StatefulRedisSentinelConnectionImpl.java @@ -15,7 +15,6 @@ /** * @author Mark Paluch */ -@ChannelHandler.Sharable public class StatefulRedisSentinelConnectionImpl extends RedisChannelHandler implements StatefulRedisSentinelConnection { @@ -24,7 +23,7 @@ public class StatefulRedisSentinelConnectionImpl extends RedisChannelHandl protected final RedisSentinelAsyncCommands async; protected final RedisSentinelReactiveCommands reactive; - public StatefulRedisSentinelConnectionImpl(RedisChannelWriter writer, RedisCodec codec, long timeout, + public StatefulRedisSentinelConnectionImpl(RedisChannelWriter writer, RedisCodec codec, long timeout, TimeUnit unit) { super(writer, timeout, unit); diff --git a/src/test/java/biz/paluch/redis/extensibility/MyExtendedRedisClient.java b/src/test/java/biz/paluch/redis/extensibility/MyExtendedRedisClient.java index 42be2f7f2f..76f2487192 100644 --- a/src/test/java/biz/paluch/redis/extensibility/MyExtendedRedisClient.java +++ b/src/test/java/biz/paluch/redis/extensibility/MyExtendedRedisClient.java @@ -4,10 +4,11 @@ import javax.enterprise.inject.Alternative; +import com.lambdaworks.redis.RedisChannelWriter; import com.lambdaworks.redis.RedisClient; import com.lambdaworks.redis.RedisURI; import com.lambdaworks.redis.codec.RedisCodec; -import com.lambdaworks.redis.pubsub.PubSubCommandHandler; +import com.lambdaworks.redis.pubsub.PubSubEndpoint; import com.lambdaworks.redis.pubsub.StatefulRedisPubSubConnectionImpl; import com.lambdaworks.redis.resource.ClientResources; @@ -27,8 +28,8 @@ public MyExtendedRedisClient() { } @Override - protected StatefulRedisPubSubConnectionImpl newStatefulRedisPubSubConnection( - PubSubCommandHandler commandHandler, RedisCodec codec, long timeout, TimeUnit unit) { - return new MyPubSubConnection<>(commandHandler, codec, timeout, unit); + protected StatefulRedisPubSubConnectionImpl newStatefulRedisPubSubConnection(PubSubEndpoint endpoint, + RedisChannelWriter channelWriter, RedisCodec codec, long timeout, TimeUnit unit) { + return new MyPubSubConnection<>(endpoint, channelWriter, codec, timeout, unit); } } diff --git a/src/test/java/biz/paluch/redis/extensibility/MyPubSubConnection.java b/src/test/java/biz/paluch/redis/extensibility/MyPubSubConnection.java index 77d1e9be71..dd3e9933d7 100644 --- a/src/test/java/biz/paluch/redis/extensibility/MyPubSubConnection.java +++ b/src/test/java/biz/paluch/redis/extensibility/MyPubSubConnection.java @@ -7,6 +7,7 @@ import com.lambdaworks.redis.codec.RedisCodec; import com.lambdaworks.redis.protocol.CommandType; import com.lambdaworks.redis.protocol.RedisCommand; +import com.lambdaworks.redis.pubsub.PubSubEndpoint; import com.lambdaworks.redis.pubsub.PubSubOutput; import com.lambdaworks.redis.pubsub.StatefulRedisPubSubConnectionImpl; @@ -22,14 +23,17 @@ public class MyPubSubConnection extends StatefulRedisPubSubConnectionImpl< /** * Initialize a new connection. - * - * @param writer + * + * @param endpoint + * @param writer the channel writer * @param codec Codec used to encode/decode keys and values. - * @param timeout Maximum time to wait for a responses. + * @param timeout Maximum time to wait for a response. * @param unit Unit of time for the timeout. */ - public MyPubSubConnection(RedisChannelWriter writer, RedisCodec codec, long timeout, TimeUnit unit) { - super(writer, codec, timeout, unit); + public MyPubSubConnection(PubSubEndpoint endpoint, + RedisChannelWriter writer, RedisCodec codec, long timeout, + TimeUnit unit) { + super(endpoint, writer, codec, timeout, unit); } @Override @@ -42,26 +46,4 @@ public > C dispatch(C cmd) { return super.dispatch(cmd); } - public void channelRead(Object msg) { - PubSubOutput output = (PubSubOutput) msg; - // update internal state - switch (output.type()) { - case psubscribe: - patterns.add(output.pattern()); - break; - case punsubscribe: - patterns.remove(output.pattern()); - break; - case subscribe: - channels.add(output.channel()); - break; - case unsubscribe: - channels.remove(output.channel()); - break; - default: - break; - } - super.channelRead(msg); - } - } diff --git a/src/test/java/com/lambdaworks/Connections.java b/src/test/java/com/lambdaworks/ConnectionTestUtil.java similarity index 60% rename from src/test/java/com/lambdaworks/Connections.java rename to src/test/java/com/lambdaworks/ConnectionTestUtil.java index 7e13bb0b8a..d13c68443b 100644 --- a/src/test/java/com/lambdaworks/Connections.java +++ b/src/test/java/com/lambdaworks/ConnectionTestUtil.java @@ -2,7 +2,6 @@ import java.util.Queue; -import com.lambdaworks.redis.api.StatefulRedisConnection; import org.springframework.test.util.ReflectionTestUtils; import com.lambdaworks.redis.RedisChannelHandler; @@ -10,14 +9,17 @@ import com.lambdaworks.redis.StatefulRedisConnectionImpl; import com.lambdaworks.redis.api.StatefulConnection; import com.lambdaworks.redis.api.async.RedisAsyncCommands; +import com.lambdaworks.redis.internal.LettuceFactories; +import com.lambdaworks.redis.protocol.CommandHandler; import com.lambdaworks.redis.protocol.ConnectionWatchdog; +import com.lambdaworks.redis.protocol.DefaultEndpoint; import io.netty.channel.Channel; /** * @author Mark Paluch */ -public class Connections { +public class ConnectionTestUtil { /** * Extract the {@link Channel} from a stateful connection. @@ -33,6 +35,7 @@ public static Channel getChannel(StatefulConnection connection) { /** * Extract the {@link ConnectionWatchdog} from a stateful connection. + * * @param connection * @return */ @@ -46,19 +49,42 @@ public static StatefulRedisConnectionImpl getStatefulConnection(Red return (StatefulRedisConnectionImpl) connection.getStatefulConnection(); } - public static RedisChannelWriter getChannelWriter(StatefulConnection connection) { + public static RedisChannelWriter getChannelWriter(StatefulConnection connection) { return ((RedisChannelHandler) connection).getChannelWriter(); } public static Queue getQueue(StatefulConnection connection) { - return (Queue) ReflectionTestUtils.getField(Connections.getChannelWriter(connection), "queue"); + + Channel channel = getChannel(connection); + + if (channel != null) { + CommandHandler commandHandler = channel.pipeline().get(CommandHandler.class); + return (Queue) commandHandler.getQueue(); + } + + return LettuceFactories.newConcurrentQueue(); + } public static Queue getCommandBuffer(StatefulConnection connection) { - return (Queue) ReflectionTestUtils.getField(Connections.getChannelWriter(connection), "commandBuffer"); + + RedisChannelWriter channelWriter = ConnectionTestUtil.getChannelWriter(connection); + if (channelWriter instanceof DefaultEndpoint) { + return (Queue) ((DefaultEndpoint) channelWriter).getQueue(); + } + + return LettuceFactories.newConcurrentQueue(); } public static String getConnectionState(StatefulConnection connection) { - return ReflectionTestUtils.getField(Connections.getChannelWriter(connection), "lifecycleState").toString(); + + Channel channel = getChannel(connection); + + if (channel != null) { + CommandHandler commandHandler = channel.pipeline().get(CommandHandler.class); + return ReflectionTestUtils.getField(commandHandler, "lifecycleState").toString(); + } + + return ""; } } diff --git a/src/test/java/com/lambdaworks/redis/ClientOptionsTest.java b/src/test/java/com/lambdaworks/redis/ClientOptionsTest.java index 785090adae..0777067daf 100644 --- a/src/test/java/com/lambdaworks/redis/ClientOptionsTest.java +++ b/src/test/java/com/lambdaworks/redis/ClientOptionsTest.java @@ -1,8 +1,8 @@ package com.lambdaworks.redis; -import static com.lambdaworks.Connections.getChannel; -import static com.lambdaworks.Connections.getConnectionWatchdog; -import static com.lambdaworks.Connections.getStatefulConnection; +import static com.lambdaworks.ConnectionTestUtil.getChannel; +import static com.lambdaworks.ConnectionTestUtil.getConnectionWatchdog; +import static com.lambdaworks.ConnectionTestUtil.getStatefulConnection; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.fail; diff --git a/src/test/java/com/lambdaworks/redis/ClientTest.java b/src/test/java/com/lambdaworks/redis/ClientTest.java index b024ade1d6..f0f2af52f3 100644 --- a/src/test/java/com/lambdaworks/redis/ClientTest.java +++ b/src/test/java/com/lambdaworks/redis/ClientTest.java @@ -4,7 +4,7 @@ import static com.google.code.tempusfugit.temporal.Duration.seconds; import static com.google.code.tempusfugit.temporal.WaitFor.waitOrTimeout; -import static com.lambdaworks.Connections.getStatefulConnection; +import static com.lambdaworks.ConnectionTestUtil.getStatefulConnection; import static org.assertj.core.api.Assertions.assertThat; import java.util.concurrent.TimeUnit; diff --git a/src/test/java/com/lambdaworks/redis/ConnectionCommandTest.java b/src/test/java/com/lambdaworks/redis/ConnectionCommandTest.java index 53d821d79a..a2fa7eab76 100644 --- a/src/test/java/com/lambdaworks/redis/ConnectionCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/ConnectionCommandTest.java @@ -4,8 +4,9 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.fail; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; -import org.assertj.core.api.Assertions; import org.junit.FixMethodOrder; import org.junit.Test; import org.junit.runners.MethodSorters; diff --git a/src/test/java/com/lambdaworks/redis/LettucePerformanceTest.java b/src/test/java/com/lambdaworks/redis/LettucePerformanceTest.java deleted file mode 100644 index 5c1de4cd35..0000000000 --- a/src/test/java/com/lambdaworks/redis/LettucePerformanceTest.java +++ /dev/null @@ -1,251 +0,0 @@ -package com.lambdaworks.redis; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.*; - -import org.apache.logging.log4j.Level; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.core.LoggerContext; -import org.apache.logging.log4j.core.config.Configuration; -import org.junit.*; - -import com.lambdaworks.redis.api.StatefulRedisConnection; -import com.lambdaworks.redis.api.async.RedisAsyncCommands; -import com.lambdaworks.redis.api.reactive.RedisReactiveCommands; - -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - -/** - * @author Mark Paluch - */ -@Ignore -public class LettucePerformanceTest { - - private static RedisClient redisClient = RedisClient.create(RedisURI.create(TestSettings.host(), TestSettings.port())); - private ExecutorService executor; - private CountDownLatch latch = new CountDownLatch(1); - - @Before - public void before() throws Exception { - - LoggerContext ctx = (LoggerContext) LogManager.getContext(); - Configuration config = ctx.getConfiguration(); - config.getLoggerConfig("com.lambdaworks.redis").setLevel(Level.OFF); - config.getLoggerConfig("com.lambdaworks.redis.protocol").setLevel(Level.OFF); - } - - @After - public void after() throws Exception { - LoggerContext ctx = (LoggerContext) LogManager.getContext(); - ctx.reconfigure(); - executor.shutdown(); - executor.awaitTermination(1, TimeUnit.MINUTES); - } - - @AfterClass - public static void afterClass() throws Exception { - redisClient.shutdown(); - } - - /** - * Multi-threaded performance test. - * - * Uses a {@link ThreadPoolExecutor} with thread and connection preheating. Execution tasks are submitted and synchronized - * with a {@link CountDownLatch} - * - * @throws Exception - */ - @Test - public void testSyncAsyncPerformance() throws Exception { - - // TWEAK ME - int threads = 4; - int totalCalls = 250000; - boolean waitForFutureCompletion = true; - boolean connectionPerThread = false; - // Keep in mind, that the size of the event loop threads is CPU count * 4 unless you - // set -Dio.netty.eventLoopThreads=... - // END OF TWEAK ME - - executor = new ThreadPoolExecutor(threads, threads, 1, TimeUnit.MINUTES, new ArrayBlockingQueue(totalCalls)); - - List>>> futurama = new ArrayList<>(); - - preheat(threads); - - final int callsPerThread = totalCalls / threads; - - submitExecutionTasks(threads, futurama, callsPerThread, connectionPerThread); - Thread.sleep(800); - - long start = System.currentTimeMillis(); - latch.countDown(); - - for (Future>> listFuture : futurama) { - for (CompletableFuture future : listFuture.get()) { - if (waitForFutureCompletion) { - future.get(); - } - } - } - - long end = System.currentTimeMillis(); - - long duration = end - start; - double durationSeconds = duration / 1000d; - double opsPerSecond = totalCalls / durationSeconds; - System.out.println(String.format("Sync/Async: Duration: %d ms (%.2f sec), operations: %d, %.2f ops/sec ", duration, - durationSeconds, totalCalls, opsPerSecond)); - - for (Future>> listFuture : futurama) { - for (CompletableFuture future : listFuture.get()) { - future.get(); - } - } - - } - - protected void submitExecutionTasks(int threads, List>>> futurama, - final int callsPerThread, final boolean connectionPerThread) { - final RedisAsyncCommands sharedConnection; - if (!connectionPerThread) { - sharedConnection = redisClient.connect().async(); - } else { - sharedConnection = null; - } - - for (int i = 0; i < threads; i++) { - Future>> submit = executor.submit(() -> { - - RedisAsyncCommands connection = sharedConnection; - if (connectionPerThread) { - connection = redisClient.connect().async(); - } - connection.ping().get(); - - List> futures = new ArrayList<>(callsPerThread); - latch.await(); - for (int i1 = 0; i1 < callsPerThread; i1++) { - futures.add(connection.ping().toCompletableFuture()); - } - - return futures; - }); - - futurama.add(submit); - } - } - - /** - * Multi-threaded performance using reactive commands. - * - * Uses a {@link ThreadPoolExecutor} with thread and connection preheating. Execution tasks are submitted and synchronized - * with a {@link CountDownLatch} - * - * @throws Exception - */ - @Test - public void testReactivePerformance() throws Exception { - - // TWEAK ME - int threads = 4; - int totalCalls = 25000; - boolean waitForCompletion = true; - boolean connectionPerThread = false; - // Keep in mind, that the size of the event loop threads is CPU count * 4 unless you - // set -Dio.netty.eventLoopThreads=... - // END OF TWEAK ME - - executor = new ThreadPoolExecutor(threads, threads, 1, TimeUnit.MINUTES, new ArrayBlockingQueue(totalCalls)); - - List>>> futurama = new ArrayList<>(); - - preheat(threads); - final int callsPerThread = totalCalls / threads; - - submitFluxTasks(threads, futurama, callsPerThread, connectionPerThread); - Thread.sleep(800); - - long start = System.currentTimeMillis(); - latch.countDown(); - - for (Future>> listFuture : futurama) { - - if (waitForCompletion) { - Flux.concat(listFuture.get()).last().subscribe().request(Long.MAX_VALUE); - - } else - for (Mono mono : listFuture.get()) { - mono.subscribe().request(Long.MAX_VALUE); - } - } - - long end = System.currentTimeMillis(); - - long duration = end - start; - double durationSeconds = duration / 1000d; - double opsPerSecond = totalCalls / durationSeconds; - System.out.println(String.format("Reactive Duration: %d ms (%.2f sec), operations: %d, %.2f ops/sec ", duration, - durationSeconds, totalCalls, opsPerSecond)); - - } - - protected void submitFluxTasks(int threads, List>>> futurama, final int callsPerThread, - final boolean connectionPerThread) { - final StatefulRedisConnection sharedConnection; - if (!connectionPerThread) { - sharedConnection = redisClient.connect(); - } else { - sharedConnection = null; - } - - for (int i = 0; i < threads; i++) { - Future>> submit = executor.submit(() -> { - - StatefulRedisConnection connection = sharedConnection; - if (connectionPerThread) { - connection = redisClient.connect(); - } - RedisReactiveCommands reactive = connection.reactive(); - - connection.sync().ping(); - - List> monos = new ArrayList<>(callsPerThread); - latch.await(); - for (int i1 = 0; i1 < callsPerThread; i1++) { - monos.add(reactive.ping()); - } - - return monos; - }); - - futurama.add(submit); - } - } - - protected void preheat(int threads) throws Exception { - - List> futures = new ArrayList<>(); - - for (int i = 0; i < threads; i++) { - - futures.add(executor.submit(new Runnable() { - @Override - public void run() { - try { - Thread.sleep(100); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - } - })); - } - - for (Future future : futures) { - future.get(); - } - - } -} diff --git a/src/test/java/com/lambdaworks/redis/cluster/ClusterCommandInternalsTest.java b/src/test/java/com/lambdaworks/redis/cluster/ClusterCommandInternalsTest.java index 4b7d8580b3..2a60483451 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/ClusterCommandInternalsTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/ClusterCommandInternalsTest.java @@ -25,7 +25,7 @@ public class ClusterCommandInternalsTest { @Mock - private RedisChannelWriter writerMock; + private RedisChannelWriter writerMock; private ClusterCommand sut; private Command command = new Command(CommandType.TYPE, diff --git a/src/test/java/com/lambdaworks/redis/cluster/ClusterNodeCommandHandlerTest.java b/src/test/java/com/lambdaworks/redis/cluster/ClusterNodeEndpointTest.java similarity index 91% rename from src/test/java/com/lambdaworks/redis/cluster/ClusterNodeCommandHandlerTest.java rename to src/test/java/com/lambdaworks/redis/cluster/ClusterNodeEndpointTest.java index 0b5e640678..564595e50a 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/ClusterNodeCommandHandlerTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/ClusterNodeEndpointTest.java @@ -9,7 +9,6 @@ import java.util.Queue; import java.util.concurrent.ExecutionException; -import java.util.concurrent.LinkedBlockingQueue; import org.junit.Before; import org.junit.Test; @@ -32,12 +31,12 @@ * @author Mark Paluch */ @RunWith(MockitoJUnitRunner.class) -public class ClusterNodeCommandHandlerTest { +public class ClusterNodeEndpointTest { private AsyncCommand command = new AsyncCommand<>( new Command<>(CommandType.APPEND, new StatusOutput(new Utf8StringCodec()), null)); - private Queue> queue = new LinkedBlockingQueue<>(); + private Queue> queue; @Mock private ClientOptions clientOptions; @@ -46,14 +45,15 @@ public class ClusterNodeCommandHandlerTest { private ClientResources clientResources; @Mock - private RedisChannelWriter clusterChannelWriter; + private RedisChannelWriter clusterChannelWriter; - private ClusterNodeCommandHandler sut; + private ClusterNodeEndpoint sut; @Before public void before() throws Exception { - sut = new ClusterNodeCommandHandler(clientOptions, clientResources, queue, clusterChannelWriter); + sut = new ClusterNodeEndpoint(clientOptions, clientResources, clusterChannelWriter); + queue = (Queue) sut.getQueue(); } @Test diff --git a/src/test/java/com/lambdaworks/redis/cluster/ClusterSetup.java b/src/test/java/com/lambdaworks/redis/cluster/ClusterSetup.java index d098ca6203..ad27046be2 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/ClusterSetup.java +++ b/src/test/java/com/lambdaworks/redis/cluster/ClusterSetup.java @@ -27,7 +27,8 @@ public class ClusterSetup { * @throws ExecutionException * @throws TimeoutException */ - public static void setup2Masters(ClusterRule clusterRule) throws InterruptedException, ExecutionException, TimeoutException { + public static void setup2Masters(ClusterRule clusterRule) + throws InterruptedException, ExecutionException, TimeoutException { clusterRule.clusterReset(); clusterRule.meet(AbstractClusterTest.host, AbstractClusterTest.port5); @@ -48,16 +49,11 @@ public static void setup2Masters(ClusterRule clusterRule) throws InterruptedExce RedisClusterAsyncCommands nodeConnection = connection.getConnection(partition.getNodeId()); for (Integer slot : partition.getSlots()) { - - try { - nodeConnection.clusterDelSlots(slot); - } catch (Exception e) { - } + nodeConnection.clusterDelSlots(slot); } } } - RedisClusterAsyncCommands node1 = connection.getConnection(AbstractClusterTest.host, AbstractClusterTest.port5); node1.clusterAddSlots(AbstractClusterTest.createSlots(0, 12000)); @@ -68,14 +64,12 @@ public static void setup2Masters(ClusterRule clusterRule) throws InterruptedExce Wait.untilTrue(clusterRule::isStable).waitOrTimeout(); - Wait.untilEquals( - 2L, - () -> { - clusterRule.getClusterClient().reloadPartitions(); + Wait.untilEquals(2L, () -> { + clusterRule.getClusterClient().reloadPartitions(); - return partitionStream(clusterRule).filter( - redisClusterNode -> redisClusterNode.is(RedisClusterNode.NodeFlag.MASTER)).count(); - }).waitOrTimeout(); + return partitionStream(clusterRule) + .filter(redisClusterNode -> redisClusterNode.is(RedisClusterNode.NodeFlag.MASTER)).count(); + }).waitOrTimeout(); connection.getStatefulConnection().close(); } @@ -89,8 +83,8 @@ public static void setup2Masters(ClusterRule clusterRule) throws InterruptedExce * @throws ExecutionException * @throws TimeoutException */ - public static void setupMasterWithSlave(ClusterRule clusterRule) throws InterruptedException, ExecutionException, - TimeoutException { + public static void setupMasterWithSlave(ClusterRule clusterRule) + throws InterruptedException, ExecutionException, TimeoutException { clusterRule.clusterReset(); clusterRule.meet(AbstractClusterTest.host, AbstractClusterTest.port5); @@ -104,8 +98,8 @@ public static void setupMasterWithSlave(ClusterRule clusterRule) throws Interrup return clusterRule.getClusterClient().getPartitions().size(); }).waitOrTimeout(); - RedisClusterCommands node1 = statefulConnection.getConnection(TestSettings.hostAddr(), - AbstractClusterTest.port5).sync(); + RedisClusterCommands node1 = statefulConnection + .getConnection(TestSettings.hostAddr(), AbstractClusterTest.port5).sync(); node1.clusterAddSlots(AbstractClusterTest.createSlots(0, 16384)); Wait.untilTrue(clusterRule::isStable).waitOrTimeout(); @@ -115,21 +109,17 @@ public static void setupMasterWithSlave(ClusterRule clusterRule) throws Interrup clusterRule.getClusterClient().reloadPartitions(); - Wait.untilEquals( - 1L, - () -> { - clusterRule.getClusterClient().reloadPartitions(); - return partitionStream(clusterRule).filter( - redisClusterNode -> redisClusterNode.is(RedisClusterNode.NodeFlag.MASTER)).count(); - }).waitOrTimeout(); - - Wait.untilEquals( - 1L, - () -> { - clusterRule.getClusterClient().reloadPartitions(); - return partitionStream(clusterRule).filter( - redisClusterNode -> redisClusterNode.is(RedisClusterNode.NodeFlag.SLAVE)).count(); - }).waitOrTimeout(); + Wait.untilEquals(1L, () -> { + clusterRule.getClusterClient().reloadPartitions(); + return partitionStream(clusterRule) + .filter(redisClusterNode -> redisClusterNode.is(RedisClusterNode.NodeFlag.MASTER)).count(); + }).waitOrTimeout(); + + Wait.untilEquals(1L, () -> { + clusterRule.getClusterClient().reloadPartitions(); + return partitionStream(clusterRule).filter(redisClusterNode -> redisClusterNode.is(RedisClusterNode.NodeFlag.SLAVE)) + .count(); + }).waitOrTimeout(); connection.getStatefulConnection().close(); } diff --git a/src/test/java/com/lambdaworks/redis/cluster/PooledClusterConnectionProviderTest.java b/src/test/java/com/lambdaworks/redis/cluster/PooledClusterConnectionProviderTest.java index 1cd9a2c0eb..08458f3a59 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/PooledClusterConnectionProviderTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/PooledClusterConnectionProviderTest.java @@ -42,7 +42,7 @@ public class PooledClusterConnectionProviderTest { private RedisClusterClient clientMock; @Mock - private RedisChannelWriter writerMock; + private RedisChannelWriter writerMock; @Mock StatefulRedisConnection nodeConnectionMock; diff --git a/src/test/java/com/lambdaworks/redis/cluster/RedisClusterClientTest.java b/src/test/java/com/lambdaworks/redis/cluster/RedisClusterClientTest.java index 1b6cfbc7dd..eb91de2444 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/RedisClusterClientTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/RedisClusterClientTest.java @@ -411,8 +411,7 @@ public void getButNoPartitionForSlothash() throws Exception { redisClusterNode.setSlots(new ArrayList<>()); } RedisChannelHandler rch = (RedisChannelHandler) sync.getStatefulConnection(); - ClusterDistributionChannelWriter writer = (ClusterDistributionChannelWriter) rch - .getChannelWriter(); + ClusterDistributionChannelWriter writer = (ClusterDistributionChannelWriter) rch.getChannelWriter(); writer.setPartitions(clusterClient.getPartitions()); clusterClient.getPartitions().reload(clusterClient.getPartitions().getPartitions()); diff --git a/src/test/java/com/lambdaworks/redis/cluster/RedisClusterSetupTest.java b/src/test/java/com/lambdaworks/redis/cluster/RedisClusterSetupTest.java index 9cb11224ed..8036310860 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/RedisClusterSetupTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/RedisClusterSetupTest.java @@ -19,7 +19,7 @@ import com.google.code.tempusfugit.temporal.Condition; import com.google.code.tempusfugit.temporal.WaitFor; -import com.lambdaworks.Connections; +import com.lambdaworks.ConnectionTestUtil; import com.lambdaworks.Futures; import com.lambdaworks.Wait; import com.lambdaworks.category.SlowTests; @@ -524,7 +524,7 @@ private void waitUntilOnlyOnePartition() throws InterruptedException, TimeoutExc private void suspendConnection(RedisClusterAsyncCommands asyncCommands) throws InterruptedException, TimeoutException { - Connections.getConnectionWatchdog(((RedisAsyncCommands) asyncCommands).getStatefulConnection()) + ConnectionTestUtil.getConnectionWatchdog(((RedisAsyncCommands) asyncCommands).getStatefulConnection()) .setReconnectSuspended(true); asyncCommands.quit(); WaitFor.waitOrTimeout(() -> !asyncCommands.isOpen(), timeout(seconds(6))); diff --git a/src/test/java/com/lambdaworks/redis/cluster/RedisClusterStressScenariosTest.java b/src/test/java/com/lambdaworks/redis/cluster/RedisClusterStressScenariosTest.java index 29b7e2ff76..59c0ff9578 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/RedisClusterStressScenariosTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/RedisClusterStressScenariosTest.java @@ -129,7 +129,7 @@ public void testClusterConnectionStability() throws Exception { RedisChannelHandler statefulConnection = (RedisChannelHandler) connection.getStatefulConnection(); connection.set("a", "b"); - ClusterDistributionChannelWriter writer = (ClusterDistributionChannelWriter) statefulConnection + ClusterDistributionChannelWriter writer = (ClusterDistributionChannelWriter) statefulConnection .getChannelWriter(); StatefulRedisConnectionImpl statefulSlotConnection = (StatefulRedisConnectionImpl) writer @@ -159,62 +159,4 @@ public void testClusterConnectionStability() throws Exception { } - @Test(timeout = 20000) - public void distributedClusteredAccessAsync() throws Exception { - - RedisAdvancedClusterAsyncCommands connection = clusterClient.connect().async(); - - List> futures = new ArrayList<>(); - for (int i = 0; i < 100; i++) { - futures.add(connection.set("a" + i, "myValue1" + i)); - futures.add(connection.set("b" + i, "myValue2" + i)); - futures.add(connection.set("d" + i, "myValue3" + i)); - } - - for (RedisFuture future : futures) { - future.get(); - } - - for (int i = 0; i < 100; i++) { - RedisFuture setA = connection.get("a" + i); - RedisFuture setB = connection.get("b" + i); - RedisFuture setD = connection.get("d" + i); - - setA.get(); - setB.get(); - setD.get(); - - assertThat(setA.getError()).isNull(); - assertThat(setB.getError()).isNull(); - assertThat(setD.getError()).isNull(); - - assertThat(setA.get()).isEqualTo("myValue1" + i); - assertThat(setB.get()).isEqualTo("myValue2" + i); - assertThat(setD.get()).isEqualTo("myValue3" + i); - } - - connection.getStatefulConnection().close(); - } - - @Test - public void distributedClusteredAccessSync() throws Exception { - - RedisAdvancedClusterCommands connection = clusterClient.connect().sync(); - - for (int i = 0; i < 100; i++) { - connection.set("a" + i, "myValue1" + i); - connection.set("b" + i, "myValue2" + i); - connection.set("d" + i, "myValue3" + i); - } - - for (int i = 0; i < 100; i++) { - - assertThat(connection.get("a" + i)).isEqualTo("myValue1" + i); - assertThat(connection.get("b" + i)).isEqualTo("myValue2" + i); - assertThat(connection.get("d" + i)).isEqualTo("myValue3" + i); - } - - connection.getStatefulConnection().close(); - } - } diff --git a/src/test/java/com/lambdaworks/redis/commands/HLLCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/HLLCommandTest.java index ca64bf3ba5..949f490402 100644 --- a/src/test/java/com/lambdaworks/redis/commands/HLLCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/HLLCommandTest.java @@ -3,6 +3,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Fail.fail; +import com.lambdaworks.redis.cluster.SlotHash; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; @@ -80,4 +81,14 @@ public void pfcountNoKeys() throws Exception { commands().pfcount(); } + @Test + public void pfaddPfmergePfCount() throws Exception { + + commands().pfadd("key2660", "rand", "mat"); + commands().pfadd("key7112", "mat", "perrin"); + + commands().pfmerge("key8885", "key2660", "key7112"); + + assertThat(commands().pfcount("key8885")).isEqualTo(3); + } } diff --git a/src/test/java/com/lambdaworks/redis/protocol/CommandHandlerTest.java b/src/test/java/com/lambdaworks/redis/protocol/CommandHandlerTest.java index 9034d3b5e9..ab73b1e9dd 100644 --- a/src/test/java/com/lambdaworks/redis/protocol/CommandHandlerTest.java +++ b/src/test/java/com/lambdaworks/redis/protocol/CommandHandlerTest.java @@ -6,11 +6,11 @@ import static org.mockito.Mockito.*; import java.io.IOException; -import java.util.*; -import java.util.concurrent.atomic.AtomicLong; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Queue; -import com.lambdaworks.redis.metrics.DefaultCommandLatencyCollector; -import com.lambdaworks.redis.metrics.DefaultCommandLatencyCollectorOptions; import org.apache.logging.log4j.Level; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.core.LoggerContext; @@ -23,21 +23,16 @@ import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Mock; -import org.mockito.invocation.InvocationOnMock; import org.mockito.runners.MockitoJUnitRunner; -import org.mockito.stubbing.Answer; import org.springframework.test.util.ReflectionTestUtils; -import com.lambdaworks.redis.ClientOptions; import com.lambdaworks.redis.ConnectionEvents; -import com.lambdaworks.redis.RedisChannelHandler; -import com.lambdaworks.redis.RedisException; import com.lambdaworks.redis.codec.Utf8StringCodec; +import com.lambdaworks.redis.metrics.DefaultCommandLatencyCollector; +import com.lambdaworks.redis.metrics.DefaultCommandLatencyCollectorOptions; import com.lambdaworks.redis.output.StatusOutput; import com.lambdaworks.redis.resource.ClientResources; -import edu.umd.cs.mtc.MultithreadedTestCase; -import edu.umd.cs.mtc.TestFramework; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufAllocator; import io.netty.channel.*; @@ -46,9 +41,9 @@ @RunWith(MockitoJUnitRunner.class) public class CommandHandlerTest { - private Queue> q = new ArrayDeque<>(10); + private Queue> q; - private CommandHandler sut; + private CommandHandler sut; private final Command command = new Command<>(CommandType.APPEND, new StatusOutput(new Utf8StringCodec()), null); @@ -72,7 +67,7 @@ public class CommandHandlerTest { private ClientResources clientResources; @Mock - private RedisChannelHandler channelHandler; + private Endpoint endpoint; @BeforeClass public static void beforeClass() { @@ -102,8 +97,8 @@ public void before() throws Exception { return null; }); - when(clientResources.commandLatencyCollector()).thenReturn(new DefaultCommandLatencyCollector( - DefaultCommandLatencyCollectorOptions.create())); + when(clientResources.commandLatencyCollector()) + .thenReturn(new DefaultCommandLatencyCollector(DefaultCommandLatencyCollectorOptions.create())); when(channel.write(any())).thenAnswer(invocation -> { @@ -129,8 +124,8 @@ public void before() throws Exception { return new DefaultChannelPromise(channel); }); - sut = new CommandHandler(ClientOptions.create(), clientResources, q); - sut.setRedisChannelHandler(channelHandler); + sut = new CommandHandler(clientResources, endpoint); + q = (Queue) ReflectionTestUtils.getField(sut, "queue"); } @Test @@ -140,133 +135,6 @@ public void testChannelActive() throws Exception { sut.channelActive(context); verify(pipeline).fireUserEventTriggered(any(ConnectionEvents.Activated.class)); - - } - - @Test - public void testChannelActiveFailureShouldCancelCommands() throws Exception { - - ClientOptions clientOptions = ClientOptions.builder().cancelCommandsOnReconnectFailure(true).build(); - - sut = new CommandHandler(clientOptions, clientResources, q); - sut.setRedisChannelHandler(channelHandler); - - sut.channelRegistered(context); - sut.write(command); - - reset(context); - when(context.channel()).thenThrow(new RuntimeException()); - try { - sut.channelActive(context); - fail("Missing RuntimeException"); - } catch (RuntimeException e) { - } - - assertThat(command.isCancelled()).isTrue(); - } - - @Test - public void testChannelActiveWithBufferedAndQueuedCommands() throws Exception { - - Command bufferedCommand = new Command<>(CommandType.GET, - new StatusOutput(new Utf8StringCodec()), null); - - Command pingCommand = new Command<>(CommandType.PING, - new StatusOutput(new Utf8StringCodec()), null); - q.add(bufferedCommand); - - AtomicLong atomicLong = (AtomicLong) ReflectionTestUtils.getField(sut, "writers"); - doAnswer(new Answer() { - @Override - public Object answer(InvocationOnMock invocation) throws Throwable { - - assertThat(atomicLong.get()).isEqualTo(-1); - assertThat(ReflectionTestUtils.getField(sut, "exclusiveLockOwner")).isNotNull(); - - sut.write(pingCommand); - - return null; - } - }).when(channelHandler).activated(); - when(channel.isActive()).thenReturn(true); - - sut.channelRegistered(context); - sut.channelActive(context); - - assertThat(atomicLong.get()).isEqualTo(0); - assertThat(ReflectionTestUtils.getField(sut, "exclusiveLockOwner")).isNull(); - assertThat(q).containsSequence(pingCommand, bufferedCommand); - - verify(pipeline).fireUserEventTriggered(any(ConnectionEvents.Activated.class)); - } - - @Test - public void testChannelActiveWithBufferedAndQueuedCommandsRetainsOrder() throws Exception { - - Command bufferedCommand1 = new Command<>(CommandType.SET, - new StatusOutput(new Utf8StringCodec()), null); - - Command bufferedCommand2 = new Command<>(CommandType.GET, - new StatusOutput(new Utf8StringCodec()), null); - - Command queuedCommand1 = new Command<>(CommandType.PING, - new StatusOutput(new Utf8StringCodec()), null); - - Command queuedCommand2 = new Command<>(CommandType.AUTH, - new StatusOutput(new Utf8StringCodec()), null); - - q.add(queuedCommand1); - q.add(queuedCommand2); - - Collection buffer = (Collection) ReflectionTestUtils.getField(sut, "commandBuffer"); - buffer.add(bufferedCommand1); - buffer.add(bufferedCommand2); - - reset(channel); - when(channel.writeAndFlush(any())).thenAnswer(invocation -> new DefaultChannelPromise(channel)); - when(channel.eventLoop()).thenReturn(eventLoop); - when(channel.pipeline()).thenReturn(pipeline); - - sut.channelRegistered(context); - sut.channelActive(context); - - assertThat(q).isEmpty(); - assertThat(buffer).isEmpty(); - - ArgumentCaptor objectArgumentCaptor = ArgumentCaptor.forClass(Object.class); - verify(channel).writeAndFlush(objectArgumentCaptor.capture()); - - assertThat((Collection) objectArgumentCaptor.getValue()).containsSequence(queuedCommand1, queuedCommand2, - bufferedCommand1, bufferedCommand2); - } - - @Test - public void testChannelActiveReplayBufferedCommands() throws Exception { - - Command bufferedCommand1 = new Command<>(CommandType.SET, - new StatusOutput(new Utf8StringCodec()), null); - - Command bufferedCommand2 = new Command<>(CommandType.GET, - new StatusOutput(new Utf8StringCodec()), null); - - Command queuedCommand1 = new Command<>(CommandType.PING, - new StatusOutput(new Utf8StringCodec()), null); - - Command queuedCommand2 = new Command<>(CommandType.AUTH, - new StatusOutput(new Utf8StringCodec()), null); - - q.add(queuedCommand1); - q.add(queuedCommand2); - - Collection buffer = (Collection) ReflectionTestUtils.getField(sut, "commandBuffer"); - buffer.add(bufferedCommand1); - buffer.add(bufferedCommand2); - - sut.channelRegistered(context); - sut.channelActive(context); - - assertThat(q).containsSequence(queuedCommand1, queuedCommand2, bufferedCommand1, bufferedCommand2); - assertThat(buffer).isEmpty(); } @Test @@ -289,37 +157,6 @@ public void testIOExceptionChannelActive() throws Exception { sut.exceptionCaught(context, new IOException("Connection timed out")); } - @Test - public void testWriteChannelDisconnected() throws Exception { - - when(channel.isActive()).thenReturn(true); - sut.channelRegistered(context); - sut.channelActive(context); - - sut.setState(CommandHandler.LifecycleState.DISCONNECTED); - - sut.write(command); - - Collection buffer = (Collection) ReflectionTestUtils.getField(sut, "commandBuffer"); - assertThat(buffer).containsOnly(command); - } - - @Test(expected = RedisException.class) - public void testWriteChannelDisconnectedWithoutReconnect() throws Exception { - - sut = new CommandHandler(ClientOptions.builder().autoReconnect(false).build(), clientResources, - q); - sut.setRedisChannelHandler(channelHandler); - - when(channel.isActive()).thenReturn(true); - sut.channelRegistered(context); - sut.channelActive(context); - - sut.setState(CommandHandler.LifecycleState.DISCONNECTED); - - sut.write(command); - } - @Test public void testExceptionChannelInactive() throws Exception { sut.setState(CommandHandler.LifecycleState.DISCONNECTED); @@ -344,14 +181,6 @@ public void testExceptionWithQueue() throws Exception { assertThat(ReflectionTestUtils.getField(command, "exception")).isNotNull(); } - @Test(expected = RedisException.class) - public void testWriteWhenClosed() throws Exception { - - sut.setState(CommandHandler.LifecycleState.CLOSED); - - sut.write(command); - } - @Test public void testExceptionWhenClosed() throws Exception { @@ -540,235 +369,4 @@ public void shouldSetLatency() throws Exception { assertThat(command.firstResponseNs).isEqualTo(-1); } - @Test - public void testMTCConcurrentWriteThenReset() throws Throwable { - TestFramework.runOnce(new MTCConcurrentWriteThenReset(clientResources, q, command)); - } - - @Test - public void testMTCConcurrentResetThenWrite() throws Throwable { - TestFramework.runOnce(new MTCConcurrentResetThenWrite(clientResources, q, command)); - } - - @Test - public void testMTCConcurrentConcurrentWrite() throws Throwable { - TestFramework.runOnce(new MTCConcurrentConcurrentWrite(clientResources, q, command)); - } - - /** - * Test of concurrent access to locks. write call wins over reset call. - */ - static class MTCConcurrentWriteThenReset extends MultithreadedTestCase { - - private final Command command; - private TestableCommandHandler handler; - private List expectedThreadOrder = Collections.synchronizedList(new ArrayList<>()); - private List entryThreadOrder = Collections.synchronizedList(new ArrayList<>()); - private List exitThreadOrder = Collections.synchronizedList(new ArrayList<>()); - - public MTCConcurrentWriteThenReset(ClientResources clientResources, - Queue> queue, - Command command) { - this.command = command; - handler = new TestableCommandHandler(ClientOptions.create(), clientResources, queue) { - - @Override - protected void incrementWriters() { - - waitForTick(2); - super.incrementWriters(); - waitForTick(4); - } - - @Override - protected void lockWritersExclusive() { - - waitForTick(4); - super.lockWritersExclusive(); - } - - @Override - protected , T> void writeToBuffer(C command) { - - entryThreadOrder.add(Thread.currentThread()); - super.writeToBuffer(command); - } - - @Override - protected List> prepareReset() { - - entryThreadOrder.add(Thread.currentThread()); - return super.prepareReset(); - } - - @Override - protected void unlockWritersExclusive() { - - exitThreadOrder.add(Thread.currentThread()); - super.unlockWritersExclusive(); - } - - @Override - protected void decrementWriters() { - - exitThreadOrder.add(Thread.currentThread()); - super.decrementWriters(); - } - }; - } - - public void thread1() throws InterruptedException { - - waitForTick(1); - expectedThreadOrder.add(Thread.currentThread()); - handler.write(command); - - } - - public void thread2() throws InterruptedException { - - waitForTick(3); - expectedThreadOrder.add(Thread.currentThread()); - handler.reset(); - } - - @Override - public void finish() { - - assertThat(entryThreadOrder).containsExactlyElementsOf(expectedThreadOrder); - assertThat(exitThreadOrder).containsExactlyElementsOf(expectedThreadOrder); - } - } - - /** - * Test of concurrent access to locks. write call wins over flush call. - */ - static class MTCConcurrentResetThenWrite extends MultithreadedTestCase { - - private final Command command; - private TestableCommandHandler handler; - private List expectedThreadOrder = Collections.synchronizedList(new ArrayList<>()); - private List entryThreadOrder = Collections.synchronizedList(new ArrayList<>()); - private List exitThreadOrder = Collections.synchronizedList(new ArrayList<>()); - - public MTCConcurrentResetThenWrite(ClientResources clientResources, - Queue> queue, - Command command) { - this.command = command; - handler = new TestableCommandHandler(ClientOptions.create(), clientResources, queue) { - - @Override - protected void incrementWriters() { - - waitForTick(4); - super.incrementWriters(); - } - - @Override - protected void lockWritersExclusive() { - - waitForTick(2); - super.lockWritersExclusive(); - waitForTick(4); - } - - @Override - protected , T> void writeToBuffer(C command) { - - entryThreadOrder.add(Thread.currentThread()); - super.writeToBuffer(command); - } - - @Override - protected List> prepareReset() { - - entryThreadOrder.add(Thread.currentThread()); - return super.prepareReset(); - } - - @Override - protected void unlockWritersExclusive() { - - exitThreadOrder.add(Thread.currentThread()); - super.unlockWritersExclusive(); - } - - @Override - protected void decrementWriters() { - - exitThreadOrder.add(Thread.currentThread()); - super.decrementWriters(); - } - }; - } - - public void thread1() throws InterruptedException { - - waitForTick(1); - expectedThreadOrder.add(Thread.currentThread()); - handler.reset(); - } - - public void thread2() throws InterruptedException { - - waitForTick(3); - expectedThreadOrder.add(Thread.currentThread()); - handler.write(command); - } - - @Override - public void finish() { - - assertThat(entryThreadOrder).containsExactlyElementsOf(expectedThreadOrder); - assertThat(exitThreadOrder).containsExactlyElementsOf(expectedThreadOrder); - } - } - - /** - * Test of concurrent access to locks. Two concurrent writes. - */ - static class MTCConcurrentConcurrentWrite extends MultithreadedTestCase { - - private final Command command; - private TestableCommandHandler handler; - - public MTCConcurrentConcurrentWrite(ClientResources clientResources, - Queue> queue, - Command command) { - this.command = command; - handler = new TestableCommandHandler(ClientOptions.create(), clientResources, queue) { - - @Override - protected , T> void writeToBuffer(C command) { - - waitForTick(2); - assertThat(writers.get()).isEqualTo(2); - waitForTick(3); - super.writeToBuffer(command); - } - - }; - } - - public void thread1() throws InterruptedException { - - waitForTick(1); - handler.write(command); - } - - public void thread2() throws InterruptedException { - - waitForTick(1); - handler.write(command); - } - - } - - static class TestableCommandHandler extends CommandHandler { - public TestableCommandHandler(ClientOptions clientOptions, ClientResources clientResources, - Queue> queue) { - super(clientOptions, clientResources, queue); - } - } - } diff --git a/src/test/java/com/lambdaworks/redis/protocol/ConnectionFailureTest.java b/src/test/java/com/lambdaworks/redis/protocol/ConnectionFailureTest.java index db3266d137..f41c63fc2b 100644 --- a/src/test/java/com/lambdaworks/redis/protocol/ConnectionFailureTest.java +++ b/src/test/java/com/lambdaworks/redis/protocol/ConnectionFailureTest.java @@ -7,7 +7,7 @@ import org.junit.Test; import org.springframework.test.util.ReflectionTestUtils; -import com.lambdaworks.Connections; +import com.lambdaworks.ConnectionTestUtil; import com.lambdaworks.Wait; import com.lambdaworks.redis.*; import com.lambdaworks.redis.api.StatefulRedisConnection; @@ -69,7 +69,7 @@ public void pingBeforeConnectFailOnReconnect() throws Exception { try { RedisAsyncCommands connection = client.connect(redisUri).async(); - ConnectionWatchdog connectionWatchdog = Connections.getConnectionWatchdog(connection.getStatefulConnection()); + ConnectionWatchdog connectionWatchdog = ConnectionTestUtil.getConnectionWatchdog(connection.getStatefulConnection()); assertThat(connectionWatchdog.isListenOnChannelInactive()).isTrue(); assertThat(connectionWatchdog.isReconnectSuspended()).isFalse(); @@ -118,12 +118,12 @@ public void pingBeforeConnectFailOnReconnectShouldSendEvents() throws Exception final BlockingQueue events = new LinkedBlockingDeque<>(); RedisAsyncCommands connection = client.connect(redisUri).async(); - ConnectionWatchdog connectionWatchdog = Connections.getConnectionWatchdog(connection.getStatefulConnection()); + ConnectionWatchdog connectionWatchdog = ConnectionTestUtil.getConnectionWatchdog(connection.getStatefulConnection()); ReconnectionListener reconnectionListener = new ReconnectionListener() { @Override public void onReconnect(ConnectionEvents.Reconnect reconnect) { - events.add(reconnect); + events.offer(reconnect); } }; @@ -167,7 +167,7 @@ public void cancelCommandsOnReconnectFailure() throws Exception { try { RedisAsyncCommandsImpl connection = (RedisAsyncCommandsImpl) client .connect(redisUri).async(); - ConnectionWatchdog connectionWatchdog = Connections.getConnectionWatchdog(connection.getStatefulConnection()); + ConnectionWatchdog connectionWatchdog = ConnectionTestUtil.getConnectionWatchdog(connection.getStatefulConnection()); assertThat(connectionWatchdog.isListenOnChannelInactive()).isTrue(); @@ -185,7 +185,7 @@ public void cancelCommandsOnReconnectFailure() throws Exception { assertThat(connection.getStatefulConnection().isOpen()).isFalse(); connectionWatchdog.setReconnectSuspended(false); - connectionWatchdog.run(null); + connectionWatchdog.run(0); Thread.sleep(500); assertThat(connection.getStatefulConnection().isOpen()).isFalse(); @@ -224,13 +224,12 @@ public void closingDisconnectedConnectionShouldDisableConnectionWatchdog() throw client.setOptions(ClientOptions.create()); - RedisURI redisUri = RedisURI.Builder.redis(TestSettings.host(), TestSettings.port()) .withTimeout(10, TimeUnit.MINUTES).build(); StatefulRedisConnection connection = client.connect(redisUri); - ConnectionWatchdog connectionWatchdog = Connections.getConnectionWatchdog(connection); + ConnectionWatchdog connectionWatchdog = ConnectionTestUtil.getConnectionWatchdog(connection); assertThat(connectionWatchdog.isReconnectSuspended()).isFalse(); assertThat(connectionWatchdog.isListenOnChannelInactive()).isTrue(); diff --git a/src/test/java/com/lambdaworks/redis/protocol/DefaultEndpointTest.java b/src/test/java/com/lambdaworks/redis/protocol/DefaultEndpointTest.java new file mode 100644 index 0000000000..44ab5f8702 --- /dev/null +++ b/src/test/java/com/lambdaworks/redis/protocol/DefaultEndpointTest.java @@ -0,0 +1,338 @@ +package com.lambdaworks.redis.protocol; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.fail; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.anyObject; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Optional; +import java.util.Queue; +import java.util.concurrent.atomic.AtomicLong; + +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.core.LoggerContext; +import org.apache.logging.log4j.core.config.Configuration; +import org.apache.logging.log4j.core.config.LoggerConfig; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; +import org.springframework.test.util.ReflectionTestUtils; + +import com.lambdaworks.redis.ClientOptions; +import com.lambdaworks.redis.RedisException; +import com.lambdaworks.redis.codec.Utf8StringCodec; +import com.lambdaworks.redis.internal.LettuceFactories; +import com.lambdaworks.redis.output.StatusOutput; +import com.lambdaworks.redis.resource.ClientResources; + +import edu.umd.cs.mtc.MultithreadedTestCase; +import edu.umd.cs.mtc.TestFramework; +import io.netty.channel.Channel; +import io.netty.channel.DefaultChannelPromise; + +@RunWith(MockitoJUnitRunner.class) +public class DefaultEndpointTest { + + private Queue> q = LettuceFactories.newConcurrentQueue(); + + private DefaultEndpoint sut; + + private final Command command = new Command<>(CommandType.APPEND, + new StatusOutput(new Utf8StringCodec()), null); + + @Mock + private Channel channel; + + @Mock + private ConnectionFacade connectionFacade; + + @Mock + private ClientResources clientResources; + + @Mock + private ConnectionWatchdog connectionWatchdog; + + @BeforeClass + public static void beforeClass() { + LoggerContext ctx = (LoggerContext) LogManager.getContext(); + Configuration config = ctx.getConfiguration(); + LoggerConfig loggerConfig = config.getLoggerConfig(CommandHandler.class.getName()); + loggerConfig.setLevel(Level.ALL); + } + + @AfterClass + public static void afterClass() { + LoggerContext ctx = (LoggerContext) LogManager.getContext(); + Configuration config = ctx.getConfiguration(); + LoggerConfig loggerConfig = config.getLoggerConfig(CommandHandler.class.getName()); + loggerConfig.setLevel(null); + } + + @Before + public void before() throws Exception { + + when(channel.write(any())).thenAnswer(invocation -> { + + if (invocation.getArguments()[0] instanceof RedisCommand) { + q.add((RedisCommand) invocation.getArguments()[0]); + } + + if (invocation.getArguments()[0] instanceof Collection) { + q.addAll((Collection) invocation.getArguments()[0]); + } + + return new DefaultChannelPromise(channel); + }); + + when(channel.writeAndFlush(any())).thenAnswer(invocation -> { + if (invocation.getArguments()[0] instanceof RedisCommand) { + q.add((RedisCommand) invocation.getArguments()[0]); + } + + if (invocation.getArguments()[0] instanceof Collection) { + q.addAll((Collection) invocation.getArguments()[0]); + } + return new DefaultChannelPromise(channel); + }); + + sut = new DefaultEndpoint(ClientOptions.create()); + sut.setConnectionFacade(connectionFacade); + } + + @Test + public void writeConnectedShouldWriteCommandToChannel() throws Exception { + + when(channel.isActive()).thenReturn(true); + when(channel.isWritable()).thenReturn(true); + + sut.notifyChannelActive(channel); + sut.write(command); + + assertThat(sut.getQueue()).isEmpty(); + verify(channel).writeAndFlush(command); + } + + @Test + public void writeDisconnectedShouldBufferCommands() throws Exception { + + when(channel.isActive()).thenReturn(true); + when(channel.isWritable()).thenReturn(true); + + sut.write(command); + + assertThat(sut.getQueue()).contains(command); + + verify(channel, never()).writeAndFlush(anyObject(), any()); + } + + @Test + public void notifyChannelActiveActivatesFacade() throws Exception { + + sut.notifyChannelActive(channel); + + verify(connectionFacade).activated(); + } + + @Test + public void notifyChannelActiveArmsConnectionWatchdog() throws Exception { + + sut.registerConnectionWatchdog(Optional.of(connectionWatchdog)); + + sut.notifyChannelActive(channel); + + verify(connectionWatchdog).arm(); + } + + @Test + public void notifyChannelInactiveDeactivatesFacade() throws Exception { + + sut.notifyChannelInactive(channel); + + verify(connectionFacade).deactivated(); + } + + @Test + public void notifyExceptionShouldStoreException() throws Exception { + + sut.notifyException(new IllegalStateException()); + sut.write(command); + + assertThat(command.exception).isInstanceOf(IllegalStateException.class); + } + + @Test + public void notifyChannelActiveClearsStoredException() throws Exception { + + sut.notifyException(new IllegalStateException()); + sut.notifyChannelActive(channel); + sut.write(command); + + assertThat(command.exception).isNull(); + } + + @Test + public void notifyDrainQueuedCommandsShouldBufferCommands() throws Exception { + + Queue> q = LettuceFactories.newConcurrentQueue(); + q.add(command); + + sut.notifyDrainQueuedCommands(() -> q); + + assertThat(q).isEmpty(); + assertThat(sut.getQueue()).contains(command); + } + + @Test + public void notifyDrainQueuedCommandsShouldWriteCommands() throws Exception { + + when(channel.isActive()).thenReturn(true); + when(channel.isWritable()).thenReturn(true); + + Queue> q = LettuceFactories.newConcurrentQueue(); + q.add(command); + + sut.notifyChannelActive(channel); + sut.notifyDrainQueuedCommands(() -> q); + + assertThat(q).isEmpty(); + verify(channel).writeAndFlush(eq(Arrays.asList(command))); + } + + @Test + public void writeShouldRejectCommandsInDisconnectedState() throws Exception { + + sut = new DefaultEndpoint(ClientOptions.builder() // + .disconnectedBehavior(ClientOptions.DisconnectedBehavior.REJECT_COMMANDS) // + .build()); + + try { + sut.write(command); + fail("Missing RedisException"); + } catch (RedisException e) { + assertThat(e).hasMessageContaining("Commands are rejected"); + } + } + + @Test + public void writeShouldRejectCommandsInClosedState() throws Exception { + + sut.close(); + + try { + sut.write(command); + fail("Missing RedisException"); + } catch (RedisException e) { + assertThat(e).hasMessageContaining("Connection is closed"); + } + } + + @Test + public void writeWithoutAutoReconnectShouldRejectCommandsInDisconnectedState() throws Exception { + + sut = new DefaultEndpoint(ClientOptions.builder() // + .autoReconnect(false) // + .disconnectedBehavior(ClientOptions.DisconnectedBehavior.DEFAULT) // + .build()); + + try { + sut.write(command); + fail("Missing RedisException"); + } catch (RedisException e) { + assertThat(e).hasMessageContaining("Commands are rejected"); + } + } + + @Test + public void closeCleansUpResources() throws Exception { + + sut.notifyChannelActive(channel); + sut.registerConnectionWatchdog(Optional.of(connectionWatchdog)); + + sut.close(); + + verify(channel).close(); + verify(connectionWatchdog).prepareClose(); + } + + @Test + public void closeAllowsOnlyOneCall() throws Exception { + + sut.notifyChannelActive(channel); + sut.registerConnectionWatchdog(Optional.of(connectionWatchdog)); + + sut.close(); + sut.close(); + + verify(channel).close(); + verify(connectionWatchdog).prepareClose(); + } + + @Test + public void testMTCConcurrentConcurrentWrite() throws Throwable { + TestFramework.runOnce(new MTCConcurrentConcurrentWrite(command)); + } + + /** + * Test of concurrent access to locks. Two concurrent writes. + */ + static class MTCConcurrentConcurrentWrite extends MultithreadedTestCase { + + private final Command command; + private TestableEndpoint handler; + + public MTCConcurrentConcurrentWrite(Command command) { + + this.command = command; + + handler = new TestableEndpoint(ClientOptions.create()) { + + @Override + protected void bufferCommand(RedisCommand command) { + + waitForTick(2); + + Object sharedLock = ReflectionTestUtils.getField(this, "sharedLock"); + AtomicLong writers = (AtomicLong) ReflectionTestUtils.getField(sharedLock, "writers"); + assertThat(writers.get()).isEqualTo(2); + waitForTick(3); + super.bufferCommand(command); + } + }; + } + + public void thread1() throws InterruptedException { + + waitForTick(1); + handler.write(command); + } + + public void thread2() throws InterruptedException { + + waitForTick(1); + handler.write(command); + } + } + + static class TestableEndpoint extends DefaultEndpoint { + + /** + * Create a new {@link DefaultEndpoint}. + * + * @param clientOptions client options for this connection, must not be {@literal null} + */ + public TestableEndpoint(ClientOptions clientOptions) { + super(clientOptions); + } + } +} diff --git a/src/test/java/com/lambdaworks/redis/protocol/StateMachineTest.java b/src/test/java/com/lambdaworks/redis/protocol/StateMachineTest.java index 8d8e3c325c..c71fa41d48 100644 --- a/src/test/java/com/lambdaworks/redis/protocol/StateMachineTest.java +++ b/src/test/java/com/lambdaworks/redis/protocol/StateMachineTest.java @@ -31,7 +31,7 @@ public class StateMachineTest { protected RedisCodec codec = new Utf8StringCodec(); protected Charset charset = Charset.forName("UTF-8"); protected CommandOutput output; - protected RedisStateMachine rsm; + protected RedisStateMachine rsm; @BeforeClass public static void beforeClass() { @@ -53,7 +53,7 @@ public static void afterClass() { @Before public final void createStateMachine() throws Exception { output = new StatusOutput(codec); - rsm = new RedisStateMachine(); + rsm = new RedisStateMachine(); } @Test diff --git a/src/test/java/com/lambdaworks/redis/reliability/AtLeastOnceTest.java b/src/test/java/com/lambdaworks/redis/reliability/AtLeastOnceTest.java index 4c5808da73..dcb95c560e 100644 --- a/src/test/java/com/lambdaworks/redis/reliability/AtLeastOnceTest.java +++ b/src/test/java/com/lambdaworks/redis/reliability/AtLeastOnceTest.java @@ -10,7 +10,7 @@ import org.junit.Before; import org.junit.Test; -import com.lambdaworks.Connections; +import com.lambdaworks.ConnectionTestUtil; import com.lambdaworks.Wait; import com.lambdaworks.redis.*; import com.lambdaworks.redis.api.StatefulRedisConnection; @@ -51,7 +51,7 @@ public void connectionIsConnectedAfterConnect() throws Exception { StatefulRedisConnection connection = client.connect(); - assertThat(Connections.getConnectionState(connection)); + assertThat(ConnectionTestUtil.getConnectionState(connection)).isEqualTo("CONNECTED"); connection.close(); } @@ -61,7 +61,7 @@ public void reconnectIsActiveHandler() throws Exception { RedisCommands connection = client.connect().sync(); - ConnectionWatchdog connectionWatchdog = Connections.getConnectionWatchdog(connection.getStatefulConnection()); + ConnectionWatchdog connectionWatchdog = ConnectionTestUtil.getConnectionWatchdog(connection.getStatefulConnection()); assertThat(connectionWatchdog).isNotNull(); assertThat(connectionWatchdog.isListenOnChannelInactive()).isTrue(); assertThat(connectionWatchdog.isReconnectSuspended()).isFalse(); @@ -87,8 +87,8 @@ public void noBufferedCommandsAfterExecute() throws Exception { connection.set(key, "1"); - assertThat(Connections.getQueue(connection.getStatefulConnection())).isEmpty(); - assertThat(Connections.getCommandBuffer(connection.getStatefulConnection())).isEmpty(); + assertThat(ConnectionTestUtil.getQueue(connection.getStatefulConnection())).isEmpty(); + assertThat(ConnectionTestUtil.getCommandBuffer(connection.getStatefulConnection())).isEmpty(); connection.getStatefulConnection().close(); } @@ -114,17 +114,16 @@ public void commandIsExecutedOnce() throws Exception { @Test public void commandFailsWhenFailOnEncode() throws Exception { - StatefulRedisConnection connection = client.connect(); - RedisCommands sync = connection.sync(); - RedisChannelWriter channelWriter = Connections.getChannelWriter(connection); + RedisCommands connection = client.connect().sync(); + RedisChannelWriter channelWriter = ConnectionTestUtil.getChannelWriter(connection.getStatefulConnection()); RedisCommands verificationConnection = client.connect().sync(); - sync.set(key, "1"); + connection.set(key, "1"); AsyncCommand working = new AsyncCommand<>( new Command<>(CommandType.INCR, new IntegerOutput(CODEC), new CommandArgs<>(CODEC).addKey(key))); channelWriter.write(working); assertThat(working.await(2, TimeUnit.SECONDS)).isTrue(); - assertThat(sync.get(key)).isEqualTo("2"); + assertThat(connection.get(key)).isEqualTo("2"); AsyncCommand command = new AsyncCommand( new Command<>(CommandType.INCR, new IntegerOutput(CODEC), new CommandArgs<>(CODEC).addKey(key))) { @@ -143,9 +142,9 @@ public void encode(ByteBuf buf) { assertThat(verificationConnection.get(key)).isEqualTo("2"); - assertThat(Connections.getQueue(connection)).isNotEmpty(); + assertThat(ConnectionTestUtil.getQueue(connection.getStatefulConnection())).isNotEmpty(); - sync.getStatefulConnection().close(); + connection.getStatefulConnection().close(); } @Test @@ -155,7 +154,7 @@ public void commandNotFailedChannelClosesWhileFlush() throws Exception { StatefulRedisConnection connection = client.connect(); RedisCommands verificationConnection = client.connect().sync(); - RedisChannelWriter channelWriter = Connections.getChannelWriter(connection); + RedisChannelWriter channelWriter = ConnectionTestUtil.getChannelWriter(connection); RedisCommands sync = connection.sync(); sync.set(key, "1"); @@ -163,7 +162,7 @@ public void commandNotFailedChannelClosesWhileFlush() throws Exception { final CountDownLatch block = new CountDownLatch(1); - ConnectionWatchdog connectionWatchdog = Connections.getConnectionWatchdog(connection); + ConnectionWatchdog connectionWatchdog = ConnectionTestUtil.getConnectionWatchdog(connection); AsyncCommand command = getBlockOnEncodeCommand(block); @@ -171,7 +170,7 @@ public void commandNotFailedChannelClosesWhileFlush() throws Exception { connectionWatchdog.setReconnectSuspended(true); - Channel channel = Connections.getChannel(connection); + Channel channel = ConnectionTestUtil.getChannel(connection); channel.unsafe().disconnect(channel.newPromise()); assertThat(channel.isOpen()).isFalse(); @@ -184,8 +183,8 @@ public void commandNotFailedChannelClosesWhileFlush() throws Exception { assertThat(verificationConnection.get(key)).isEqualTo("1"); - assertThat(Connections.getQueue(connection)).isEmpty(); - assertThat(Connections.getCommandBuffer(connection)).isNotEmpty().contains(command); + assertThat(ConnectionTestUtil.getQueue(connection)).isEmpty(); + assertThat(ConnectionTestUtil.getCommandBuffer(connection)).isNotEmpty().contains(command); connection.close(); } @@ -198,14 +197,14 @@ public void commandRetriedChannelClosesWhileFlush() throws Exception { StatefulRedisConnection connection = client.connect(); RedisCommands sync = connection.sync(); RedisCommands verificationConnection = client.connect().sync(); - RedisChannelWriter channelWriter = Connections.getChannelWriter(connection); + RedisChannelWriter channelWriter = ConnectionTestUtil.getChannelWriter(connection); sync.set(key, "1"); assertThat(verificationConnection.get(key)).isEqualTo("1"); final CountDownLatch block = new CountDownLatch(1); - ConnectionWatchdog connectionWatchdog = Connections.getConnectionWatchdog(sync.getStatefulConnection()); + ConnectionWatchdog connectionWatchdog = ConnectionTestUtil.getConnectionWatchdog(sync.getStatefulConnection()); AsyncCommand command = getBlockOnEncodeCommand(block); @@ -213,7 +212,7 @@ public void commandRetriedChannelClosesWhileFlush() throws Exception { connectionWatchdog.setReconnectSuspended(true); - Channel channel = Connections.getChannel(sync.getStatefulConnection()); + Channel channel = ConnectionTestUtil.getChannel(sync.getStatefulConnection()); channel.unsafe().disconnect(channel.newPromise()); assertThat(channel.isOpen()).isFalse(); @@ -231,8 +230,8 @@ public void commandRetriedChannelClosesWhileFlush() throws Exception { assertThat(verificationConnection.get(key)).isEqualTo("2"); - assertThat(Connections.getQueue(sync.getStatefulConnection())).isEmpty(); - assertThat(Connections.getCommandBuffer(sync.getStatefulConnection())).isEmpty(); + assertThat(ConnectionTestUtil.getQueue(sync.getStatefulConnection())).isEmpty(); + assertThat(ConnectionTestUtil.getCommandBuffer(sync.getStatefulConnection())).isEmpty(); sync.getStatefulConnection().close(); verificationConnection.getStatefulConnection().close(); @@ -256,12 +255,11 @@ public void encode(ByteBuf buf) { @Test public void commandFailsDuringDecode() throws Exception { - StatefulRedisConnection connection = client.connect(); - RedisCommands sync = connection.sync(); - RedisChannelWriter channelWriter = Connections.getChannelWriter(connection); + RedisCommands connection = client.connect().sync(); + RedisChannelWriter channelWriter = ConnectionTestUtil.getChannelWriter(connection.getStatefulConnection()); RedisCommands verificationConnection = client.connect().sync(); - sync.set(key, "1"); + connection.set(key, "1"); AsyncCommand command = new AsyncCommand( new Command<>(CommandType.INCR, new StatusOutput<>(CODEC), new CommandArgs<>(CODEC).addKey(key))); @@ -274,9 +272,9 @@ public void commandFailsDuringDecode() throws Exception { assertThat(getException(command)).isInstanceOf(IllegalStateException.class); assertThat(verificationConnection.get(key)).isEqualTo("2"); - assertThat(sync.get(key)).isEqualTo("2"); + assertThat(connection.get(key)).isEqualTo("2"); - sync.getStatefulConnection().close(); + connection.getStatefulConnection().close(); verificationConnection.getStatefulConnection().close(); } @@ -289,7 +287,7 @@ public void commandCancelledOverSyncAPIAfterConnectionIsDisconnected() throws Ex sync.set(key, "1"); - ConnectionWatchdog connectionWatchdog = Connections.getConnectionWatchdog(sync.getStatefulConnection()); + ConnectionWatchdog connectionWatchdog = ConnectionTestUtil.getConnectionWatchdog(sync.getStatefulConnection()); connectionWatchdog.setListenOnChannelInactive(false); sync.quit(); @@ -303,13 +301,13 @@ public void commandCancelledOverSyncAPIAfterConnectionIsDisconnected() throws Ex assertThat(verificationConnection.get("key")).isEqualTo("1"); - assertThat(Connections.getQueue(connection)).isEmpty(); - assertThat(Connections.getCommandBuffer(connection).size()).isGreaterThan(0); + assertThat(ConnectionTestUtil.getQueue(connection)).isEmpty(); + assertThat(ConnectionTestUtil.getCommandBuffer(connection).size()).isGreaterThan(0); connectionWatchdog.setListenOnChannelInactive(true); connectionWatchdog.scheduleReconnect(); - while (!Connections.getCommandBuffer(connection).isEmpty() || !Connections.getQueue(connection).isEmpty()) { + while (!ConnectionTestUtil.getCommandBuffer(connection).isEmpty() || !ConnectionTestUtil.getQueue(connection).isEmpty()) { Thread.sleep(10); } @@ -327,7 +325,7 @@ public void retryAfterConnectionIsDisconnected() throws Exception { connection.sync().set(key, "1"); - ConnectionWatchdog connectionWatchdog = Connections.getConnectionWatchdog(connection); + ConnectionWatchdog connectionWatchdog = ConnectionTestUtil.getConnectionWatchdog(connection); connectionWatchdog.setListenOnChannelInactive(false); connection.async().quit(); @@ -339,13 +337,13 @@ public void retryAfterConnectionIsDisconnected() throws Exception { assertThat(verificationConnection.get("key")).isEqualTo("1"); - assertThat(Connections.getQueue(connection)).isEmpty(); - assertThat(Connections.getCommandBuffer(connection).size()).isGreaterThan(0); + assertThat(ConnectionTestUtil.getQueue(connection)).isEmpty(); + assertThat(ConnectionTestUtil.getCommandBuffer(connection).size()).isGreaterThan(0); connectionWatchdog.setListenOnChannelInactive(true); connectionWatchdog.scheduleReconnect(); - while (!Connections.getCommandBuffer(connection).isEmpty() || !Connections.getQueue(connection).isEmpty()) { + while (!ConnectionTestUtil.getCommandBuffer(connection).isEmpty() || !ConnectionTestUtil.getQueue(connection).isEmpty()) { Thread.sleep(10); } diff --git a/src/test/java/com/lambdaworks/redis/reliability/AtMostOnceTest.java b/src/test/java/com/lambdaworks/redis/reliability/AtMostOnceTest.java index 072b3c787c..6561e72ec5 100644 --- a/src/test/java/com/lambdaworks/redis/reliability/AtMostOnceTest.java +++ b/src/test/java/com/lambdaworks/redis/reliability/AtMostOnceTest.java @@ -1,8 +1,8 @@ package com.lambdaworks.redis.reliability; import static com.google.code.tempusfugit.temporal.Duration.millis; -import static com.lambdaworks.Connections.getCommandBuffer; -import static com.lambdaworks.Connections.getQueue; +import static com.lambdaworks.ConnectionTestUtil.getCommandBuffer; +import static com.lambdaworks.ConnectionTestUtil.getQueue; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assume.assumeTrue; @@ -10,15 +10,14 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; -import com.google.code.tempusfugit.temporal.Duration; import com.lambdaworks.Delay; +import com.lambdaworks.redis.api.StatefulRedisConnection; import org.junit.Before; import org.junit.Test; -import com.lambdaworks.Connections; +import com.lambdaworks.ConnectionTestUtil; import com.lambdaworks.Wait; import com.lambdaworks.redis.*; -import com.lambdaworks.redis.api.StatefulRedisConnection; import com.lambdaworks.redis.api.sync.RedisCommands; import com.lambdaworks.redis.codec.Utf8StringCodec; import com.lambdaworks.redis.output.IntegerOutput; @@ -57,7 +56,7 @@ public void connectionIsConnectedAfterConnect() throws Exception { StatefulRedisConnection connection = client.connect(); - assertThat(Connections.getConnectionState(connection)); + assertThat(ConnectionTestUtil.getConnectionState(connection)); connection.close(); } @@ -65,12 +64,11 @@ public void connectionIsConnectedAfterConnect() throws Exception { @Test public void noReconnectHandler() throws Exception { - RedisCommands connection = client.connect().sync(); + StatefulRedisConnection connection = client.connect(); - ConnectionWatchdog connectionWatchdog = Connections.getConnectionWatchdog(connection.getStatefulConnection()); - assertThat(connectionWatchdog).isNull(); + assertThat(ConnectionTestUtil.getConnectionWatchdog(connection)).isNull(); - connection.getStatefulConnection().close(); + connection.close(); } @Test @@ -121,8 +119,8 @@ public void commandIsExecutedOnce() throws Exception { public void commandNotExecutedFailsOnEncode() throws Exception { StatefulRedisConnection connection = client.connect(); - RedisCommands sync = connection.sync(); - RedisChannelWriter channelWriter = Connections.getChannelWriter(connection); + RedisCommands sync = client.connect().sync(); + RedisChannelWriter channelWriter = ConnectionTestUtil.getChannelWriter(connection); sync.set(key, "1"); AsyncCommand working = new AsyncCommand<>(new Command(CommandType.INCR, @@ -146,13 +144,13 @@ public void encode(ByteBuf buf) { assertThat(command.await(2, TimeUnit.SECONDS)).isTrue(); assertThat(command.isCancelled()).isFalse(); assertThat(getException(command)).isInstanceOf(EncoderException.class); - assertThat(getQueue(connection)).isNotEmpty(); - getQueue(connection).clear(); + assertThat(ConnectionTestUtil.getQueue(connection)).isNotEmpty(); + ConnectionTestUtil.getQueue(connection).clear(); assertThat(sync.get(key)).isEqualTo("2"); - assertThat(getQueue(connection)).isEmpty(); - assertThat(getCommandBuffer(connection)).isEmpty(); + assertThat(ConnectionTestUtil.getQueue(connection)).isEmpty(); + assertThat(ConnectionTestUtil.getCommandBuffer(connection)).isEmpty(); connection.close(); } @@ -165,15 +163,15 @@ public void commandNotExecutedChannelClosesWhileFlush() throws Exception { StatefulRedisConnection connection = client.connect(); RedisCommands sync = connection.sync(); RedisCommands verificationConnection = client.connect().sync(); - RedisChannelWriter channelWriter = Connections.getChannelWriter(connection); + RedisChannelWriter channelWriter = ConnectionTestUtil.getChannelWriter(connection); sync.set(key, "1"); assertThat(verificationConnection.get(key)).isEqualTo("1"); final CountDownLatch block = new CountDownLatch(1); - AsyncCommand command = new AsyncCommand(new Command<>(CommandType.INCR, - new IntegerOutput(CODEC), new CommandArgs<>(CODEC).addKey(key))) { + AsyncCommand command = new AsyncCommand( + new Command<>(CommandType.INCR, new IntegerOutput(CODEC), new CommandArgs<>(CODEC).addKey(key))) { @Override public void encode(ByteBuf buf) { @@ -187,7 +185,7 @@ public void encode(ByteBuf buf) { channelWriter.write(command); - Channel channel = Connections.getChannel(connection); + Channel channel = ConnectionTestUtil.getChannel(connection); channel.unsafe().disconnect(channel.newPromise()); assertThat(channel.isOpen()).isFalse(); @@ -211,13 +209,13 @@ public void commandFailsDuringDecode() throws Exception { StatefulRedisConnection connection = client.connect(); RedisCommands sync = connection.sync(); - RedisChannelWriter channelWriter = Connections.getChannelWriter(connection); + RedisChannelWriter channelWriter = ConnectionTestUtil.getChannelWriter(connection); RedisCommands verificationConnection = client.connect().sync(); sync.set(key, "1"); - AsyncCommand command = new AsyncCommand<>(new Command<>(CommandType.INCR, new StatusOutput<>( - CODEC), new CommandArgs<>(CODEC).addKey(key))); + AsyncCommand command = new AsyncCommand<>( + new Command<>(CommandType.INCR, new StatusOutput<>(CODEC), new CommandArgs<>(CODEC).addKey(key))); channelWriter.write(command); diff --git a/src/test/jmh/com/lambdaworks/redis/cluster/EmptyRedisChannelWriter.java b/src/test/jmh/com/lambdaworks/redis/cluster/EmptyRedisChannelWriter.java index 18b5a66aad..7cecaab844 100644 --- a/src/test/jmh/com/lambdaworks/redis/cluster/EmptyRedisChannelWriter.java +++ b/src/test/jmh/com/lambdaworks/redis/cluster/EmptyRedisChannelWriter.java @@ -1,7 +1,7 @@ package com.lambdaworks.redis.cluster; -import com.lambdaworks.redis.RedisChannelHandler; import com.lambdaworks.redis.RedisChannelWriter; +import com.lambdaworks.redis.protocol.ConnectionFacade; import com.lambdaworks.redis.protocol.RedisCommand; /** @@ -9,7 +9,7 @@ */ public class EmptyRedisChannelWriter implements RedisChannelWriter { @Override - public RedisCommand write(RedisCommand command) { + public RedisCommand write(RedisCommand command) { return null; } @@ -24,7 +24,7 @@ public void reset() { } @Override - public void setRedisChannelHandler(RedisChannelHandler redisChannelHandler) { + public void setConnectionFacade(ConnectionFacade connection) { } diff --git a/src/test/jmh/com/lambdaworks/redis/cluster/EmptyRedisClusterClient.java b/src/test/jmh/com/lambdaworks/redis/cluster/EmptyRedisClusterClient.java index dfa02c93ee..e6cc25a240 100644 --- a/src/test/jmh/com/lambdaworks/redis/cluster/EmptyRedisClusterClient.java +++ b/src/test/jmh/com/lambdaworks/redis/cluster/EmptyRedisClusterClient.java @@ -20,7 +20,7 @@ public EmptyRedisClusterClient(RedisURI initialUri) { } StatefulRedisConnection connectToNode(RedisCodec codec, String nodeId, - RedisChannelWriter clusterWriter, final Supplier socketAddressSupplier) { + RedisChannelWriter clusterWriter, final Supplier socketAddressSupplier) { return CONNECTION; } } diff --git a/src/test/jmh/com/lambdaworks/redis/cluster/EmptyStatefulRedisConnection.java b/src/test/jmh/com/lambdaworks/redis/cluster/EmptyStatefulRedisConnection.java index 2a67c5c455..fd5d860d80 100644 --- a/src/test/jmh/com/lambdaworks/redis/cluster/EmptyStatefulRedisConnection.java +++ b/src/test/jmh/com/lambdaworks/redis/cluster/EmptyStatefulRedisConnection.java @@ -5,6 +5,7 @@ import com.lambdaworks.redis.api.async.RedisAsyncCommands; import com.lambdaworks.redis.api.rx.RedisReactiveCommands; import com.lambdaworks.redis.api.sync.RedisCommands; +import com.lambdaworks.redis.protocol.ConnectionFacade; import com.lambdaworks.redis.protocol.RedisCommand; import java.util.concurrent.TimeUnit; @@ -12,7 +13,7 @@ /** * @author Mark Paluch */ -public class EmptyStatefulRedisConnection implements StatefulRedisConnection { +public class EmptyStatefulRedisConnection implements StatefulRedisConnection, ConnectionFacade { @Override public boolean isMulti() { return false; @@ -63,6 +64,16 @@ public ClientOptions getOptions() { return null; } + @Override + public void activated() { + + } + + @Override + public void deactivated() { + + } + @Override public void reset() { diff --git a/src/test/jmh/com/lambdaworks/redis/protocol/CommandBenchmark.java b/src/test/jmh/com/lambdaworks/redis/protocol/CommandBenchmark.java index 03a489848d..82d5b6afd6 100644 --- a/src/test/jmh/com/lambdaworks/redis/protocol/CommandBenchmark.java +++ b/src/test/jmh/com/lambdaworks/redis/protocol/CommandBenchmark.java @@ -1,14 +1,6 @@ package com.lambdaworks.redis.protocol; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.nio.channels.GatheringByteChannel; -import java.nio.channels.ScatteringByteChannel; -import java.nio.charset.Charset; - +import com.lambdaworks.redis.codec.StringCodec; import com.lambdaworks.redis.protocol.CommandArgs.ExperimentalByteArrayCodec; import org.openjdk.jmh.annotations.*; @@ -17,9 +9,7 @@ import com.lambdaworks.redis.codec.Utf8StringCodec; import com.lambdaworks.redis.output.ValueOutput; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.ByteBufAllocator; -import io.netty.buffer.ByteBufProcessor; +import java.nio.charset.StandardCharsets; /** * Benchmark for {@link Command}. Test cases: @@ -35,7 +25,8 @@ public class CommandBenchmark { private final static ByteArrayCodec BYTE_ARRAY_CODEC = new ByteArrayCodec(); private final static ExperimentalByteArrayCodec BYTE_ARRAY_CODEC2 = ExperimentalByteArrayCodec.INSTANCE; - private final static Utf8StringCodec STRING_CODEC = new Utf8StringCodec(); + private final static Utf8StringCodec OLD_STRING_CODEC = new Utf8StringCodec(); + private final static StringCodec NEW_STRING_CODEC = new StringCodec(StandardCharsets.UTF_8); private final static EmptyByteBuf DUMMY_BYTE_BUF = new EmptyByteBuf(); private final static String KEY = "key"; @@ -48,7 +39,7 @@ public void createCommandUsingByteArrayCodec() { @Benchmark public void createCommandUsingStringCodec() { - createCommand(KEY, STRING_CODEC); + createCommand(KEY, OLD_STRING_CODEC); } @Benchmark @@ -62,8 +53,13 @@ public void encodeCommandUsingByteArrayCodec2() { } @Benchmark - public void encodeCommandUsingStringCodec() { - createCommand(KEY, STRING_CODEC).encode(DUMMY_BYTE_BUF); + public void encodeCommandUsingOldStringCodec() { + createCommand(KEY, OLD_STRING_CODEC).encode(DUMMY_BYTE_BUF); + } + + @Benchmark + public void encodeCommandUsingNewStringCodec() { + createCommand(KEY, NEW_STRING_CODEC).encode(DUMMY_BYTE_BUF); } private Command createCommand(K key, RedisCodec codec) { @@ -71,5 +67,4 @@ private Command createCommand(K key, RedisCodec codec) return command; } - } diff --git a/src/test/jmh/com/lambdaworks/redis/protocol/CommandHandlerBenchmark.java b/src/test/jmh/com/lambdaworks/redis/protocol/CommandHandlerBenchmark.java index cef5462fd1..1ebad7ea84 100644 --- a/src/test/jmh/com/lambdaworks/redis/protocol/CommandHandlerBenchmark.java +++ b/src/test/jmh/com/lambdaworks/redis/protocol/CommandHandlerBenchmark.java @@ -1,21 +1,17 @@ package com.lambdaworks.redis.protocol; -import java.util.ArrayDeque; - -import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; import com.lambdaworks.redis.ClientOptions; import com.lambdaworks.redis.codec.ByteArrayCodec; import com.lambdaworks.redis.output.ValueOutput; -import io.netty.channel.ChannelFuture; -import io.netty.channel.ChannelPromise; -import io.netty.channel.embedded.EmbeddedChannel; - /** * Benchmark for {@link CommandHandler}. Test cases: *
    - *
  • user command writes
  • *
  • netty (in-eventloop) writes
  • *
* @@ -28,7 +24,6 @@ public class CommandHandlerBenchmark { private final static ClientOptions CLIENT_OPTIONS = ClientOptions.create(); private final static EmptyContext CHANNEL_HANDLER_CONTEXT = new EmptyContext(); private final static byte[] KEY = "key".getBytes(); - private final static ChannelFuture EMPTY = new EmptyFuture(); private CommandHandler commandHandler; private Command command; @@ -36,59 +31,18 @@ public class CommandHandlerBenchmark { @Setup public void setup() { - commandHandler = new CommandHandler(CLIENT_OPTIONS, EmptyClientResources.INSTANCE, new ArrayDeque<>(512)); + commandHandler = new CommandHandler(EmptyClientResources.INSTANCE, new DefaultEndpoint(CLIENT_OPTIONS)); command = new Command(CommandType.GET, new ValueOutput<>(CODEC), new CommandArgs(CODEC).addKey(KEY)); commandHandler.setState(CommandHandler.LifecycleState.CONNECTED); - - commandHandler.channel = new MyLocalChannel(); - } - - @TearDown(Level.Iteration) - public void tearDown() { - commandHandler.reset(); - } - - @Benchmark - public void measureUserWrite() { - commandHandler.write(command); } @Benchmark public void measureNettyWrite() throws Exception { - commandHandler.write(CHANNEL_HANDLER_CONTEXT, command, null); - } - - private final static class MyLocalChannel extends EmbeddedChannel { - @Override - public boolean isActive() { - return true; - } - - @Override - public boolean isOpen() { - return true; - } - @Override - public ChannelFuture write(Object msg) { - return EMPTY; - } - - @Override - public ChannelFuture write(Object msg, ChannelPromise promise) { - return promise; - } - - @Override - public ChannelFuture writeAndFlush(Object msg) { - return EMPTY; - } + commandHandler.write(CHANNEL_HANDLER_CONTEXT, command, null); - @Override - public ChannelFuture writeAndFlush(Object msg, ChannelPromise promise) { - return promise; - } + // Prevent OOME + commandHandler.getQueue().clear(); } - } diff --git a/src/test/jmh/com/lambdaworks/redis/protocol/EmptyClientResources.java b/src/test/jmh/com/lambdaworks/redis/protocol/EmptyClientResources.java index 4d4d5415e6..7dd3a7d959 100644 --- a/src/test/jmh/com/lambdaworks/redis/protocol/EmptyClientResources.java +++ b/src/test/jmh/com/lambdaworks/redis/protocol/EmptyClientResources.java @@ -1,16 +1,24 @@ package com.lambdaworks.redis.protocol; +import java.net.SocketAddress; +import java.util.Map; +import java.util.concurrent.TimeUnit; + import com.lambdaworks.redis.event.DefaultEventPublisherOptions; import com.lambdaworks.redis.event.EventBus; import com.lambdaworks.redis.event.EventPublisherOptions; import com.lambdaworks.redis.metrics.CommandLatencyCollector; +import com.lambdaworks.redis.metrics.CommandLatencyId; +import com.lambdaworks.redis.metrics.CommandMetrics; import com.lambdaworks.redis.resource.ClientResources; import com.lambdaworks.redis.resource.Delay; import com.lambdaworks.redis.resource.DnsResolver; import com.lambdaworks.redis.resource.EventLoopGroupProvider; -import io.netty.util.concurrent.*; -import java.util.concurrent.TimeUnit; +import io.netty.util.concurrent.EventExecutorGroup; +import io.netty.util.concurrent.Future; +import io.netty.util.concurrent.GlobalEventExecutor; +import io.netty.util.concurrent.SucceededFuture; /** * @author Mark Paluch @@ -18,6 +26,7 @@ public class EmptyClientResources implements ClientResources { public static final DefaultEventPublisherOptions PUBLISHER_OPTIONS = DefaultEventPublisherOptions.disabled(); + public static final EmptyCommandLatencyCollector LATENCY_COLLECTOR = new EmptyCommandLatencyCollector(); public static final EmptyClientResources INSTANCE = new EmptyClientResources(); @Override @@ -62,7 +71,7 @@ public EventPublisherOptions commandLatencyPublisherOptions() { @Override public CommandLatencyCollector commandLatencyCollector() { - return null; + return LATENCY_COLLECTOR; } @Override @@ -74,4 +83,28 @@ public DnsResolver dnsResolver() { public Delay reconnectDelay() { return null; } + + public static class EmptyCommandLatencyCollector implements CommandLatencyCollector { + + @Override + public void shutdown() { + + } + + @Override + public Map retrieveMetrics() { + return null; + } + + @Override + public boolean isEnabled() { + return false; + } + + @Override + public void recordCommandLatency(SocketAddress local, SocketAddress remote, ProtocolKeyword commandType, + long firstResponseLatency, long completionLatency) { + + } + } } diff --git a/src/test/jmh/com/lambdaworks/redis/protocol/JmhMain.java b/src/test/jmh/com/lambdaworks/redis/protocol/JmhMain.java index 5f405f4d8b..97e41efffa 100644 --- a/src/test/jmh/com/lambdaworks/redis/protocol/JmhMain.java +++ b/src/test/jmh/com/lambdaworks/redis/protocol/JmhMain.java @@ -25,13 +25,12 @@ public static void main(String... args) throws IOException, RunnerException { // runRedisStateMachineBenchmark(); // or all - // runBenchmarks(); + //runBenchmarks(); } private static void runBenchmarks() throws RunnerException { new Runner(prepareOptions().mode(Mode.AverageTime).timeUnit(TimeUnit.NANOSECONDS).build()).run(); - } private static void runCommandBenchmark() throws RunnerException { diff --git a/src/test/jmh/com/lambdaworks/redis/protocol/RedisEndpointBenchmark.java b/src/test/jmh/com/lambdaworks/redis/protocol/RedisEndpointBenchmark.java new file mode 100644 index 0000000000..3f6bb8286b --- /dev/null +++ b/src/test/jmh/com/lambdaworks/redis/protocol/RedisEndpointBenchmark.java @@ -0,0 +1,85 @@ +package com.lambdaworks.redis.protocol; + +import com.lambdaworks.redis.cluster.EmptyStatefulRedisConnection; +import org.openjdk.jmh.annotations.*; + +import com.lambdaworks.redis.ClientOptions; +import com.lambdaworks.redis.codec.ByteArrayCodec; +import com.lambdaworks.redis.output.ValueOutput; + +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelPromise; +import io.netty.channel.embedded.EmbeddedChannel; + +/** + * Benchmark for {@link DefaultEndpoint}. Test cases: + *
    + *
  • user command writes
  • + *
+ * + * @author Mark Paluch + */ +@State(Scope.Benchmark) +public class RedisEndpointBenchmark { + + private final static ByteArrayCodec CODEC = new ByteArrayCodec(); + private final static ClientOptions CLIENT_OPTIONS = ClientOptions.create(); + private final static byte[] KEY = "key".getBytes(); + private final static ChannelFuture EMPTY = new EmptyFuture(); + + private DefaultEndpoint defaultEndpoint; + private Command command; + + @Setup + public void setup() { + + defaultEndpoint = new DefaultEndpoint(CLIENT_OPTIONS); + command = new Command(CommandType.GET, new ValueOutput<>(CODEC), new CommandArgs(CODEC).addKey(KEY)); + + defaultEndpoint.setConnectionFacade(new EmptyStatefulRedisConnection()); + defaultEndpoint.notifyChannelActive(new MyLocalChannel()); + } + + @TearDown(Level.Iteration) + public void tearDown() { + defaultEndpoint.reset(); + } + + @Benchmark + public void measureUserWrite() { + defaultEndpoint.write(command); + } + + private final static class MyLocalChannel extends EmbeddedChannel { + @Override + public boolean isActive() { + return true; + } + + @Override + public boolean isOpen() { + return true; + } + + @Override + public ChannelFuture write(Object msg) { + return EMPTY; + } + + @Override + public ChannelFuture write(Object msg, ChannelPromise promise) { + return promise; + } + + @Override + public ChannelFuture writeAndFlush(Object msg) { + return EMPTY; + } + + @Override + public ChannelFuture writeAndFlush(Object msg, ChannelPromise promise) { + return promise; + } + } + +} diff --git a/src/test/jmh/com/lambdaworks/redis/protocol/RedisStateMachineBenchmark.java b/src/test/jmh/com/lambdaworks/redis/protocol/RedisStateMachineBenchmark.java index 83f58c9def..10e39ad6dc 100644 --- a/src/test/jmh/com/lambdaworks/redis/protocol/RedisStateMachineBenchmark.java +++ b/src/test/jmh/com/lambdaworks/redis/protocol/RedisStateMachineBenchmark.java @@ -43,7 +43,7 @@ public void set(long integer) { private ByteBuf masterBuffer; - private final RedisStateMachine stateMachine = new RedisStateMachine<>(); + private final RedisStateMachine stateMachine = new RedisStateMachine(); private final byte[] payload = ("*3\r\n" + // "$4\r\n" + // "LLEN\r\n" + // From 8723a33865e9289157f75028d2ce96faf744dd47 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Wed, 31 Aug 2016 19:51:32 +0200 Subject: [PATCH 013/808] Polishing Reorder fields. Fix link to reactive API. Fix reactive test names. Improve JavaDoc --- .../com/lambdaworks/redis/AbstractRedisClient.java | 13 ++++++------- .../com/lambdaworks/redis/TransactionResult.java | 1 + .../redis/api/async/RedisGeoAsyncCommands.java | 4 ++-- .../redis/api/async/RedisServerAsyncCommands.java | 4 ---- .../api/reactive/RedisGeoReactiveCommands.java | 4 ++-- .../api/reactive/RedisServerReactiveCommands.java | 1 + .../redis/api/reactive/package-info.java | 2 +- .../redis/api/sync/RedisGeoCommands.java | 2 +- .../redis/api/sync/RedisServerCommands.java | 4 ---- .../redis/cluster/RedisClusterClient.java | 5 +++-- .../api/async/BaseNodeSelectionAsyncCommands.java | 4 ++-- .../api/async/NodeSelectionGeoAsyncCommands.java | 4 ++-- .../redis/cluster/api/reactive/package-info.java | 2 +- .../cluster/api/sync/BaseNodeSelectionCommands.java | 5 +++-- .../cluster/api/sync/NodeSelectionGeoCommands.java | 4 ++-- .../lambdaworks/redis/internal/LettuceAssert.java | 1 + .../pubsub/StatefulRedisPubSubConnectionImpl.java | 3 ++- .../redis/pubsub/api/reactive/package-info.java | 2 +- .../redis/sentinel/api/reactive/package-info.java | 4 ++++ src/main/javadoc/overview.html | 2 +- ...est.java => ListClusterReactiveCommandTest.java} | 2 +- ...ndTest.java => SentinelReactiveCommandTest.java} | 2 +- 22 files changed, 38 insertions(+), 37 deletions(-) create mode 100644 src/main/java/com/lambdaworks/redis/sentinel/api/reactive/package-info.java rename src/test/java/com/lambdaworks/redis/cluster/commands/reactive/{ListClusterRxCommandTest.java => ListClusterReactiveCommandTest.java} (97%) rename src/test/java/com/lambdaworks/redis/sentinel/reactive/{SentinelRxCommandTest.java => SentinelReactiveCommandTest.java} (94%) diff --git a/src/main/java/com/lambdaworks/redis/AbstractRedisClient.java b/src/main/java/com/lambdaworks/redis/AbstractRedisClient.java index 94bf808c27..cd651e8151 100644 --- a/src/main/java/com/lambdaworks/redis/AbstractRedisClient.java +++ b/src/main/java/com/lambdaworks/redis/AbstractRedisClient.java @@ -51,19 +51,19 @@ public abstract class AbstractRedisClient { protected static final PooledByteBufAllocator BUF_ALLOCATOR = PooledByteBufAllocator.DEFAULT; protected static final InternalLogger logger = InternalLoggerFactory.getInstance(RedisClient.class); - protected EventExecutorGroup genericWorkerPool; - protected final Map, EventLoopGroup> eventLoopGroups = new ConcurrentHashMap<>(2); + protected final ConnectionEvents connectionEvents = new ConnectionEvents(); + protected final Set closeableResources = new ConcurrentSet<>(); + protected final EventExecutorGroup genericWorkerPool; protected final HashedWheelTimer timer; protected final ChannelGroup channels; protected final ClientResources clientResources; - protected long timeout = 60; - protected TimeUnit unit; - protected ConnectionEvents connectionEvents = new ConnectionEvents(); - protected Set closeableResources = new ConcurrentSet<>(); protected volatile ClientOptions clientOptions = ClientOptions.builder().build(); + protected long timeout = 60; + protected TimeUnit unit; + private final boolean sharedResources; private final AtomicBoolean shutdown = new AtomicBoolean(); @@ -84,7 +84,6 @@ protected AbstractRedisClient(ClientResources clientResources) { } unit = TimeUnit.SECONDS; - genericWorkerPool = this.clientResources.eventExecutorGroup(); channels = new DefaultChannelGroup(genericWorkerPool.next()); timer = new HashedWheelTimer(); diff --git a/src/main/java/com/lambdaworks/redis/TransactionResult.java b/src/main/java/com/lambdaworks/redis/TransactionResult.java index 0bb9afdef8..e4103d4d0e 100644 --- a/src/main/java/com/lambdaworks/redis/TransactionResult.java +++ b/src/main/java/com/lambdaworks/redis/TransactionResult.java @@ -37,6 +37,7 @@ public interface TransactionResult extends Iterable { * Returns the element at the specified position in this {@link TransactionResult}. * * @param index index of the element to return + * @param inferred type * @return the element at the specified position in this {@link TransactionResult} * @throws IndexOutOfBoundsException if the index is out of range (index < 0 || index >= size()) */ diff --git a/src/main/java/com/lambdaworks/redis/api/async/RedisGeoAsyncCommands.java b/src/main/java/com/lambdaworks/redis/api/async/RedisGeoAsyncCommands.java index 0709b14176..8c002f57e2 100644 --- a/src/main/java/com/lambdaworks/redis/api/async/RedisGeoAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/async/RedisGeoAsyncCommands.java @@ -69,7 +69,7 @@ public interface RedisGeoAsyncCommands { RedisFuture>> georadius(K key, double longitude, double latitude, double distance, GeoArgs.Unit unit, GeoArgs geoArgs); /** - * Perform a {@link #georadius(Object, double, double, double, Unit, GeoArgs)} query and store the results in a sorted set. + * Perform a {@link #georadius(Object, double, double, double, GeoArgs.Unit, GeoArgs)} query and store the results in a sorted set. * * @param key the key of the geo set * @param longitude the longitude coordinate according to WGS84 @@ -109,7 +109,7 @@ public interface RedisGeoAsyncCommands { RedisFuture>> georadiusbymember(K key, V member, double distance, GeoArgs.Unit unit, GeoArgs geoArgs); /** - * Perform a {@link #georadiusbymember(Object, Object, double, Unit, GeoArgs)} query and store the results in a sorted set. + * Perform a {@link #georadiusbymember(Object, Object, double, GeoArgs.Unit, GeoArgs)} query and store the results in a sorted set. * * @param key the key of the geo set * @param member reference member diff --git a/src/main/java/com/lambdaworks/redis/api/async/RedisServerAsyncCommands.java b/src/main/java/com/lambdaworks/redis/api/async/RedisServerAsyncCommands.java index 3d40677882..18453935e3 100644 --- a/src/main/java/com/lambdaworks/redis/api/async/RedisServerAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/async/RedisServerAsyncCommands.java @@ -172,15 +172,11 @@ public interface RedisServerAsyncCommands { /** * Make the server crash: Out of memory. - * - * @return nothing, because the server crashes before returning. */ void debugOom(); /** * Make the server crash: Invalid pointer access. - * - * @return nothing, because the server crashes before returning. */ void debugSegfault(); diff --git a/src/main/java/com/lambdaworks/redis/api/reactive/RedisGeoReactiveCommands.java b/src/main/java/com/lambdaworks/redis/api/reactive/RedisGeoReactiveCommands.java index aea256d2c8..f57520c7b4 100644 --- a/src/main/java/com/lambdaworks/redis/api/reactive/RedisGeoReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/reactive/RedisGeoReactiveCommands.java @@ -71,7 +71,7 @@ public interface RedisGeoReactiveCommands { Flux> georadius(K key, double longitude, double latitude, double distance, GeoArgs.Unit unit, GeoArgs geoArgs); /** - * Perform a {@link #georadius(Object, double, double, double, Unit, GeoArgs)} query and store the results in a sorted set. + * Perform a {@link #georadius(Object, double, double, double, GeoArgs.Unit, GeoArgs)} query and store the results in a sorted set. * * @param key the key of the geo set * @param longitude the longitude coordinate according to WGS84 @@ -111,7 +111,7 @@ public interface RedisGeoReactiveCommands { Flux> georadiusbymember(K key, V member, double distance, GeoArgs.Unit unit, GeoArgs geoArgs); /** - * Perform a {@link #georadiusbymember(Object, Object, double, Unit, GeoArgs)} query and store the results in a sorted set. + * Perform a {@link #georadiusbymember(Object, Object, double, GeoArgs.Unit, GeoArgs)} query and store the results in a sorted set. * * @param key the key of the geo set * @param member reference member diff --git a/src/main/java/com/lambdaworks/redis/api/reactive/RedisServerReactiveCommands.java b/src/main/java/com/lambdaworks/redis/api/reactive/RedisServerReactiveCommands.java index 788b88b074..ff02fa90f4 100644 --- a/src/main/java/com/lambdaworks/redis/api/reactive/RedisServerReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/reactive/RedisServerReactiveCommands.java @@ -268,6 +268,7 @@ public interface RedisServerReactiveCommands { * Synchronously save the dataset to disk and then shut down the server. * * @param save {@literal true} force save operation + * @return nothing */ Mono shutdown(boolean save); diff --git a/src/main/java/com/lambdaworks/redis/api/reactive/package-info.java b/src/main/java/com/lambdaworks/redis/api/reactive/package-info.java index 70d9f046c8..09f535d46b 100644 --- a/src/main/java/com/lambdaworks/redis/api/reactive/package-info.java +++ b/src/main/java/com/lambdaworks/redis/api/reactive/package-info.java @@ -1,4 +1,4 @@ /** - * Standalone Redis API for reactive commands. + * Standalone Redis API for commands executed in a reactive manner. */ package com.lambdaworks.redis.api.reactive; \ No newline at end of file diff --git a/src/main/java/com/lambdaworks/redis/api/sync/RedisGeoCommands.java b/src/main/java/com/lambdaworks/redis/api/sync/RedisGeoCommands.java index 1f5dff8cf5..e064b93c81 100644 --- a/src/main/java/com/lambdaworks/redis/api/sync/RedisGeoCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/sync/RedisGeoCommands.java @@ -109,7 +109,7 @@ public interface RedisGeoCommands { List> georadiusbymember(K key, V member, double distance, GeoArgs.Unit unit, GeoArgs geoArgs); /** - * Perform a {@link #georadiusbymember(Object, Object, double, Unit, GeoArgs)} query and store the results in a sorted set. + * Perform a {@link #georadiusbymember(Object, Object, double, GeoArgs.Unit, GeoArgs)} query and store the results in a sorted set. * * @param key the key of the geo set * @param member reference member diff --git a/src/main/java/com/lambdaworks/redis/api/sync/RedisServerCommands.java b/src/main/java/com/lambdaworks/redis/api/sync/RedisServerCommands.java index 1d82353e5d..13cccac13e 100644 --- a/src/main/java/com/lambdaworks/redis/api/sync/RedisServerCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/sync/RedisServerCommands.java @@ -171,15 +171,11 @@ public interface RedisServerCommands { /** * Make the server crash: Out of memory. - * - * @return nothing, because the server crashes before returning. */ void debugOom(); /** * Make the server crash: Invalid pointer access. - * - * @return nothing, because the server crashes before returning. */ void debugSegfault(); diff --git a/src/main/java/com/lambdaworks/redis/cluster/RedisClusterClient.java b/src/main/java/com/lambdaworks/redis/cluster/RedisClusterClient.java index d2fb069990..01991e40ae 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/RedisClusterClient.java +++ b/src/main/java/com/lambdaworks/redis/cluster/RedisClusterClient.java @@ -27,6 +27,7 @@ import com.lambdaworks.redis.codec.StringCodec; import com.lambdaworks.redis.internal.LettuceAssert; import com.lambdaworks.redis.internal.LettuceLists; +import com.lambdaworks.redis.output.KeyValueStreamingChannel; import com.lambdaworks.redis.output.ValueStreamingChannel; import com.lambdaworks.redis.protocol.DefaultEndpoint; import com.lambdaworks.redis.protocol.CommandHandler; @@ -53,7 +54,7 @@ *

*

* The Redis cluster client provides a {@link RedisAdvancedClusterCommands sync}, {@link RedisAdvancedClusterAsyncCommands - * async} and {@link com.lambdaworks.redis.cluster.api.rx.RedisAdvancedClusterReactiveCommands reactive} API. + * async} and {@link com.lambdaworks.redis.cluster.api.reactive.RedisAdvancedClusterReactiveCommands reactive} API. *

* *

@@ -70,7 +71,7 @@ *

  • {@link RedisAdvancedClusterAsyncCommands#del(Object[]) DEL}
  • *
  • {@link RedisAdvancedClusterAsyncCommands#unlink(Object[]) UNLINK}
  • *
  • {@link RedisAdvancedClusterAsyncCommands#mget(Object[]) MGET}
  • - *
  • {@link RedisAdvancedClusterAsyncCommands#mget(ValueStreamingChannel, Object[]) MGET with streaming}
  • + *
  • {@link RedisAdvancedClusterAsyncCommands#mget(KeyValueStreamingChannel, Object[])} ) MGET with streaming}
  • *
  • {@link RedisAdvancedClusterAsyncCommands#mset(Map) MSET}
  • *
  • {@link RedisAdvancedClusterAsyncCommands#msetnx(Map) MSETNX}
  • * diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/async/BaseNodeSelectionAsyncCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/async/BaseNodeSelectionAsyncCommands.java index 9d87be0ee8..fd757d0d91 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/async/BaseNodeSelectionAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/async/BaseNodeSelectionAsyncCommands.java @@ -125,11 +125,11 @@ public interface BaseNodeSelectionAsyncCommands { * * @param autoFlush state of autoFlush. */ - AsyncExecutions setAutoFlushCommands(boolean autoFlush); + void setAutoFlushCommands(boolean autoFlush); /** * Flush pending commands. This commands forces a flush on the channel and can be used to buffer ("pipeline") commands to * achieve batching. No-op if channel is not connected. */ - AsyncExecutions flushCommands(); + void flushCommands(); } diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionGeoAsyncCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionGeoAsyncCommands.java index 3f923c0bcb..1fca498ef7 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionGeoAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionGeoAsyncCommands.java @@ -69,7 +69,7 @@ public interface NodeSelectionGeoAsyncCommands { AsyncExecutions>> georadius(K key, double longitude, double latitude, double distance, GeoArgs.Unit unit, GeoArgs geoArgs); /** - * Perform a {@link #georadius(Object, double, double, double, Unit, GeoArgs)} query and store the results in a sorted set. + * Perform a {@link #georadius(Object, double, double, double, GeoArgs.Unit, GeoArgs)} query and store the results in a sorted set. * * @param key the key of the geo set * @param longitude the longitude coordinate according to WGS84 @@ -109,7 +109,7 @@ public interface NodeSelectionGeoAsyncCommands { AsyncExecutions>> georadiusbymember(K key, V member, double distance, GeoArgs.Unit unit, GeoArgs geoArgs); /** - * Perform a {@link #georadiusbymember(Object, Object, double, Unit, GeoArgs)} query and store the results in a sorted set. + * Perform a {@link #georadiusbymember(Object, Object, double, GeoArgs.Unit, GeoArgs)} query and store the results in a sorted set. * * @param key the key of the geo set * @param member reference member diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/reactive/package-info.java b/src/main/java/com/lambdaworks/redis/cluster/api/reactive/package-info.java index 1477849c97..4cf3456595 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/reactive/package-info.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/reactive/package-info.java @@ -1,4 +1,4 @@ /** - * Redis Cluster API for reactive commands. + * Redis Cluster API for commands executed in a reactive manner. */ package com.lambdaworks.redis.cluster.api.reactive; \ No newline at end of file diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/sync/BaseNodeSelectionCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/sync/BaseNodeSelectionCommands.java index e81667ebc6..d5bc731987 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/sync/BaseNodeSelectionCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/sync/BaseNodeSelectionCommands.java @@ -103,11 +103,12 @@ public interface BaseNodeSelectionCommands { * * @param autoFlush state of autoFlush. */ - Executions setAutoFlushCommands(boolean autoFlush); + void setAutoFlushCommands(boolean autoFlush); /** * Flush pending commands. This commands forces a flush on the channel and can be used to buffer ("pipeline") commands to * achieve batching. No-op if channel is not connected. + * */ - Executions flushCommands(); + void flushCommands(); } diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionGeoCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionGeoCommands.java index d502ba9011..4db82c42ca 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionGeoCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionGeoCommands.java @@ -69,7 +69,7 @@ public interface NodeSelectionGeoCommands { Executions>> georadius(K key, double longitude, double latitude, double distance, GeoArgs.Unit unit, GeoArgs geoArgs); /** - * Perform a {@link #georadius(Object, double, double, double, Unit, GeoArgs)} query and store the results in a sorted set. + * Perform a {@link #georadius(Object, double, double, double, GeoArgs.Unit, GeoArgs)} query and store the results in a sorted set. * * @param key the key of the geo set * @param longitude the longitude coordinate according to WGS84 @@ -109,7 +109,7 @@ public interface NodeSelectionGeoCommands { Executions>> georadiusbymember(K key, V member, double distance, GeoArgs.Unit unit, GeoArgs geoArgs); /** - * Perform a {@link #georadiusbymember(Object, Object, double, Unit, GeoArgs)} query and store the results in a sorted set. + * Perform a {@link #georadiusbymember(Object, Object, double, GeoArgs.Unit, GeoArgs)} query and store the results in a sorted set. * * @param key the key of the geo set * @param member reference member diff --git a/src/main/java/com/lambdaworks/redis/internal/LettuceAssert.java b/src/main/java/com/lambdaworks/redis/internal/LettuceAssert.java index d7116036d7..ae5c415b71 100644 --- a/src/main/java/com/lambdaworks/redis/internal/LettuceAssert.java +++ b/src/main/java/com/lambdaworks/redis/internal/LettuceAssert.java @@ -122,6 +122,7 @@ public static void isTrue(boolean value, String message) { * calling method. * * @param condition a boolean expression + * @param message the exception message to use if the assertion fails * @throws IllegalStateException if {@code expression} is false */ public static void assertState(boolean condition, String message) { diff --git a/src/main/java/com/lambdaworks/redis/pubsub/StatefulRedisPubSubConnectionImpl.java b/src/main/java/com/lambdaworks/redis/pubsub/StatefulRedisPubSubConnectionImpl.java index fc92f01593..938b34a0d5 100644 --- a/src/main/java/com/lambdaworks/redis/pubsub/StatefulRedisPubSubConnectionImpl.java +++ b/src/main/java/com/lambdaworks/redis/pubsub/StatefulRedisPubSubConnectionImpl.java @@ -38,7 +38,8 @@ public class StatefulRedisPubSubConnectionImpl extends StatefulRedisConnec /** * Initialize a new connection. * - * @param writer the channel writer + * @param endpoint the {@link PubSubEndpoint} + * @param writer the writer used to write commands * @param codec Codec used to encode/decode keys and values. * @param timeout Maximum time to wait for a response. * @param unit Unit of time for the timeout. diff --git a/src/main/java/com/lambdaworks/redis/pubsub/api/reactive/package-info.java b/src/main/java/com/lambdaworks/redis/pubsub/api/reactive/package-info.java index 8e45ee225b..4a134068c8 100644 --- a/src/main/java/com/lambdaworks/redis/pubsub/api/reactive/package-info.java +++ b/src/main/java/com/lambdaworks/redis/pubsub/api/reactive/package-info.java @@ -1,4 +1,4 @@ /** - * Pub/Sub Redis API for reactive commands. + * Pub/Sub Redis API for commands executed in a reactive manner. */ package com.lambdaworks.redis.pubsub.api.reactive; \ No newline at end of file diff --git a/src/main/java/com/lambdaworks/redis/sentinel/api/reactive/package-info.java b/src/main/java/com/lambdaworks/redis/sentinel/api/reactive/package-info.java new file mode 100644 index 0000000000..fe9fedf806 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/sentinel/api/reactive/package-info.java @@ -0,0 +1,4 @@ +/** + * Redis Sentinel API for commands executed in a reactive manner. + */ +package com.lambdaworks.redis.sentinel.api.reactive; \ No newline at end of file diff --git a/src/main/javadoc/overview.html b/src/main/javadoc/overview.html index 461f3826c1..aec3a3ec1e 100644 --- a/src/main/javadoc/overview.html +++ b/src/main/javadoc/overview.html @@ -3,7 +3,7 @@ {@link com.lambdaworks.redis.RedisClient RedisClient} providing {@link com.lambdaworks.redis.api.sync.RedisCommands synchronous}, {@link com.lambdaworks.redis.api.async.RedisAsyncCommands asynchronous} and -{@link com.lambdaworks.redis.api.rx.RedisReactiveCommands reactive} APIs for Redis Standalone, PubSub, +{@link com.lambdaworks.redis.api.reactive.RedisReactiveCommands reactive} APIs for Redis Standalone, PubSub, Redis Sentinel and {@link com.lambdaworks.redis.cluster.RedisClusterClient Redis Cluster}. Multiple threads may share one connection if they avoid blocking and transactional diff --git a/src/test/java/com/lambdaworks/redis/cluster/commands/reactive/ListClusterRxCommandTest.java b/src/test/java/com/lambdaworks/redis/cluster/commands/reactive/ListClusterReactiveCommandTest.java similarity index 97% rename from src/test/java/com/lambdaworks/redis/cluster/commands/reactive/ListClusterRxCommandTest.java rename to src/test/java/com/lambdaworks/redis/cluster/commands/reactive/ListClusterReactiveCommandTest.java index a1d265693a..2eae3213a8 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/commands/reactive/ListClusterRxCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/commands/reactive/ListClusterReactiveCommandTest.java @@ -20,7 +20,7 @@ /** * @author Mark Paluch */ -public class ListClusterRxCommandTest extends ListCommandTest { +public class ListClusterReactiveCommandTest extends ListCommandTest { private static RedisClusterClient redisClusterClient; private StatefulRedisClusterConnection clusterConnection; diff --git a/src/test/java/com/lambdaworks/redis/sentinel/reactive/SentinelRxCommandTest.java b/src/test/java/com/lambdaworks/redis/sentinel/reactive/SentinelReactiveCommandTest.java similarity index 94% rename from src/test/java/com/lambdaworks/redis/sentinel/reactive/SentinelRxCommandTest.java rename to src/test/java/com/lambdaworks/redis/sentinel/reactive/SentinelReactiveCommandTest.java index 489a004747..a7c2ec784a 100644 --- a/src/test/java/com/lambdaworks/redis/sentinel/reactive/SentinelRxCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/sentinel/reactive/SentinelReactiveCommandTest.java @@ -12,7 +12,7 @@ /** * @author Mark Paluch */ -public class SentinelRxCommandTest extends SentinelCommandTest { +public class SentinelReactiveCommandTest extends SentinelCommandTest { @Override public void openConnection() throws Exception { From d721e978f0d1029dc8f41191fd56eddeea3ebd3e Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Wed, 31 Aug 2016 22:00:09 +0200 Subject: [PATCH 014/808] Integrate Reactive Streams TCK for RedisPublisher #349 --- pom.xml | 20 ++++- .../com/lambdaworks/redis/RedisPublisher.java | 28 +++++- .../lambdaworks/redis/TestRedisPublisher.java | 21 +++++ .../reactive/RedisPublisherVerification.java | 86 +++++++++++++++++++ 4 files changed, 148 insertions(+), 7 deletions(-) create mode 100644 src/test/java/com/lambdaworks/redis/TestRedisPublisher.java create mode 100644 src/test/java/com/lambdaworks/redis/reactive/RedisPublisherVerification.java diff --git a/pom.xml b/pom.xml index f6245f6b33..e9ac882ddf 100644 --- a/pom.xml +++ b/pom.xml @@ -180,7 +180,7 @@ 4.12 test - + com.googlecode.multithreadedtc multithreadedtc @@ -251,6 +251,13 @@ test + + org.reactivestreams + reactive-streams-tck + 1.0.0 + test + + org.hamcrest hamcrest-library @@ -278,7 +285,7 @@ netty-40 - 4.0.40.Final + 4.0.40.Final @@ -429,7 +436,7 @@ test -classpath - + org.openjdk.jmh.Main .* @@ -507,6 +514,13 @@ 4 + + + org.apache.maven.surefire + surefire-junit47 + 2.17 + + diff --git a/src/main/java/com/lambdaworks/redis/RedisPublisher.java b/src/main/java/com/lambdaworks/redis/RedisPublisher.java index f01f0c94db..0617212e00 100644 --- a/src/main/java/com/lambdaworks/redis/RedisPublisher.java +++ b/src/main/java/com/lambdaworks/redis/RedisPublisher.java @@ -116,6 +116,7 @@ private static class RedisSubscription implements Subscription, StreamingOutp private final AtomicLong demand = new AtomicLong(); private final Queue data = new ConcurrentLinkedQueue(); private final AtomicBoolean dispatched = new AtomicBoolean(); + private volatile boolean allDataRead = false; private final StatefulConnection connection; private final RedisCommand command; @@ -142,7 +143,9 @@ private static class RedisSubscription implements Subscription, StreamingOutp */ void subscribe(Subscriber subscriber) { - LettuceAssert.notNull(subscriber, "Subscriber must not be null"); + if (subscriber == null) { + throw new NullPointerException("Subscriber must not be null"); + } if (traceEnabled) { LOG.trace("{} subscribe: {}@{}", state(), subscriber.getClass().getName(), Objects.hashCode(subscriber)); @@ -219,6 +222,8 @@ final void onAllDataRead() { if (traceEnabled) { LOG.trace("{} onAllDataRead()", state()); } + + allDataRead = true; this.state.get().onAllDataRead(this); } @@ -376,19 +381,32 @@ void onDataAvailable(RedisSubscription subscription) { if (subscription.changeState(this, READING)) { try { - boolean demandAvailable = subscription.readAndPublish(); if (demandAvailable) { subscription.changeState(READING, DEMAND); subscription.checkOnDataAvailable(); } else { - subscription.changeState(READING, NO_DEMAND); + + if (subscription.allDataRead && subscription.data.isEmpty()) { + subscription.onAllDataRead(); + } else { + subscription.changeState(READING, NO_DEMAND); + } } } catch (IOException ex) { subscription.onError(ex); } } } + + @Override + void request(RedisSubscription subscription, long n) { + + if (BackpressureUtils.checkRequest(n, subscription.subscriber)) { + BackpressureUtils.addAndGet(subscription.demand, n); + } + } + }, READING { @@ -447,7 +465,9 @@ void onDataAvailable(RedisSubscription subscription) { void onAllDataRead(RedisSubscription subscription) { - if (subscription.changeState(this, COMPLETED)) { + subscription.allDataRead = true; + + if (subscription.data.isEmpty() && subscription.changeState(this, COMPLETED)) { if (subscription.subscriber != null) { subscription.subscriber.onComplete(); } diff --git a/src/test/java/com/lambdaworks/redis/TestRedisPublisher.java b/src/test/java/com/lambdaworks/redis/TestRedisPublisher.java new file mode 100644 index 0000000000..3f6777ed2d --- /dev/null +++ b/src/test/java/com/lambdaworks/redis/TestRedisPublisher.java @@ -0,0 +1,21 @@ +package com.lambdaworks.redis; + +import java.util.function.Supplier; + +import com.lambdaworks.redis.api.StatefulConnection; +import com.lambdaworks.redis.protocol.RedisCommand; + +/** + * @author Mark Paluch + */ +public class TestRedisPublisher extends RedisPublisher { + + public TestRedisPublisher(RedisCommand staticCommand, StatefulConnection connection, boolean dissolve) { + super(staticCommand, connection, dissolve); + } + + public TestRedisPublisher(Supplier> redisCommandSupplier, StatefulConnection connection, + boolean dissolve) { + super(redisCommandSupplier, connection, dissolve); + } +} diff --git a/src/test/java/com/lambdaworks/redis/reactive/RedisPublisherVerification.java b/src/test/java/com/lambdaworks/redis/reactive/RedisPublisherVerification.java new file mode 100644 index 0000000000..7700a7625d --- /dev/null +++ b/src/test/java/com/lambdaworks/redis/reactive/RedisPublisherVerification.java @@ -0,0 +1,86 @@ +package com.lambdaworks.redis.reactive; + +import static com.lambdaworks.redis.protocol.CommandType.LRANGE; + +import java.util.List; +import java.util.UUID; +import java.util.function.Supplier; + +import org.reactivestreams.Publisher; +import org.reactivestreams.tck.PublisherVerification; +import org.reactivestreams.tck.TestEnvironment; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; + +import com.lambdaworks.TestClientResources; +import com.lambdaworks.redis.*; +import com.lambdaworks.redis.api.StatefulRedisConnection; +import com.lambdaworks.redis.api.sync.RedisCommands; +import com.lambdaworks.redis.codec.Utf8StringCodec; +import com.lambdaworks.redis.output.ValueListOutput; +import com.lambdaworks.redis.protocol.Command; +import com.lambdaworks.redis.protocol.CommandArgs; + +/** + * @author Mark Paluch + */ +public class RedisPublisherVerification extends PublisherVerification { + + private static final Utf8StringCodec CODEC = new Utf8StringCodec(); + private static RedisClient client; + private static StatefulRedisConnection connection; + + public RedisPublisherVerification() { + super(new TestEnvironment(1000)); + } + + @BeforeClass + private static void beforeClass() { + client = RedisClient.create(TestClientResources.get(), RedisURI.create(TestSettings.host(), TestSettings.port())); + connection = client.connect(); + connection.sync().flushall(); + } + + @AfterClass + private static void afterClass() { + connection.close(); + FastShutdown.shutdown(client); + } + + @Override + public Publisher createPublisher(long elements) { + + RedisCommands sync = connection.sync(); + + if (elements == Long.MAX_VALUE) { + return null; + } + + String id = UUID.randomUUID().toString(); + String key = "PublisherVerification-" + id; + + for (int i = 0; i < elements; i++) { + sync.lpush(key, "element-" + i); + } + + Supplier>> supplier = () -> { + CommandArgs args = new CommandArgs<>(CODEC).addKey(key).add(0).add(-1); + return new Command<>(LRANGE, new ValueListOutput<>(CODEC), args); + }; + + TestRedisPublisher publisher = new TestRedisPublisher(supplier, connection, true); + + return publisher; + } + + @Override + public long maxElementsFromPublisher() { + return 1000; + } + + @Override + public Publisher createFailedPublisher() { + return null; + } + +} \ No newline at end of file From 65a58a3e4e33447b08ba8d7777edcc85c90bd5a4 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Wed, 31 Aug 2016 22:47:21 +0200 Subject: [PATCH 015/808] Use different return types for geopos in reactive and other APIs #349 The reactive API requires non-null value emission, therefore commands known to possibly emit null elements require a Value wrapper. The Value wrapper is not necessary for the sync/async APIs as these APIs deal with lists so null values are possible. --- .../redis/AbstractRedisAsyncCommands.java | 2 +- .../redis/AbstractRedisReactiveCommands.java | 2 +- .../redis/RedisCommandBuilder.java | 12 +++- .../api/async/RedisGeoAsyncCommands.java | 2 +- .../redis/api/sync/RedisGeoCommands.java | 2 +- .../async/NodeSelectionGeoAsyncCommands.java | 2 +- .../api/sync/NodeSelectionGeoCommands.java | 2 +- .../output/GeoCoordinatesListOutput.java | 19 +----- .../output/GeoCoordinatesValueListOutput.java | 61 +++++++++++++++++++ .../redis/api/RedisGeoCommands.java | 2 +- .../redis/extensibility/LettuceGeoDemo.java | 4 +- .../apigenerator/CreateReactiveApi.java | 25 +++++++- .../redis/commands/GeoCommandTest.java | 16 ++--- .../reactive/GeoReactiveCommandTest.java | 32 ++++++++++ .../output/GeoCoordinatesListOutputTest.java | 20 +++--- .../GeoCoordinatesValueListOutputTest.java | 39 ++++++++++++ 16 files changed, 193 insertions(+), 49 deletions(-) create mode 100644 src/main/java/com/lambdaworks/redis/output/GeoCoordinatesValueListOutput.java create mode 100644 src/test/java/com/lambdaworks/redis/output/GeoCoordinatesValueListOutputTest.java diff --git a/src/main/java/com/lambdaworks/redis/AbstractRedisAsyncCommands.java b/src/main/java/com/lambdaworks/redis/AbstractRedisAsyncCommands.java index be5c55e2c5..60c2e9596e 100644 --- a/src/main/java/com/lambdaworks/redis/AbstractRedisAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/AbstractRedisAsyncCommands.java @@ -1729,7 +1729,7 @@ public RedisFuture georadiusbymember(K key, V member, double distance, Uni } @Override - public RedisFuture>> geopos(K key, V... members) { + public RedisFuture> geopos(K key, V... members) { return dispatch(commandBuilder.geopos(key, members)); } diff --git a/src/main/java/com/lambdaworks/redis/AbstractRedisReactiveCommands.java b/src/main/java/com/lambdaworks/redis/AbstractRedisReactiveCommands.java index 01e6ccd96e..87fb9695c3 100644 --- a/src/main/java/com/lambdaworks/redis/AbstractRedisReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/AbstractRedisReactiveCommands.java @@ -1740,7 +1740,7 @@ public Mono georadiusbymember(K key, V member, double distance, Unit unit, @Override public Flux> geopos(K key, V... members) { - return createDissolvingFlux(() -> commandBuilder.geopos(key, members)); + return createDissolvingFlux(() -> commandBuilder.geoposValues(key, members)); } @Override diff --git a/src/main/java/com/lambdaworks/redis/RedisCommandBuilder.java b/src/main/java/com/lambdaworks/redis/RedisCommandBuilder.java index 449704ed3f..b9daa80e32 100644 --- a/src/main/java/com/lambdaworks/redis/RedisCommandBuilder.java +++ b/src/main/java/com/lambdaworks/redis/RedisCommandBuilder.java @@ -2527,7 +2527,7 @@ public Command georadiusbymember(K key, V member, double distance, S } @SuppressWarnings({ "unchecked", "rawtypes" }) - public Command>> geopos(K key, V[] members) { + public Command> geopos(K key, V[] members) { notNullKey(key); LettuceAssert.notNull(members, "Members " + MUST_NOT_BE_NULL); LettuceAssert.notEmpty(members, "Members " + MUST_NOT_BE_EMPTY); @@ -2536,6 +2536,16 @@ public Command>> geopos(K key, V[] members) { return (Command) createCommand(GEOPOS, new GeoCoordinatesListOutput(codec), args); } + @SuppressWarnings({ "unchecked", "rawtypes" }) + public Command>> geoposValues(K key, V[] members) { + notNullKey(key); + LettuceAssert.notNull(members, "Members " + MUST_NOT_BE_NULL); + LettuceAssert.notEmpty(members, "Members " + MUST_NOT_BE_EMPTY); + CommandArgs args = new CommandArgs(codec).addKey(key).addValues(members); + + return (Command) createCommand(GEOPOS, new GeoCoordinatesValueListOutput(codec), args); + } + public Command geodist(K key, V from, V to, GeoArgs.Unit unit) { notNullKey(key); LettuceAssert.notNull(from, "From " + MUST_NOT_BE_NULL); diff --git a/src/main/java/com/lambdaworks/redis/api/async/RedisGeoAsyncCommands.java b/src/main/java/com/lambdaworks/redis/api/async/RedisGeoAsyncCommands.java index 8c002f57e2..e4a923d8d1 100644 --- a/src/main/java/com/lambdaworks/redis/api/async/RedisGeoAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/async/RedisGeoAsyncCommands.java @@ -130,7 +130,7 @@ public interface RedisGeoAsyncCommands { * @return a list of {@link GeoCoordinates}s representing the x,y position of each element specified in the arguments. For * missing elements {@literal null} is returned. */ - RedisFuture>> geopos(K key, V... members); + RedisFuture> geopos(K key, V... members); /** * diff --git a/src/main/java/com/lambdaworks/redis/api/sync/RedisGeoCommands.java b/src/main/java/com/lambdaworks/redis/api/sync/RedisGeoCommands.java index e064b93c81..88eea5e100 100644 --- a/src/main/java/com/lambdaworks/redis/api/sync/RedisGeoCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/sync/RedisGeoCommands.java @@ -130,7 +130,7 @@ public interface RedisGeoCommands { * @return a list of {@link GeoCoordinates}s representing the x,y position of each element specified in the arguments. For * missing elements {@literal null} is returned. */ - List> geopos(K key, V... members); + List geopos(K key, V... members); /** * diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionGeoAsyncCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionGeoAsyncCommands.java index 1fca498ef7..93e0c6e99e 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionGeoAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionGeoAsyncCommands.java @@ -130,7 +130,7 @@ public interface NodeSelectionGeoAsyncCommands { * @return a list of {@link GeoCoordinates}s representing the x,y position of each element specified in the arguments. For * missing elements {@literal null} is returned. */ - AsyncExecutions>> geopos(K key, V... members); + AsyncExecutions> geopos(K key, V... members); /** * diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionGeoCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionGeoCommands.java index 4db82c42ca..dac1d65873 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionGeoCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionGeoCommands.java @@ -130,7 +130,7 @@ public interface NodeSelectionGeoCommands { * @return a list of {@link GeoCoordinates}s representing the x,y position of each element specified in the arguments. For * missing elements {@literal null} is returned. */ - Executions>> geopos(K key, V... members); + Executions> geopos(K key, V... members); /** * diff --git a/src/main/java/com/lambdaworks/redis/output/GeoCoordinatesListOutput.java b/src/main/java/com/lambdaworks/redis/output/GeoCoordinatesListOutput.java index e348611f2d..c080f63555 100644 --- a/src/main/java/com/lambdaworks/redis/output/GeoCoordinatesListOutput.java +++ b/src/main/java/com/lambdaworks/redis/output/GeoCoordinatesListOutput.java @@ -16,14 +16,12 @@ * * @author Mark Paluch */ -public class GeoCoordinatesListOutput extends CommandOutput>> implements StreamingOutput> { +public class GeoCoordinatesListOutput extends CommandOutput> { private Double x; - private Subscriber> subscriber; public GeoCoordinatesListOutput(RedisCodec codec) { super(codec, new ArrayList<>()); - setSubscriber(ListSubscriber.of(output)); } @Override @@ -36,25 +34,14 @@ public void set(ByteBuffer bytes) { return; } - subscriber.onNext(Value.fromNullable(new GeoCoordinates(x, value))); + output.add(new GeoCoordinates(x, value)); x = null; } @Override public void multi(int count) { if (count == -1) { - subscriber.onNext(Value.empty()); + output.add(null); } } - - @Override - public void setSubscriber(Subscriber> subscriber) { - LettuceAssert.notNull(subscriber, "Subscriber must not be null"); - this.subscriber = subscriber; - } - - @Override - public Subscriber> getSubscriber() { - return subscriber; - } } diff --git a/src/main/java/com/lambdaworks/redis/output/GeoCoordinatesValueListOutput.java b/src/main/java/com/lambdaworks/redis/output/GeoCoordinatesValueListOutput.java new file mode 100644 index 0000000000..66beae9741 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/output/GeoCoordinatesValueListOutput.java @@ -0,0 +1,61 @@ +package com.lambdaworks.redis.output; + +import static java.lang.Double.parseDouble; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; + +import com.lambdaworks.redis.GeoCoordinates; +import com.lambdaworks.redis.Value; +import com.lambdaworks.redis.codec.RedisCodec; +import com.lambdaworks.redis.internal.LettuceAssert; + +/** + * A list output that creates a list with {@link GeoCoordinates} {@link Value}s. + * + * @author Mark Paluch + */ +public class GeoCoordinatesValueListOutput extends CommandOutput>> + implements StreamingOutput> { + + private Double x; + private Subscriber> subscriber; + + public GeoCoordinatesValueListOutput(RedisCodec codec) { + super(codec, new ArrayList<>()); + setSubscriber(ListSubscriber.of(output)); + } + + @Override + public void set(ByteBuffer bytes) { + + Double value = (bytes == null) ? 0 : parseDouble(decodeAscii(bytes)); + + if (x == null) { + x = value; + return; + } + + subscriber.onNext(Value.fromNullable(new GeoCoordinates(x, value))); + x = null; + } + + @Override + public void multi(int count) { + if (count == -1) { + subscriber.onNext(Value.empty()); + } + } + + @Override + public void setSubscriber(Subscriber> subscriber) { + LettuceAssert.notNull(subscriber, "Subscriber must not be null"); + this.subscriber = subscriber; + } + + @Override + public Subscriber> getSubscriber() { + return subscriber; + } +} diff --git a/src/main/templates/com/lambdaworks/redis/api/RedisGeoCommands.java b/src/main/templates/com/lambdaworks/redis/api/RedisGeoCommands.java index 765b7a0ae4..205093706f 100644 --- a/src/main/templates/com/lambdaworks/redis/api/RedisGeoCommands.java +++ b/src/main/templates/com/lambdaworks/redis/api/RedisGeoCommands.java @@ -132,7 +132,7 @@ public interface RedisGeoCommands { * @return a list of {@link GeoCoordinates}s representing the x,y position of each element specified in the arguments. For * missing elements {@literal null} is returned. */ - List> geopos(K key, V... members); + List geopos(K key, V... members); /** * diff --git a/src/test/java/biz/paluch/redis/extensibility/LettuceGeoDemo.java b/src/test/java/biz/paluch/redis/extensibility/LettuceGeoDemo.java index 0c61a3e500..770b244fd8 100644 --- a/src/test/java/biz/paluch/redis/extensibility/LettuceGeoDemo.java +++ b/src/test/java/biz/paluch/redis/extensibility/LettuceGeoDemo.java @@ -40,8 +40,8 @@ public static void main(String[] args) { System.out.println("Distance: " + weinheim.distance); System.out.println("Coordinates: " + weinheim.coordinates.x + "/" + weinheim.coordinates.y); - List> geopos = redis.geopos(key, "Weinheim", "Train station"); - GeoCoordinates weinheimGeopos = geopos.get(0).getValue(); + List geopos = redis.geopos(key, "Weinheim", "Train station"); + GeoCoordinates weinheimGeopos = geopos.get(0); System.out.println("Coordinates: " + weinheimGeopos.x + "/" + weinheimGeopos.y); redis.getStatefulConnection().close(); diff --git a/src/test/java/com/lambdaworks/apigenerator/CreateReactiveApi.java b/src/test/java/com/lambdaworks/apigenerator/CreateReactiveApi.java index 8ab4f7bcac..d1508dde47 100644 --- a/src/test/java/com/lambdaworks/apigenerator/CreateReactiveApi.java +++ b/src/test/java/com/lambdaworks/apigenerator/CreateReactiveApi.java @@ -3,6 +3,7 @@ import java.io.File; import java.util.*; import java.util.function.Function; +import java.util.function.Predicate; import java.util.function.Supplier; import org.junit.Test; @@ -29,6 +30,7 @@ public class CreateReactiveApi { "BaseRedisCommands.reset", "getStatefulConnection", "setAutoFlushCommands", "flushCommands"); private static Set FORCE_FLUX_RESULT = LettuceSets.unmodifiableSet("eval", "evalsha", "dispatch"); + private static Map RESULT_SPEC = Collections.singletonMap("geopos", "Flux>"); private CompilationUnitFactory factory; @@ -101,8 +103,9 @@ protected Function methodTypeMutator() { } String typeAsString = method.getType().toStringWithoutComments().trim(); - - if (methodMatch(FORCE_FLUX_RESULT, method, classOfMethod)) { + if(getResultType(method, classOfMethod) != null){ + typeAsString = getResultType(method, classOfMethod); + }else if (methodMatch(FORCE_FLUX_RESULT, method, classOfMethod)) { typeAsString = "Flux<" + typeAsString + ">"; } else if (typeAsString.equals("void")) { typeAsString = "Mono"; @@ -123,6 +126,24 @@ private boolean methodMatch(Collection methodNames, MethodDeclaration me return methodNames.contains(method.getName()) || methodNames.contains(classOfMethod.getName() + "." + method.getName()); } + + private String getResultType(MethodDeclaration method, + ClassOrInterfaceDeclaration classOfMethod) { + + if(RESULT_SPEC.containsKey(method.getName())){ + return RESULT_SPEC.get(method.getName()); + } + + String key = classOfMethod.getName() + "." + method.getName(); + + if(RESULT_SPEC.containsKey(key)){ + return RESULT_SPEC.get(key); + } + + return null; + } + + /** * Supply additional imports. * diff --git a/src/test/java/com/lambdaworks/redis/commands/GeoCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/GeoCommandTest.java index c79cbe8f38..429f08a39f 100644 --- a/src/test/java/com/lambdaworks/redis/commands/GeoCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/GeoCommandTest.java @@ -122,12 +122,12 @@ public void geopos() throws Exception { prepareGeo(); - List> geopos = redis.geopos(key, "Weinheim", "foobar", "Bahn"); + List geopos = redis.geopos(key, "Weinheim", "foobar", "Bahn"); assertThat(geopos).hasSize(3); - assertThat(geopos.get(0).getValue().x.doubleValue()).isEqualTo(8.6638, offset(0.001)); - assertThat(geopos.get(1).hasValue()).isFalse(); - assertThat(geopos.get(2).hasValue()).isTrue(); + assertThat(geopos.get(0).x.doubleValue()).isEqualTo(8.6638, offset(0.001)); + assertThat(geopos.get(1)).isNull(); + assertThat(geopos.get(2)).isNotNull(); } @Test @@ -138,12 +138,12 @@ public void geoposWithTransaction() throws Exception { redis.multi(); redis.geopos(key, "Weinheim", "foobar", "Bahn"); redis.geopos(key, "Weinheim", "foobar", "Bahn"); - List> geopos = redis.exec().get(1); + List geopos = redis.exec().get(1); assertThat(geopos).hasSize(3); - assertThat(geopos.get(0).getValue().x.doubleValue()).isEqualTo(8.6638, offset(0.001)); - assertThat(geopos.get(1).hasValue()).isFalse(); - assertThat(geopos.get(2).hasValue()).isTrue(); + assertThat(geopos.get(0).x.doubleValue()).isEqualTo(8.6638, offset(0.001)); + assertThat(geopos.get(1)).isNull(); + assertThat(geopos.get(2)).isNotNull(); } @Test diff --git a/src/test/java/com/lambdaworks/redis/commands/reactive/GeoReactiveCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/reactive/GeoReactiveCommandTest.java index 2ddbdbbc66..4a6940458a 100644 --- a/src/test/java/com/lambdaworks/redis/commands/reactive/GeoReactiveCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/reactive/GeoReactiveCommandTest.java @@ -1,8 +1,18 @@ package com.lambdaworks.redis.commands.reactive; +import com.lambdaworks.redis.GeoCoordinates; +import com.lambdaworks.redis.Value; +import com.lambdaworks.redis.api.reactive.RedisReactiveCommands; import com.lambdaworks.redis.api.sync.RedisCommands; import com.lambdaworks.redis.commands.GeoCommandTest; import com.lambdaworks.util.ReactiveSyncInvocationHandler; +import org.junit.Ignore; +import org.testng.annotations.Test; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.AssertionsForClassTypes.offset; public class GeoReactiveCommandTest extends GeoCommandTest { @@ -10,4 +20,26 @@ public class GeoReactiveCommandTest extends GeoCommandTest { protected RedisCommands connect() { return ReactiveSyncInvocationHandler.sync(client.connect()); } + + @Test + @Override + public void geopos() throws Exception { + + RedisReactiveCommands reactive = client.connect().reactive(); + + prepareGeo(); + + List> geopos = reactive.geopos(key, "Weinheim", "foobar", "Bahn").collectList().block(); + + assertThat(geopos).hasSize(3); + assertThat(geopos.get(0).getValue().x.doubleValue()).isEqualTo(8.6638, offset(0.001)); + assertThat(geopos.get(1).hasValue()).isFalse(); + assertThat(geopos.get(2).hasValue()).isTrue(); + } + + @Test + @Ignore("API differences") + @Override + public void geoposWithTransaction() throws Exception { + } } diff --git a/src/test/java/com/lambdaworks/redis/output/GeoCoordinatesListOutputTest.java b/src/test/java/com/lambdaworks/redis/output/GeoCoordinatesListOutputTest.java index e0831df2cb..9612ea3462 100644 --- a/src/test/java/com/lambdaworks/redis/output/GeoCoordinatesListOutputTest.java +++ b/src/test/java/com/lambdaworks/redis/output/GeoCoordinatesListOutputTest.java @@ -4,7 +4,6 @@ import java.nio.ByteBuffer; -import com.lambdaworks.redis.Value; import org.junit.Test; import com.lambdaworks.redis.GeoCoordinates; @@ -15,25 +14,20 @@ */ public class GeoCoordinatesListOutputTest { - private GeoCoordinatesListOutput sut = new GeoCoordinatesListOutput<>(new Utf8StringCodec()); - - @Test - public void defaultSubscriberIsSet() throws Exception { - assertThat(sut.getSubscriber()).isNotNull().isInstanceOf(ListSubscriber.class); - } + private GeoCoordinatesListOutput sut = new GeoCoordinatesListOutput<>(new Utf8StringCodec()); @Test(expected = IllegalStateException.class) public void setIntegerShouldFail() throws Exception { sut.set(123L); } - @Test + @Test public void commandOutputCorrectlyDecoded() throws Exception { - sut.set(ByteBuffer.wrap("1.234".getBytes())); - sut.set(ByteBuffer.wrap("4.567".getBytes())); - sut.multi(-1); + sut.set(ByteBuffer.wrap("1.234".getBytes())); + sut.set(ByteBuffer.wrap("4.567".getBytes())); + sut.multi(-1); - assertThat(sut.get()).contains(Value.just(new GeoCoordinates(1.234, 4.567))); - } + assertThat(sut.get()).contains(new GeoCoordinates(1.234, 4.567)); + } } \ No newline at end of file diff --git a/src/test/java/com/lambdaworks/redis/output/GeoCoordinatesValueListOutputTest.java b/src/test/java/com/lambdaworks/redis/output/GeoCoordinatesValueListOutputTest.java new file mode 100644 index 0000000000..c6c0bfaa2f --- /dev/null +++ b/src/test/java/com/lambdaworks/redis/output/GeoCoordinatesValueListOutputTest.java @@ -0,0 +1,39 @@ +package com.lambdaworks.redis.output; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.nio.ByteBuffer; + +import org.junit.Test; + +import com.lambdaworks.redis.GeoCoordinates; +import com.lambdaworks.redis.Value; +import com.lambdaworks.redis.codec.Utf8StringCodec; + +/** + * @author Mark Paluch + */ +public class GeoCoordinatesValueListOutputTest { + + private GeoCoordinatesValueListOutput sut = new GeoCoordinatesValueListOutput<>(new Utf8StringCodec()); + + @Test + public void defaultSubscriberIsSet() throws Exception { + assertThat(sut.getSubscriber()).isNotNull().isInstanceOf(ListSubscriber.class); + } + + @Test(expected = IllegalStateException.class) + public void setIntegerShouldFail() throws Exception { + sut.set(123L); + } + + @Test + public void commandOutputCorrectlyDecoded() throws Exception { + + sut.set(ByteBuffer.wrap("1.234".getBytes())); + sut.set(ByteBuffer.wrap("4.567".getBytes())); + sut.multi(-1); + + assertThat(sut.get()).contains(Value.just(new GeoCoordinates(1.234, 4.567))); + } +} \ No newline at end of file From 122f33194d9869151cc7d65f5b8d2d0fa1f7ff1f Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Thu, 1 Sep 2016 23:36:10 +0200 Subject: [PATCH 016/808] Upgrade to Reactor 3.0.1.BUILD-SNAPSHOT --- pom.xml | 13 +- .../lambdaworks/redis/BackpressureUtils.java | 104 -- .../com/lambdaworks/redis/RedisPublisher.java | 13 +- .../lambdaworks/redis/ClientMetricsTest.java | 3 +- .../lambdaworks/redis/CustomCodecTest.java | 3 +- .../redis/ReactiveConnectionTest.java | 2 +- .../redis/ReactiveStreamingOutputTest.java | 2 +- .../reactive/CustomReactiveCommandTest.java | 6 +- .../TransactionReactiveCommandTest.java | 2 +- .../event/ConnectionEventsTriggeredTest.java | 3 +- .../redis/event/DefaultEventBusTest.java | 2 +- .../redis/pubsub/PubSubReactiveTest.java | 2 +- .../redis/reactive/TestSubscriber.java | 1128 +++++++++++++++++ .../resource/DefaultClientResourcesTest.java | 2 +- 14 files changed, 1157 insertions(+), 128 deletions(-) create mode 100644 src/test/java/com/lambdaworks/redis/reactive/TestSubscriber.java diff --git a/pom.xml b/pom.xml index e9ac882ddf..d582b96756 100644 --- a/pom.xml +++ b/pom.xml @@ -76,7 +76,7 @@ io.projectreactor reactor-core - 3.0.0.RC1 + 3.0.1.BUILD-SNAPSHOT @@ -700,4 +700,15 @@ + + + + spring-snapshots + Spring Snapshots + https://repo.spring.io/libs-snapshot + + true + + + diff --git a/src/main/java/com/lambdaworks/redis/BackpressureUtils.java b/src/main/java/com/lambdaworks/redis/BackpressureUtils.java index 3a211e789d..df1a872817 100644 --- a/src/main/java/com/lambdaworks/redis/BackpressureUtils.java +++ b/src/main/java/com/lambdaworks/redis/BackpressureUtils.java @@ -1,85 +1,10 @@ package com.lambdaworks.redis; -import java.util.Objects; import java.util.concurrent.atomic.AtomicLong; -import org.reactivestreams.Subscriber; -import org.reactivestreams.Subscription; - -import reactor.core.Exceptions; - enum BackpressureUtils { ; - /** - * Check Subscription current state and cancel new Subscription if different null, returning true if ready to subscribe. - * - * @param current current Subscription, expected to be null - * @param next new Subscription - * @return true if Subscription can be used - */ - public static boolean validate(Subscription current, Subscription next) { - Objects.requireNonNull(next, "Subscription cannot be null"); - if (current != null) { - next.cancel(); - // reportSubscriptionSet(); - return false; - } - - return true; - } - - /** - * Evaluate if a request is strictly positive otherwise {@link #reportBadRequest(long)} - * - * @param n the request value - * @return true if valid - */ - public static boolean validate(long n) { - if (n < 0) { - reportBadRequest(n); - return false; - } - return true; - } - - /** - * Throws an exception if request is 0 or negative as specified in rule 3.09 of Reactive Streams - * - * @param n demand to check - * @param subscriber Subscriber to onError if non strict positive n - * - * @return true if valid or false if specification exception occured - * - * @throws IllegalArgumentException if subscriber is null and demand is negative or 0. - */ - public static boolean checkRequest(long n, Subscriber subscriber) { - if (n <= 0L) { - if (null != subscriber) { - subscriber.onError(Exceptions.nullOrNegativeRequestException(n)); - } else { - throw Exceptions.nullOrNegativeRequestException(n); - } - return false; - } - return true; - } - - /** - * Cap an addition to Long.MAX_VALUE - * - * @param a left operand - * @param b right operand - * @return Addition result or Long.MAX_VALUE if overflow - */ - public static long addCap(long a, long b) { - long res = a + b; - if (res < 0L) { - return Long.MAX_VALUE; - } - return res; - } - /** * Cap a substraction to 0 * @@ -95,26 +20,6 @@ public static long subOrZero(long a, long b) { return res; } - /** - * Concurrent addition bound to Long.MAX_VALUE. Any concurrent write will "happen" before this operation. - * - * @param current current atomic to update - * @param toAdd delta to add - * @return Addition result or Long.MAX_VALUE - */ - public static long addAndGet(AtomicLong current, long toAdd) { - long u, r; - do { - r = current.get(); - if (r == Long.MAX_VALUE) { - return Long.MAX_VALUE; - } - u = addCap(r, toAdd); - } while (!current.compareAndSet(r, u)); - - return u; - } - /** * Concurrent substraction bound to 0 and Long.MAX_VALUE. Any concurrent write will "happen" before this operation. * @@ -134,13 +39,4 @@ public static long getAndSub(AtomicLong sequence, long toSub) { return r; } - - /** - * Throw {@link IllegalArgumentException} - * - * @param n the demand to evaluate - */ - public static void reportBadRequest(long n) { - throw Exceptions.nullOrNegativeRequestException(n); - } } \ No newline at end of file diff --git a/src/main/java/com/lambdaworks/redis/RedisPublisher.java b/src/main/java/com/lambdaworks/redis/RedisPublisher.java index 0617212e00..9ab50c4017 100644 --- a/src/main/java/com/lambdaworks/redis/RedisPublisher.java +++ b/src/main/java/com/lambdaworks/redis/RedisPublisher.java @@ -24,6 +24,7 @@ import io.netty.util.internal.logging.InternalLogger; import io.netty.util.internal.logging.InternalLoggerFactory; +import reactor.core.publisher.Operators; /** * Reactive command {@link Publisher} using ReactiveStreams. @@ -359,8 +360,8 @@ void subscribe(RedisSubscription subscription, Subscriber subscriber) { @Override void request(RedisSubscription subscription, long n) { - if (BackpressureUtils.checkRequest(n, subscription.subscriber)) { - BackpressureUtils.addAndGet(subscription.demand, n); + if (Operators.checkRequest(n, subscription.subscriber)) { + Operators.addAndGet(subscription.demand, n); if (subscription.changeState(this, DEMAND)) { subscription.checkCommandDispatch(); @@ -402,8 +403,8 @@ void onDataAvailable(RedisSubscription subscription) { @Override void request(RedisSubscription subscription, long n) { - if (BackpressureUtils.checkRequest(n, subscription.subscriber)) { - BackpressureUtils.addAndGet(subscription.demand, n); + if (Operators.checkRequest(n, subscription.subscriber)) { + Operators.addAndGet(subscription.demand, n); } } @@ -413,8 +414,8 @@ void request(RedisSubscription subscription, long n) { @Override void request(RedisSubscription subscription, long n) { - if (BackpressureUtils.checkRequest(n, subscription.subscriber)) { - BackpressureUtils.addAndGet(subscription.demand, n); + if (Operators.checkRequest(n, subscription.subscriber)) { + Operators.addAndGet(subscription.demand, n); } } }, diff --git a/src/test/java/com/lambdaworks/redis/ClientMetricsTest.java b/src/test/java/com/lambdaworks/redis/ClientMetricsTest.java index 647ec54f77..ddc5c212be 100644 --- a/src/test/java/com/lambdaworks/redis/ClientMetricsTest.java +++ b/src/test/java/com/lambdaworks/redis/ClientMetricsTest.java @@ -9,6 +9,7 @@ import java.util.concurrent.TimeUnit; import com.lambdaworks.Wait; +import com.lambdaworks.redis.reactive.TestSubscriber; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; @@ -23,8 +24,6 @@ import com.lambdaworks.redis.metrics.CommandLatencyId; import com.lambdaworks.redis.metrics.CommandMetrics; -import reactor.test.TestSubscriber; - /** * @author Mark Paluch */ diff --git a/src/test/java/com/lambdaworks/redis/CustomCodecTest.java b/src/test/java/com/lambdaworks/redis/CustomCodecTest.java index 29463bc4f2..f0e71b9308 100644 --- a/src/test/java/com/lambdaworks/redis/CustomCodecTest.java +++ b/src/test/java/com/lambdaworks/redis/CustomCodecTest.java @@ -12,17 +12,16 @@ import java.nio.ByteBuffer; import java.nio.charset.Charset; import java.util.List; -import java.util.concurrent.TimeUnit; import com.lambdaworks.redis.api.StatefulRedisConnection; import com.lambdaworks.redis.api.sync.RedisCommands; import com.lambdaworks.redis.protocol.CommandArgs; +import com.lambdaworks.redis.reactive.TestSubscriber; import org.junit.Test; import com.lambdaworks.redis.codec.ByteArrayCodec; import com.lambdaworks.redis.codec.CompressionCodec; import com.lambdaworks.redis.codec.RedisCodec; -import reactor.test.TestSubscriber; public class CustomCodecTest extends AbstractRedisClientTest { diff --git a/src/test/java/com/lambdaworks/redis/ReactiveConnectionTest.java b/src/test/java/com/lambdaworks/redis/ReactiveConnectionTest.java index 395de86637..9c37e3f5e8 100644 --- a/src/test/java/com/lambdaworks/redis/ReactiveConnectionTest.java +++ b/src/test/java/com/lambdaworks/redis/ReactiveConnectionTest.java @@ -11,6 +11,7 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +import com.lambdaworks.redis.reactive.TestSubscriber; import org.junit.After; import org.junit.Before; import org.junit.Rule; @@ -27,7 +28,6 @@ import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import reactor.core.scheduler.Schedulers; -import reactor.test.TestSubscriber; public class ReactiveConnectionTest extends AbstractRedisClientTest { diff --git a/src/test/java/com/lambdaworks/redis/ReactiveStreamingOutputTest.java b/src/test/java/com/lambdaworks/redis/ReactiveStreamingOutputTest.java index d528f58d51..4d39b19e38 100644 --- a/src/test/java/com/lambdaworks/redis/ReactiveStreamingOutputTest.java +++ b/src/test/java/com/lambdaworks/redis/ReactiveStreamingOutputTest.java @@ -4,6 +4,7 @@ import java.util.List; import java.util.stream.Collectors; +import com.lambdaworks.redis.reactive.TestSubscriber; import org.junit.After; import org.junit.Before; import org.junit.Rule; @@ -15,7 +16,6 @@ import com.lambdaworks.redis.api.StatefulRedisConnection; import com.lambdaworks.redis.api.reactive.RedisReactiveCommands; import org.springframework.test.util.ReflectionTestUtils; -import reactor.test.TestSubscriber; import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; diff --git a/src/test/java/com/lambdaworks/redis/commands/reactive/CustomReactiveCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/reactive/CustomReactiveCommandTest.java index 4dcb02ab84..6ec73e14b2 100644 --- a/src/test/java/com/lambdaworks/redis/commands/reactive/CustomReactiveCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/reactive/CustomReactiveCommandTest.java @@ -1,9 +1,6 @@ package com.lambdaworks.redis.commands.reactive; -import static org.assertj.core.api.Assertions.assertThat; - -import java.util.List; - +import com.lambdaworks.redis.reactive.TestSubscriber; import org.junit.Test; import com.lambdaworks.redis.api.reactive.RedisReactiveCommands; @@ -16,7 +13,6 @@ import com.lambdaworks.util.ReactiveSyncInvocationHandler; import reactor.core.publisher.Flux; -import reactor.test.TestSubscriber; /** * @author Mark Paluch diff --git a/src/test/java/com/lambdaworks/redis/commands/reactive/TransactionReactiveCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/reactive/TransactionReactiveCommandTest.java index a949512c4d..7760a6e294 100644 --- a/src/test/java/com/lambdaworks/redis/commands/reactive/TransactionReactiveCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/reactive/TransactionReactiveCommandTest.java @@ -4,6 +4,7 @@ import java.util.List; +import com.lambdaworks.redis.reactive.TestSubscriber; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -20,7 +21,6 @@ import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; -import reactor.test.TestSubscriber; public class TransactionReactiveCommandTest extends TransactionCommandTest { diff --git a/src/test/java/com/lambdaworks/redis/event/ConnectionEventsTriggeredTest.java b/src/test/java/com/lambdaworks/redis/event/ConnectionEventsTriggeredTest.java index 0b385d117d..76fc7650a1 100644 --- a/src/test/java/com/lambdaworks/redis/event/ConnectionEventsTriggeredTest.java +++ b/src/test/java/com/lambdaworks/redis/event/ConnectionEventsTriggeredTest.java @@ -5,6 +5,7 @@ import java.util.ArrayList; import java.util.List; +import com.lambdaworks.redis.reactive.TestSubscriber; import org.assertj.core.api.Condition; import org.junit.Test; @@ -12,8 +13,6 @@ import com.lambdaworks.redis.AbstractRedisClientTest; import com.lambdaworks.redis.event.connection.*; -import reactor.test.TestSubscriber; - /** * @author Mark Paluch */ diff --git a/src/test/java/com/lambdaworks/redis/event/DefaultEventBusTest.java b/src/test/java/com/lambdaworks/redis/event/DefaultEventBusTest.java index f97d331f08..0135d080e5 100644 --- a/src/test/java/com/lambdaworks/redis/event/DefaultEventBusTest.java +++ b/src/test/java/com/lambdaworks/redis/event/DefaultEventBusTest.java @@ -4,12 +4,12 @@ import java.util.concurrent.TimeUnit; +import com.lambdaworks.redis.reactive.TestSubscriber; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; import reactor.core.scheduler.Schedulers; -import reactor.test.TestSubscriber; /** * @author Mark Paluch diff --git a/src/test/java/com/lambdaworks/redis/pubsub/PubSubReactiveTest.java b/src/test/java/com/lambdaworks/redis/pubsub/PubSubReactiveTest.java index 656213477a..5834dda498 100644 --- a/src/test/java/com/lambdaworks/redis/pubsub/PubSubReactiveTest.java +++ b/src/test/java/com/lambdaworks/redis/pubsub/PubSubReactiveTest.java @@ -9,6 +9,7 @@ import java.util.concurrent.BlockingQueue; import java.util.concurrent.TimeUnit; +import com.lambdaworks.redis.reactive.TestSubscriber; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -29,7 +30,6 @@ import reactor.core.Cancellation; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; -import reactor.test.TestSubscriber; /** * @author Mark Paluch diff --git a/src/test/java/com/lambdaworks/redis/reactive/TestSubscriber.java b/src/test/java/com/lambdaworks/redis/reactive/TestSubscriber.java new file mode 100644 index 0000000000..f866135eca --- /dev/null +++ b/src/test/java/com/lambdaworks/redis/reactive/TestSubscriber.java @@ -0,0 +1,1128 @@ +package com.lambdaworks.redis.reactive; + +import java.time.Duration; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLongFieldUpdater; +import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; +import java.util.function.BooleanSupplier; +import java.util.function.Consumer; +import java.util.function.Supplier; + +import org.reactivestreams.Publisher; +import org.reactivestreams.Subscriber; +import org.reactivestreams.Subscription; +import reactor.core.Fuseable; +import reactor.core.Receiver; +import reactor.core.Trackable; +import reactor.core.publisher.Operators; + +/** + * A Subscriber implementation that hosts assertion tests for its state and allows + * asynchronous cancellation and requesting. + * + *

    To create a new instance of {@link TestSubscriber}, you have the choice between + * these static methods: + *

      + *
    • {@link TestSubscriber#subscribe(Publisher)}: create a new {@link TestSubscriber}, + * subscribe to it with the specified {@link Publisher} and requests an unbounded + * number of elements.
    • + *
    • {@link TestSubscriber#subscribe(Publisher, long)}: create a new {@link TestSubscriber}, + * subscribe to it with the specified {@link Publisher} and requests {@code n} elements + * (can be 0 if you want no initial demand). + *
    • {@link TestSubscriber#create()}: create a new {@link TestSubscriber} and requests + * an unbounded number of elements.
    • + *
    • {@link TestSubscriber#create(long)}: create a new {@link TestSubscriber} and + * requests {@code n} elements (can be 0 if you want no initial demand). + *
    + * + *

    If you are testing asynchronous publishers, don't forget to use one of the + * {@code await*()} methods to wait for the data to assert. + * + *

    You can extend this class but only the onNext, onError and onComplete can be overridden. + * You can call {@link #request(long)} and {@link #cancel()} from any thread or from within + * the overridable methods but you should avoid calling the assertXXX methods asynchronously. + * + *

    Usage: + *

    + * {@code
    + * TestSubscriber
    + *   .subscribe(publisher)
    + *   .await()
    + *   .assertValues("ABC", "DEF");
    + * }
    + * 
    + * + * @param the value type. + * + * @author Sebastien Deleuze + * @author David Karnok + * @author Anatoly Kadyshev + * @author Stephane Maldini + * @author Brian Clozel + */ +public class TestSubscriber + implements Subscriber, Subscription, Trackable, Receiver { + + /** + * Default timeout for waiting next values to be received + */ + public static final Duration DEFAULT_VALUES_TIMEOUT = Duration.ofSeconds(3); + + @SuppressWarnings("rawtypes") + private static final AtomicLongFieldUpdater REQUESTED = + AtomicLongFieldUpdater.newUpdater(TestSubscriber.class, "requested"); + + @SuppressWarnings("rawtypes") + private static final AtomicReferenceFieldUpdater NEXT_VALUES = + AtomicReferenceFieldUpdater.newUpdater(TestSubscriber.class, List.class, + "values"); + + @SuppressWarnings("rawtypes") + private static final AtomicReferenceFieldUpdater S = + AtomicReferenceFieldUpdater.newUpdater(TestSubscriber.class, Subscription.class, "s"); + + + private final List errors = new LinkedList<>(); + + private final CountDownLatch cdl = new CountDownLatch(1); + + volatile Subscription s; + + volatile long requested; + + volatile List values = new LinkedList<>(); + + /** + * The fusion mode to request. + */ + private int requestedFusionMode = -1; + + /** + * The established fusion mode. + */ + private volatile int establishedFusionMode = -1; + + /** + * The fuseable QueueSubscription in case a fusion mode was specified. + */ + private Fuseable.QueueSubscription qs; + + private int subscriptionCount = 0; + + private int completionCount = 0; + + private volatile long valueCount = 0L; + + private volatile long nextValueAssertedCount = 0L; + + private Duration valuesTimeout = DEFAULT_VALUES_TIMEOUT; + + private boolean valuesStorage = true; + +// ============================================================================================================== +// Static methods +// ============================================================================================================== + + /** + * Blocking method that waits until {@code conditionSupplier} returns true, or if it + * does not before the specified timeout, throws an {@link AssertionError} with the + * specified error message supplier. + * + * @param timeout the timeout duration + * @param errorMessageSupplier the error message supplier + * @param conditionSupplier condition to break out of the wait loop + * + * @throws AssertionError + */ + public static void await(Duration timeout, Supplier errorMessageSupplier, + BooleanSupplier conditionSupplier) { + + Objects.requireNonNull(errorMessageSupplier); + Objects.requireNonNull(conditionSupplier); + Objects.requireNonNull(timeout); + + long timeoutNs = timeout.toNanos(); + long startTime = System.nanoTime(); + do { + if (conditionSupplier.getAsBoolean()) { + return; + } + try { + Thread.sleep(100); + } + catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new RuntimeException(e); + } + } + while (System.nanoTime() - startTime < timeoutNs); + throw new AssertionError(errorMessageSupplier.get()); + } + + /** + * Blocking method that waits until {@code conditionSupplier} returns true, or if it + * does not before the specified timeout, throw an {@link AssertionError} with the + * specified error message. + * + * @param timeout the timeout duration + * @param errorMessage the error message + * @param conditionSupplier condition to break out of the wait loop + * + * @throws AssertionError + */ + public static void await(Duration timeout, + final String errorMessage, + BooleanSupplier conditionSupplier) { + await(timeout, new Supplier() { + @Override + public String get() { + return errorMessage; + } + }, conditionSupplier); + } + + /** + * Create a new {@link TestSubscriber} that requests an unbounded number of elements. + *

    Be sure at least a publisher has subscribed to it via {@link Publisher#subscribe(Subscriber)} + * before use assert methods. + * @see #subscribe(Publisher) + * @param the observed value type + * @return a fresh TestSubscriber instance + */ + public static TestSubscriber create() { + return new TestSubscriber<>(); + } + + /** + * Create a new {@link TestSubscriber} that requests initially {@code n} elements. You + * can then manage the demand with {@link Subscription#request(long)}. + *

    Be sure at least a publisher has subscribed to it via {@link Publisher#subscribe(Subscriber)} + * before use assert methods. + * @param n Number of elements to request (can be 0 if you want no initial demand). + * @see #subscribe(Publisher, long) + * @param the observed value type + * @return a fresh TestSubscriber instance + */ + public static TestSubscriber create(long n) { + return new TestSubscriber<>(n); + } + + /** + * Create a new {@link TestSubscriber} that requests an unbounded number of elements, + * and make the specified {@code publisher} subscribe to it. + * @param publisher The publisher to subscribe with + * @param the observed value type + * @return a fresh TestSubscriber instance + */ + public static TestSubscriber subscribe(Publisher publisher) { + TestSubscriber subscriber = new TestSubscriber<>(); + publisher.subscribe(subscriber); + return subscriber; + } + + /** + * Create a new {@link TestSubscriber} that requests initially {@code n} elements, + * and make the specified {@code publisher} subscribe to it. You can then manage the + * demand with {@link Subscription#request(long)}. + * @param publisher The publisher to subscribe with + * @param n Number of elements to request (can be 0 if you want no initial demand). + * @param the observed value type + * @return a fresh TestSubscriber instance + */ + public static TestSubscriber subscribe(Publisher publisher, long n) { + TestSubscriber subscriber = new TestSubscriber<>(n); + publisher.subscribe(subscriber); + return subscriber; + } + +// ============================================================================================================== +// Private constructors +// ============================================================================================================== + + private TestSubscriber() { + this(Long.MAX_VALUE); + } + + private TestSubscriber(long n) { + if (n < 0) { + throw new IllegalArgumentException("initialRequest >= required but it was " + n); + } + REQUESTED.lazySet(this, n); + } + +// ============================================================================================================== +// Configuration +// ============================================================================================================== + + + /** + * Enable or disabled the values storage. It is enabled by default, and can be disable + * in order to be able to perform performance benchmarks or tests with a huge amount + * values. + * @param enabled enable value storage? + * @return this + */ + public final TestSubscriber configureValuesStorage(boolean enabled) { + this.valuesStorage = enabled; + return this; + } + + /** + * Configure the timeout in seconds for waiting next values to be received (3 seconds + * by default). + * @param timeout the new default value timeout duration + * @return this + */ + public final TestSubscriber configureValuesTimeout(Duration timeout) { + this.valuesTimeout = timeout; + return this; + } + + /** + * Returns the established fusion mode or -1 if it was not enabled + * + * @return the fusion mode, see Fuseable constants + */ + public final int establishedFusionMode() { + return establishedFusionMode; + } + +// ============================================================================================================== +// Assertions +// ============================================================================================================== + + /** + * Assert a complete successfully signal has been received. + * @return this + */ + public final TestSubscriber assertComplete() { + int c = completionCount; + if (c == 0) { + throw new AssertionError("Not completed", null); + } + if (c > 1) { + throw new AssertionError("Multiple completions: " + c, null); + } + return this; + } + + /** + * Assert the specified values have been received. Values storage should be enabled to + * use this method. + * @param expectedValues the values to assert + * @see #configureValuesStorage(boolean) + * @return this + */ + public final TestSubscriber assertContainValues(Set expectedValues) { + if (!valuesStorage) { + throw new IllegalStateException( + "Using assertNoValues() requires enabling values storage"); + } + if (expectedValues.size() > values.size()) { + throw new AssertionError("Actual contains fewer elements" + values, null); + } + + Iterator expected = expectedValues.iterator(); + + for (; ; ) { + boolean n2 = expected.hasNext(); + if (n2) { + T t2 = expected.next(); + if (!values.contains(t2)) { + throw new AssertionError("The element is not contained in the " + + "received resuls" + + " = " + valueAndClass(t2), null); + } + } + else{ + break; + } + } + return this; + } + + /** + * Assert an error signal has been received. + * @return this + */ + public final TestSubscriber assertError() { + int s = errors.size(); + if (s == 0) { + throw new AssertionError("No error", null); + } + if (s > 1) { + throw new AssertionError("Multiple errors: " + s, null); + } + return this; + } + + /** + * Assert an error signal has been received. + * @param clazz The class of the exception contained in the error signal + * @return this + */ + public final TestSubscriber assertError(Class clazz) { + int s = errors.size(); + if (s == 0) { + throw new AssertionError("No error", null); + } + if (s == 1) { + Throwable e = errors.get(0); + if (!clazz.isInstance(e)) { + throw new AssertionError("Error class incompatible: expected = " + + clazz + ", actual = " + e, null); + } + } + if (s > 1) { + throw new AssertionError("Multiple errors: " + s, null); + } + return this; + } + + public final TestSubscriber assertErrorMessage(String message) { + int s = errors.size(); + if (s == 0) { + assertionError("No error", null); + } + if (s == 1) { + if (!Objects.equals(message, + errors.get(0) + .getMessage())) { + assertionError("Error class incompatible: expected = \"" + message + + "\", actual = \"" + errors.get(0).getMessage() + "\"", null); + } + } + if (s > 1) { + assertionError("Multiple errors: " + s, null); + } + + return this; + } + + /** + * Assert an error signal has been received. + * @param expectation A method that can verify the exception contained in the error signal + * and throw an exception (like an {@link AssertionError}) if the exception is not valid. + * @return this + */ + public final TestSubscriber assertErrorWith(Consumer expectation) { + int s = errors.size(); + if (s == 0) { + throw new AssertionError("No error", null); + } + if (s == 1) { + expectation.accept(errors.get(0)); + } + if (s > 1) { + throw new AssertionError("Multiple errors: " + s, null); + } + return this; + } + + /** + * Assert that the upstream was a Fuseable source. + * + * @return this + */ + public final TestSubscriber assertFuseableSource() { + if (qs == null) { + throw new AssertionError("Upstream was not Fuseable"); + } + return this; + } + + /** + * Assert that the fusion mode was granted. + * + * @return this + */ + public final TestSubscriber assertFusionEnabled() { + if (establishedFusionMode != Fuseable.SYNC && establishedFusionMode != Fuseable.ASYNC) { + throw new AssertionError("Fusion was not enabled"); + } + return this; + } + + public final TestSubscriber assertFusionMode(int expectedMode) { + if (establishedFusionMode != expectedMode) { + throw new AssertionError("Wrong fusion mode: expected: " + fusionModeName( + expectedMode) + ", actual: " + fusionModeName(establishedFusionMode)); + } + return this; + } + + /** + * Assert that the fusion mode was granted. + * + * @return this + */ + public final TestSubscriber assertFusionRejected() { + if (establishedFusionMode != Fuseable.NONE) { + throw new AssertionError("Fusion was granted"); + } + return this; + } + + /** + * Assert no error signal has been received. + * @return this + */ + public final TestSubscriber assertNoError() { + int s = errors.size(); + if (s == 1) { + Throwable e = errors.get(0); + String valueAndClass = e == null ? null : e + " (" + e.getClass().getSimpleName() + ")"; + throw new AssertionError("Error present: " + valueAndClass, null); + } + if (s > 1) { + throw new AssertionError("Multiple errors: " + s, null); + } + return this; + } + + /** + * Assert no values have been received. + * + * @return this + */ + public final TestSubscriber assertNoValues() { + if (valueCount != 0) { + throw new AssertionError("No values expected but received: [length = " + values.size() + "] " + values, + null); + } + return this; + } + + /** + * Assert that the upstream was not a Fuseable source. + * @return this + */ + public final TestSubscriber assertNonFuseableSource() { + if (qs != null) { + throw new AssertionError("Upstream was Fuseable"); + } + return this; + } + + /** + * Assert no complete successfully signal has been received. + * @return this + */ + public final TestSubscriber assertNotComplete() { + int c = completionCount; + if (c == 1) { + throw new AssertionError("Completed", null); + } + if (c > 1) { + throw new AssertionError("Multiple completions: " + c, null); + } + return this; + } + + /** + * Assert no subscription occurred. + * + * @return this + */ + public final TestSubscriber assertNotSubscribed() { + int s = subscriptionCount; + + if (s == 1) { + throw new AssertionError("OnSubscribe called once", null); + } + if (s > 1) { + throw new AssertionError("OnSubscribe called multiple times: " + s, null); + } + + return this; + } + + /** + * Assert no complete successfully or error signal has been received. + * @return this + */ + public final TestSubscriber assertNotTerminated() { + if (cdl.getCount() == 0) { + throw new AssertionError("Terminated", null); + } + return this; + } + + /** + * Assert subscription occurred (once). + * @return this + */ + public final TestSubscriber assertSubscribed() { + int s = subscriptionCount; + + if (s == 0) { + throw new AssertionError("OnSubscribe not called", null); + } + if (s > 1) { + throw new AssertionError("OnSubscribe called multiple times: " + s, null); + } + + return this; + } + + /** + * Assert either complete successfully or error signal has been received. + * @return this + */ + public final TestSubscriber assertTerminated() { + if (cdl.getCount() != 0) { + throw new AssertionError("Not terminated", null); + } + return this; + } + + /** + * Assert {@code n} values has been received. + * + * @param n the expected value count + * + * @return this + */ + public final TestSubscriber assertValueCount(long n) { + if (valueCount != n) { + throw new AssertionError("Different value count: expected = " + n + ", actual = " + valueCount, + null); + } + return this; + } + + /** + * Assert the specified values have been received in the same order read by the + * passed {@link Iterable}. Values storage + * should be enabled to + * use this method. + * @param expectedSequence the values to assert + * @see #configureValuesStorage(boolean) + * @return this + */ + public final TestSubscriber assertValueSequence(Iterable expectedSequence) { + if (!valuesStorage) { + throw new IllegalStateException("Using assertNoValues() requires enabling values storage"); + } + Iterator actual = values.iterator(); + Iterator expected = expectedSequence.iterator(); + int i = 0; + for (; ; ) { + boolean n1 = actual.hasNext(); + boolean n2 = expected.hasNext(); + if (n1 && n2) { + T t1 = actual.next(); + T t2 = expected.next(); + if (!Objects.equals(t1, t2)) { + throw new AssertionError("The element with index " + i + " does not match: expected = " + valueAndClass(t2) + ", actual = " + + valueAndClass( + t1), null); + } + i++; + } else if (n1 && !n2) { + throw new AssertionError("Actual contains more elements" + values, null); + } else if (!n1 && n2) { + throw new AssertionError("Actual contains fewer elements: " + values, null); + } else { + break; + } + } + return this; + } + + /** + * Assert the specified values have been received in the declared order. Values + * storage should be enabled to use this method. + * + * @param expectedValues the values to assert + * + * @return this + * + * @see #configureValuesStorage(boolean) + */ + @SafeVarargs + public final TestSubscriber assertValues(T... expectedValues) { + return assertValueSequence(Arrays.asList(expectedValues)); + } + + /** + * Assert the specified values have been received in the declared order. Values + * storage should be enabled to use this method. + * + * @param expectations One or more methods that can verify the values and throw a + * exception (like an {@link AssertionError}) if the value is not valid. + * + * @return this + * + * @see #configureValuesStorage(boolean) + */ + @SafeVarargs + public final TestSubscriber assertValuesWith(Consumer... expectations) { + if (!valuesStorage) { + throw new IllegalStateException( + "Using assertNoValues() requires enabling values storage"); + } + final int expectedValueCount = expectations.length; + if (expectedValueCount != values.size()) { + throw new AssertionError("Different value count: expected = " + expectedValueCount + ", actual = " + valueCount, null); + } + for (int i = 0; i < expectedValueCount; i++) { + Consumer consumer = expectations[i]; + T actualValue = values.get(i); + consumer.accept(actualValue); + } + return this; + } + +// ============================================================================================================== +// Await methods +// ============================================================================================================== + + /** + * Blocking method that waits until a complete successfully or error signal is received. + * @return this + */ + public final TestSubscriber await() { + if (cdl.getCount() == 0) { + return this; + } + try { + cdl.await(); + } catch (InterruptedException ex) { + throw new AssertionError("Wait interrupted", ex); + } + return this; + } + + /** + * Blocking method that waits until a complete successfully or error signal is received + * or until a timeout occurs. + * @param timeout The timeout value + * @return this + */ + public final TestSubscriber await(Duration timeout) { + if (cdl.getCount() == 0) { + return this; + } + try { + if (!cdl.await(timeout.toMillis(), TimeUnit.MILLISECONDS)) { + throw new AssertionError("No complete or error signal before timeout"); + } + return this; + } + catch (InterruptedException ex) { + throw new AssertionError("Wait interrupted", ex); + } + } + + /** + * Blocking method that waits until {@code n} next values have been received. + * + * @param n the value count to assert + * + * @return this + */ + public final TestSubscriber awaitAndAssertNextValueCount(final long n) { + await(valuesTimeout, new Supplier() { + @Override + public String get() { + return String.format("%d out of %d next values received within %d", + valueCount - nextValueAssertedCount, + n, + valuesTimeout.toMillis()); + } + }, () -> valueCount == (nextValueAssertedCount + n)); + nextValueAssertedCount += n; + return this; + } + + /** + * Blocking method that waits until {@code n} next values have been received (n is the + * number of values provided) to assert them. + * + * @param values the values to assert + * + * @return this + */ + @SafeVarargs + @SuppressWarnings("unchecked") + public final TestSubscriber awaitAndAssertNextValues(T... values) { + final int expectedNum = values.length; + final List> expectations = new ArrayList<>(); + for (int i = 0; i < expectedNum; i++) { + final T expectedValue = values[i]; + expectations.add(actualValue -> { + if (!actualValue.equals(expectedValue)) { + throw new AssertionError(String.format( + "Expected Next signal: %s, but got: %s", + expectedValue, + actualValue)); + } + }); + } + awaitAndAssertNextValuesWith(expectations.toArray((Consumer[]) new Consumer[0])); + return this; + } + + /** + * Blocking method that waits until {@code n} next values have been received + * (n is the number of expectations provided) to assert them. + * @param expectations One or more methods that can verify the values and throw a + * exception (like an {@link AssertionError}) if the value is not valid. + * @return this + */ + @SafeVarargs + public final TestSubscriber awaitAndAssertNextValuesWith(Consumer... expectations) { + valuesStorage = true; + final int expectedValueCount = expectations.length; + await(valuesTimeout, () -> { + return String.format("%d out of %d next values received within %d ms", + valueCount - nextValueAssertedCount, + expectedValueCount, + valuesTimeout.toMillis()); + }, () -> valueCount >= (nextValueAssertedCount + expectedValueCount)); + List nextValuesSnapshot; + List empty = new ArrayList<>(); + for(;;){ + nextValuesSnapshot = values; + if(NEXT_VALUES.compareAndSet(this, values, empty)){ + break; + } + } + if (nextValuesSnapshot.size() < expectedValueCount) { + throw new AssertionError(String.format("Expected %d number of signals but received %d", + expectedValueCount, + nextValuesSnapshot.size())); + } + for (int i = 0; i < expectedValueCount; i++) { + Consumer consumer = expectations[i]; + T actualValue = nextValuesSnapshot.get(i); + consumer.accept(actualValue); + } + nextValueAssertedCount += expectedValueCount; + return this; + } + +// ============================================================================================================== +// Overrides +// ============================================================================================================== + + @Override + public void cancel() { + Subscription a = s; + if (a != Operators.cancelledSubscription()) { + a = S.getAndSet(this, Operators.cancelledSubscription()); + if (a != null && a != Operators.cancelledSubscription()) { + a.cancel(); + } + } + } + + @Override + public final boolean isCancelled() { + return s == Operators.cancelledSubscription(); + } + + @Override + public final boolean isStarted() { + return s != null; + } + + @Override + public final boolean isTerminated() { + return isCancelled(); + } + + @Override + public void onComplete() { + completionCount++; + cdl.countDown(); + } + + @Override + public void onError(Throwable t) { + errors.add(t); + cdl.countDown(); + } + + @Override + public void onNext(T t) { + if (establishedFusionMode == Fuseable.ASYNC) { + for (; ; ) { + t = qs.poll(); + if (t == null) { + break; + } + valueCount++; + if (valuesStorage) { + List nextValuesSnapshot; + for (; ; ) { + nextValuesSnapshot = values; + nextValuesSnapshot.add(t); + if (NEXT_VALUES.compareAndSet(this, + nextValuesSnapshot, + nextValuesSnapshot)) { + break; + } + } + } + } + } + else { + valueCount++; + if (valuesStorage) { + List nextValuesSnapshot; + for (; ; ) { + nextValuesSnapshot = values; + nextValuesSnapshot.add(t); + if (NEXT_VALUES.compareAndSet(this, + nextValuesSnapshot, + nextValuesSnapshot)) { + break; + } + } + } + } + } + + @Override + @SuppressWarnings("unchecked") + public void onSubscribe(Subscription s) { + subscriptionCount++; + int requestMode = requestedFusionMode; + if (requestMode >= 0) { + if (!setWithoutRequesting(s)) { + if (!isCancelled()) { + errors.add(new IllegalStateException("Subscription already set: " + + subscriptionCount)); + } + } else { + if (s instanceof Fuseable.QueueSubscription) { + this.qs = (Fuseable.QueueSubscription)s; + + int m = qs.requestFusion(requestMode); + establishedFusionMode = m; + + if (m == Fuseable.SYNC) { + for (;;) { + T v = qs.poll(); + if (v == null) { + onComplete(); + break; + } + + onNext(v); + } + } + else { + requestDeferred(); + } + } + else { + requestDeferred(); + } + } + } else { + if (!set(s)) { + if (!isCancelled()) { + errors.add(new IllegalStateException("Subscription already set: " + + subscriptionCount)); + } + } + } + } + + @Override + public void request(long n) { + if (Operators.validate(n)) { + if (establishedFusionMode != Fuseable.SYNC) { + normalRequest(n); + } + } + } + + @Override + public final long requestedFromDownstream() { + return requested; + } + + /** + * Setup what fusion mode should be requested from the incomining + * Subscription if it happens to be QueueSubscription + * @param requestMode the mode to request, see Fuseable constants + * @return this + */ + public final TestSubscriber requestedFusionMode(int requestMode) { + this.requestedFusionMode = requestMode; + return this; + } + + @Override + public Subscription upstream() { + return s; + } + + +// ============================================================================================================== +// Non public methods +// ============================================================================================================== + + protected final void normalRequest(long n) { + Subscription a = s; + if (a != null) { + a.request(n); + } else { + Operators.addAndGet(REQUESTED, this, n); + + a = s; + + if (a != null) { + long r = REQUESTED.getAndSet(this, 0L); + + if (r != 0L) { + a.request(r); + } + } + } + } + + /** + * Requests the deferred amount if not zero. + */ + protected final void requestDeferred() { + long r = REQUESTED.getAndSet(this, 0L); + + if (r != 0L) { + s.request(r); + } + } + + /** + * Atomically sets the single subscription and requests the missed amount from it. + * + * @param s + * @return false if this arbiter is cancelled or there was a subscription already set + */ + protected final boolean set(Subscription s) { + Objects.requireNonNull(s, "s"); + Subscription a = this.s; + if (a == Operators.cancelledSubscription()) { + s.cancel(); + return false; + } + if (a != null) { + s.cancel(); + Operators.reportSubscriptionSet(); + return false; + } + + if (S.compareAndSet(this, null, s)) { + + long r = REQUESTED.getAndSet(this, 0L); + + if (r != 0L) { + s.request(r); + } + + return true; + } + + a = this.s; + + if (a != Operators.cancelledSubscription()) { + s.cancel(); + return false; + } + + Operators.reportSubscriptionSet(); + return false; + } + + /** + * Sets the Subscription once but does not request anything. + * @param s the Subscription to set + * @return true if successful, false if the current subscription is not null + */ + protected final boolean setWithoutRequesting(Subscription s) { + Objects.requireNonNull(s, "s"); + for (;;) { + Subscription a = this.s; + if (a == Operators.cancelledSubscription()) { + s.cancel(); + return false; + } + if (a != null) { + s.cancel(); + Operators.reportSubscriptionSet(); + return false; + } + + if (S.compareAndSet(this, null, s)) { + return true; + } + } + } + + /** + * Prepares and throws an AssertionError exception based on the message, cause, the + * active state and the potential errors so far. + * + * @param message the message + * @param cause the optional Throwable cause + * + * @throws AssertionError as expected + */ + protected final void assertionError(String message, Throwable cause) { + StringBuilder b = new StringBuilder(); + + if (cdl.getCount() != 0) { + b.append("(active) "); + } + b.append(message); + + List err = errors; + if (!err.isEmpty()) { + b.append(" (+ ") + .append(err.size()) + .append(" errors)"); + } + AssertionError e = new AssertionError(b.toString(), cause); + + for (Throwable t : err) { + e.addSuppressed(t); + } + + throw e; + } + + protected final String fusionModeName(int mode) { + switch (mode) { + case -1: + return "Disabled"; + case Fuseable.NONE: + return "None"; + case Fuseable.SYNC: + return "Sync"; + case Fuseable.ASYNC: + return "Async"; + default: + return "Unknown(" + mode + ")"; + } + } + + protected final String valueAndClass(Object o) { + if (o == null) { + return null; + } + return o + " (" + o.getClass().getSimpleName() + ")"; + } + +} \ No newline at end of file diff --git a/src/test/java/com/lambdaworks/redis/resource/DefaultClientResourcesTest.java b/src/test/java/com/lambdaworks/redis/resource/DefaultClientResourcesTest.java index a6fbeb5d76..05ed927233 100644 --- a/src/test/java/com/lambdaworks/redis/resource/DefaultClientResourcesTest.java +++ b/src/test/java/com/lambdaworks/redis/resource/DefaultClientResourcesTest.java @@ -8,6 +8,7 @@ import java.util.concurrent.TimeUnit; +import com.lambdaworks.redis.reactive.TestSubscriber; import org.junit.Test; import com.lambdaworks.redis.event.Event; @@ -18,7 +19,6 @@ import io.netty.channel.nio.NioEventLoopGroup; import io.netty.util.concurrent.EventExecutorGroup; import io.netty.util.concurrent.Future; -import reactor.test.TestSubscriber; /** * @author Mark Paluch From 06e49bb5d0fcc6b0f744e08666f3ab5358498b5c Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Sat, 3 Sep 2016 18:15:33 +0200 Subject: [PATCH 017/808] Encapsulate fields in GeoCoordinates and GeoWithin. --- .../com/lambdaworks/redis/GeoCoordinates.java | 34 +++++-- .../java/com/lambdaworks/redis/GeoWithin.java | 49 ++++++++++- .../redis/extensibility/LettuceGeoDemo.java | 10 +-- .../com/lambdaworks/redis/GeoModelTest.java | 11 --- .../redis/commands/GeoCommandTest.java | 88 +++++++++---------- .../reactive/GeoReactiveCommandTest.java | 2 +- 6 files changed, 123 insertions(+), 71 deletions(-) diff --git a/src/main/java/com/lambdaworks/redis/GeoCoordinates.java b/src/main/java/com/lambdaworks/redis/GeoCoordinates.java index d5bbe855c7..4be9bc549a 100644 --- a/src/main/java/com/lambdaworks/redis/GeoCoordinates.java +++ b/src/main/java/com/lambdaworks/redis/GeoCoordinates.java @@ -1,6 +1,6 @@ package com.lambdaworks.redis; -import com.lambdaworks.redis.output.DoubleOutput; +import com.lambdaworks.redis.internal.LettuceAssert; /** * A tuple consisting of numerical geo data points to describe geo coordinates. @@ -9,15 +9,39 @@ */ public class GeoCoordinates { - public final Number x; - public final Number y; + private final Number x; + private final Number y; + /** + * Creates new {@link GeoCoordinates}. + * @param x the longitude, must not be {@literal null}. + * @param y the latitude, must not be {@literal null}. + */ public GeoCoordinates(Number x, Number y) { + LettuceAssert.notNull(x, "X must not be null"); + LettuceAssert.notNull(y, "Y must not be null"); + this.x = x; this.y = y; } + /** + * + * @return the longitude. + */ + public Number getX() { + return x; + } + + /** + * + * @return the latitude. + */ + public Number getY() { + return y; + } + @Override public boolean equals(Object o) { if (this == o) @@ -41,8 +65,6 @@ public int hashCode() { @Override public String toString() { - - return String.format("(%s, %s)", x, y); + return String.format("(%s, %s)", getX(), getY()); } - } diff --git a/src/main/java/com/lambdaworks/redis/GeoWithin.java b/src/main/java/com/lambdaworks/redis/GeoWithin.java index df546ab179..6d1c765f02 100644 --- a/src/main/java/com/lambdaworks/redis/GeoWithin.java +++ b/src/main/java/com/lambdaworks/redis/GeoWithin.java @@ -14,18 +14,59 @@ */ public class GeoWithin { - public final V member; - public final Double distance; - public final Long geohash; - public final GeoCoordinates coordinates; + private final V member; + private final Double distance; + private final Long geohash; + private final GeoCoordinates coordinates; + /** + * Creates a new {@link GeoWithin}. + * + * @param member the member. + * @param distance the distance, may be {@literal null}. + * @param geohash the geohash, may be {@literal null}. + * @param coordinates the coordinates, may be {@literal null}. + */ public GeoWithin(V member, Double distance, Long geohash, GeoCoordinates coordinates) { + this.member = member; this.distance = distance; this.geohash = geohash; this.coordinates = coordinates; } + /** + * + * @return the member within the Geo set. + */ + public V getMember() { + return member; + } + + /** + * + * @return distance if requested otherwise {@literal null}. + */ + public Double getDistance() { + return distance; + } + + /** + * + * @return geohash if requested otherwise {@literal null}. + */ + public Long getGeohash() { + return geohash; + } + + /** + * + * @return coordinates if requested otherwise {@literal null}. + */ + public GeoCoordinates getCoordinates() { + return coordinates; + } + @Override public boolean equals(Object o) { if (this == o) diff --git a/src/test/java/biz/paluch/redis/extensibility/LettuceGeoDemo.java b/src/test/java/biz/paluch/redis/extensibility/LettuceGeoDemo.java index 770b244fd8..cc15040672 100644 --- a/src/test/java/biz/paluch/redis/extensibility/LettuceGeoDemo.java +++ b/src/test/java/biz/paluch/redis/extensibility/LettuceGeoDemo.java @@ -35,14 +35,14 @@ public static void main(String[] args) { // ordered descending by distance and containing distance/coordinates GeoWithin weinheim = georadiusWithArgs.get(0); - System.out.println("Member: " + weinheim.member); - System.out.println("Geo hash: " + weinheim.geohash); - System.out.println("Distance: " + weinheim.distance); - System.out.println("Coordinates: " + weinheim.coordinates.x + "/" + weinheim.coordinates.y); + System.out.println("Member: " + weinheim.getMember()); + System.out.println("Geo hash: " + weinheim.getGeohash()); + System.out.println("Distance: " + weinheim.getDistance()); + System.out.println("Coordinates: " + weinheim.getCoordinates().getX() + "/" + weinheim.getCoordinates().getY()); List geopos = redis.geopos(key, "Weinheim", "Train station"); GeoCoordinates weinheimGeopos = geopos.get(0); - System.out.println("Coordinates: " + weinheimGeopos.x + "/" + weinheimGeopos.y); + System.out.println("Coordinates: " + weinheimGeopos.getX() + "/" + weinheimGeopos.getY()); redis.getStatefulConnection().close(); redisClient.shutdown(); diff --git a/src/test/java/com/lambdaworks/redis/GeoModelTest.java b/src/test/java/com/lambdaworks/redis/GeoModelTest.java index a19ec88e32..a6168e7ad9 100644 --- a/src/test/java/com/lambdaworks/redis/GeoModelTest.java +++ b/src/test/java/com/lambdaworks/redis/GeoModelTest.java @@ -83,15 +83,4 @@ public void geoCoordinatesSlightlyDifferent() throws Exception { assertThat(sut.toString()).isNotEqualTo(slightlyDifferent.toString()); } - - @Test - public void geoCoordinatesEmpty() throws Exception { - - GeoCoordinates sut = new GeoCoordinates(null, null); - GeoCoordinates equalsToSut = new GeoCoordinates(null, null); - - assertThat(sut).isEqualTo(equalsToSut); - assertThat(sut.hashCode()).isEqualTo(equalsToSut.hashCode()); - } - } diff --git a/src/test/java/com/lambdaworks/redis/commands/GeoCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/GeoCommandTest.java index 429f08a39f..01da41a338 100644 --- a/src/test/java/com/lambdaworks/redis/commands/GeoCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/GeoCommandTest.java @@ -125,7 +125,7 @@ public void geopos() throws Exception { List geopos = redis.geopos(key, "Weinheim", "foobar", "Bahn"); assertThat(geopos).hasSize(3); - assertThat(geopos.get(0).x.doubleValue()).isEqualTo(8.6638, offset(0.001)); + assertThat(geopos.get(0).getX().doubleValue()).isEqualTo(8.6638, offset(0.001)); assertThat(geopos.get(1)).isNull(); assertThat(geopos.get(2)).isNotNull(); } @@ -141,7 +141,7 @@ public void geoposWithTransaction() throws Exception { List geopos = redis.exec().get(1); assertThat(geopos).hasSize(3); - assertThat(geopos.get(0).x.doubleValue()).isEqualTo(8.6638, offset(0.001)); + assertThat(geopos.get(0).getX().doubleValue()).isEqualTo(8.6638, offset(0.001)); assertThat(geopos.get(1)).isNull(); assertThat(geopos.get(2)).isNotNull(); } @@ -158,23 +158,23 @@ public void georadiusWithArgs() throws Exception { GeoWithin weinheim = result.get(0); - assertThat(weinheim.member).isEqualTo("Weinheim"); - assertThat(weinheim.geohash).isEqualTo(3666615932941099L); + assertThat(weinheim.getMember()).isEqualTo("Weinheim"); + assertThat(weinheim.getGeohash()).isEqualTo(3666615932941099L); - assertThat(weinheim.distance).isEqualTo(2.7882, offset(0.5)); - assertThat(weinheim.coordinates.x.doubleValue()).isEqualTo(8.663875, offset(0.5)); - assertThat(weinheim.coordinates.y.doubleValue()).isEqualTo(49.52825, offset(0.5)); + assertThat(weinheim.getDistance()).isEqualTo(2.7882, offset(0.5)); + assertThat(weinheim.getCoordinates().getX().doubleValue()).isEqualTo(8.663875, offset(0.5)); + assertThat(weinheim.getCoordinates().getY().doubleValue()).isEqualTo(49.52825, offset(0.5)); result = redis.georadius(key, 8.665351, 49.553302, 1, GeoArgs.Unit.km, new GeoArgs()); assertThat(result).hasSize(1); GeoWithin bahn = result.get(0); - assertThat(bahn.member).isEqualTo("Bahn"); - assertThat(bahn.geohash).isNull(); + assertThat(bahn.getMember()).isEqualTo("Bahn"); + assertThat(bahn.getGeohash()).isNull(); - assertThat(bahn.distance).isNull(); - assertThat(bahn.coordinates).isNull(); + assertThat(bahn.getDistance()).isNull(); + assertThat(bahn.getCoordinates()).isNull(); } @Test @@ -195,23 +195,23 @@ public void georadiusWithArgsAndTransaction() throws Exception { GeoWithin weinheim = result.get(0); - assertThat(weinheim.member).isEqualTo("Weinheim"); - assertThat(weinheim.geohash).isEqualTo(3666615932941099L); + assertThat(weinheim.getMember()).isEqualTo("Weinheim"); + assertThat(weinheim.getGeohash()).isEqualTo(3666615932941099L); - assertThat(weinheim.distance).isEqualTo(2.7882, offset(0.5)); - assertThat(weinheim.coordinates.x.doubleValue()).isEqualTo(8.663875, offset(0.5)); - assertThat(weinheim.coordinates.y.doubleValue()).isEqualTo(49.52825, offset(0.5)); + assertThat(weinheim.getDistance()).isEqualTo(2.7882, offset(0.5)); + assertThat(weinheim.getCoordinates().getX().doubleValue()).isEqualTo(8.663875, offset(0.5)); + assertThat(weinheim.getCoordinates().getY().doubleValue()).isEqualTo(49.52825, offset(0.5)); result = redis.georadius(key, 8.665351, 49.553302, 1, GeoArgs.Unit.km, new GeoArgs()); assertThat(result).hasSize(1); GeoWithin bahn = result.get(0); - assertThat(bahn.member).isEqualTo("Bahn"); - assertThat(bahn.geohash).isNull(); + assertThat(bahn.getMember()).isEqualTo("Bahn"); + assertThat(bahn.getGeohash()).isNull(); - assertThat(bahn.distance).isNull(); - assertThat(bahn.coordinates).isNull(); + assertThat(bahn.getDistance()).isNull(); + assertThat(bahn.getCoordinates()).isNull(); } @Test @@ -360,30 +360,30 @@ public void georadiusbymemberWithArgs() throws Exception { assertThat(withDistanceAndCoordinates).hasSize(2); GeoWithin weinheim = withDistanceAndCoordinates.get(0); - assertThat(weinheim.member).isEqualTo("Weinheim"); - assertThat(weinheim.geohash).isNull(); - assertThat(weinheim.distance).isNotNull(); - assertThat(weinheim.coordinates).isNotNull(); + assertThat(weinheim.getMember()).isEqualTo("Weinheim"); + assertThat(weinheim.getGeohash()).isNull(); + assertThat(weinheim.getDistance()).isNotNull(); + assertThat(weinheim.getCoordinates()).isNotNull(); List> withDistanceAndHash = redis.georadiusbymember(key, "Bahn", 5, GeoArgs.Unit.km, new GeoArgs().withDistance().withHash().desc()); assertThat(withDistanceAndHash).hasSize(2); GeoWithin weinheimDistanceHash = withDistanceAndHash.get(0); - assertThat(weinheimDistanceHash.member).isEqualTo("Weinheim"); - assertThat(weinheimDistanceHash.geohash).isNotNull(); - assertThat(weinheimDistanceHash.distance).isNotNull(); - assertThat(weinheimDistanceHash.coordinates).isNull(); + assertThat(weinheimDistanceHash.getMember()).isEqualTo("Weinheim"); + assertThat(weinheimDistanceHash.getGeohash()).isNotNull(); + assertThat(weinheimDistanceHash.getDistance()).isNotNull(); + assertThat(weinheimDistanceHash.getCoordinates()).isNull(); List> withCoordinates = redis.georadiusbymember(key, "Bahn", 5, GeoArgs.Unit.km, new GeoArgs().withCoordinates().desc()); assertThat(withCoordinates).hasSize(2); GeoWithin weinheimCoordinates = withCoordinates.get(0); - assertThat(weinheimCoordinates.member).isEqualTo("Weinheim"); - assertThat(weinheimCoordinates.geohash).isNull(); - assertThat(weinheimCoordinates.distance).isNull(); - assertThat(weinheimCoordinates.coordinates).isNotNull(); + assertThat(weinheimCoordinates.getMember()).isEqualTo("Weinheim"); + assertThat(weinheimCoordinates.getGeohash()).isNull(); + assertThat(weinheimCoordinates.getDistance()).isNull(); + assertThat(weinheimCoordinates.getCoordinates()).isNotNull(); } @Test @@ -407,28 +407,28 @@ public void georadiusbymemberWithArgsAndTransaction() throws Exception { assertThat(withDistanceAndCoordinates).hasSize(2); GeoWithin weinheim = withDistanceAndCoordinates.get(0); - assertThat(weinheim.member).isEqualTo("Weinheim"); - assertThat(weinheim.geohash).isNull(); - assertThat(weinheim.distance).isNotNull(); - assertThat(weinheim.coordinates).isNotNull(); + assertThat(weinheim.getMember()).isEqualTo("Weinheim"); + assertThat(weinheim.getGeohash()).isNull(); + assertThat(weinheim.getDistance()).isNotNull(); + assertThat(weinheim.getCoordinates()).isNotNull(); List> withDistanceAndHash = exec.get(2); assertThat(withDistanceAndHash).hasSize(2); GeoWithin weinheimDistanceHash = withDistanceAndHash.get(0); - assertThat(weinheimDistanceHash.member).isEqualTo("Weinheim"); - assertThat(weinheimDistanceHash.geohash).isNotNull(); - assertThat(weinheimDistanceHash.distance).isNotNull(); - assertThat(weinheimDistanceHash.coordinates).isNull(); + assertThat(weinheimDistanceHash.getMember()).isEqualTo("Weinheim"); + assertThat(weinheimDistanceHash.getGeohash()).isNotNull(); + assertThat(weinheimDistanceHash.getDistance()).isNotNull(); + assertThat(weinheimDistanceHash.getCoordinates()).isNull(); List> withCoordinates = exec.get(3); assertThat(withCoordinates).hasSize(2); GeoWithin weinheimCoordinates = withCoordinates.get(0); - assertThat(weinheimCoordinates.member).isEqualTo("Weinheim"); - assertThat(weinheimCoordinates.geohash).isNull(); - assertThat(weinheimCoordinates.distance).isNull(); - assertThat(weinheimCoordinates.coordinates).isNotNull(); + assertThat(weinheimCoordinates.getMember()).isEqualTo("Weinheim"); + assertThat(weinheimCoordinates.getGeohash()).isNull(); + assertThat(weinheimCoordinates.getDistance()).isNull(); + assertThat(weinheimCoordinates.getCoordinates()).isNotNull(); } @Test(expected = IllegalArgumentException.class) diff --git a/src/test/java/com/lambdaworks/redis/commands/reactive/GeoReactiveCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/reactive/GeoReactiveCommandTest.java index 4a6940458a..ee5b74020f 100644 --- a/src/test/java/com/lambdaworks/redis/commands/reactive/GeoReactiveCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/reactive/GeoReactiveCommandTest.java @@ -32,7 +32,7 @@ public void geopos() throws Exception { List> geopos = reactive.geopos(key, "Weinheim", "foobar", "Bahn").collectList().block(); assertThat(geopos).hasSize(3); - assertThat(geopos.get(0).getValue().x.doubleValue()).isEqualTo(8.6638, offset(0.001)); + assertThat(geopos.get(0).getValue().getX().doubleValue()).isEqualTo(8.6638, offset(0.001)); assertThat(geopos.get(1).hasValue()).isFalse(); assertThat(geopos.get(2).hasValue()).isTrue(); } From b7f7e91af9f5ac16643065f09147c61825d45d2c Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Sat, 3 Sep 2016 19:01:18 +0200 Subject: [PATCH 018/808] Polishing Reduce field visibility. Replace StringBuffer by StringBuilder. Reorder fields. Move constructor field initialization to field initialization. --- .../java/com/lambdaworks/redis/CloseEvents.java | 1 + .../lambdaworks/redis/ConnectionEventTrigger.java | 1 + .../com/lambdaworks/redis/ConnectionEvents.java | 1 + .../java/com/lambdaworks/redis/EpollProvider.java | 7 ++++--- .../java/com/lambdaworks/redis/GeoWithin.java | 2 +- .../java/com/lambdaworks/redis/JavaRuntime.java | 2 +- .../redis/PlainChannelInitializer.java | 5 +++-- src/main/java/com/lambdaworks/redis/ReadFrom.java | 8 ++++---- .../lambdaworks/redis/RedisChannelHandler.java | 15 +++++++-------- .../redis/RedisChannelInitializerImpl.java | 2 +- .../java/com/lambdaworks/redis/RedisClient.java | 4 ++-- .../redis/RedisConnectionStateListener.java | 1 + .../com/lambdaworks/redis/RedisException.java | 1 + .../com/lambdaworks/redis/RedisPublisher.java | 4 ++-- .../java/com/lambdaworks/redis/ScanCursor.java | 4 ++-- .../java/com/lambdaworks/redis/ScoredValue.java | 2 +- src/main/java/com/lambdaworks/redis/SetArgs.java | 1 + src/main/java/com/lambdaworks/redis/SortArgs.java | 1 + .../lambdaworks/redis/SslConnectionBuilder.java | 9 +++++---- src/main/java/com/lambdaworks/redis/Value.java | 2 +- src/main/java/com/lambdaworks/redis/ZAddArgs.java | 1 + .../java/com/lambdaworks/redis/ZStoreArgs.java | 1 + .../redis/cluster/AbstractNodeSelection.java | 3 ++- .../lambdaworks/redis/cluster/ClusterCommand.java | 5 +++-- .../cluster/ClusterDistributionChannelWriter.java | 4 +--- .../redis/cluster/ClusterScanSupport.java | 8 ++++---- .../redis/cluster/MultiNodeExecution.java | 1 + .../cluster/NodeSelectionInvocationHandler.java | 11 +++++++---- .../redis/cluster/PipelinedRedisFuture.java | 2 +- .../cluster/PooledClusterConnectionProvider.java | 5 +++-- .../redis/cluster/ReadOnlyCommands.java | 2 +- .../RedisAdvancedClusterAsyncCommandsImpl.java | 2 +- .../RedisAdvancedClusterReactiveCommandsImpl.java | 2 +- .../redis/cluster/RedisClusterClient.java | 6 +++--- .../com/lambdaworks/redis/cluster/RoundRobin.java | 1 + .../cluster/RoundRobinSocketAddressSupplier.java | 2 ++ .../StatefulRedisClusterConnectionImpl.java | 2 +- .../event/ClusterTopologyChangedEvent.java | 3 ++- .../cluster/models/partitions/Partitions.java | 3 ++- .../cluster/models/slots/ClusterSlotRange.java | 1 + .../lambdaworks/redis/codec/ByteArrayCodec.java | 4 ++-- .../com/lambdaworks/redis/codec/StringCodec.java | 6 +++--- .../lambdaworks/redis/codec/Utf8StringCodec.java | 2 +- .../event/connection/ConnectionEventSupport.java | 10 +++------- .../redis/event/metrics/CommandLatencyEvent.java | 2 +- .../redis/internal/LettuceFactories.java | 4 ++-- .../redis/masterslave/MasterSlave.java | 2 +- .../MasterSlaveConnectionProvider.java | 3 +-- .../masterslave/MasterSlaveTopologyProvider.java | 12 ++++++------ .../masterslave/MasterSlaveTopologyRefresh.java | 2 +- .../redis/masterslave/ReadOnlyCommands.java | 2 +- .../redis/masterslave/RedisMasterSlaveNode.java | 2 +- .../masterslave/SentinelTopologyRefresh.java | 2 +- .../redis/metrics/CommandLatencyId.java | 2 +- .../lambdaworks/redis/metrics/CommandMetrics.java | 4 ++-- .../metrics/DefaultCommandLatencyCollector.java | 2 +- .../lambdaworks/redis/protocol/AsyncCommand.java | 2 +- .../redis/protocol/BaseRedisCommandBuilder.java | 1 + .../lambdaworks/redis/protocol/CommandArgs.java | 6 +++--- .../redis/protocol/CommandEncoder.java | 13 ++----------- .../redis/protocol/CommandHandler.java | 11 ++--------- .../redis/protocol/CommandKeyword.java | 1 + .../redis/protocol/CommandWrapper.java | 4 ++-- .../redis/protocol/ConnectionWatchdog.java | 1 - .../redis/protocol/DefaultEndpoint.java | 10 ++-------- .../redis/protocol/RedisStateMachine.java | 11 ++++------- .../lambdaworks/redis/protocol/SharedLock.java | 2 +- .../redis/pubsub/PubSubCommandHandler.java | 4 ++-- .../lambdaworks/redis/pubsub/PubSubOutput.java | 1 + .../redis/pubsub/RedisPubSubAdapter.java | 1 + .../pubsub/RedisPubSubAsyncCommandsImpl.java | 2 +- .../redis/resource/DirContextDnsResolver.java | 6 +++--- 72 files changed, 135 insertions(+), 140 deletions(-) diff --git a/src/main/java/com/lambdaworks/redis/CloseEvents.java b/src/main/java/com/lambdaworks/redis/CloseEvents.java index 05476d44ec..0be034dfcd 100644 --- a/src/main/java/com/lambdaworks/redis/CloseEvents.java +++ b/src/main/java/com/lambdaworks/redis/CloseEvents.java @@ -11,6 +11,7 @@ * @since 3.0 */ class CloseEvents { + private Set listeners = new ConcurrentSet(); public void fireEventClosed(Object resource) { diff --git a/src/main/java/com/lambdaworks/redis/ConnectionEventTrigger.java b/src/main/java/com/lambdaworks/redis/ConnectionEventTrigger.java index 81b73625c7..1810554d85 100644 --- a/src/main/java/com/lambdaworks/redis/ConnectionEventTrigger.java +++ b/src/main/java/com/lambdaworks/redis/ConnectionEventTrigger.java @@ -16,6 +16,7 @@ * @since 3.0 */ class ConnectionEventTrigger extends ChannelInboundHandlerAdapter { + private final ConnectionEvents connectionEvents; private final RedisChannelHandler connection; private final EventBus eventBus; diff --git a/src/main/java/com/lambdaworks/redis/ConnectionEvents.java b/src/main/java/com/lambdaworks/redis/ConnectionEvents.java index f4ca0615b5..e0309b8b26 100644 --- a/src/main/java/com/lambdaworks/redis/ConnectionEvents.java +++ b/src/main/java/com/lambdaworks/redis/ConnectionEvents.java @@ -12,6 +12,7 @@ * @since 3.0 */ public class ConnectionEvents { + private final Set listeners = new ConcurrentSet<>(); protected void fireEventRedisConnected(RedisChannelHandler connection) { diff --git a/src/main/java/com/lambdaworks/redis/EpollProvider.java b/src/main/java/com/lambdaworks/redis/EpollProvider.java index 95e1bf6447..b8323666e8 100644 --- a/src/main/java/com/lambdaworks/redis/EpollProvider.java +++ b/src/main/java/com/lambdaworks/redis/EpollProvider.java @@ -23,9 +23,10 @@ public class EpollProvider { protected static final InternalLogger logger = InternalLoggerFactory.getInstance(EpollProvider.class); - public final static Class epollEventLoopGroupClass; - public final static Class epollDomainSocketChannelClass; - public final static Class domainSocketAddressClass; + public static final Class epollEventLoopGroupClass; + public static final Class epollDomainSocketChannelClass; + public static final Class domainSocketAddressClass; + static { epollEventLoopGroupClass = getClass("io.netty.channel.epoll.EpollEventLoopGroup"); diff --git a/src/main/java/com/lambdaworks/redis/GeoWithin.java b/src/main/java/com/lambdaworks/redis/GeoWithin.java index 6d1c765f02..a17b9359b5 100644 --- a/src/main/java/com/lambdaworks/redis/GeoWithin.java +++ b/src/main/java/com/lambdaworks/redis/GeoWithin.java @@ -96,7 +96,7 @@ public int hashCode() { @Override public String toString() { - final StringBuffer sb = new StringBuffer(); + StringBuilder sb = new StringBuilder(); sb.append(getClass().getSimpleName()); sb.append(" [member=").append(member); sb.append(", distance=").append(distance); diff --git a/src/main/java/com/lambdaworks/redis/JavaRuntime.java b/src/main/java/com/lambdaworks/redis/JavaRuntime.java index 46fbfb57a9..ed8ee58eb7 100644 --- a/src/main/java/com/lambdaworks/redis/JavaRuntime.java +++ b/src/main/java/com/lambdaworks/redis/JavaRuntime.java @@ -12,6 +12,6 @@ public class JavaRuntime { /** * Constant whether the current JDK is Java 8 or higher. */ - public final static boolean AT_LEAST_JDK_8 = isPresent("java.lang.FunctionalInterface"); + public static final boolean AT_LEAST_JDK_8 = isPresent("java.lang.FunctionalInterface"); } diff --git a/src/main/java/com/lambdaworks/redis/PlainChannelInitializer.java b/src/main/java/com/lambdaworks/redis/PlainChannelInitializer.java index d6aa81ef17..83131cbf2a 100644 --- a/src/main/java/com/lambdaworks/redis/PlainChannelInitializer.java +++ b/src/main/java/com/lambdaworks/redis/PlainChannelInitializer.java @@ -24,12 +24,13 @@ */ class PlainChannelInitializer extends io.netty.channel.ChannelInitializer implements RedisChannelInitializer { - final static RedisCommandBuilder INITIALIZING_CMD_BUILDER = new RedisCommandBuilder<>( + static final RedisCommandBuilder INITIALIZING_CMD_BUILDER = new RedisCommandBuilder<>( new Utf8StringCodec()); + protected final char[] password; + private boolean pingBeforeActivate; private CompletableFuture initializedFuture = new CompletableFuture<>(); - protected final char[] password; private final Supplier> handlers; private final EventBus eventBus; diff --git a/src/main/java/com/lambdaworks/redis/ReadFrom.java b/src/main/java/com/lambdaworks/redis/ReadFrom.java index ea878616d6..c727c18a78 100644 --- a/src/main/java/com/lambdaworks/redis/ReadFrom.java +++ b/src/main/java/com/lambdaworks/redis/ReadFrom.java @@ -15,22 +15,22 @@ public abstract class ReadFrom { /** * Setting to read from the master only. */ - public final static ReadFrom MASTER = new ReadFromImpl.ReadFromMaster(); + public static final ReadFrom MASTER = new ReadFromImpl.ReadFromMaster(); /** * Setting to read preferred from the master and fall back to a slave if the master is not available. */ - public final static ReadFrom MASTER_PREFERRED = new ReadFromImpl.ReadFromMasterPreferred(); + public static final ReadFrom MASTER_PREFERRED = new ReadFromImpl.ReadFromMasterPreferred(); /** * Setting to read from the slave only. */ - public final static ReadFrom SLAVE = new ReadFromImpl.ReadFromSlave(); + public static final ReadFrom SLAVE = new ReadFromImpl.ReadFromSlave(); /** * Setting to read from the nearest node. */ - public final static ReadFrom NEAREST = new ReadFromImpl.ReadFromNearest(); + public static final ReadFrom NEAREST = new ReadFromImpl.ReadFromNearest(); /** * Chooses the nodes from the matching Redis nodes that match this read selector. diff --git a/src/main/java/com/lambdaworks/redis/RedisChannelHandler.java b/src/main/java/com/lambdaworks/redis/RedisChannelHandler.java index 8be11b9474..f7b2e4c284 100644 --- a/src/main/java/com/lambdaworks/redis/RedisChannelHandler.java +++ b/src/main/java/com/lambdaworks/redis/RedisChannelHandler.java @@ -27,17 +27,16 @@ public abstract class RedisChannelHandler implements Closeable, Connection private static final InternalLogger logger = InternalLoggerFactory.getInstance(RedisChannelHandler.class); - protected long timeout; - protected TimeUnit unit; - + private long timeout; + private TimeUnit unit; private CloseEvents closeEvents = new CloseEvents(); + private final RedisChannelWriter channelWriter; + private final boolean debugEnabled = logger.isDebugEnabled(); + private volatile boolean closed; private volatile boolean active = true; private volatile ClientOptions clientOptions; - - // If DEBUG level logging has been enabled at startup. - private final boolean debugEnabled; /** * @param writer the channel writer @@ -47,8 +46,7 @@ public abstract class RedisChannelHandler implements Closeable, Connection public RedisChannelHandler(RedisChannelWriter writer, long timeout, TimeUnit unit) { this.channelWriter = writer; - debugEnabled = logger.isDebugEnabled(); - + writer.setConnectionFacade(this); setTimeout(timeout, unit); } @@ -60,6 +58,7 @@ public RedisChannelHandler(RedisChannelWriter writer, long timeout, TimeUnit uni * @param unit Unit of time for the timeout. */ public void setTimeout(long timeout, TimeUnit unit) { + this.timeout = timeout; this.unit = unit; } diff --git a/src/main/java/com/lambdaworks/redis/RedisChannelInitializerImpl.java b/src/main/java/com/lambdaworks/redis/RedisChannelInitializerImpl.java index 9381ae63a3..66a7a51601 100644 --- a/src/main/java/com/lambdaworks/redis/RedisChannelInitializerImpl.java +++ b/src/main/java/com/lambdaworks/redis/RedisChannelInitializerImpl.java @@ -7,5 +7,5 @@ * * @author Mark Paluch */ -public abstract class RedisChannelInitializerImpl extends ChannelDuplexHandler implements RedisChannelInitializer { +abstract class RedisChannelInitializerImpl extends ChannelDuplexHandler implements RedisChannelInitializer { } diff --git a/src/main/java/com/lambdaworks/redis/RedisClient.java b/src/main/java/com/lambdaworks/redis/RedisClient.java index a8ecc2e2fe..cdcc455459 100644 --- a/src/main/java/com/lambdaworks/redis/RedisClient.java +++ b/src/main/java/com/lambdaworks/redis/RedisClient.java @@ -41,8 +41,8 @@ */ public class RedisClient extends AbstractRedisClient { - private final static RedisURI EMPTY_URI = new RedisURI(); - private final static boolean POOL_AVAILABLE = isPresent("org.apache.commons.pool2.impl.GenericObjectPool"); + private static final RedisURI EMPTY_URI = new RedisURI(); + private static final boolean POOL_AVAILABLE = isPresent("org.apache.commons.pool2.impl.GenericObjectPool"); private final RedisURI redisURI; diff --git a/src/main/java/com/lambdaworks/redis/RedisConnectionStateListener.java b/src/main/java/com/lambdaworks/redis/RedisConnectionStateListener.java index 2ebaf139a2..66662c9add 100644 --- a/src/main/java/com/lambdaworks/redis/RedisConnectionStateListener.java +++ b/src/main/java/com/lambdaworks/redis/RedisConnectionStateListener.java @@ -7,6 +7,7 @@ * @author ze */ public interface RedisConnectionStateListener { + /** * Event handler for successful connection event. * diff --git a/src/main/java/com/lambdaworks/redis/RedisException.java b/src/main/java/com/lambdaworks/redis/RedisException.java index c9f78826b5..5400e50426 100644 --- a/src/main/java/com/lambdaworks/redis/RedisException.java +++ b/src/main/java/com/lambdaworks/redis/RedisException.java @@ -9,6 +9,7 @@ */ @SuppressWarnings("serial") public class RedisException extends RuntimeException { + public RedisException(String msg) { super(msg); } diff --git a/src/main/java/com/lambdaworks/redis/RedisPublisher.java b/src/main/java/com/lambdaworks/redis/RedisPublisher.java index 9ab50c4017..eb2dfea4e0 100644 --- a/src/main/java/com/lambdaworks/redis/RedisPublisher.java +++ b/src/main/java/com/lambdaworks/redis/RedisPublisher.java @@ -41,7 +41,7 @@ */ class RedisPublisher implements Publisher { - private final static InternalLogger LOG = InternalLoggerFactory.getInstance(RedisPublisher.class); + private static final InternalLogger LOG = InternalLoggerFactory.getInstance(RedisPublisher.class); private final boolean traceEnabled = LOG.isTraceEnabled(); @@ -111,7 +111,7 @@ public void subscribe(Subscriber subscriber) { */ private static class RedisSubscription implements Subscription, StreamingOutput.Subscriber { - private final static InternalLogger LOG = InternalLoggerFactory.getInstance(RedisPublisher.class); + private static final InternalLogger LOG = InternalLoggerFactory.getInstance(RedisPublisher.class); private final boolean traceEnabled = LOG.isTraceEnabled(); private final AtomicLong demand = new AtomicLong(); diff --git a/src/main/java/com/lambdaworks/redis/ScanCursor.java b/src/main/java/com/lambdaworks/redis/ScanCursor.java index d18082e706..297f8d2ad7 100644 --- a/src/main/java/com/lambdaworks/redis/ScanCursor.java +++ b/src/main/java/com/lambdaworks/redis/ScanCursor.java @@ -13,12 +13,12 @@ public class ScanCursor { /** * Finished cursor. */ - public final static ScanCursor FINISHED = new ImmutableScanCursor("0", true); + public static final ScanCursor FINISHED = new ImmutableScanCursor("0", true); /** * Initial cursor. */ - public final static ScanCursor INITIAL = new ImmutableScanCursor("0", false); + public static final ScanCursor INITIAL = new ImmutableScanCursor("0", false); private String cursor; private boolean finished; diff --git a/src/main/java/com/lambdaworks/redis/ScoredValue.java b/src/main/java/com/lambdaworks/redis/ScoredValue.java index 54b902aaf1..f3530ea243 100644 --- a/src/main/java/com/lambdaworks/redis/ScoredValue.java +++ b/src/main/java/com/lambdaworks/redis/ScoredValue.java @@ -14,7 +14,7 @@ */ public class ScoredValue extends Value { - private final static ScoredValue EMPTY = new ScoredValue<>(0, null); + private static final ScoredValue EMPTY = new ScoredValue<>(0, null); private final double score; diff --git a/src/main/java/com/lambdaworks/redis/SetArgs.java b/src/main/java/com/lambdaworks/redis/SetArgs.java index e35cad1c61..53b03b566b 100644 --- a/src/main/java/com/lambdaworks/redis/SetArgs.java +++ b/src/main/java/com/lambdaworks/redis/SetArgs.java @@ -12,6 +12,7 @@ * @author Vincent Rischmann */ public class SetArgs { + private Long ex; private Long px; private boolean nx = false; diff --git a/src/main/java/com/lambdaworks/redis/SortArgs.java b/src/main/java/com/lambdaworks/redis/SortArgs.java index e4219e9fdd..87b6a08942 100644 --- a/src/main/java/com/lambdaworks/redis/SortArgs.java +++ b/src/main/java/com/lambdaworks/redis/SortArgs.java @@ -18,6 +18,7 @@ * @author Will Glozer */ public class SortArgs { + private String by; private Long offset, count; private List get; diff --git a/src/main/java/com/lambdaworks/redis/SslConnectionBuilder.java b/src/main/java/com/lambdaworks/redis/SslConnectionBuilder.java index 1c256cbb8a..3cbf7bbb10 100644 --- a/src/main/java/com/lambdaworks/redis/SslConnectionBuilder.java +++ b/src/main/java/com/lambdaworks/redis/SslConnectionBuilder.java @@ -38,17 +38,18 @@ * @author Mark Paluch */ public class SslConnectionBuilder extends ConnectionBuilder { - private RedisURI redisURI; - public static SslConnectionBuilder sslConnectionBuilder() { - return new SslConnectionBuilder(); - } + private RedisURI redisURI; public SslConnectionBuilder ssl(RedisURI redisURI) { this.redisURI = redisURI; return this; } + public static SslConnectionBuilder sslConnectionBuilder() { + return new SslConnectionBuilder(); + } + @Override protected List buildHandlers() { LettuceAssert.assertState(redisURI != null, "RedisURI must not be null"); diff --git a/src/main/java/com/lambdaworks/redis/Value.java b/src/main/java/com/lambdaworks/redis/Value.java index 6f2af1204d..7c28f6e1a9 100644 --- a/src/main/java/com/lambdaworks/redis/Value.java +++ b/src/main/java/com/lambdaworks/redis/Value.java @@ -22,7 +22,7 @@ */ public class Value implements Serializable { - private final static Value EMPTY = new Value<>(null); + private static final Value EMPTY = new Value<>(null); private final V value; diff --git a/src/main/java/com/lambdaworks/redis/ZAddArgs.java b/src/main/java/com/lambdaworks/redis/ZAddArgs.java index f3c3059615..1a5fd103b8 100644 --- a/src/main/java/com/lambdaworks/redis/ZAddArgs.java +++ b/src/main/java/com/lambdaworks/redis/ZAddArgs.java @@ -9,6 +9,7 @@ * @author Mark Paluch */ public class ZAddArgs { + private boolean nx = false; private boolean xx = false; private boolean ch = false; diff --git a/src/main/java/com/lambdaworks/redis/ZStoreArgs.java b/src/main/java/com/lambdaworks/redis/ZStoreArgs.java index 1117caa92a..a0d74629c8 100644 --- a/src/main/java/com/lambdaworks/redis/ZStoreArgs.java +++ b/src/main/java/com/lambdaworks/redis/ZStoreArgs.java @@ -17,6 +17,7 @@ * @author Will Glozer */ public class ZStoreArgs { + private static enum Aggregate { SUM, MIN, MAX } diff --git a/src/main/java/com/lambdaworks/redis/cluster/AbstractNodeSelection.java b/src/main/java/com/lambdaworks/redis/cluster/AbstractNodeSelection.java index 93625c45fd..f0f3271315 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/AbstractNodeSelection.java +++ b/src/main/java/com/lambdaworks/redis/cluster/AbstractNodeSelection.java @@ -22,9 +22,10 @@ */ abstract class AbstractNodeSelection implements NodeSelectionSupport { + protected ClusterDistributionChannelWriter writer; protected StatefulRedisClusterConnection globalConnection; + private ClusterConnectionProvider.Intent intent; - protected ClusterDistributionChannelWriter writer; public AbstractNodeSelection(StatefulRedisClusterConnection globalConnection, ClusterConnectionProvider.Intent intent) { this.globalConnection = globalConnection; diff --git a/src/main/java/com/lambdaworks/redis/cluster/ClusterCommand.java b/src/main/java/com/lambdaworks/redis/cluster/ClusterCommand.java index 51375b41d6..9b8935b299 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/ClusterCommand.java +++ b/src/main/java/com/lambdaworks/redis/cluster/ClusterCommand.java @@ -14,9 +14,10 @@ */ class ClusterCommand extends CommandWrapper implements RedisCommand { - private RedisChannelWriter retry; private int redirections; - private int maxRedirections; + private final int maxRedirections; + + private final RedisChannelWriter retry; private boolean completed; /** diff --git a/src/main/java/com/lambdaworks/redis/cluster/ClusterDistributionChannelWriter.java b/src/main/java/com/lambdaworks/redis/cluster/ClusterDistributionChannelWriter.java index cb5c7a77c6..6e85bba035 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/ClusterDistributionChannelWriter.java +++ b/src/main/java/com/lambdaworks/redis/cluster/ClusterDistributionChannelWriter.java @@ -23,12 +23,10 @@ class ClusterDistributionChannelWriter implements RedisChannelWriter { private final ClusterEventListener clusterEventListener; private final EventExecutorGroup eventExecutors; private final int executionLimit; + private ClusterConnectionProvider clusterConnectionProvider; private boolean closed = false; - long p20, p21, p22, p23, p24, p25, p26; - long p30, p31, p32, p33, p34, p35, p36, p37; - ClusterDistributionChannelWriter(ClientOptions clientOptions, RedisChannelWriter defaultWriter, ClusterEventListener clusterEventListener, EventExecutorGroup eventExecutors) { diff --git a/src/main/java/com/lambdaworks/redis/cluster/ClusterScanSupport.java b/src/main/java/com/lambdaworks/redis/cluster/ClusterScanSupport.java index 9838f51779..afa9cb53fb 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/ClusterScanSupport.java +++ b/src/main/java/com/lambdaworks/redis/cluster/ClusterScanSupport.java @@ -22,7 +22,7 @@ class ClusterScanSupport { /** * Map a {@link RedisFuture} of {@link KeyScanCursor} to a {@link RedisFuture} of {@link ClusterKeyScanCursor}. */ - final static ScanCursorMapper>> futureKeyScanCursorMapper = new ScanCursorMapper>>() { + static final ScanCursorMapper>> futureKeyScanCursorMapper = new ScanCursorMapper>>() { @Override public RedisFuture> map(List nodeIds, String currentNodeId, RedisFuture> cursor) { @@ -38,7 +38,7 @@ public KeyScanCursor apply(KeyScanCursor result) { /** * Map a {@link RedisFuture} of {@link StreamScanCursor} to a {@link RedisFuture} of {@link ClusterStreamScanCursor}. */ - final static ScanCursorMapper> futureStreamScanCursorMapper = new ScanCursorMapper>() { + static final ScanCursorMapper> futureStreamScanCursorMapper = new ScanCursorMapper>() { @Override public RedisFuture map(List nodeIds, String currentNodeId, RedisFuture cursor) { @@ -54,13 +54,13 @@ public StreamScanCursor apply(StreamScanCursor result) { /** * Map a {@link Mono} of {@link KeyScanCursor} to a {@link Mono} of {@link ClusterKeyScanCursor}. */ - final static ScanCursorMapper>> reactiveKeyScanCursorMapper = (nodeIds, currentNodeId, + static final ScanCursorMapper>> reactiveKeyScanCursorMapper = (nodeIds, currentNodeId, cursor) -> cursor.map(keyScanCursor -> new ClusterKeyScanCursor<>(nodeIds, currentNodeId, keyScanCursor)); /** * Map a {@link Mono} of {@link StreamScanCursor} to a {@link Mono} of {@link ClusterStreamScanCursor}. */ - final static ScanCursorMapper> reactiveStreamScanCursorMapper = (nodeIds, currentNodeId, + static final ScanCursorMapper> reactiveStreamScanCursorMapper = (nodeIds, currentNodeId, cursor) -> cursor.map(new Function() { @Override public StreamScanCursor apply(StreamScanCursor streamScanCursor) { diff --git a/src/main/java/com/lambdaworks/redis/cluster/MultiNodeExecution.java b/src/main/java/com/lambdaworks/redis/cluster/MultiNodeExecution.java index 5417420baf..1418b9f554 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/MultiNodeExecution.java +++ b/src/main/java/com/lambdaworks/redis/cluster/MultiNodeExecution.java @@ -24,6 +24,7 @@ * @author Mark Paluch */ class MultiNodeExecution { + static T execute(Callable function) { try { return function.call(); diff --git a/src/main/java/com/lambdaworks/redis/cluster/NodeSelectionInvocationHandler.java b/src/main/java/com/lambdaworks/redis/cluster/NodeSelectionInvocationHandler.java index 38d7e95145..dcec2426d4 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/NodeSelectionInvocationHandler.java +++ b/src/main/java/com/lambdaworks/redis/cluster/NodeSelectionInvocationHandler.java @@ -23,13 +23,15 @@ */ class NodeSelectionInvocationHandler extends AbstractInvocationHandler { + private static final Method NULL_MARKER_METHOD; + + private final Map nodeSelectionMethods = new ConcurrentHashMap<>(); + private final Map connectionMethod = new ConcurrentHashMap<>(); + private AbstractNodeSelection selection; private boolean sync; private long timeout; private TimeUnit unit; - private final Map nodeSelectionMethods = new ConcurrentHashMap<>(); - private final Map connectionMethod = new ConcurrentHashMap<>(); - public final static Method NULL_MARKER_METHOD; static { try { @@ -44,7 +46,8 @@ public NodeSelectionInvocationHandler(AbstractNodeSelection selectio this(selection, false, 0, null); } - public NodeSelectionInvocationHandler(AbstractNodeSelection selection, boolean sync, long timeout, TimeUnit unit) { + public NodeSelectionInvocationHandler(AbstractNodeSelection selection, boolean sync, long timeout, + TimeUnit unit) { if (sync) { LettuceAssert.isTrue(timeout > 0, "Timeout must be greater 0 when using sync mode"); LettuceAssert.notNull(unit, "Unit must not be null when using sync mode"); diff --git a/src/main/java/com/lambdaworks/redis/cluster/PipelinedRedisFuture.java b/src/main/java/com/lambdaworks/redis/cluster/PipelinedRedisFuture.java index d4090c740c..ae83fbd2da 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/PipelinedRedisFuture.java +++ b/src/main/java/com/lambdaworks/redis/cluster/PipelinedRedisFuture.java @@ -16,7 +16,7 @@ */ class PipelinedRedisFuture extends CompletableFuture implements RedisFuture { - private CountDownLatch latch = new CountDownLatch(1); + private final CountDownLatch latch = new CountDownLatch(1); public PipelinedRedisFuture(CompletionStage completionStage, Function converter) { completionStage.thenAccept(v -> complete(converter.apply(v))) diff --git a/src/main/java/com/lambdaworks/redis/cluster/PooledClusterConnectionProvider.java b/src/main/java/com/lambdaworks/redis/cluster/PooledClusterConnectionProvider.java index a290f96ba2..7c4ff9b0e9 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/PooledClusterConnectionProvider.java +++ b/src/main/java/com/lambdaworks/redis/cluster/PooledClusterConnectionProvider.java @@ -34,12 +34,13 @@ */ @SuppressWarnings({ "unchecked", "rawtypes" }) class PooledClusterConnectionProvider implements ClusterConnectionProvider { + private static final InternalLogger logger = InternalLoggerFactory.getInstance(PooledClusterConnectionProvider.class); // Contains NodeId-identified and HostAndPort-identified connections. private final Map> connections = new ConcurrentHashMap<>(); private final Object stateLock = new Object(); - private final boolean debugEnabled; + private final boolean debugEnabled = logger.isDebugEnabled(); private final StatefulRedisConnection writers[] = new StatefulRedisConnection[SlotHash.SLOT_COUNT]; private final StatefulRedisConnection readers[][] = new StatefulRedisConnection[SlotHash.SLOT_COUNT][]; private final RedisClusterClient redisClusterClient; @@ -51,8 +52,8 @@ class PooledClusterConnectionProvider implements ClusterConnectionProvider public PooledClusterConnectionProvider(RedisClusterClient redisClusterClient, RedisChannelWriter clusterWriter, RedisCodec redisCodec) { + this.redisClusterClient = redisClusterClient; - this.debugEnabled = logger.isDebugEnabled(); this.connectionFactory = new ConnectionFactory(redisClusterClient, redisCodec, clusterWriter); } diff --git a/src/main/java/com/lambdaworks/redis/cluster/ReadOnlyCommands.java b/src/main/java/com/lambdaworks/redis/cluster/ReadOnlyCommands.java index 22e9846cc6..95088c4c89 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/ReadOnlyCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/ReadOnlyCommands.java @@ -13,7 +13,7 @@ */ class ReadOnlyCommands { - public final static ProtocolKeyword READ_ONLY_COMMANDS[]; + static final ProtocolKeyword READ_ONLY_COMMANDS[]; static { diff --git a/src/main/java/com/lambdaworks/redis/cluster/RedisAdvancedClusterAsyncCommandsImpl.java b/src/main/java/com/lambdaworks/redis/cluster/RedisAdvancedClusterAsyncCommandsImpl.java index 3db9c0ff02..39882bf075 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/RedisAdvancedClusterAsyncCommandsImpl.java +++ b/src/main/java/com/lambdaworks/redis/cluster/RedisAdvancedClusterAsyncCommandsImpl.java @@ -44,7 +44,7 @@ public class RedisAdvancedClusterAsyncCommandsImpl extends AbstractRedisAsyncCommands implements RedisAdvancedClusterAsyncCommands { - private Random random = new Random(); + private final Random random = new Random(); /** * Initialize a new connection. diff --git a/src/main/java/com/lambdaworks/redis/cluster/RedisAdvancedClusterReactiveCommandsImpl.java b/src/main/java/com/lambdaworks/redis/cluster/RedisAdvancedClusterReactiveCommandsImpl.java index f2eb5c4cc0..4d69878e1e 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/RedisAdvancedClusterReactiveCommandsImpl.java +++ b/src/main/java/com/lambdaworks/redis/cluster/RedisAdvancedClusterReactiveCommandsImpl.java @@ -36,7 +36,7 @@ public class RedisAdvancedClusterReactiveCommandsImpl extends AbstractRedisReactiveCommands implements RedisAdvancedClusterReactiveCommands { - private Random random = new Random(); + private final Random random = new Random(); /** * Initialize a new connection. diff --git a/src/main/java/com/lambdaworks/redis/cluster/RedisClusterClient.java b/src/main/java/com/lambdaworks/redis/cluster/RedisClusterClient.java index 01991e40ae..8137f700a7 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/RedisClusterClient.java +++ b/src/main/java/com/lambdaworks/redis/cluster/RedisClusterClient.java @@ -114,15 +114,15 @@ public class RedisClusterClient extends AbstractRedisClient { private static final InternalLogger logger = InternalLoggerFactory.getInstance(RedisClusterClient.class); - protected AtomicBoolean clusterTopologyRefreshActivated = new AtomicBoolean(false); - protected AtomicReference> clusterTopologyRefreshFuture = new AtomicReference<>(); + protected final AtomicBoolean clusterTopologyRefreshActivated = new AtomicBoolean(false); + protected final AtomicReference> clusterTopologyRefreshFuture = new AtomicReference<>(); private final ClusterTopologyRefresh refresh = new ClusterTopologyRefresh(new NodeConnectionFactoryImpl(), getResources()); private final ClusterTopologyRefreshScheduler clusterTopologyRefreshScheduler = new ClusterTopologyRefreshScheduler(this, getResources()); + private final Iterable initialUris; private Partitions partitions; - private final Iterable initialUris; private RedisClusterClient() { diff --git a/src/main/java/com/lambdaworks/redis/cluster/RoundRobin.java b/src/main/java/com/lambdaworks/redis/cluster/RoundRobin.java index bb22c99e39..a2c311ffd5 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/RoundRobin.java +++ b/src/main/java/com/lambdaworks/redis/cluster/RoundRobin.java @@ -11,6 +11,7 @@ class RoundRobin { protected final Collection collection; + protected V offset; public RoundRobin(Collection collection) { diff --git a/src/main/java/com/lambdaworks/redis/cluster/RoundRobinSocketAddressSupplier.java b/src/main/java/com/lambdaworks/redis/cluster/RoundRobinSocketAddressSupplier.java index fc7214d103..167d986f73 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/RoundRobinSocketAddressSupplier.java +++ b/src/main/java/com/lambdaworks/redis/cluster/RoundRobinSocketAddressSupplier.java @@ -22,10 +22,12 @@ class RoundRobinSocketAddressSupplier implements Supplier { private static final InternalLogger logger = InternalLoggerFactory.getInstance(RoundRobinSocketAddressSupplier.class); + private final Collection partitions; private final Collection clusterNodes = new ArrayList<>(); private final Function, Collection> sortFunction; private final ClientResources clientResources; + private RoundRobin roundRobin; public RoundRobinSocketAddressSupplier(Collection partitions, diff --git a/src/main/java/com/lambdaworks/redis/cluster/StatefulRedisClusterConnectionImpl.java b/src/main/java/com/lambdaworks/redis/cluster/StatefulRedisClusterConnectionImpl.java index 995b9813d0..09344249f5 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/StatefulRedisClusterConnectionImpl.java +++ b/src/main/java/com/lambdaworks/redis/cluster/StatefulRedisClusterConnectionImpl.java @@ -221,7 +221,7 @@ private static class ClusterFutureSyncInvocationHandler extends AbstractIn private final Map apiMethodCache = new ConcurrentHashMap<>(RedisClusterCommands.class.getMethods().length, 1); private final Map connectionMethodCache = new ConcurrentHashMap<>(5, 1); - private final static Constructor LOOKUP_CONSTRUCTOR; + private static final Constructor LOOKUP_CONSTRUCTOR; static { try { diff --git a/src/main/java/com/lambdaworks/redis/cluster/event/ClusterTopologyChangedEvent.java b/src/main/java/com/lambdaworks/redis/cluster/event/ClusterTopologyChangedEvent.java index b735673135..87c31aca4b 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/event/ClusterTopologyChangedEvent.java +++ b/src/main/java/com/lambdaworks/redis/cluster/event/ClusterTopologyChangedEvent.java @@ -13,6 +13,7 @@ * @since 3.4 */ public class ClusterTopologyChangedEvent implements Event { + private final List before; private final List after; @@ -47,7 +48,7 @@ public List after() { @Override public String toString() { - final StringBuffer sb = new StringBuffer(); + StringBuilder sb = new StringBuilder(); sb.append(getClass().getSimpleName()); sb.append(" [before=").append(before.size()); sb.append(", after=").append(after.size()); diff --git a/src/main/java/com/lambdaworks/redis/cluster/models/partitions/Partitions.java b/src/main/java/com/lambdaworks/redis/cluster/models/partitions/Partitions.java index 1312eb7ce0..26fd5b2c01 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/models/partitions/Partitions.java +++ b/src/main/java/com/lambdaworks/redis/cluster/models/partitions/Partitions.java @@ -36,8 +36,9 @@ */ public class Partitions implements Collection { + private static final RedisClusterNode[] EMPTY = new RedisClusterNode[SlotHash.SLOT_COUNT]; + private final List partitions = new ArrayList<>(); - private final static RedisClusterNode[] EMPTY = new RedisClusterNode[SlotHash.SLOT_COUNT]; private volatile RedisClusterNode slotCache[] = EMPTY; private volatile Collection nodeReadView = Collections.emptyList(); diff --git a/src/main/java/com/lambdaworks/redis/cluster/models/slots/ClusterSlotRange.java b/src/main/java/com/lambdaworks/redis/cluster/models/slots/ClusterSlotRange.java index a0fdb55191..fa6e9502de 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/models/slots/ClusterSlotRange.java +++ b/src/main/java/com/lambdaworks/redis/cluster/models/slots/ClusterSlotRange.java @@ -19,6 +19,7 @@ */ @SuppressWarnings("serial") public class ClusterSlotRange implements Serializable { + private int from; private int to; diff --git a/src/main/java/com/lambdaworks/redis/codec/ByteArrayCodec.java b/src/main/java/com/lambdaworks/redis/codec/ByteArrayCodec.java index 55d6311da9..23e9d8ee47 100644 --- a/src/main/java/com/lambdaworks/redis/codec/ByteArrayCodec.java +++ b/src/main/java/com/lambdaworks/redis/codec/ByteArrayCodec.java @@ -10,8 +10,8 @@ */ public class ByteArrayCodec implements RedisCodec { - public final static ByteArrayCodec INSTANCE = new ByteArrayCodec(); - private final static byte[] EMPTY = new byte[0]; + public static final ByteArrayCodec INSTANCE = new ByteArrayCodec(); + private static final byte[] EMPTY = new byte[0]; @Override public byte[] decodeKey(ByteBuffer bytes) { diff --git a/src/main/java/com/lambdaworks/redis/codec/StringCodec.java b/src/main/java/com/lambdaworks/redis/codec/StringCodec.java index 4121559729..08a773fd2b 100644 --- a/src/main/java/com/lambdaworks/redis/codec/StringCodec.java +++ b/src/main/java/com/lambdaworks/redis/codec/StringCodec.java @@ -24,10 +24,10 @@ */ public class StringCodec implements RedisCodec, ToByteBufEncoder { - public final static StringCodec UTF8 = new StringCodec(LettuceCharsets.UTF8); - public final static StringCodec ASCII = new StringCodec(LettuceCharsets.ASCII); + public static final StringCodec UTF8 = new StringCodec(LettuceCharsets.UTF8); + public static final StringCodec ASCII = new StringCodec(LettuceCharsets.ASCII); - private final static byte[] EMPTY = new byte[0]; + private static final byte[] EMPTY = new byte[0]; private final Charset charset; private final boolean ascii; diff --git a/src/main/java/com/lambdaworks/redis/codec/Utf8StringCodec.java b/src/main/java/com/lambdaworks/redis/codec/Utf8StringCodec.java index 137808a000..5d258cfd71 100644 --- a/src/main/java/com/lambdaworks/redis/codec/Utf8StringCodec.java +++ b/src/main/java/com/lambdaworks/redis/codec/Utf8StringCodec.java @@ -18,7 +18,7 @@ */ public class Utf8StringCodec implements RedisCodec { - private final static byte[] EMPTY = new byte[0]; + private static final byte[] EMPTY = new byte[0]; private Charset charset; private CharsetDecoder decoder; diff --git a/src/main/java/com/lambdaworks/redis/event/connection/ConnectionEventSupport.java b/src/main/java/com/lambdaworks/redis/event/connection/ConnectionEventSupport.java index 78dfe5bc6e..f07be809e8 100644 --- a/src/main/java/com/lambdaworks/redis/event/connection/ConnectionEventSupport.java +++ b/src/main/java/com/lambdaworks/redis/event/connection/ConnectionEventSupport.java @@ -41,16 +41,12 @@ public SocketAddress remoteAddress() { @Override public String toString() { - final StringBuffer sb = new StringBuffer(); + StringBuilder sb = new StringBuilder(); sb.append(getClass().getSimpleName()); sb.append(" ["); - appendConnectionId(sb); - sb.append(']'); - return sb.toString(); - } - - void appendConnectionId(StringBuffer sb) { sb.append(local); sb.append(" -> ").append(remote); + sb.append(']'); + return sb.toString(); } } diff --git a/src/main/java/com/lambdaworks/redis/event/metrics/CommandLatencyEvent.java b/src/main/java/com/lambdaworks/redis/event/metrics/CommandLatencyEvent.java index d179c83a29..46494f46b2 100644 --- a/src/main/java/com/lambdaworks/redis/event/metrics/CommandLatencyEvent.java +++ b/src/main/java/com/lambdaworks/redis/event/metrics/CommandLatencyEvent.java @@ -30,7 +30,7 @@ public Map getLatencies() { @Override public String toString() { - final StringBuffer sb = new StringBuffer(); + StringBuilder sb = new StringBuilder(); sb.append(latencies); return sb.toString(); } diff --git a/src/main/java/com/lambdaworks/redis/internal/LettuceFactories.java b/src/main/java/com/lambdaworks/redis/internal/LettuceFactories.java index 8d6cf9daed..dde084d96d 100644 --- a/src/main/java/com/lambdaworks/redis/internal/LettuceFactories.java +++ b/src/main/java/com/lambdaworks/redis/internal/LettuceFactories.java @@ -21,7 +21,7 @@ public class LettuceFactories { * @param * @return a new, empty {@link ConcurrentLinkedDeque}. */ - public final static Deque newConcurrentQueue() { + public static final Deque newConcurrentQueue() { return new ConcurrentLinkedDeque(); } @@ -31,7 +31,7 @@ public final static Deque newConcurrentQueue() { * @param * @return a new, empty {@link ArrayDeque}. */ - public final static Deque newSpScQueue() { + public static final Deque newSpScQueue() { return new ArrayDeque<>(); } diff --git a/src/main/java/com/lambdaworks/redis/masterslave/MasterSlave.java b/src/main/java/com/lambdaworks/redis/masterslave/MasterSlave.java index e1fd9e1698..68c3e81a4d 100644 --- a/src/main/java/com/lambdaworks/redis/masterslave/MasterSlave.java +++ b/src/main/java/com/lambdaworks/redis/masterslave/MasterSlave.java @@ -72,7 +72,7 @@ */ public class MasterSlave { - private final static InternalLogger LOG = InternalLoggerFactory.getInstance(MasterSlave.class); + private static final InternalLogger LOG = InternalLoggerFactory.getInstance(MasterSlave.class); /** * Open a new connection to a Redis Master-Slave server/servers using the supplied {@link RedisURI} and the supplied diff --git a/src/main/java/com/lambdaworks/redis/masterslave/MasterSlaveConnectionProvider.java b/src/main/java/com/lambdaworks/redis/masterslave/MasterSlaveConnectionProvider.java index cf181b96de..478ba20023 100644 --- a/src/main/java/com/lambdaworks/redis/masterslave/MasterSlaveConnectionProvider.java +++ b/src/main/java/com/lambdaworks/redis/masterslave/MasterSlaveConnectionProvider.java @@ -30,7 +30,7 @@ public class MasterSlaveConnectionProvider { private static final InternalLogger logger = InternalLoggerFactory.getInstance(MasterSlaveConnectionProvider.class); - private final boolean debugEnabled; + private final boolean debugEnabled = logger.isDebugEnabled(); // Contains HostAndPort-identified connections. private final Map> connections = new ConcurrentHashMap<>(); @@ -47,7 +47,6 @@ public class MasterSlaveConnectionProvider { Map> initialConnections) { this.initialRedisUri = initialRedisUri; - this.debugEnabled = logger.isDebugEnabled(); this.connectionFactory = new ConnectionFactory<>(redisClient, redisCodec); for (Map.Entry> entry : initialConnections.entrySet()) { diff --git a/src/main/java/com/lambdaworks/redis/masterslave/MasterSlaveTopologyProvider.java b/src/main/java/com/lambdaworks/redis/masterslave/MasterSlaveTopologyProvider.java index 83c55186ff..624e177216 100644 --- a/src/main/java/com/lambdaworks/redis/masterslave/MasterSlaveTopologyProvider.java +++ b/src/main/java/com/lambdaworks/redis/masterslave/MasterSlaveTopologyProvider.java @@ -24,13 +24,13 @@ */ public class MasterSlaveTopologyProvider implements TopologyProvider { - public final static Pattern ROLE_PATTERN = Pattern.compile("^role\\:([a-z]+)$", Pattern.MULTILINE); - public final static Pattern SLAVE_PATTERN = Pattern.compile("^slave(\\d+)\\:([a-zA-Z\\,\\=\\d\\.\\:]+)$", Pattern.MULTILINE); - public final static Pattern MASTER_HOST_PATTERN = Pattern.compile("^master_host\\:([a-zA-Z\\,\\=\\d\\.\\:]+)$", + public static final Pattern ROLE_PATTERN = Pattern.compile("^role\\:([a-z]+)$", Pattern.MULTILINE); + public static final Pattern SLAVE_PATTERN = Pattern.compile("^slave(\\d+)\\:([a-zA-Z\\,\\=\\d\\.\\:]+)$", Pattern.MULTILINE); + public static final Pattern MASTER_HOST_PATTERN = Pattern.compile("^master_host\\:([a-zA-Z\\,\\=\\d\\.\\:]+)$", Pattern.MULTILINE); - public final static Pattern MASTER_PORT_PATTERN = Pattern.compile("^master_port\\:(\\d+)$", Pattern.MULTILINE); - public final static Pattern IP_PATTERN = Pattern.compile("ip\\=([a-zA-Z\\d\\.\\:]+)"); - public final static Pattern PORT_PATTERN = Pattern.compile("port\\=([\\d]+)"); + public static final Pattern MASTER_PORT_PATTERN = Pattern.compile("^master_port\\:(\\d+)$", Pattern.MULTILINE); + public static final Pattern IP_PATTERN = Pattern.compile("ip\\=([a-zA-Z\\d\\.\\:]+)"); + public static final Pattern PORT_PATTERN = Pattern.compile("port\\=([\\d]+)"); private static final InternalLogger logger = InternalLoggerFactory.getInstance(MasterSlaveTopologyProvider.class); diff --git a/src/main/java/com/lambdaworks/redis/masterslave/MasterSlaveTopologyRefresh.java b/src/main/java/com/lambdaworks/redis/masterslave/MasterSlaveTopologyRefresh.java index c8cac87356..bdd72922ed 100644 --- a/src/main/java/com/lambdaworks/redis/masterslave/MasterSlaveTopologyRefresh.java +++ b/src/main/java/com/lambdaworks/redis/masterslave/MasterSlaveTopologyRefresh.java @@ -165,7 +165,7 @@ private Map> getConnections(It */ static class RedisUriComparator implements Comparator { - public final static RedisUriComparator INSTANCE = new RedisUriComparator(); + public static final RedisUriComparator INSTANCE = new RedisUriComparator(); @Override public int compare(RedisURI o1, RedisURI o2) { diff --git a/src/main/java/com/lambdaworks/redis/masterslave/ReadOnlyCommands.java b/src/main/java/com/lambdaworks/redis/masterslave/ReadOnlyCommands.java index 157f2412e3..ee67adb9ad 100644 --- a/src/main/java/com/lambdaworks/redis/masterslave/ReadOnlyCommands.java +++ b/src/main/java/com/lambdaworks/redis/masterslave/ReadOnlyCommands.java @@ -13,7 +13,7 @@ */ class ReadOnlyCommands { - public final static ProtocolKeyword READ_ONLY_COMMANDS[]; + public static final ProtocolKeyword READ_ONLY_COMMANDS[]; static { diff --git a/src/main/java/com/lambdaworks/redis/masterslave/RedisMasterSlaveNode.java b/src/main/java/com/lambdaworks/redis/masterslave/RedisMasterSlaveNode.java index 74efeac8d4..c92ab7282e 100644 --- a/src/main/java/com/lambdaworks/redis/masterslave/RedisMasterSlaveNode.java +++ b/src/main/java/com/lambdaworks/redis/masterslave/RedisMasterSlaveNode.java @@ -57,7 +57,7 @@ public int hashCode() { @Override public String toString() { - final StringBuffer sb = new StringBuffer(); + StringBuilder sb = new StringBuilder(); sb.append(getClass().getSimpleName()); sb.append(" [redisURI=").append(redisURI); sb.append(", role=").append(role); diff --git a/src/main/java/com/lambdaworks/redis/masterslave/SentinelTopologyRefresh.java b/src/main/java/com/lambdaworks/redis/masterslave/SentinelTopologyRefresh.java index 08acc1ecb8..fa4e605e3a 100644 --- a/src/main/java/com/lambdaworks/redis/masterslave/SentinelTopologyRefresh.java +++ b/src/main/java/com/lambdaworks/redis/masterslave/SentinelTopologyRefresh.java @@ -26,7 +26,7 @@ */ class SentinelTopologyRefresh implements Closeable { - private final static InternalLogger LOG = InternalLoggerFactory.getInstance(SentinelTopologyRefresh.class); + private static final InternalLogger LOG = InternalLoggerFactory.getInstance(SentinelTopologyRefresh.class); private final List> pubSubConnections = new ArrayList<>(); private final RedisClient redisClient; diff --git a/src/main/java/com/lambdaworks/redis/metrics/CommandLatencyId.java b/src/main/java/com/lambdaworks/redis/metrics/CommandLatencyId.java index 3312755820..a468385d3a 100644 --- a/src/main/java/com/lambdaworks/redis/metrics/CommandLatencyId.java +++ b/src/main/java/com/lambdaworks/redis/metrics/CommandLatencyId.java @@ -113,7 +113,7 @@ public int compareTo(CommandLatencyId o) { @Override public String toString() { - final StringBuffer sb = new StringBuffer(); + StringBuilder sb = new StringBuilder(); sb.append("[").append(localAddress); sb.append(" -> ").append(remoteAddress); sb.append(", commandType=").append(commandType); diff --git a/src/main/java/com/lambdaworks/redis/metrics/CommandMetrics.java b/src/main/java/com/lambdaworks/redis/metrics/CommandMetrics.java index c7b4b0770c..49c0f67667 100644 --- a/src/main/java/com/lambdaworks/redis/metrics/CommandMetrics.java +++ b/src/main/java/com/lambdaworks/redis/metrics/CommandMetrics.java @@ -56,7 +56,7 @@ public CommandLatency getCompletion() { @Override public String toString() { - final StringBuffer sb = new StringBuffer(); + StringBuilder sb = new StringBuilder(); sb.append("[count=").append(count); sb.append(", timeUnit=").append(timeUnit); sb.append(", firstResponse=").append(firstResponse); @@ -102,7 +102,7 @@ public Map getPercentiles() { @Override public String toString() { - final StringBuffer sb = new StringBuffer(); + StringBuilder sb = new StringBuilder(); sb.append("[min=").append(min); sb.append(", max=").append(max); sb.append(", percentiles=").append(percentiles); diff --git a/src/main/java/com/lambdaworks/redis/metrics/DefaultCommandLatencyCollector.java b/src/main/java/com/lambdaworks/redis/metrics/DefaultCommandLatencyCollector.java index aa65cb45f0..986104373d 100644 --- a/src/main/java/com/lambdaworks/redis/metrics/DefaultCommandLatencyCollector.java +++ b/src/main/java/com/lambdaworks/redis/metrics/DefaultCommandLatencyCollector.java @@ -206,7 +206,7 @@ public Latencies(PauseDetector pauseDetector) { } private static class PauseDetectorWrapper { - public final static AtomicLong counter = new AtomicLong(); + public static final AtomicLong counter = new AtomicLong(); PauseDetector pauseDetector; public void initialize() { diff --git a/src/main/java/com/lambdaworks/redis/protocol/AsyncCommand.java b/src/main/java/com/lambdaworks/redis/protocol/AsyncCommand.java index eeb8319109..50773f9923 100644 --- a/src/main/java/com/lambdaworks/redis/protocol/AsyncCommand.java +++ b/src/main/java/com/lambdaworks/redis/protocol/AsyncCommand.java @@ -25,8 +25,8 @@ public class AsyncCommand extends CompletableFuture implements RedisCommand, RedisFuture, CompleteableCommand, DecoratedCommand { - protected RedisCommand command; protected CountDownLatch latch = new CountDownLatch(1); + protected RedisCommand command; /** * diff --git a/src/main/java/com/lambdaworks/redis/protocol/BaseRedisCommandBuilder.java b/src/main/java/com/lambdaworks/redis/protocol/BaseRedisCommandBuilder.java index 1cd7afb3d8..7aab8637f7 100644 --- a/src/main/java/com/lambdaworks/redis/protocol/BaseRedisCommandBuilder.java +++ b/src/main/java/com/lambdaworks/redis/protocol/BaseRedisCommandBuilder.java @@ -10,6 +10,7 @@ * @since 3.0 */ public class BaseRedisCommandBuilder { + protected RedisCodec codec; public BaseRedisCommandBuilder(RedisCodec codec) { diff --git a/src/main/java/com/lambdaworks/redis/protocol/CommandArgs.java b/src/main/java/com/lambdaworks/redis/protocol/CommandArgs.java index de2d79da83..14ebb07d77 100644 --- a/src/main/java/com/lambdaworks/redis/protocol/CommandArgs.java +++ b/src/main/java/com/lambdaworks/redis/protocol/CommandArgs.java @@ -438,7 +438,7 @@ static void writeInteger(ByteBuf target, long value) { static class IntegerCache { - final static IntegerArgument cache[]; + static final IntegerArgument cache[]; static { int high = Integer.getInteger("biz.paluch.redis.CommandArgs.IntegerCache", 128); @@ -578,9 +578,9 @@ void encode(ByteBuf target) { * This codec writes directly {@code byte[]} to the target buffer without wrapping it in a {@link ByteBuffer} to reduce GC * pressure. */ - public final static class ExperimentalByteArrayCodec extends ByteArrayCodec { + public static final class ExperimentalByteArrayCodec extends ByteArrayCodec { - public final static ExperimentalByteArrayCodec INSTANCE = new ExperimentalByteArrayCodec(); + public static final ExperimentalByteArrayCodec INSTANCE = new ExperimentalByteArrayCodec(); private ExperimentalByteArrayCodec() { diff --git a/src/main/java/com/lambdaworks/redis/protocol/CommandEncoder.java b/src/main/java/com/lambdaworks/redis/protocol/CommandEncoder.java index 69321f1cef..1562f3ea7c 100644 --- a/src/main/java/com/lambdaworks/redis/protocol/CommandEncoder.java +++ b/src/main/java/com/lambdaworks/redis/protocol/CommandEncoder.java @@ -23,15 +23,8 @@ public class CommandEncoder extends MessageToByteEncoder { private static final InternalLogger logger = InternalLoggerFactory.getInstance(CommandEncoder.class); - /** - * If TRACE level logging has been enabled at startup. - */ - private final boolean traceEnabled; - - /** - * If DEBUG level logging has been enabled at startup. - */ - private final boolean debugEnabled; + private final boolean traceEnabled = logger.isTraceEnabled(); + private final boolean debugEnabled = logger.isDebugEnabled(); public CommandEncoder() { this(true); @@ -39,8 +32,6 @@ public CommandEncoder() { public CommandEncoder(boolean preferDirect) { super(preferDirect); - traceEnabled = logger.isTraceEnabled(); - debugEnabled = logger.isDebugEnabled(); } @Override diff --git a/src/main/java/com/lambdaworks/redis/protocol/CommandHandler.java b/src/main/java/com/lambdaworks/redis/protocol/CommandHandler.java index e31409700d..13db3aeec8 100644 --- a/src/main/java/com/lambdaworks/redis/protocol/CommandHandler.java +++ b/src/main/java/com/lambdaworks/redis/protocol/CommandHandler.java @@ -45,12 +45,8 @@ public class CommandHandler extends ChannelDuplexHandler implements HasQueuedCom private final long commandHandlerId = COMMAND_HANDLER_COUNTER.incrementAndGet(); private final Queue> queue = LettuceFactories.newConcurrentQueue(); private final RedisStateMachine rsm = new RedisStateMachine(); - - // If TRACE level logging has been enabled at startup. - private final boolean traceEnabled; - - // If DEBUG level logging has been enabled at startup. - private final boolean debugEnabled; + private final boolean traceEnabled = logger.isTraceEnabled(); + private final boolean debugEnabled = logger.isDebugEnabled(); private final ClientResources clientResources; private final Endpoint endpoint; @@ -73,9 +69,6 @@ public CommandHandler(ClientResources clientResources, Endpoint endpoint) { this.clientResources = clientResources; this.endpoint = endpoint; - - this.traceEnabled = logger.isTraceEnabled(); - this.debugEnabled = logger.isDebugEnabled(); } /** diff --git a/src/main/java/com/lambdaworks/redis/protocol/CommandKeyword.java b/src/main/java/com/lambdaworks/redis/protocol/CommandKeyword.java index 130f85bbeb..de906e0b13 100644 --- a/src/main/java/com/lambdaworks/redis/protocol/CommandKeyword.java +++ b/src/main/java/com/lambdaworks/redis/protocol/CommandKeyword.java @@ -8,6 +8,7 @@ * @author Will Glozer */ public enum CommandKeyword implements ProtocolKeyword { + ADDR, ADDSLOTS, AFTER, AGGREGATE, ALPHA, AND, ASK, ASC, ASYNC, BEFORE, BUMPEPOCH, BY, CHANNELS, COPY, COUNT, COUNTKEYSINSLOT, DELSLOTS, DESC, SOFT, HARD, ENCODING, FAILOVER, FORGET, FLUSH, FORCE, FLUSHSLOTS, GETNAME, GETKEYSINSLOT, HTSTATS, ID, IDLETIME, KILL, KEYSLOT, LEN, LIMIT, LIST, LOAD, MATCH, diff --git a/src/main/java/com/lambdaworks/redis/protocol/CommandWrapper.java b/src/main/java/com/lambdaworks/redis/protocol/CommandWrapper.java index f3675ed03f..c05f0ea1b4 100644 --- a/src/main/java/com/lambdaworks/redis/protocol/CommandWrapper.java +++ b/src/main/java/com/lambdaworks/redis/protocol/CommandWrapper.java @@ -14,8 +14,8 @@ */ public class CommandWrapper implements RedisCommand, CompleteableCommand, DecoratedCommand { - protected RedisCommand command; - private List> onComplete = new ArrayList<>(); + protected final RedisCommand command; + private final List> onComplete = new ArrayList<>(); public CommandWrapper(RedisCommand command) { this.command = command; diff --git a/src/main/java/com/lambdaworks/redis/protocol/ConnectionWatchdog.java b/src/main/java/com/lambdaworks/redis/protocol/ConnectionWatchdog.java index b567e8f608..59d96e0497 100644 --- a/src/main/java/com/lambdaworks/redis/protocol/ConnectionWatchdog.java +++ b/src/main/java/com/lambdaworks/redis/protocol/ConnectionWatchdog.java @@ -32,7 +32,6 @@ public class ConnectionWatchdog extends ChannelInboundHandlerAdapter { private static final long LOGGING_QUIET_TIME_MS = TimeUnit.MILLISECONDS.convert(5, TimeUnit.SECONDS); - private static final InternalLogger logger = InternalLoggerFactory.getInstance(ConnectionWatchdog.class); private final Delay reconnectDelay; diff --git a/src/main/java/com/lambdaworks/redis/protocol/DefaultEndpoint.java b/src/main/java/com/lambdaworks/redis/protocol/DefaultEndpoint.java index b2c9b67274..8f0b46b394 100644 --- a/src/main/java/com/lambdaworks/redis/protocol/DefaultEndpoint.java +++ b/src/main/java/com/lambdaworks/redis/protocol/DefaultEndpoint.java @@ -45,12 +45,8 @@ public class DefaultEndpoint implements RedisChannelWriter, Endpoint, HasQueuedC private final ClientOptions clientOptions; private final QueuedCommands queuedCommands = new QueuedCommands(); - - // If TRACE level logging has been enabled at startup. - private final boolean traceEnabled; - - // If DEBUG level logging has been enabled at startup. - private final boolean debugEnabled; + private final boolean traceEnabled = logger.isTraceEnabled(); + private final boolean debugEnabled = logger.isDebugEnabled(); protected volatile Channel channel; private String logPrefix; @@ -71,8 +67,6 @@ public DefaultEndpoint(ClientOptions clientOptions) { LettuceAssert.notNull(clientOptions, "ClientOptions must not be null"); this.clientOptions = clientOptions; - this.traceEnabled = logger.isTraceEnabled(); - this.debugEnabled = logger.isDebugEnabled(); this.reliability = clientOptions.isAutoReconnect() ? Reliability.AT_LEAST_ONCE : Reliability.AT_MOST_ONCE; this.queuedCommands.register(this); } diff --git a/src/main/java/com/lambdaworks/redis/protocol/RedisStateMachine.java b/src/main/java/com/lambdaworks/redis/protocol/RedisStateMachine.java index ecd0fee04e..a8d96f5869 100644 --- a/src/main/java/com/lambdaworks/redis/protocol/RedisStateMachine.java +++ b/src/main/java/com/lambdaworks/redis/protocol/RedisStateMachine.java @@ -40,21 +40,18 @@ enum Type { int count = -1; } - private final State[] stack; - private int stackElements; - - // If DEBUG level logging has been enabled at startup. - private final boolean debugEnabled; + private final State[] stack = new State[32]; + private final boolean debugEnabled = logger.isDebugEnabled(); private final LongProcessor longProcessor; private final ByteBuf responseElementBuffer = PooledByteBufAllocator.DEFAULT.directBuffer(1024); private final AtomicBoolean closed = new AtomicBoolean(); + private int stackElements; + /** * Initialize a new instance. */ public RedisStateMachine() { - stack = new State[32]; - debugEnabled = logger.isDebugEnabled(); Version nettyBufferVersion = Version.identify().get("netty-buffer"); diff --git a/src/main/java/com/lambdaworks/redis/protocol/SharedLock.java b/src/main/java/com/lambdaworks/redis/protocol/SharedLock.java index 4a3bce3c33..55956ba3ab 100644 --- a/src/main/java/com/lambdaworks/redis/protocol/SharedLock.java +++ b/src/main/java/com/lambdaworks/redis/protocol/SharedLock.java @@ -20,7 +20,7 @@ class SharedLock { private final AtomicLong writers = new AtomicLong(); - private Thread exclusiveLockOwner; + private volatile Thread exclusiveLockOwner; /** * Wait for stateLock and increment writers. Will wait if stateLock is locked and if writer counter is negative. diff --git a/src/main/java/com/lambdaworks/redis/pubsub/PubSubCommandHandler.java b/src/main/java/com/lambdaworks/redis/pubsub/PubSubCommandHandler.java index 2877dec55a..0b03c2e9fa 100644 --- a/src/main/java/com/lambdaworks/redis/pubsub/PubSubCommandHandler.java +++ b/src/main/java/com/lambdaworks/redis/pubsub/PubSubCommandHandler.java @@ -22,8 +22,8 @@ */ public class PubSubCommandHandler extends CommandHandler { - private PubSubEndpoint endpoint; - private RedisCodec codec; + private final PubSubEndpoint endpoint; + private final RedisCodec codec; private PubSubOutput output; /** diff --git a/src/main/java/com/lambdaworks/redis/pubsub/PubSubOutput.java b/src/main/java/com/lambdaworks/redis/pubsub/PubSubOutput.java index 18fecddc70..aace0280c2 100644 --- a/src/main/java/com/lambdaworks/redis/pubsub/PubSubOutput.java +++ b/src/main/java/com/lambdaworks/redis/pubsub/PubSubOutput.java @@ -16,6 +16,7 @@ * @author Will Glozer */ public class PubSubOutput extends CommandOutput { + public enum Type { message, pmessage, psubscribe, punsubscribe, subscribe, unsubscribe } diff --git a/src/main/java/com/lambdaworks/redis/pubsub/RedisPubSubAdapter.java b/src/main/java/com/lambdaworks/redis/pubsub/RedisPubSubAdapter.java index dc699fad82..de04d28b52 100644 --- a/src/main/java/com/lambdaworks/redis/pubsub/RedisPubSubAdapter.java +++ b/src/main/java/com/lambdaworks/redis/pubsub/RedisPubSubAdapter.java @@ -11,6 +11,7 @@ * @author Will Glozer */ public class RedisPubSubAdapter implements RedisPubSubListener { + @Override public void message(K channel, V message) { // empty adapter method diff --git a/src/main/java/com/lambdaworks/redis/pubsub/RedisPubSubAsyncCommandsImpl.java b/src/main/java/com/lambdaworks/redis/pubsub/RedisPubSubAsyncCommandsImpl.java index 7a74854617..1a11b1e1ed 100644 --- a/src/main/java/com/lambdaworks/redis/pubsub/RedisPubSubAsyncCommandsImpl.java +++ b/src/main/java/com/lambdaworks/redis/pubsub/RedisPubSubAsyncCommandsImpl.java @@ -19,7 +19,7 @@ */ public class RedisPubSubAsyncCommandsImpl extends RedisAsyncCommandsImpl implements RedisPubSubAsyncCommands { - private PubSubCommandBuilder commandBuilder; + private final PubSubCommandBuilder commandBuilder; /** * Initialize a new connection. diff --git a/src/main/java/com/lambdaworks/redis/resource/DirContextDnsResolver.java b/src/main/java/com/lambdaworks/redis/resource/DirContextDnsResolver.java index 6bb81e7110..08eaa61798 100644 --- a/src/main/java/com/lambdaworks/redis/resource/DirContextDnsResolver.java +++ b/src/main/java/com/lambdaworks/redis/resource/DirContextDnsResolver.java @@ -36,8 +36,8 @@ */ public class DirContextDnsResolver implements DnsResolver, Closeable { - final static String PREFER_IPV4_KEY = "java.net.preferIPv4Stack"; - final static String PREFER_IPV6_KEY = "java.net.preferIPv6Stack"; + static final String PREFER_IPV4_KEY = "java.net.preferIPv4Stack"; + static final String PREFER_IPV6_KEY = "java.net.preferIPv6Stack"; private static final int IPV4_PART_COUNT = 4; private static final int IPV6_PART_COUNT = 8; @@ -280,7 +280,7 @@ private static Properties getProperties(Iterable dnsServers) { /** * Stack preference utility. */ - private final static class StackPreference { + private static final class StackPreference { final boolean preferIpv4; final boolean preferIpv6; From 5a8c1baa69d2c87eada3e375b03cf4e2878c0afc Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Sat, 3 Sep 2016 20:06:56 +0200 Subject: [PATCH 019/808] Fix RandomKeys generation Make sure that 500 different random keys are generated. Previously, it was possible that duplicate keys were generated. --- src/test/java/com/lambdaworks/RandomKeys.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/test/java/com/lambdaworks/RandomKeys.java b/src/test/java/com/lambdaworks/RandomKeys.java index 0524e3f7e1..95ee0cf500 100644 --- a/src/test/java/com/lambdaworks/RandomKeys.java +++ b/src/test/java/com/lambdaworks/RandomKeys.java @@ -36,15 +36,19 @@ public class RandomKeys { List keys = new ArrayList<>(); List values = new ArrayList<>(); Map map = new HashMap<>(); + Set uniqueKeys = new HashSet<>(); - for (int i = 0; i < COUNT; i++) { + while (map.size() < COUNT) { String key = RandomStringUtils.random(10, true, true); String value = RandomStringUtils.random(10, true, true); - keys.add(key); - values.add(value); - map.put(key, value); + if (uniqueKeys.add(key)) { + + keys.add(key); + values.add(value); + map.put(key, value); + } } KEYS = Collections.unmodifiableList(keys); From 4507911b8d08750846e5eb3d822b67029a4e74fd Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Sat, 3 Sep 2016 20:59:18 +0200 Subject: [PATCH 020/808] Fix race condition in ConnectionTestUtil.getConnectionWatchdog #216 Extract ConnectionWatchdog from DefaultEndpoint and not the Channel as channels are reconnected and may enter a state where no handlers are available yet. --- .../com/lambdaworks/ConnectionTestUtil.java | 56 +++++++++++++------ .../lambdaworks/redis/ClientOptionsTest.java | 17 +++--- .../com/lambdaworks/redis/ClientTest.java | 3 +- 3 files changed, 49 insertions(+), 27 deletions(-) diff --git a/src/test/java/com/lambdaworks/ConnectionTestUtil.java b/src/test/java/com/lambdaworks/ConnectionTestUtil.java index d13c68443b..47fb6216f0 100644 --- a/src/test/java/com/lambdaworks/ConnectionTestUtil.java +++ b/src/test/java/com/lambdaworks/ConnectionTestUtil.java @@ -6,9 +6,7 @@ import com.lambdaworks.redis.RedisChannelHandler; import com.lambdaworks.redis.RedisChannelWriter; -import com.lambdaworks.redis.StatefulRedisConnectionImpl; import com.lambdaworks.redis.api.StatefulConnection; -import com.lambdaworks.redis.api.async.RedisAsyncCommands; import com.lambdaworks.redis.internal.LettuceFactories; import com.lambdaworks.redis.protocol.CommandHandler; import com.lambdaworks.redis.protocol.ConnectionWatchdog; @@ -19,40 +17,53 @@ /** * @author Mark Paluch */ +@SuppressWarnings("unchecked") public class ConnectionTestUtil { /** - * Extract the {@link Channel} from a stateful connection. + * Extract the {@link Channel} from a {@link StatefulConnection}. * - * @param connection - * @return + * @param connection the connection + * @return the {@link Channel} */ public static Channel getChannel(StatefulConnection connection) { - RedisChannelHandler channelHandler = (RedisChannelHandler) connection; + RedisChannelHandler channelHandler = (RedisChannelHandler) connection; return (Channel) ReflectionTestUtils.getField(channelHandler.getChannelWriter(), "channel"); } /** - * Extract the {@link ConnectionWatchdog} from a stateful connection. + * Extract the {@link ConnectionWatchdog} from a {@link StatefulConnection}. * - * @param connection - * @return + * @param connection the connection + * @return the {@link ConnectionWatchdog} */ public static ConnectionWatchdog getConnectionWatchdog(StatefulConnection connection) { - Channel channel = getChannel(connection); - return channel.pipeline().get(ConnectionWatchdog.class); - } + RedisChannelWriter channelWriter = ConnectionTestUtil.getChannelWriter(connection); + if (channelWriter instanceof DefaultEndpoint) { + return (ConnectionWatchdog) ReflectionTestUtils.getField(channelWriter, "connectionWatchdog"); + } - public static StatefulRedisConnectionImpl getStatefulConnection(RedisAsyncCommands connection) { - return (StatefulRedisConnectionImpl) connection.getStatefulConnection(); + return null; } - public static RedisChannelWriter getChannelWriter(StatefulConnection connection) { - return ((RedisChannelHandler) connection).getChannelWriter(); + /** + * Extract the {@link RedisChannelWriter} from a {@link StatefulConnection}. + * + * @param connection the connection + * @return the {@link RedisChannelWriter} + */ + public static RedisChannelWriter getChannelWriter(StatefulConnection connection) { + return ((RedisChannelHandler) connection).getChannelWriter(); } + /** + * Extract the queue from a from a {@link StatefulConnection}. + * + * @param connection the connection + * @return the queue + */ public static Queue getQueue(StatefulConnection connection) { Channel channel = getChannel(connection); @@ -63,9 +74,14 @@ public static Queue getQueue(StatefulConnection connection) { } return LettuceFactories.newConcurrentQueue(); - } + /** + * Extract the command buffer from a from a {@link StatefulConnection}. + * + * @param connection the connection + * @return the queue + */ public static Queue getCommandBuffer(StatefulConnection connection) { RedisChannelWriter channelWriter = ConnectionTestUtil.getChannelWriter(connection); @@ -76,6 +92,12 @@ public static Queue getCommandBuffer(StatefulConnection connection return LettuceFactories.newConcurrentQueue(); } + /** + * Extract the connection state from a from a {@link StatefulConnection}. + * + * @param connection the connection + * @return the connection state as {@link String} + */ public static String getConnectionState(StatefulConnection connection) { Channel channel = getChannel(connection); diff --git a/src/test/java/com/lambdaworks/redis/ClientOptionsTest.java b/src/test/java/com/lambdaworks/redis/ClientOptionsTest.java index 0777067daf..a53dd74b4f 100644 --- a/src/test/java/com/lambdaworks/redis/ClientOptionsTest.java +++ b/src/test/java/com/lambdaworks/redis/ClientOptionsTest.java @@ -2,7 +2,6 @@ import static com.lambdaworks.ConnectionTestUtil.getChannel; import static com.lambdaworks.ConnectionTestUtil.getConnectionWatchdog; -import static com.lambdaworks.ConnectionTestUtil.getStatefulConnection; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.fail; @@ -51,18 +50,20 @@ protected void checkAssertions(ClientOptions sut) { @Test public void variousClientOptions() throws Exception { - RedisAsyncCommands plain = client.connect().async(); + StatefulRedisConnection connection1 = client.connect(); - assertThat(getStatefulConnection(plain).getOptions().isAutoReconnect()).isTrue(); + assertThat(connection1.getOptions().isAutoReconnect()).isTrue(); + connection1.close(); client.setOptions(ClientOptions.builder().autoReconnect(false).build()); - RedisAsyncCommands connection = client.connect().async(); - assertThat(getStatefulConnection(connection).getOptions().isAutoReconnect()).isFalse(); - assertThat(getStatefulConnection(plain).getOptions().isAutoReconnect()).isTrue(); + StatefulRedisConnection connection2 = client.connect(); + assertThat(connection2.getOptions().isAutoReconnect()).isFalse(); - plain.getStatefulConnection().close(); - connection.getStatefulConnection().close(); + assertThat(connection1.getOptions().isAutoReconnect()).isTrue(); + + connection1.close(); + connection2.close(); } @Test diff --git a/src/test/java/com/lambdaworks/redis/ClientTest.java b/src/test/java/com/lambdaworks/redis/ClientTest.java index f0f2af52f3..47c773cc7f 100644 --- a/src/test/java/com/lambdaworks/redis/ClientTest.java +++ b/src/test/java/com/lambdaworks/redis/ClientTest.java @@ -4,7 +4,6 @@ import static com.google.code.tempusfugit.temporal.Duration.seconds; import static com.google.code.tempusfugit.temporal.WaitFor.waitOrTimeout; -import static com.lambdaworks.ConnectionTestUtil.getStatefulConnection; import static org.assertj.core.api.Assertions.assertThat; import java.util.concurrent.TimeUnit; @@ -76,7 +75,7 @@ public void listenerTest() throws Exception { RedisAsyncCommands connection = client.connect().async(); - StatefulRedisConnection statefulRedisConnection = getStatefulConnection(connection); + StatefulRedisConnection statefulRedisConnection = connection.getStatefulConnection(); waitOrTimeout(() -> listener.onConnected != null, Timeout.timeout(seconds(2))); From 0e8d53d05666d26da5c91c27b843ae6a3558850e Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Sat, 3 Sep 2016 21:15:00 +0200 Subject: [PATCH 021/808] Fix error handling on reactive command dispatching #349 Command dispatching errors are now dispatched to the subscriber using onError. --- .../com/lambdaworks/redis/RedisPublisher.java | 6 ++++- .../redis/ReactiveConnectionTest.java | 25 +++++++++++++++++-- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/lambdaworks/redis/RedisPublisher.java b/src/main/java/com/lambdaworks/redis/RedisPublisher.java index eb2dfea4e0..f145a10ade 100644 --- a/src/main/java/com/lambdaworks/redis/RedisPublisher.java +++ b/src/main/java/com/lambdaworks/redis/RedisPublisher.java @@ -364,7 +364,11 @@ void request(RedisSubscription subscription, long n) { Operators.addAndGet(subscription.demand, n); if (subscription.changeState(this, DEMAND)) { - subscription.checkCommandDispatch(); + try { + subscription.checkCommandDispatch(); + } catch (Exception ex) { + subscription.onError(ex); + } subscription.checkOnDataAvailable(); } } diff --git a/src/test/java/com/lambdaworks/redis/ReactiveConnectionTest.java b/src/test/java/com/lambdaworks/redis/ReactiveConnectionTest.java index 9c37e3f5e8..8ca90b8d21 100644 --- a/src/test/java/com/lambdaworks/redis/ReactiveConnectionTest.java +++ b/src/test/java/com/lambdaworks/redis/ReactiveConnectionTest.java @@ -1,17 +1,16 @@ package com.lambdaworks.redis; import static com.google.code.tempusfugit.temporal.Duration.millis; +import static com.lambdaworks.redis.ClientOptions.DisconnectedBehavior.REJECT_COMMANDS; import static org.assertj.core.api.Assertions.assertThat; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.concurrent.CancellationException; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; -import com.lambdaworks.redis.reactive.TestSubscriber; import org.junit.After; import org.junit.Before; import org.junit.Rule; @@ -24,6 +23,7 @@ import com.lambdaworks.Wait; import com.lambdaworks.redis.api.StatefulRedisConnection; import com.lambdaworks.redis.api.reactive.RedisReactiveCommands; +import com.lambdaworks.redis.reactive.TestSubscriber; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -198,6 +198,27 @@ public void subscriberCompletingWithExceptionShouldBeHandledSafely() throws Exce assertThat(valueB).isEqualTo("valueB"); } + @Test + public void subscribeWithDisconnectedClient() throws Exception { + + client.setOptions(ClientOptions.builder().disconnectedBehavior(REJECT_COMMANDS).autoReconnect(false).build()); + + try (StatefulRedisConnection connection = client.connect()) { + + connection.async().quit(); + Wait.untilTrue(() -> !connection.isOpen()).waitOrTimeout(); + + Mono ping = connection.reactive().ping(); + + ping.subscribeWith(TestSubscriber.create()).assertErrorWith(throwable -> { + + assertThat(throwable).isInstanceOf(RedisException.class) + .hasMessageContaining("not connected. Commands are rejected"); + + }).await(); + } + } + private static Subscriber createSubscriberWithExceptionOnComplete() { return new Subscriber() { From 33852b786f62eee658546b5455b2ab3cdf1681b9 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Sat, 3 Sep 2016 21:25:57 +0200 Subject: [PATCH 022/808] Upgrade to AssertJ 3.5.2 #352 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index d582b96756..5aff840ea4 100644 --- a/pom.xml +++ b/pom.xml @@ -219,7 +219,7 @@ org.assertj assertj-core - 3.2.0 + 3.5.2 test From 7047cc5ae830839d14416deb7ad6be6bfd7fe319 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Sat, 3 Sep 2016 21:35:19 +0200 Subject: [PATCH 023/808] Upgrade netty to 4.0.41.Final and 4.1.5.Final #353 --- pom.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 5aff840ea4..fadd047171 100644 --- a/pom.xml +++ b/pom.xml @@ -57,7 +57,7 @@ true 4.2.2.Final 3.5.0.Final - 4.1.4.Final + 4.1.5.Final @@ -110,7 +110,7 @@ io.netty netty-tcnative - 1.1.33.Fork20 + 1.1.33.Fork21 ${os.detected.classifier} provided true @@ -285,7 +285,7 @@ netty-40 - 4.0.40.Final + 4.0.41.Final From 50f2814348281cccd66933b4a6ab48d609088c54 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Sat, 3 Sep 2016 21:40:38 +0200 Subject: [PATCH 024/808] Polishing --- .../lambdaworks/redis/AbstractRedisReactiveCommands.java | 6 +++--- src/main/java/com/lambdaworks/redis/RedisClient.java | 4 ++-- src/main/java/com/lambdaworks/redis/RedisPublisher.java | 2 +- .../cluster/RedisAdvancedClusterReactiveCommandsImpl.java | 1 + 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/lambdaworks/redis/AbstractRedisReactiveCommands.java b/src/main/java/com/lambdaworks/redis/AbstractRedisReactiveCommands.java index 87fb9695c3..9451d3d22f 100644 --- a/src/main/java/com/lambdaworks/redis/AbstractRedisReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/AbstractRedisReactiveCommands.java @@ -1768,7 +1768,7 @@ public Flux dispatch(ProtocolKeyword type, CommandOutput output, } public Flux createFlux(Supplier> commandSupplier) { - return Flux.from(new RedisPublisher(commandSupplier, connection, false)); + return Flux.from(new RedisPublisher<>(commandSupplier, connection, false)); } protected Mono createMono(CommandType type, CommandOutput output, CommandArgs args) { @@ -1776,12 +1776,12 @@ protected Mono createMono(CommandType type, CommandOutput output } public Mono createMono(Supplier> commandSupplier) { - return Mono.from(new RedisPublisher(commandSupplier, connection, false)); + return Mono.from(new RedisPublisher<>(commandSupplier, connection, false)); } @SuppressWarnings("unchecked") public Flux createDissolvingFlux(Supplier> commandSupplier) { - return (Flux) Flux.from(new RedisPublisher(commandSupplier, connection, true)); + return (Flux) Flux.from(new RedisPublisher<>(commandSupplier, connection, true)); } public void setTimeout(long timeout, TimeUnit unit) { diff --git a/src/main/java/com/lambdaworks/redis/RedisClient.java b/src/main/java/com/lambdaworks/redis/RedisClient.java index cdcc455459..91292f3391 100644 --- a/src/main/java/com/lambdaworks/redis/RedisClient.java +++ b/src/main/java/com/lambdaworks/redis/RedisClient.java @@ -290,9 +290,9 @@ private StatefulRedisPubSubConnection connectPubSub(RedisCodec endpoint = new PubSubEndpoint(clientOptions); StatefulRedisPubSubConnectionImpl connection = newStatefulRedisPubSubConnection(endpoint, - (RedisChannelWriter) endpoint, codec, timeout.timeout, timeout.timeUnit); + endpoint, codec, timeout.timeout, timeout.timeUnit); - connectStateful(connection, redisURI, endpoint, () -> new PubSubCommandHandler(clientResources, codec, endpoint)); + connectStateful(connection, redisURI, endpoint, () -> new PubSubCommandHandler<>(clientResources, codec, endpoint)); return connection; } diff --git a/src/main/java/com/lambdaworks/redis/RedisPublisher.java b/src/main/java/com/lambdaworks/redis/RedisPublisher.java index f145a10ade..9f25888566 100644 --- a/src/main/java/com/lambdaworks/redis/RedisPublisher.java +++ b/src/main/java/com/lambdaworks/redis/RedisPublisher.java @@ -286,7 +286,7 @@ void checkCommandDispatch() { } } - @SuppressWarnings("unchecked") + @SuppressWarnings({"unchecked", "rawtypes"}) private void dispatchCommand() { if (command.getOutput() instanceof StreamingOutput) { StreamingOutput streamingOutput = (StreamingOutput) command.getOutput(); diff --git a/src/main/java/com/lambdaworks/redis/cluster/RedisAdvancedClusterReactiveCommandsImpl.java b/src/main/java/com/lambdaworks/redis/cluster/RedisAdvancedClusterReactiveCommandsImpl.java index 4d69878e1e..985812a43a 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/RedisAdvancedClusterReactiveCommandsImpl.java +++ b/src/main/java/com/lambdaworks/redis/cluster/RedisAdvancedClusterReactiveCommandsImpl.java @@ -124,6 +124,7 @@ public Flux> mget(K... keys) { return mget(Arrays.asList(keys)); } + @SuppressWarnings("unchecked") public Flux> mget(Iterable keys) { List keyList = LettuceLists.newList(keys); From 3c410bf8d4c0e85cddea17358038102b57fc2d21 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Sun, 4 Sep 2016 12:51:06 +0200 Subject: [PATCH 025/808] Provide connection pooling support #264 Lettuce now provides a more generic support to connection pooling. ConnectionPoolSupport requires a connection supplier to construct a connection pool. Pooled connection instances can be either wrapped to release connections back to the pool once they are closed or direct connections that require to be released after usage. ConnectionPoolSupport is intended to replace connection pooling on RedisClient entirely. Users get full control over the pool and can set up connection pooling to their needs without being constrained by predefined client methods. --- .../com/lambdaworks/redis/RedisClient.java | 6 - .../redis/support/ConnectionPoolSupport.java | 323 ++++++++++++++++++ .../support/ConnectionPoolSupportTest.java | 208 +++++++++++ 3 files changed, 531 insertions(+), 6 deletions(-) create mode 100644 src/main/java/com/lambdaworks/redis/support/ConnectionPoolSupport.java create mode 100644 src/test/java/com/lambdaworks/redis/support/ConnectionPoolSupportTest.java diff --git a/src/main/java/com/lambdaworks/redis/RedisClient.java b/src/main/java/com/lambdaworks/redis/RedisClient.java index 91292f3391..c90d311f2c 100644 --- a/src/main/java/com/lambdaworks/redis/RedisClient.java +++ b/src/main/java/com/lambdaworks/redis/RedisClient.java @@ -42,7 +42,6 @@ public class RedisClient extends AbstractRedisClient { private static final RedisURI EMPTY_URI = new RedisURI(); - private static final boolean POOL_AVAILABLE = isPresent("org.apache.commons.pool2.impl.GenericObjectPool"); private final RedisURI redisURI; @@ -568,11 +567,6 @@ private void checkForRedisURI() { checkValidRedisURI(this.redisURI); } - private void checkPoolDependency() { - LettuceAssert.assertState(POOL_AVAILABLE, - "Cannot use connection pooling without the optional Apache commons-pool2 library on the class path"); - } - /** * Set the {@link ClientOptions} for the client. * diff --git a/src/main/java/com/lambdaworks/redis/support/ConnectionPoolSupport.java b/src/main/java/com/lambdaworks/redis/support/ConnectionPoolSupport.java new file mode 100644 index 0000000000..5cb18ea4cb --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/support/ConnectionPoolSupport.java @@ -0,0 +1,323 @@ +package com.lambdaworks.redis.support; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Supplier; + +import com.lambdaworks.redis.RedisClient; +import com.lambdaworks.redis.RedisURI; +import com.lambdaworks.redis.api.StatefulRedisConnection; +import com.lambdaworks.redis.cluster.RedisClusterClient; +import com.lambdaworks.redis.cluster.api.StatefulRedisClusterConnection; +import org.apache.commons.pool2.BasePooledObjectFactory; +import org.apache.commons.pool2.ObjectPool; +import org.apache.commons.pool2.PooledObject; +import org.apache.commons.pool2.impl.DefaultPooledObject; +import org.apache.commons.pool2.impl.GenericObjectPool; +import org.apache.commons.pool2.impl.GenericObjectPoolConfig; +import org.apache.commons.pool2.impl.SoftReferenceObjectPool; + +import com.lambdaworks.redis.ClientOptions; +import com.lambdaworks.redis.RedisException; +import com.lambdaworks.redis.api.StatefulConnection; +import com.lambdaworks.redis.internal.AbstractInvocationHandler; +import com.lambdaworks.redis.internal.LettuceAssert; + +/** + * Connection pool support for {@link GenericObjectPool} and {@link SoftReferenceObjectPool}. Connection pool creation requires + * a {@link Supplier} that creates Redis connections. The pool can allocate either wrapped or direct connections. + *
      + *
    • Wrapped instances will return the connection back to the pool when called {@link StatefulConnection#close()}.
    • + *
    • Regular connections need to be returned to the pool with {@link GenericObjectPool#returnObject(Object)}
    • + *
    + *

    + * Lettuce connections are designed to be thread-safe so one connection can be shared amongst multiple threads and lettuce + * connections {@link ClientOptions#isAutoReconnect() auto-reconnect} by default. Connection pooling with lettuce might be + * required when you're invoking Redis operations in multiple threads and you use + *

      + *
    • blocking commands such as {@code BLPOP}.
    • + *
    • transactions {@code BLPOP}.
    • + *
    • {@link StatefulConnection#setAutoFlushCommands(boolean) command batching}.
    • + *
    + * + * Transactions and command batching affect connection state. Blocking commands won't propagate queued commands to Redis until + * the blocking command is resolved. + * + *

    Example usage

    + * + *
    + * // application initialization
    + * RedisClusterClient clusterClient = RedisClusterClient.create(RedisURI.create(host, port));
    + * GenericObjectPool<StatefulRedisClusterConnection<String, String>> pool = ConnectionPoolSupport
    + *         .createGenericObjectPool(() -> clusterClient.connect(), new GenericObjectPoolConfig());
    + * 
    + * // executing work
    + * try (StatefulRedisClusterConnection<String, String> connection = pool.borrowObject()) {
    + *     // perform some work
    + * }
    + * 
    + * // terminating
    + * pool.close();
    + * clusterClient.shutdown();
    + * 
    + * + * @author Mark Paluch + * @since 4.3 + */ +public abstract class ConnectionPoolSupport { + + private ConnectionPoolSupport() { + } + + /** + * Creates a new {@link GenericObjectPool} using the {@link Supplier}. Allocated instances are wrapped and must not be + * returned with {@link ObjectPool#returnObject(Object)}. + * + * @param connectionSupplier must not be {@literal null}. + * @param config must not be {@literal null}. + * @param connection type. + * @return the connection pool. + */ + public static > GenericObjectPool createGenericObjectPool( + Supplier connectionSupplier, GenericObjectPoolConfig config) { + return createGenericObjectPool(connectionSupplier, config, true); + } + + /** + * Creates a new {@link GenericObjectPool} using the {@link Supplier}. + * + * @param connectionSupplier must not be {@literal null}. + * @param config must not be {@literal null}. + * @param wrapConnections {@literal false} to return direct connections that need to be returned to the pool using + * {@link ObjectPool#returnObject(Object)}. {@literal true} to return wrapped connection that are returned to the + * pool when invoking {@link StatefulConnection#close()}. + * @param connection type. + * @return the connection pool. + */ + public static > GenericObjectPool createGenericObjectPool( + Supplier connectionSupplier, GenericObjectPoolConfig config, boolean wrapConnections) { + + LettuceAssert.notNull(connectionSupplier, "Connection supplier must not be null"); + LettuceAssert.notNull(config, "GenericObjectPoolConfig must not be null"); + + AtomicReference> poolRef = new AtomicReference<>(); + Supplier providerToUse = wrapConnections ? wrappedConnectionSupplier(connectionSupplier, poolRef) + : connectionSupplier; + + GenericObjectPool pool = new GenericObjectPool<>(new RedisPooledObjectFactory(providerToUse), config); + + poolRef.set(pool); + + return pool; + } + + /** + * Creates a new {@link SoftReferenceObjectPool} using the {@link Supplier}. Allocated instances are wrapped and must not be + * returned with {@link ObjectPool#returnObject(Object)}. + * + * @param connectionSupplier must not be {@literal null}. + * @param connection type. + * @return the connection pool. + */ + public static > SoftReferenceObjectPool createSoftReferenceObjectPool( + Supplier connectionSupplier) { + return createSoftReferenceObjectPool(connectionSupplier, true); + } + + /** + * Creates a new {@link SoftReferenceObjectPool} using the {@link Supplier}. + * + * @param connectionSupplier must not be {@literal null}. + * @param wrapConnections {@literal false} to return direct connections that need to be returned to the pool using + * {@link ObjectPool#returnObject(Object)}. {@literal true} to return wrapped connection that are returned to the + * pool when invoking {@link StatefulConnection#close()}. + * @param connection type. + * @return the connection pool. + */ + public static > SoftReferenceObjectPool createSoftReferenceObjectPool( + Supplier connectionSupplier, boolean wrapConnections) { + + LettuceAssert.notNull(connectionSupplier, "Connection supplier must not be null"); + + AtomicReference> poolRef = new AtomicReference<>(); + Supplier providerToUse = wrapConnections ? wrappedConnectionSupplier(connectionSupplier, poolRef) + : connectionSupplier; + + SoftReferenceObjectPool pool = new SoftReferenceObjectPool<>(new RedisPooledObjectFactory<>(providerToUse)); + poolRef.set(pool); + + return pool; + } + + @SuppressWarnings("unchecked") + private static Supplier wrappedConnectionSupplier(Supplier connectionSupplier, + AtomicReference> poolRef) { + + return new Supplier() { + + @Override + public T get() { + + T connection = connectionSupplier.get(); + ReturnObjectOnCloseInvocationHandler handler = new ReturnObjectOnCloseInvocationHandler<>(connection, + poolRef.get()); + + T proxiedConnection = (T) Proxy.newProxyInstance(getClass().getClassLoader(), + connection.getClass().getInterfaces(), handler); + handler.setProxiedConnection(proxiedConnection); + + return proxiedConnection; + } + }; + } + + /** + * @author Mark Paluch + * @since 4.3 + */ + private static class RedisPooledObjectFactory> extends BasePooledObjectFactory { + + private final Supplier connectionSupplier; + + RedisPooledObjectFactory(Supplier connectionSupplier) { + this.connectionSupplier = connectionSupplier; + } + + @Override + public T create() throws Exception { + return connectionSupplier.get(); + } + + @Override + public PooledObject wrap(T obj) { + return new DefaultPooledObject<>(obj); + } + + @Override + public boolean validateObject(PooledObject p) { + return p.getObject().isOpen(); + } + } + + /** + * Invocation handler that takes care of connection.close(). Connections are returned to the pool on a close()-call. + * + * @author Mark Paluch + * @param Connection type. + * @since 4.3 + */ + private static class ReturnObjectOnCloseInvocationHandler extends AbstractInvocationHandler { + + private T connection; + private T proxiedConnection; + private Map connectionProxies = new ConcurrentHashMap<>(5, 1); + + private final ObjectPool pool; + + ReturnObjectOnCloseInvocationHandler(T connection, ObjectPool pool) { + this.connection = connection; + this.pool = pool; + } + + void setProxiedConnection(T proxiedConnection) { + this.proxiedConnection = proxiedConnection; + } + + @SuppressWarnings("unchecked") + @Override + protected Object handleInvocation(Object proxy, Method method, Object[] args) throws Throwable { + + if (method.getName().equals("getStatefulConnection")) { + return proxiedConnection; + } + + if (connection == null) { + throw new RedisException("Connection is deallocated and cannot be used anymore."); + } + + if (method.getName().equals("close")) { + pool.returnObject(proxiedConnection); + connection = null; + proxiedConnection = null; + connectionProxies.clear(); + return null; + } + + try { + + if (method.getName().equals("sync") || method.getName().equals("async") + || method.getName().equals("reactive")) { + return connectionProxies.computeIfAbsent(method, m -> { + + try { + Object result = method.invoke(connection, args); + + result = Proxy.newProxyInstance(getClass().getClassLoader(), result.getClass().getInterfaces(), + new DelegateCloseToConnectionInvocationHandler((AutoCloseable) proxiedConnection, result)); + + return result; + } catch (IllegalAccessException e) { + throw new RedisException(e); + } catch (InvocationTargetException e) { + throw new RedisException(e.getTargetException()); + } + }); + } + + return method.invoke(connection, args); + + } catch (InvocationTargetException e) { + throw e.getTargetException(); + } + } + + public T getConnection() { + return connection; + } + } + + /** + * Invocation handler that takes care of connection.close(). Connections are returned to the pool on a close()-call. + * + * @author Mark Paluch + * @param Connection type. + * @since 4.3 + */ + private static class DelegateCloseToConnectionInvocationHandler extends AbstractInvocationHandler { + + private final T proxiedConnection; + private final Object api; + + DelegateCloseToConnectionInvocationHandler(T proxiedConnection, Object api) { + + this.proxiedConnection = proxiedConnection; + this.api = api; + } + + @SuppressWarnings("unchecked") + @Override + protected Object handleInvocation(Object proxy, Method method, Object[] args) throws Throwable { + + if (method.getName().equals("getStatefulConnection")) { + return proxiedConnection; + } + + try { + + if (method.getName().equals("close")) { + proxiedConnection.close(); + return null; + } + + return method.invoke(api, args); + + } catch (InvocationTargetException e) { + throw e.getTargetException(); + } + } + } +} diff --git a/src/test/java/com/lambdaworks/redis/support/ConnectionPoolSupportTest.java b/src/test/java/com/lambdaworks/redis/support/ConnectionPoolSupportTest.java new file mode 100644 index 0000000000..a9bf9246f8 --- /dev/null +++ b/src/test/java/com/lambdaworks/redis/support/ConnectionPoolSupportTest.java @@ -0,0 +1,208 @@ +package com.lambdaworks.redis.support; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.fail; + +import java.lang.reflect.Proxy; + +import org.apache.commons.pool2.impl.GenericObjectPool; +import org.apache.commons.pool2.impl.GenericObjectPoolConfig; +import org.apache.commons.pool2.impl.SoftReferenceObjectPool; +import org.junit.Test; + +import com.lambdaworks.TestClientResources; +import com.lambdaworks.redis.*; +import com.lambdaworks.redis.api.StatefulRedisConnection; +import com.lambdaworks.redis.api.async.RedisAsyncCommands; +import com.lambdaworks.redis.api.reactive.RedisReactiveCommands; +import com.lambdaworks.redis.api.sync.RedisCommands; +import com.lambdaworks.redis.cluster.RedisAdvancedClusterAsyncCommandsImpl; +import com.lambdaworks.redis.cluster.RedisAdvancedClusterReactiveCommandsImpl; +import com.lambdaworks.redis.cluster.RedisClusterClient; +import com.lambdaworks.redis.cluster.StatefulRedisClusterConnectionImpl; +import com.lambdaworks.redis.cluster.api.StatefulRedisClusterConnection; +import com.lambdaworks.redis.cluster.api.async.RedisAdvancedClusterAsyncCommands; +import com.lambdaworks.redis.cluster.api.reactive.RedisAdvancedClusterReactiveCommands; +import com.lambdaworks.redis.cluster.api.sync.RedisAdvancedClusterCommands; +import com.lambdaworks.redis.codec.StringCodec; +import com.lambdaworks.redis.masterslave.MasterSlave; +import com.lambdaworks.redis.masterslave.StatefulRedisMasterSlaveConnection; + +/** + * @author Mark Paluch + */ +public class ConnectionPoolSupportTest extends AbstractRedisClientTest { + + @Test + public void genericPoolShouldWorkWithWrappedConnections() throws Exception { + + GenericObjectPool> pool = ConnectionPoolSupport + .createGenericObjectPool(() -> client.connect(), new GenericObjectPoolConfig()); + + StatefulRedisConnection connection = pool.borrowObject(); + RedisCommands sync = connection.sync(); + sync.ping(); + + connection.close(); + pool.close(); + } + + @Test + public void genericPoolUsingWrappingShouldPropagateExceptionsCorrectly() throws Exception { + + GenericObjectPool> pool = ConnectionPoolSupport + .createGenericObjectPool(() -> client.connect(), new GenericObjectPoolConfig()); + + StatefulRedisConnection connection = pool.borrowObject(); + RedisCommands sync = connection.sync(); + sync.set(key, value); + + try { + sync.hgetall(key); + fail("Missing RedisCommandExecutionException"); + } catch (RedisCommandExecutionException e) { + assertThat(e).hasMessageContaining("WRONGTYPE"); + } + + connection.close(); + pool.close(); + } + + @Test + public void wrappedConnectionShouldUseWrappers() throws Exception { + + GenericObjectPool> pool = ConnectionPoolSupport + .createGenericObjectPool(() -> client.connect(), new GenericObjectPoolConfig()); + + StatefulRedisConnection connection = pool.borrowObject(); + RedisCommands sync = connection.sync(); + + assertThat(connection).isInstanceOf(StatefulRedisConnection.class) + .isNotInstanceOf(StatefulRedisClusterConnectionImpl.class); + assertThat(Proxy.isProxyClass(connection.getClass())).isTrue(); + + assertThat(sync).isInstanceOf(RedisCommands.class); + assertThat(connection.async()).isInstanceOf(RedisAsyncCommands.class).isNotInstanceOf(RedisAsyncCommandsImpl.class); + assertThat(connection.reactive()).isInstanceOf(RedisReactiveCommands.class) + .isNotInstanceOf(RedisReactiveCommandsImpl.class); + assertThat(sync.getStatefulConnection()).isInstanceOf(StatefulRedisConnection.class) + .isNotInstanceOf(StatefulRedisConnectionImpl.class).isSameAs(connection); + + connection.close(); + pool.close(); + } + + @Test + public void wrappedMasterSlaveConnectionShouldUseWrappers() throws Exception { + + GenericObjectPool> pool = ConnectionPoolSupport + .createGenericObjectPool(() -> MasterSlave.connect(client, new StringCodec(), RedisURI.create(host, port)), + new GenericObjectPoolConfig()); + + StatefulRedisMasterSlaveConnection connection = pool.borrowObject(); + RedisCommands sync = connection.sync(); + + assertThat(connection).isInstanceOf(StatefulRedisMasterSlaveConnection.class); + assertThat(Proxy.isProxyClass(connection.getClass())).isTrue(); + + assertThat(sync).isInstanceOf(RedisCommands.class); + assertThat(connection.async()).isInstanceOf(RedisAsyncCommands.class).isNotInstanceOf(RedisAsyncCommandsImpl.class); + assertThat(connection.reactive()).isInstanceOf(RedisReactiveCommands.class) + .isNotInstanceOf(RedisReactiveCommandsImpl.class); + assertThat(sync.getStatefulConnection()).isInstanceOf(StatefulRedisConnection.class) + .isNotInstanceOf(StatefulRedisConnectionImpl.class).isSameAs(connection); + + connection.close(); + pool.close(); + } + + @Test + public void wrappedClusterConnectionShouldUseWrappers() throws Exception { + + RedisClusterClient redisClusterClient = RedisClusterClient.create(TestClientResources.create(), + RedisURI.create(TestSettings.host(), 7379)); + + GenericObjectPool> pool = ConnectionPoolSupport + .createGenericObjectPool(redisClusterClient::connect, new GenericObjectPoolConfig()); + + StatefulRedisClusterConnection connection = pool.borrowObject(); + RedisAdvancedClusterCommands sync = connection.sync(); + + assertThat(connection).isInstanceOf(StatefulRedisClusterConnection.class) + .isNotInstanceOf(StatefulRedisClusterConnectionImpl.class); + assertThat(Proxy.isProxyClass(connection.getClass())).isTrue(); + + assertThat(sync).isInstanceOf(RedisAdvancedClusterCommands.class); + assertThat(connection.async()).isInstanceOf(RedisAdvancedClusterAsyncCommands.class) + .isNotInstanceOf(RedisAdvancedClusterAsyncCommandsImpl.class); + assertThat(connection.reactive()).isInstanceOf(RedisAdvancedClusterReactiveCommands.class) + .isNotInstanceOf(RedisAdvancedClusterReactiveCommandsImpl.class); + assertThat(sync.getStatefulConnection()).isInstanceOf(StatefulRedisClusterConnection.class) + .isNotInstanceOf(StatefulRedisClusterConnectionImpl.class).isSameAs(connection); + + connection.close(); + pool.close(); + + FastShutdown.shutdown(redisClusterClient); + } + + @Test + public void plainConnectionShouldNotUseWrappers() throws Exception { + + GenericObjectPool> pool = ConnectionPoolSupport + .createGenericObjectPool(() -> client.connect(), new GenericObjectPoolConfig(), false); + + StatefulRedisConnection connection = pool.borrowObject(); + RedisCommands sync = connection.sync(); + + assertThat(connection).isInstanceOf(StatefulRedisConnection.class) + .isNotInstanceOf(StatefulRedisClusterConnectionImpl.class); + assertThat(Proxy.isProxyClass(connection.getClass())).isFalse(); + + assertThat(sync).isInstanceOf(RedisCommands.class); + assertThat(connection.async()).isInstanceOf(RedisAsyncCommands.class).isInstanceOf(RedisAsyncCommandsImpl.class); + assertThat(connection.reactive()).isInstanceOf(RedisReactiveCommands.class) + .isInstanceOf(RedisReactiveCommandsImpl.class); + assertThat(sync.getStatefulConnection()).isInstanceOf(StatefulRedisConnection.class) + .isInstanceOf(StatefulRedisConnectionImpl.class); + + pool.returnObject(connection); + pool.close(); + } + + @Test + public void softRefPoolShouldWorkWithWrappedConnections() throws Exception { + + SoftReferenceObjectPool> pool = ConnectionPoolSupport + .createSoftReferenceObjectPool(() -> client.connect()); + + StatefulRedisConnection connection = pool.borrowObject(); + RedisCommands sync = connection.sync(); + sync.ping(); + + connection.close(); + pool.close(); + } + + @Test + public void wrappedObjectClosedAfterReturn() throws Exception { + + GenericObjectPool> pool = ConnectionPoolSupport + .createGenericObjectPool(() -> client.connect(), new GenericObjectPoolConfig(), true); + + StatefulRedisConnection connection = pool.borrowObject(); + RedisCommands sync = connection.sync(); + sync.ping(); + + connection.close(); + + try { + connection.isMulti(); + fail("Missing RedisException"); + } catch (RedisException e) { + assertThat(e).hasMessageContaining("deallocated"); + } + + pool.close(); + } +} \ No newline at end of file From 7fe21a7c10be42e2f9ec5dc4425859335f376242 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Sun, 18 Sep 2016 15:53:39 +0200 Subject: [PATCH 026/808] Polishing Add toString method to DefaultTransactionResult. --- .../redis/output/DefaultTransactionResult.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/main/java/com/lambdaworks/redis/output/DefaultTransactionResult.java b/src/main/java/com/lambdaworks/redis/output/DefaultTransactionResult.java index 3e73fdf480..10408b5965 100644 --- a/src/main/java/com/lambdaworks/redis/output/DefaultTransactionResult.java +++ b/src/main/java/com/lambdaworks/redis/output/DefaultTransactionResult.java @@ -65,4 +65,15 @@ public T get(int index) { public Stream stream() { return result.stream(); } + + @Override + public String toString() { + + StringBuilder sb = new StringBuilder(); + sb.append(getClass().getSimpleName()); + sb.append(" [wasRolledBack=").append(wasRolledBack); + sb.append(", responses=").append(size()); + sb.append(']'); + return sb.toString(); + } } From 4f677a2269c3b182aca681d6f1c85db45b1d8fd9 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Fri, 16 Sep 2016 17:57:07 +0200 Subject: [PATCH 027/808] Add support for topology consensus #355 Previously, cluster topology refreshing could get stuck on a node that was previously discovered but got removed from the cluster. This was possible because multiple views were obtained and any arbitrary topology view was chosen. Lettuce now implements two consensus algorithms: Healthy Majority and Known Majority. Healthy Majority is applied on the very first topology retrieval, Known Majority for all subsequent topology refreshes. Healthy Majority votes for topology views containing the most nodes with healthy flags (without FAIL/PFAIL/NOADDR flags) to use a most healthy view. Known Majority selects topology views that contain nodes that were previously known. This consensus works for adding and removing nodes one-by-one or even multiple nodes. In case a cluster is split into even partitions the client can still get stuck on either side, but that issue can be solved by disabling dynamic refresh sources and specifying stable cluster seed nodes. --- .../redis/cluster/PartitionsConsensus.java | 41 ++++++ .../cluster/PartitionsConsensusImpl.java | 103 +++++++++++++++ .../redis/cluster/RedisClusterClient.java | 18 ++- ...ealthyMajorityPartitionsConsensusTest.java | 97 ++++++++++++++ .../KnownMajorityPartitionsConsensusTest.java | 123 ++++++++++++++++++ .../PartitionsConsensusTestSupport.java | 37 ++++++ .../redis/cluster/RedisClusterClientTest.java | 8 +- .../redis/cluster/RedisClusterSetupTest.java | 9 -- 8 files changed, 424 insertions(+), 12 deletions(-) create mode 100644 src/main/java/com/lambdaworks/redis/cluster/PartitionsConsensus.java create mode 100644 src/main/java/com/lambdaworks/redis/cluster/PartitionsConsensusImpl.java create mode 100644 src/test/java/com/lambdaworks/redis/cluster/HealthyMajorityPartitionsConsensusTest.java create mode 100644 src/test/java/com/lambdaworks/redis/cluster/KnownMajorityPartitionsConsensusTest.java create mode 100644 src/test/java/com/lambdaworks/redis/cluster/PartitionsConsensusTestSupport.java diff --git a/src/main/java/com/lambdaworks/redis/cluster/PartitionsConsensus.java b/src/main/java/com/lambdaworks/redis/cluster/PartitionsConsensus.java new file mode 100644 index 0000000000..47b53d19f3 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/cluster/PartitionsConsensus.java @@ -0,0 +1,41 @@ +package com.lambdaworks.redis.cluster; + +import java.util.Map; + +import com.lambdaworks.redis.RedisURI; +import com.lambdaworks.redis.cluster.models.partitions.Partitions; + +/** + * Consensus API to decide on the {@link com.lambdaworks.redis.cluster.models.partitions.Partitions topology view} to be used by + * {@link RedisClusterClient}. + *

    + * {@link PartitionsConsensus} takes the current {@link Partitions} and a {@link java.util.Map} of newly retrieved + * {@link Partitions} to determine a view that shall be used. Implementing classes may reuse {@link Partitions} from input + * arguments or construct a new {@link Partitions} object. + * + * @author Mark Paluch + * @since 4.2 + * @see com.lambdaworks.redis.cluster.models.partitions.Partitions + * @see RedisClusterClient + */ +abstract class PartitionsConsensus { + + /** + * Consensus algorithm to select a partition containing the most previously known nodes. + */ + public static final PartitionsConsensus KNOWN_MAJORITY = new PartitionsConsensusImpl.KnownMajority(); + + /** + * Consensus algorithm to select a topology view containing the most active nodes. + */ + public static final PartitionsConsensus HEALTHY_MAJORITY = new PartitionsConsensusImpl.HealthyMajority(); + + /** + * Determine the {@link Partitions} to be used by {@link RedisClusterClient}. + * + * @param current the currently used topology view, must not be {@literal null}. + * @param topologyViews the newly retrieved views, must not be {@literal null}. + * @return the resulting {@link Partitions} to be used by {@link RedisClusterClient}. + */ + abstract Partitions getPartitions(Partitions current, Map topologyViews); +} diff --git a/src/main/java/com/lambdaworks/redis/cluster/PartitionsConsensusImpl.java b/src/main/java/com/lambdaworks/redis/cluster/PartitionsConsensusImpl.java new file mode 100644 index 0000000000..8fda339be0 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/cluster/PartitionsConsensusImpl.java @@ -0,0 +1,103 @@ +package com.lambdaworks.redis.cluster; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import com.lambdaworks.redis.RedisURI; +import com.lambdaworks.redis.cluster.models.partitions.Partitions; +import com.lambdaworks.redis.cluster.models.partitions.RedisClusterNode; + +/** + * Implementations for {@link PartitionsConsensus}. + * + * @author Mark Paluch + * @since 4.2 + */ +class PartitionsConsensusImpl { + + /** + * Votes for {@link Partitions} that contains the most known (previously existing) nodes. + */ + static final class KnownMajority extends PartitionsConsensus { + + @Override + Partitions getPartitions(Partitions current, Map topologyViews) { + + if (topologyViews.isEmpty()) { + return current; + } + + List votedList = new ArrayList<>(); + + for (Partitions partitions : topologyViews.values()) { + + int knownNodes = 0; + for (RedisClusterNode knownNode : current) { + + if (partitions.getPartitionByNodeId(knownNode.getNodeId()) != null) { + knownNodes++; + } + } + + votedList.add(new VotedPartitions(knownNodes, partitions)); + } + + Collections.shuffle(votedList); + Collections.sort(votedList, (o1, o2) -> Integer.compare(o2.votes, o1.votes)); + + return votedList.get(0).partitions; + } + } + + /** + * Votes for {@link Partitions} that contains the most active (in total) nodes. + */ + static final class HealthyMajority extends PartitionsConsensus { + + @Override + Partitions getPartitions(Partitions current, Map topologyViews) { + + if (topologyViews.isEmpty()) { + return current; + } + + List votedList = new ArrayList<>(); + + for (Partitions partitions : topologyViews.values()) { + + int votes = 0; + + for (RedisClusterNode node : partitions) { + + if (node.is(RedisClusterNode.NodeFlag.FAIL) || node.is(RedisClusterNode.NodeFlag.EVENTUAL_FAIL) + || node.is(RedisClusterNode.NodeFlag.NOADDR)) { + continue; + } + + votes++; + + } + + votedList.add(new VotedPartitions(votes, partitions)); + } + + Collections.shuffle(votedList); + Collections.sort(votedList, (o1, o2) -> Integer.compare(o2.votes, o1.votes)); + + return votedList.get(0).partitions; + } + } + + static final class VotedPartitions { + + final int votes; + final Partitions partitions; + + public VotedPartitions(int votes, Partitions partitions) { + this.votes = votes; + this.partitions = partitions; + } + } +} diff --git a/src/main/java/com/lambdaworks/redis/cluster/RedisClusterClient.java b/src/main/java/com/lambdaworks/redis/cluster/RedisClusterClient.java index 8137f700a7..44c97df19c 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/RedisClusterClient.java +++ b/src/main/java/com/lambdaworks/redis/cluster/RedisClusterClient.java @@ -657,7 +657,7 @@ protected Partitions loadPartitions() { throw new RedisException("Cannot retrieve initial cluster partitions from initial URIs " + topologyRefreshSource); } - Partitions loadedPartitions = partitions.values().iterator().next(); + Partitions loadedPartitions = determinePartitions(this.partitions, partitions); RedisURI viewedBy = refresh.getViewedBy(partitions, loadedPartitions); for (RedisClusterNode partition : loadedPartitions) { @@ -672,6 +672,22 @@ protected Partitions loadPartitions() { return loadedPartitions; } + /** + * Determines a {@link Partitions topology view} based on the current and the obtain topology views. + * + * @param current the current topology view. May be {@literal null} if {@link RedisClusterClient} has no topology view yet. + * @param topologyViews the obtain topology views + * @return the {@link Partitions topology view} to use. + */ + protected Partitions determinePartitions(Partitions current, Map topologyViews) { + + if (current == null) { + return PartitionsConsensus.HEALTHY_MAJORITY.getPartitions(null, topologyViews); + } + + return PartitionsConsensus.KNOWN_MAJORITY.getPartitions(current, topologyViews); + } + private void activateTopologyRefreshIfNeeded() { if (getOptions() instanceof ClusterClientOptions) { diff --git a/src/test/java/com/lambdaworks/redis/cluster/HealthyMajorityPartitionsConsensusTest.java b/src/test/java/com/lambdaworks/redis/cluster/HealthyMajorityPartitionsConsensusTest.java new file mode 100644 index 0000000000..b8cbd9df5d --- /dev/null +++ b/src/test/java/com/lambdaworks/redis/cluster/HealthyMajorityPartitionsConsensusTest.java @@ -0,0 +1,97 @@ +package com.lambdaworks.redis.cluster; + +import static com.lambdaworks.redis.cluster.PartitionsConsensusTestSupport.createMap; +import static com.lambdaworks.redis.cluster.PartitionsConsensusTestSupport.createNode; +import static com.lambdaworks.redis.cluster.PartitionsConsensusTestSupport.createPartitions; +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Arrays; +import java.util.Collections; +import java.util.Map; + +import org.junit.Test; + +import com.lambdaworks.redis.RedisURI; +import com.lambdaworks.redis.cluster.models.partitions.Partitions; +import com.lambdaworks.redis.cluster.models.partitions.RedisClusterNode; + +/** + * @author Mark Paluch + */ +public class HealthyMajorityPartitionsConsensusTest { + + private RedisClusterNode node1 = createNode(1); + private RedisClusterNode node2 = createNode(2); + private RedisClusterNode node3 = createNode(3); + private RedisClusterNode node4 = createNode(4); + private RedisClusterNode node5 = createNode(5); + + @Test + public void sameSharedViewShouldDecideForHealthyNodes() throws Exception { + + Partitions partitions1 = createPartitions(node1, node2, node3, node4, node5); + Partitions partitions2 = createPartitions(node1, node2, node3, node4, node5); + Partitions partitions3 = createPartitions(node1, node2, node3, node4, node5); + + Map map = createMap(partitions1, partitions2, partitions3); + + Partitions result = PartitionsConsensus.HEALTHY_MAJORITY.getPartitions(null, map); + + assertThat(Arrays.asList(partitions1, partitions2, partitions3)).contains(result); + } + + @Test + public void unhealthyNodeViewShouldDecideForHealthyNodes() throws Exception { + + Partitions partitions1 = createPartitions(node1, node2); + Partitions partitions2 = createPartitions(node2, node3, node4, node5); + Partitions partitions3 = createPartitions(node2, node3, node4, node5); + + Map map = createMap(partitions1, partitions2, partitions3); + + node2.setFlags(Collections.singleton(RedisClusterNode.NodeFlag.FAIL)); + node3.setFlags(Collections.singleton(RedisClusterNode.NodeFlag.FAIL)); + node4.setFlags(Collections.singleton(RedisClusterNode.NodeFlag.FAIL)); + node5.setFlags(Collections.singleton(RedisClusterNode.NodeFlag.FAIL)); + + Partitions result = PartitionsConsensus.HEALTHY_MAJORITY.getPartitions(null, map); + + assertThat(result).isSameAs(partitions1); + } + + @Test + public void splitNodeViewShouldDecideForHealthyNodes() throws Exception { + + Partitions partitions1 = createPartitions(node1, node2, node3); + Partitions partitions2 = createPartitions(); + Partitions partitions3 = createPartitions(node3, node4, node5); + + Map map = createMap(partitions1, partitions2, partitions3); + + node1.setFlags(Collections.singleton(RedisClusterNode.NodeFlag.FAIL)); + node2.setFlags(Collections.singleton(RedisClusterNode.NodeFlag.FAIL)); + node3.setFlags(Collections.singleton(RedisClusterNode.NodeFlag.FAIL)); + + Partitions result = PartitionsConsensus.HEALTHY_MAJORITY.getPartitions(null, map); + + assertThat(result).isSameAs(partitions3); + } + + @Test + public void splitUnhealthyNodeViewShouldDecideForHealthyNodes() throws Exception { + + Partitions partitions1 = createPartitions(node1, node2); + Partitions partitions2 = createPartitions(node2, node3); + Partitions partitions3 = createPartitions(node3, node4, node5); + + Map map = createMap(partitions1, partitions2, partitions3); + + node2.setFlags(Collections.singleton(RedisClusterNode.NodeFlag.FAIL)); + node3.setFlags(Collections.singleton(RedisClusterNode.NodeFlag.FAIL)); + node4.setFlags(Collections.singleton(RedisClusterNode.NodeFlag.FAIL)); + + Partitions result = PartitionsConsensus.HEALTHY_MAJORITY.getPartitions(null, map); + + assertThat(Arrays.asList(partitions1, partitions3)).contains(result); + } +} diff --git a/src/test/java/com/lambdaworks/redis/cluster/KnownMajorityPartitionsConsensusTest.java b/src/test/java/com/lambdaworks/redis/cluster/KnownMajorityPartitionsConsensusTest.java new file mode 100644 index 0000000000..08192f04ca --- /dev/null +++ b/src/test/java/com/lambdaworks/redis/cluster/KnownMajorityPartitionsConsensusTest.java @@ -0,0 +1,123 @@ +package com.lambdaworks.redis.cluster; + +import static com.lambdaworks.redis.cluster.PartitionsConsensusTestSupport.createMap; +import static com.lambdaworks.redis.cluster.PartitionsConsensusTestSupport.createNode; +import static com.lambdaworks.redis.cluster.PartitionsConsensusTestSupport.createPartitions; +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Arrays; +import java.util.Map; + +import org.junit.Test; + +import com.lambdaworks.redis.RedisURI; +import com.lambdaworks.redis.cluster.models.partitions.Partitions; +import com.lambdaworks.redis.cluster.models.partitions.RedisClusterNode; + +/** + * @author Mark Paluch + */ +public class KnownMajorityPartitionsConsensusTest { + + private RedisClusterNode node1 = createNode(1); + private RedisClusterNode node2 = createNode(2); + private RedisClusterNode node3 = createNode(3); + private RedisClusterNode node4 = createNode(4); + private RedisClusterNode node5 = createNode(5); + + @Test + public void sameSharedViewShouldDecideForKnownMajority() throws Exception { + + Partitions current = createPartitions(node1, node2, node3, node4, node5); + + Partitions partitions1 = createPartitions(node1, node2, node3, node4, node5); + Partitions partitions2 = createPartitions(node1, node2, node3, node4, node5); + Partitions partitions3 = createPartitions(node1, node2, node3, node4, node5); + + Map map = createMap(partitions1, partitions2, partitions3); + + Partitions result = PartitionsConsensus.KNOWN_MAJORITY.getPartitions(current, map); + + assertThat(Arrays.asList(partitions1, partitions2, partitions3)).contains(result); + } + + @Test + public void addedNodeViewShouldDecideForKnownMajority() throws Exception { + + Partitions current = createPartitions(node1, node2, node3, node4); + + Partitions partitions1 = createPartitions(node1, node2, node3, node4, node5); + Partitions partitions2 = createPartitions(node1, node2, node3, node4, node5); + Partitions partitions3 = createPartitions(node1, node2, node3, node4, node5); + + Map map = createMap(partitions1, partitions2, partitions3); + + Partitions result = PartitionsConsensus.KNOWN_MAJORITY.getPartitions(current, map); + + assertThat(Arrays.asList(partitions1, partitions2, partitions3)).contains(result); + } + + @Test + public void removedNodeViewShouldDecideForKnownMajority() throws Exception { + + Partitions current = createPartitions(node1, node2, node3, node4, node5); + + Partitions partitions1 = createPartitions(node1, node2, node3, node4); + Partitions partitions2 = createPartitions(node1, node2, node3, node4); + Partitions partitions3 = createPartitions(node1, node2, node3, node4); + + Map map = createMap(partitions1, partitions2, partitions3); + + Partitions result = PartitionsConsensus.KNOWN_MAJORITY.getPartitions(current, map); + + assertThat(Arrays.asList(partitions1, partitions2, partitions3)).contains(result); + } + + @Test + public void mixedViewShouldDecideForKnownMajority() throws Exception { + + Partitions current = createPartitions(node1, node2, node3, node4, node5); + + Partitions partitions1 = createPartitions(node1, node2, node3, node4); + Partitions partitions2 = createPartitions(node1, node2, node3, node5); + Partitions partitions3 = createPartitions(node1, node2, node4, node5); + + Map map = createMap(partitions1, partitions2, partitions3); + + Partitions result = PartitionsConsensus.KNOWN_MAJORITY.getPartitions(current, map); + + assertThat(Arrays.asList(partitions1, partitions2, partitions3)).contains(result); + } + + @Test + public void clusterSplitViewShouldDecideForKnownMajority() throws Exception { + + Partitions current = createPartitions(node1, node2, node3, node4, node5); + + Partitions partitions1 = createPartitions(node1, node2); + Partitions partitions2 = createPartitions(node1, node2); + Partitions partitions3 = createPartitions(node1, node2, node3, node4, node5); + + Map map = createMap(partitions1, partitions2, partitions3); + + Partitions result = PartitionsConsensus.KNOWN_MAJORITY.getPartitions(current, map); + + assertThat(result).isEqualTo(partitions3).isNotEqualTo(partitions1); + } + + @Test + public void strangeClusterSplitViewShouldDecideForKnownMajority() throws Exception { + + Partitions current = createPartitions(node1, node2, node3, node4, node5); + + Partitions partitions1 = createPartitions(node1); + Partitions partitions2 = createPartitions(node2); + Partitions partitions3 = createPartitions(node3); + + Map map = createMap(partitions1, partitions2, partitions3); + + Partitions result = PartitionsConsensus.KNOWN_MAJORITY.getPartitions(current, map); + + assertThat(Arrays.asList(partitions1, partitions2, partitions3)).contains(result); + } +} diff --git a/src/test/java/com/lambdaworks/redis/cluster/PartitionsConsensusTestSupport.java b/src/test/java/com/lambdaworks/redis/cluster/PartitionsConsensusTestSupport.java new file mode 100644 index 0000000000..94bb244045 --- /dev/null +++ b/src/test/java/com/lambdaworks/redis/cluster/PartitionsConsensusTestSupport.java @@ -0,0 +1,37 @@ +package com.lambdaworks.redis.cluster; + +import java.util.*; + +import com.lambdaworks.redis.RedisURI; +import com.lambdaworks.redis.cluster.models.partitions.Partitions; +import com.lambdaworks.redis.cluster.models.partitions.RedisClusterNode; + +/** + * @author Mark Paluch + */ +class PartitionsConsensusTestSupport { + + static RedisClusterNode createNode(int nodeId) { + return new RedisClusterNode(RedisURI.create("localhost", 6379 + nodeId), "" + nodeId, true, "", 0, 0, 0, + Collections.emptyList(), new HashSet<>()); + } + + static Partitions createPartitions(RedisClusterNode... nodes) { + + Partitions partitions = new Partitions(); + partitions.addAll(Arrays.asList(nodes)); + return partitions; + } + + static Map createMap(Partitions... partitionses) { + + Map partitionsMap = new HashMap<>(); + + int counter = 0; + for (Partitions partitions : partitionses) { + partitionsMap.put(createNode(counter++).getUri(), partitions); + } + + return partitionsMap; + } +} diff --git a/src/test/java/com/lambdaworks/redis/cluster/RedisClusterClientTest.java b/src/test/java/com/lambdaworks/redis/cluster/RedisClusterClientTest.java index eb91de2444..755da79b8e 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/RedisClusterClientTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/RedisClusterClientTest.java @@ -276,13 +276,17 @@ public void testClusterRedirectionLimit() throws Exception { Partitions partitions = clusterClient.getPartitions(); for (RedisClusterNode partition : partitions) { - partition.setSlots(new ArrayList<>()); - if (partition.getFlags().contains(RedisClusterNode.NodeFlag.MYSELF)) { + + if (partition.getSlots().contains(15495)) { + partition.setSlots(new ArrayList<>()); + } else { + partition.setSlots(new ArrayList<>()); int[] slots = createSlots(0, 16384); for (int i = 0; i < slots.length; i++) { partition.getSlots().add(i); } } + } partitions.updateCache(); diff --git a/src/test/java/com/lambdaworks/redis/cluster/RedisClusterSetupTest.java b/src/test/java/com/lambdaworks/redis/cluster/RedisClusterSetupTest.java index 8036310860..f9866abfe1 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/RedisClusterSetupTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/RedisClusterSetupTest.java @@ -511,15 +511,6 @@ private void assertExecuted(RedisFuture set) throws Exception { private void waitUntilOnlyOnePartition() throws InterruptedException, TimeoutException { Wait.untilEquals(1, () -> clusterClient.getPartitions().size()).waitOrTimeout(); - Wait.untilTrue(() -> { - for (RedisClusterNode redisClusterNode : clusterClient.getPartitions()) { - if (redisClusterNode.getSlots().size() > 16380) { - return true; - } - } - - return false; - }).waitOrTimeout(); } private void suspendConnection(RedisClusterAsyncCommands asyncCommands) From e059b38b48d399f8974322ac642792d51dc7793f Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Thu, 22 Sep 2016 14:12:35 +0200 Subject: [PATCH 028/808] Add test to verify behavior of GEODIST if a geoset is unknown #362 --- .../redis/commands/GeoCommandTest.java | 12 ++++++++++- .../reactive/GeoReactiveCommandTest.java | 20 ++++++++++++------- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/src/test/java/com/lambdaworks/redis/commands/GeoCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/GeoCommandTest.java index 01da41a338..0fa9d3c01f 100644 --- a/src/test/java/com/lambdaworks/redis/commands/GeoCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/GeoCommandTest.java @@ -103,6 +103,17 @@ public void geodist() throws Exception { assertThat(result).isGreaterThan(2.5).isLessThan(2.9); } + // See https://github.com/antirez/redis/issues/3512 and https://github.com/mp911de/lettuce/issues/362 + @Test(expected = RedisException.class) + public void geodistMissingElements() throws Exception { + + prepareGeo(); + + assertThat(redis.geodist("Unknown", "Unknown", "Bahn", GeoArgs.Unit.km)).isNull(); + assertThat(redis.geodist(key, "Unknown", "Bahn", GeoArgs.Unit.km)).isNull(); + assertThat(redis.geodist(key, "Weinheim", "Unknown", GeoArgs.Unit.km)).isNull(); + } + @Test public void geodistWithTransaction() throws Exception { @@ -114,7 +125,6 @@ public void geodistWithTransaction() throws Exception { // 10 mins with the bike assertThat(result).isGreaterThan(2.5).isLessThan(2.9); - } @Test diff --git a/src/test/java/com/lambdaworks/redis/commands/reactive/GeoReactiveCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/reactive/GeoReactiveCommandTest.java index ee5b74020f..c6f351ea4a 100644 --- a/src/test/java/com/lambdaworks/redis/commands/reactive/GeoReactiveCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/reactive/GeoReactiveCommandTest.java @@ -1,18 +1,19 @@ package com.lambdaworks.redis.commands.reactive; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.AssertionsForClassTypes.offset; + +import java.util.List; + +import org.junit.Ignore; +import org.junit.Test; + import com.lambdaworks.redis.GeoCoordinates; import com.lambdaworks.redis.Value; import com.lambdaworks.redis.api.reactive.RedisReactiveCommands; import com.lambdaworks.redis.api.sync.RedisCommands; import com.lambdaworks.redis.commands.GeoCommandTest; import com.lambdaworks.util.ReactiveSyncInvocationHandler; -import org.junit.Ignore; -import org.testng.annotations.Test; - -import java.util.List; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.AssertionsForClassTypes.offset; public class GeoReactiveCommandTest extends GeoCommandTest { @@ -42,4 +43,9 @@ public void geopos() throws Exception { @Override public void geoposWithTransaction() throws Exception { } + + @Test(expected = NumberFormatException.class) + public void geodistMissingElements() throws Exception { + super.geodistMissingElements(); + } } From 732d3ec920c3c3338e9d346cbba4942235ea3dc2 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Thu, 22 Sep 2016 21:01:13 +0200 Subject: [PATCH 029/808] Provide a more conceise API for Sorted Set query operations using Range/Limit #363 Lettuce now provides a more conceise API for Sorted Set handling. It adds Range/Limit types to encapsulate range boundaries and limitation arguments. Range now also encodes the boundary value using RedisCodec to guarantee same encoding and values to query using Z...LEX commands. Previous usage: redis.zrangebyscore(key, 2.0, 3.0); redis.zrangebyscore(key, "(1.0", "4.0"); redis.zrangebyscore(key, "-inf", "+inf"); redis.zrangebyscore(key, 0.0, 4.0, 1, 3); Range/Limit usage: redis.zrangebyscore(key, Range.create(2.0, 3.0))).isEqualTo(list("b", "c") redis.zrangebyscore(key, Range.from(Boundary.excluding(1.0), Boundary.including(4.0))) redis.zrangebyscore(key, Range.unbounded()) redis.zrangebyscore(key, Range.create(0.0, 4.0), Limit.create(1, 3)) --- .../redis/AbstractRedisAsyncCommands.java | 112 +++++++ .../redis/AbstractRedisReactiveCommands.java | 114 ++++++- .../java/com/lambdaworks/redis/Limit.java | 83 +++++ .../java/com/lambdaworks/redis/Range.java | 210 ++++++++++++ .../redis/RedisCommandBuilder.java | 231 ++++++++++++- .../async/RedisSortedSetAsyncCommands.java | 317 ++++++++++++++++++ .../RedisSortedSetReactiveCommands.java | 317 ++++++++++++++++++ .../api/sync/RedisSortedSetCommands.java | 317 ++++++++++++++++++ .../NodeSelectionSortedSetAsyncCommands.java | 317 ++++++++++++++++++ .../sync/NodeSelectionSortedSetCommands.java | 317 ++++++++++++++++++ .../redis/api/RedisSortedSetCommands.java | 317 ++++++++++++++++++ .../apigenerator/CompilationUnitFactory.java | 18 +- .../lambdaworks/apigenerator/Constants.java | 3 +- .../java/com/lambdaworks/redis/LimitTest.java | 31 ++ .../java/com/lambdaworks/redis/RangeTest.java | 92 +++++ .../redis/commands/CustomCommandTest.java | 5 + .../redis/commands/SortedSetCommandTest.java | 129 +++++-- 17 files changed, 2885 insertions(+), 45 deletions(-) create mode 100644 src/main/java/com/lambdaworks/redis/Limit.java create mode 100644 src/main/java/com/lambdaworks/redis/Range.java create mode 100644 src/test/java/com/lambdaworks/redis/LimitTest.java create mode 100644 src/test/java/com/lambdaworks/redis/RangeTest.java diff --git a/src/main/java/com/lambdaworks/redis/AbstractRedisAsyncCommands.java b/src/main/java/com/lambdaworks/redis/AbstractRedisAsyncCommands.java index 60c2e9596e..a8f102d1e7 100644 --- a/src/main/java/com/lambdaworks/redis/AbstractRedisAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/AbstractRedisAsyncCommands.java @@ -1074,6 +1074,11 @@ public RedisFuture zcount(K key, String min, String max) { return dispatch(commandBuilder.zcount(key, min, max)); } + @Override + public RedisFuture zcount(K key, Range range) { + return dispatch(commandBuilder.zcount(key, range)); + } + @Override public RedisFuture zincrby(K key, double amount, K member) { return dispatch(commandBuilder.zincrby(key, amount, member)); @@ -1109,6 +1114,11 @@ public RedisFuture> zrangebyscore(K key, String min, String max) { return dispatch(commandBuilder.zrangebyscore(key, min, max)); } + @Override + public RedisFuture> zrangebyscore(K key, Range range) { + return dispatch(commandBuilder.zrangebyscore(key, range, Limit.unlimited())); + } + @Override public RedisFuture> zrangebyscore(K key, double min, double max, long offset, long count) { return dispatch(commandBuilder.zrangebyscore(key, min, max, offset, count)); @@ -1119,6 +1129,11 @@ public RedisFuture> zrangebyscore(K key, String min, String max, long of return dispatch(commandBuilder.zrangebyscore(key, min, max, offset, count)); } + @Override + public RedisFuture> zrangebyscore(K key, Range range, Limit limit) { + return dispatch(commandBuilder.zrangebyscore(key, range, limit)); + } + @Override public RedisFuture>> zrangebyscoreWithScores(K key, double min, double max) { return dispatch(commandBuilder.zrangebyscoreWithScores(key, min, max)); @@ -1129,6 +1144,11 @@ public RedisFuture>> zrangebyscoreWithScores(K key, String m return dispatch(commandBuilder.zrangebyscoreWithScores(key, min, max)); } + @Override + public RedisFuture>> zrangebyscoreWithScores(K key, Range range) { + return dispatch(commandBuilder.zrangebyscoreWithScores(key, range, Limit.unlimited())); + } + @Override public RedisFuture>> zrangebyscoreWithScores(K key, double min, double max, long offset, long count) { return dispatch(commandBuilder.zrangebyscoreWithScores(key, min, max, offset, count)); @@ -1139,6 +1159,11 @@ public RedisFuture>> zrangebyscoreWithScores(K key, String m return dispatch(commandBuilder.zrangebyscoreWithScores(key, min, max, offset, count)); } + @Override + public RedisFuture>> zrangebyscoreWithScores(K key, Range range, Limit limit) { + return dispatch(commandBuilder.zrangebyscoreWithScores(key, range, limit)); + } + @Override public RedisFuture zrange(ValueStreamingChannel channel, K key, long start, long stop) { return dispatch(commandBuilder.zrange(channel, key, start, stop)); @@ -1159,6 +1184,11 @@ public RedisFuture zrangebyscore(ValueStreamingChannel channel, K key, return dispatch(commandBuilder.zrangebyscore(channel, key, min, max)); } + @Override + public RedisFuture zrangebyscore(ValueStreamingChannel channel, K key, Range range) { + return dispatch(commandBuilder.zrangebyscore(channel, key, range, Limit.unlimited())); + } + @Override public RedisFuture zrangebyscore(ValueStreamingChannel channel, K key, double min, double max, long offset, long count) { @@ -1171,6 +1201,11 @@ public RedisFuture zrangebyscore(ValueStreamingChannel channel, K key, return dispatch(commandBuilder.zrangebyscore(channel, key, min, max, offset, count)); } + @Override + public RedisFuture zrangebyscore(ValueStreamingChannel channel, K key, Range range, Limit limit) { + return dispatch(commandBuilder.zrangebyscore(channel, key, range, limit)); + } + @Override public RedisFuture zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, double min, double max) { return dispatch(commandBuilder.zrangebyscoreWithScores(channel, key, min, max)); @@ -1181,6 +1216,11 @@ public RedisFuture zrangebyscoreWithScores(ScoredValueStreamingChannel return dispatch(commandBuilder.zrangebyscoreWithScores(channel, key, min, max)); } + @Override + public RedisFuture zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, Range range) { + return dispatch(commandBuilder.zrangebyscoreWithScores(channel, key, range, Limit.unlimited())); + } + @Override public RedisFuture zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, double min, double max, long offset, long count) { @@ -1193,6 +1233,12 @@ public RedisFuture zrangebyscoreWithScores(ScoredValueStreamingChannel return dispatch(commandBuilder.zrangebyscoreWithScores(channel, key, min, max, offset, count)); } + @Override + public RedisFuture zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, Range range, + Limit limit) { + return dispatch(commandBuilder.zrangebyscoreWithScores(channel, key, range, limit)); + } + @Override public RedisFuture zrank(K key, V member) { return dispatch(commandBuilder.zrank(key, member)); @@ -1218,6 +1264,11 @@ public RedisFuture zremrangebyscore(K key, String min, String max) { return dispatch(commandBuilder.zremrangebyscore(key, min, max)); } + @Override + public RedisFuture zremrangebyscore(K key, Range range) { + return dispatch(commandBuilder.zremrangebyscore(key, range)); + } + @Override public RedisFuture> zrevrange(K key, long start, long stop) { return dispatch(commandBuilder.zrevrange(key, start, stop)); @@ -1238,6 +1289,11 @@ public RedisFuture> zrevrangebyscore(K key, String max, String min) { return dispatch(commandBuilder.zrevrangebyscore(key, max, min)); } + @Override + public RedisFuture> zrevrangebyscore(K key, Range range) { + return dispatch(commandBuilder.zrevrangebyscore(key, range, Limit.unlimited())); + } + @Override public RedisFuture> zrevrangebyscore(K key, double max, double min, long offset, long count) { return dispatch(commandBuilder.zrevrangebyscore(key, max, min, offset, count)); @@ -1248,6 +1304,11 @@ public RedisFuture> zrevrangebyscore(K key, String max, String min, long return dispatch(commandBuilder.zrevrangebyscore(key, max, min, offset, count)); } + @Override + public RedisFuture> zrevrangebyscore(K key, Range range, Limit limit) { + return dispatch(commandBuilder.zrevrangebyscore(key, range, limit)); + } + @Override public RedisFuture>> zrevrangebyscoreWithScores(K key, double max, double min) { return dispatch(commandBuilder.zrevrangebyscoreWithScores(key, max, min)); @@ -1258,6 +1319,11 @@ public RedisFuture>> zrevrangebyscoreWithScores(K key, Strin return dispatch(commandBuilder.zrevrangebyscoreWithScores(key, max, min)); } + @Override + public RedisFuture>> zrevrangebyscoreWithScores(K key, Range range) { + return dispatch(commandBuilder.zrevrangebyscoreWithScores(key, range, Limit.unlimited())); + } + @Override public RedisFuture>> zrevrangebyscoreWithScores(K key, double max, double min, long offset, long count) { return dispatch(commandBuilder.zrevrangebyscoreWithScores(key, max, min, offset, count)); @@ -1268,6 +1334,11 @@ public RedisFuture>> zrevrangebyscoreWithScores(K key, Strin return dispatch(commandBuilder.zrevrangebyscoreWithScores(key, max, min, offset, count)); } + @Override + public RedisFuture>> zrevrangebyscoreWithScores(K key, Range range, Limit limit) { + return dispatch(commandBuilder.zrevrangebyscoreWithScores(key, range, limit)); + } + @Override public RedisFuture zrevrange(ValueStreamingChannel channel, K key, long start, long stop) { return dispatch(commandBuilder.zrevrange(channel, key, start, stop)); @@ -1288,6 +1359,11 @@ public RedisFuture zrevrangebyscore(ValueStreamingChannel channel, K ke return dispatch(commandBuilder.zrevrangebyscore(channel, key, max, min)); } + @Override + public RedisFuture zrevrangebyscore(ValueStreamingChannel channel, K key, Range range) { + return dispatch(commandBuilder.zrevrangebyscore(channel, key, range, Limit.unlimited())); + } + @Override public RedisFuture zrevrangebyscore(ValueStreamingChannel channel, K key, double max, double min, long offset, long count) { @@ -1300,6 +1376,11 @@ public RedisFuture zrevrangebyscore(ValueStreamingChannel channel, K ke return dispatch(commandBuilder.zrevrangebyscore(channel, key, max, min, offset, count)); } + @Override + public RedisFuture zrevrangebyscore(ValueStreamingChannel channel, K key, Range range, Limit limit) { + return dispatch(commandBuilder.zrevrangebyscore(channel, key, range, limit)); + } + @Override public RedisFuture zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, double max, double min) { return dispatch(commandBuilder.zrevrangebyscoreWithScores(channel, key, max, min)); @@ -1310,6 +1391,11 @@ public RedisFuture zrevrangebyscoreWithScores(ScoredValueStreamingChannel< return dispatch(commandBuilder.zrevrangebyscoreWithScores(channel, key, max, min)); } + @Override + public RedisFuture zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, Range range) { + return dispatch(commandBuilder.zrevrangebyscoreWithScores(channel, key, range, Limit.unlimited())); + } + @Override public RedisFuture zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, double max, double min, long offset, long count) { @@ -1322,6 +1408,12 @@ public RedisFuture zrevrangebyscoreWithScores(ScoredValueStreamingChannel< return dispatch(commandBuilder.zrevrangebyscoreWithScores(channel, key, max, min, offset, count)); } + @Override + public RedisFuture zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, Range range, + Limit limit) { + return dispatch(commandBuilder.zrevrangebyscoreWithScores(channel, key, range, limit)); + } + @Override public RedisFuture zrevrank(K key, V member) { return dispatch(commandBuilder.zrevrank(key, member)); @@ -1664,21 +1756,41 @@ public RedisFuture zlexcount(K key, String min, String max) { return dispatch(commandBuilder.zlexcount(key, min, max)); } + @Override + public RedisFuture zlexcount(K key, Range range) { + return dispatch(commandBuilder.zlexcount(key, range)); + } + @Override public RedisFuture zremrangebylex(K key, String min, String max) { return dispatch(commandBuilder.zremrangebylex(key, min, max)); } + @Override + public RedisFuture zremrangebylex(K key, Range range) { + return dispatch(commandBuilder.zremrangebylex(key, range)); + } + @Override public RedisFuture> zrangebylex(K key, String min, String max) { return dispatch(commandBuilder.zrangebylex(key, min, max)); } + @Override + public RedisFuture> zrangebylex(K key, Range range) { + return dispatch(commandBuilder.zrangebylex(key, range, Limit.unlimited())); + } + @Override public RedisFuture> zrangebylex(K key, String min, String max, long offset, long count) { return dispatch(commandBuilder.zrangebylex(key, min, max, offset, count)); } + @Override + public RedisFuture> zrangebylex(K key, Range range, Limit limit) { + return dispatch(commandBuilder.zrangebylex(key, range, limit)); + } + @Override public RedisFuture geoadd(K key, double longitude, double latitude, V member) { return dispatch(commandBuilder.geoadd(key, longitude, latitude, member)); diff --git a/src/main/java/com/lambdaworks/redis/AbstractRedisReactiveCommands.java b/src/main/java/com/lambdaworks/redis/AbstractRedisReactiveCommands.java index 9451d3d22f..a34dc499ca 100644 --- a/src/main/java/com/lambdaworks/redis/AbstractRedisReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/AbstractRedisReactiveCommands.java @@ -1080,6 +1080,11 @@ public Mono zinterstore(K destination, K... keys) { return createMono(() -> commandBuilder.zinterstore(destination, keys)); } + @Override + public Mono zcount(K key, Range range) { + return createMono(() -> commandBuilder.zcount(key, range)); + } + @Override public Mono zinterstore(K destination, ZStoreArgs storeArgs, K... keys) { return createMono(() -> commandBuilder.zinterstore(destination, storeArgs, keys)); @@ -1115,6 +1120,11 @@ public Flux zrangebyscore(K key, String min, String max, long offset, long co return createDissolvingFlux(() -> commandBuilder.zrangebyscore(key, min, max, offset, count)); } + @Override + public Flux zrangebyscore(K key, Range range) { + return createDissolvingFlux(() -> commandBuilder.zrangebyscore(key, range, Limit.unlimited())); + } + @Override public Flux> zrangebyscoreWithScores(K key, double min, double max) { return createDissolvingFlux(() -> commandBuilder.zrangebyscoreWithScores(key, min, max)); @@ -1125,6 +1135,11 @@ public Flux> zrangebyscoreWithScores(K key, String min, String ma return createDissolvingFlux(() -> commandBuilder.zrangebyscoreWithScores(key, min, max)); } + @Override + public Flux zrangebyscore(K key, Range range, Limit limit) { + return createDissolvingFlux(() -> commandBuilder.zrangebyscore(key, range, limit)); + } + @Override public Flux> zrangebyscoreWithScores(K key, double min, double max, long offset, long count) { return createDissolvingFlux(() -> commandBuilder.zrangebyscoreWithScores(key, min, max, offset, count)); @@ -1135,6 +1150,11 @@ public Flux> zrangebyscoreWithScores(K key, String min, String ma return createDissolvingFlux(() -> commandBuilder.zrangebyscoreWithScores(key, min, max, offset, count)); } + @Override + public Flux> zrangebyscoreWithScores(K key, Range range) { + return createDissolvingFlux(() -> commandBuilder.zrangebyscoreWithScores(key, range, Limit.unlimited())); + } + @Override public Mono zrange(ValueStreamingChannel channel, K key, long start, long stop) { return createMono(() -> commandBuilder.zrange(channel, key, start, stop)); @@ -1145,6 +1165,11 @@ public Mono zrangeWithScores(ScoredValueStreamingChannel channel, K key return createMono(() -> commandBuilder.zrangeWithScores(channel, key, start, stop)); } + @Override + public Flux> zrangebyscoreWithScores(K key, Range range, Limit limit) { + return createDissolvingFlux(() -> commandBuilder.zrangebyscoreWithScores(key, range, limit)); + } + @Override public Mono zrangebyscore(ValueStreamingChannel channel, K key, double min, double max) { return createMono(() -> commandBuilder.zrangebyscore(channel, key, min, max)); @@ -1161,12 +1186,22 @@ public Mono zrangebyscore(ValueStreamingChannel channel, K key, double return createMono(() -> commandBuilder.zrangebyscore(channel, key, min, max, offset, count)); } + @Override + public Mono zrangebyscore(ValueStreamingChannel channel, K key, Range range) { + return createMono(() -> commandBuilder.zrangebyscore(channel, key, range, Limit.unlimited())); + } + @Override public Mono zrangebyscore(ValueStreamingChannel channel, K key, String min, String max, long offset, long count) { return createMono(() -> commandBuilder.zrangebyscore(channel, key, min, max, offset, count)); } + @Override + public Mono zrangebyscore(ValueStreamingChannel channel, K key, Range range, Limit limit) { + return createMono(() -> commandBuilder.zrangebyscore(channel, key, range, limit)); + } + @Override public Mono zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, double min, double max) { return createMono(() -> commandBuilder.zrangebyscoreWithScores(channel, key, min, max)); @@ -1177,6 +1212,11 @@ public Mono zrangebyscoreWithScores(ScoredValueStreamingChannel channel return createMono(() -> commandBuilder.zrangebyscoreWithScores(channel, key, min, max)); } + @Override + public Mono zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, Range range) { + return createMono(() -> commandBuilder.zrangebyscoreWithScores(channel, key, range, Limit.unlimited())); + } + @Override public Mono zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, double min, double max, long offset, long count) { @@ -1189,6 +1229,12 @@ public Mono zrangebyscoreWithScores(ScoredValueStreamingChannel channel return createMono(() -> commandBuilder.zrangebyscoreWithScores(channel, key, min, max, offset, count)); } + @Override + public Mono zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, Range range, + Limit limit) { + return createMono(() -> commandBuilder.zrangebyscoreWithScores(channel, key, range, limit)); + } + @Override public Mono zrank(K key, V member) { return createMono(() -> commandBuilder.zrank(key, member)); @@ -1214,6 +1260,11 @@ public Mono zremrangebyscore(K key, String min, String max) { return createMono(() -> commandBuilder.zremrangebyscore(key, min, max)); } + @Override + public Mono zremrangebyscore(K key, Range range) { + return createMono(() -> commandBuilder.zremrangebyscore(key, range)); + } + @Override public Flux zrevrange(K key, long start, long stop) { return createDissolvingFlux(() -> commandBuilder.zrevrange(key, start, stop)); @@ -1234,6 +1285,11 @@ public Flux zrevrangebyscore(K key, String max, String min) { return createDissolvingFlux(() -> commandBuilder.zrevrangebyscore(key, max, min)); } + @Override + public Flux zrevrangebyscore(K key, Range range) { + return createDissolvingFlux(() -> commandBuilder.zrevrangebyscore(key, range, Limit.unlimited())); + } + @Override public Flux zrevrangebyscore(K key, double max, double min, long offset, long count) { return createDissolvingFlux(() -> commandBuilder.zrevrangebyscore(key, max, min, offset, count)); @@ -1244,6 +1300,11 @@ public Flux zrevrangebyscore(K key, String max, String min, long offset, long return createDissolvingFlux(() -> commandBuilder.zrevrangebyscore(key, max, min, offset, count)); } + @Override + public Flux zrevrangebyscore(K key, Range range, Limit limit) { + return createDissolvingFlux(() -> commandBuilder.zrevrangebyscore(key, range, limit)); + } + @Override public Flux> zrevrangebyscoreWithScores(K key, double max, double min) { return createDissolvingFlux(() -> commandBuilder.zrevrangebyscoreWithScores(key, max, min)); @@ -1254,6 +1315,11 @@ public Flux> zrevrangebyscoreWithScores(K key, String max, String return createDissolvingFlux(() -> commandBuilder.zrevrangebyscoreWithScores(key, max, min)); } + @Override + public Flux> zrevrangebyscoreWithScores(K key, Range range) { + return createDissolvingFlux(() -> commandBuilder.zrevrangebyscoreWithScores(key, range, Limit.unlimited())); + } + @Override public Flux> zrevrangebyscoreWithScores(K key, double max, double min, long offset, long count) { return createDissolvingFlux(() -> commandBuilder.zrevrangebyscoreWithScores(key, max, min, offset, count)); @@ -1264,6 +1330,11 @@ public Flux> zrevrangebyscoreWithScores(K key, String max, String return createDissolvingFlux(() -> commandBuilder.zrevrangebyscoreWithScores(key, max, min, offset, count)); } + @Override + public Flux> zrevrangebyscoreWithScores(K key, Range range, Limit limit) { + return createDissolvingFlux(() -> commandBuilder.zrevrangebyscoreWithScores(key, range, limit)); + } + @Override public Mono zrevrange(ValueStreamingChannel channel, K key, long start, long stop) { return createMono(() -> commandBuilder.zrevrange(channel, key, start, stop)); @@ -1284,6 +1355,11 @@ public Mono zrevrangebyscore(ValueStreamingChannel channel, K key, Stri return createMono(() -> commandBuilder.zrevrangebyscore(channel, key, max, min)); } + @Override + public Mono zrevrangebyscore(ValueStreamingChannel channel, K key, Range range) { + return createMono(() -> commandBuilder.zrevrangebyscore(channel, key, range, Limit.unlimited())); + } + @Override public Mono zrevrangebyscore(ValueStreamingChannel channel, K key, double max, double min, long offset, long count) { @@ -1296,6 +1372,11 @@ public Mono zrevrangebyscore(ValueStreamingChannel channel, K key, Stri return createMono(() -> commandBuilder.zrevrangebyscore(channel, key, max, min, offset, count)); } + @Override + public Mono zrevrangebyscore(ValueStreamingChannel channel, K key, Range range, Limit limit) { + return createMono(() -> commandBuilder.zrevrangebyscore(channel, key, range, limit)); + } + @Override public Mono zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, double max, double min) { return createMono(() -> commandBuilder.zrevrangebyscoreWithScores(channel, key, max, min)); @@ -1306,6 +1387,11 @@ public Mono zrevrangebyscoreWithScores(ScoredValueStreamingChannel chan return createMono(() -> commandBuilder.zrevrangebyscoreWithScores(channel, key, max, min)); } + @Override + public Mono zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, Range range) { + return createMono(() -> commandBuilder.zrevrangebyscoreWithScores(channel, key, range, Limit.unlimited())); + } + @Override public Mono zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, double max, double min, long offset, long count) { @@ -1318,6 +1404,12 @@ public Mono zrevrangebyscoreWithScores(ScoredValueStreamingChannel chan return createMono(() -> commandBuilder.zrevrangebyscoreWithScores(channel, key, max, min, offset, count)); } + @Override + public Mono zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, Range range, + Limit limit) { + return createMono(() -> commandBuilder.zrevrangebyscoreWithScores(channel, key, range, limit)); + } + @Override public Mono zrevrank(K key, V member) { return createMono(() -> commandBuilder.zrevrank(key, member)); @@ -1672,21 +1764,41 @@ public Mono zlexcount(K key, String min, String max) { return createMono(() -> commandBuilder.zlexcount(key, min, max)); } + @Override + public Mono zlexcount(K key, Range range) { + return createMono(() -> commandBuilder.zlexcount(key, range)); + } + @Override public Mono zremrangebylex(K key, String min, String max) { return createMono(() -> commandBuilder.zremrangebylex(key, min, max)); } + @Override + public Mono zremrangebylex(K key, Range range) { + return createMono(() -> commandBuilder.zremrangebylex(key, range)); + } + @Override public Flux zrangebylex(K key, String min, String max) { return createDissolvingFlux(() -> commandBuilder.zrangebylex(key, min, max)); } + @Override + public Flux zrangebylex(K key, Range range) { + return createDissolvingFlux(() -> commandBuilder.zrangebylex(key, range, Limit.unlimited())); + } + @Override public Flux zrangebylex(K key, String min, String max, long offset, long count) { return createDissolvingFlux(() -> commandBuilder.zrangebylex(key, min, max, offset, count)); } + @Override + public Flux zrangebylex(K key, Range range, Limit limit) { + return createDissolvingFlux(() -> commandBuilder.zrangebylex(key, range, limit)); + } + @Override public Mono geoadd(K key, double longitude, double latitude, V member) { return createMono(() -> commandBuilder.geoadd(key, longitude, latitude, member)); @@ -1778,7 +1890,7 @@ protected Mono createMono(CommandType type, CommandOutput output public Mono createMono(Supplier> commandSupplier) { return Mono.from(new RedisPublisher<>(commandSupplier, connection, false)); } - + @SuppressWarnings("unchecked") public Flux createDissolvingFlux(Supplier> commandSupplier) { return (Flux) Flux.from(new RedisPublisher<>(commandSupplier, connection, true)); diff --git a/src/main/java/com/lambdaworks/redis/Limit.java b/src/main/java/com/lambdaworks/redis/Limit.java new file mode 100644 index 0000000000..87042362a0 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/Limit.java @@ -0,0 +1,83 @@ +package com.lambdaworks.redis; + +/** + * Value object for a slice of data (offset/count). + * + * @author Mark Paluch + * @since 4.2 + */ +public class Limit { + + private static final Limit UNLIMITED = new Limit(null, null); + + private final Long offset; + private final Long count; + + protected Limit(Long offset, Long count) { + this.offset = offset; + this.count = count; + } + + /** + * + * @return an unlimited limit. + */ + public static Limit unlimited() { + return UNLIMITED; + } + + /** + * Creates a {@link Limit} given {@code offset} and {@code count}. + * + * @param offset + * @param count + * @return the {@link Limit} + */ + public static Limit create(long offset, long count) { + return new Limit(offset, count); + } + + /** + * @return the offset or {@literal -1} if unlimited. + */ + public long getOffset() { + + if (offset != null) { + return offset; + } + + return -1; + } + + /** + * @return the count or {@literal -1} if unlimited. + */ + public long getCount() { + + if (count != null) { + return count; + } + + return -1; + } + + /** + * + * @return {@literal true} if the {@link Limit} contains a limitation. + */ + public boolean isLimited() { + return offset != null && count != null; + } + + @Override + public String toString() { + + StringBuilder sb = new StringBuilder(); + sb.append(getClass().getSimpleName()); + if (isLimited()) { + return sb.append(" [offset=").append(getOffset()).append(", count=").append(getCount()).append("]").toString(); + } + + return sb.append(" [unlimited]").toString(); + } +} diff --git a/src/main/java/com/lambdaworks/redis/Range.java b/src/main/java/com/lambdaworks/redis/Range.java new file mode 100644 index 0000000000..98a416f0a5 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/Range.java @@ -0,0 +1,210 @@ +package com.lambdaworks.redis; + +import com.lambdaworks.redis.internal.LettuceAssert; + +/** + * {@link Range} defines {@literal lower} and {@literal upper} boundaries to retrieve items from a sorted set. + * + * @author Mark Paluch + * @since 4.3 + */ +public class Range { + + private Boundary lower; + private Boundary upper; + + private Range(Boundary lower, Boundary upper) { + + LettuceAssert.notNull(lower, "Lower boundary must not be null"); + LettuceAssert.notNull(upper, "Upper boundary must not be null"); + + this.lower = lower; + this.upper = upper; + } + + /** + * Create a new range from {@code lower} and {@code upper} boundary values. Both values are included (greater than or equals + * and less than or equals). + * + * @return new {@link Range} + */ + public static Range create(T lower, T upper) { + return new Range(Boundary.including(lower), Boundary.including(upper)); + } + + /** + * Create a new range from {@code lower} and {@code upper} boundaries. + * + * @param lower lower boundary, must not be {@literal null}. + * @param upper upper boundary, must not be {@literal null}. + * @return new {@link Range} + */ + public static Range from(Boundary lower, Boundary upper) { + return new Range(lower, upper); + } + + /** + * @return new {@link Range} with {@code lower} and {@code upper} set to {@link Boundary#unbounded()}. + */ + public static Range unbounded() { + return new Range(Boundary.unbounded(), Boundary.unbounded()); + } + + /** + * Greater than or equals {@code lower}. + * + * @param lower the lower boundary value. + * @return {@code this} {@link Range} with {@code lower} applied. + */ + public Range gte(T lower) { + + this.lower = Boundary.including(lower); + return this; + } + + /** + * Greater than {@code lower}. + * + * @param lower the lower boundary value. + * @return {@code this} {@link Range} with {@code lower} applied. + */ + public Range gt(T lower) { + + this.lower = Boundary.excluding(lower); + return this; + } + + /** + * Less than or equals {@code lower}. + * + * @param upper the upper boundary value. + * @return {@code this} {@link Range} with {@code upper} applied. + */ + public Range lte(T upper) { + + this.upper = Boundary.including(upper); + return this; + } + + /** + * Less than {@code lower}. + * + * @param upper the upper boundary value. + * @return {@code this} {@link Range} with {@code upper} applied. + */ + public Range lt(T upper) { + + this.upper = Boundary.excluding(upper); + return this; + } + + /** + * @return the lower boundary. + */ + public Boundary getLower() { + return lower; + } + + /** + * @return the upper boundary. + */ + public Boundary getUpper() { + return upper; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(getClass().getSimpleName()).append(" ["); + sb.append(lower).append(" to ").append(upper).append("]"); + return sb.toString(); + } + + /** + * @author Mark Paluch + */ + public static class Boundary { + + private final static Boundary UNBOUNDED = new Boundary<>(null, true); + + private final T value; + private final boolean including; + + private Boundary(T value, boolean including) { + this.value = value; + this.including = including; + } + + /** + * Creates an unbounded (infinite) boundary that marks the beginning/end of the range. + * + * @return the unbounded boundary. + */ + @SuppressWarnings("unchecked") + public static Boundary unbounded() { + return (Boundary) UNBOUNDED; + } + + /** + * Create a {@link Boundary} based on the {@code value} that includes the value when comparing ranges. Greater or + * equals, less or equals. but not Greater or equal, less or equal to {@code value}. + * + * @param value must not be {@literal null}. + * @param value type + * @return the {@link Boundary}. + */ + public static Boundary including(T value) { + + LettuceAssert.notNull(value, "Value must not be null"); + + return new Boundary<>(value, true); + } + + /** + * Create a {@link Boundary} based on the {@code value} that excludes the value when comparing ranges. Greater or less + * to {@code value} but not greater or equal, less or equal. + * + * @param value must not be {@literal null}. + * @param value type + * @return the {@link Boundary}. + */ + public static Boundary excluding(T value) { + + LettuceAssert.notNull(value, "Value must not be null"); + + return new Boundary<>(value, false); + } + + /** + * @return the value + */ + public T getValue() { + return value; + } + + /** + * @return {@literal true} if the boundary includes the value. + */ + public boolean isIncluding() { + return including; + } + + @Override + public String toString() { + + if (value == null) { + return "[unbounded]"; + } + + StringBuilder sb = new StringBuilder(); + if (including) { + sb.append('['); + } else { + sb.append('('); + } + + sb.append(value); + return sb.toString(); + } + } +} diff --git a/src/main/java/com/lambdaworks/redis/RedisCommandBuilder.java b/src/main/java/com/lambdaworks/redis/RedisCommandBuilder.java index b9daa80e32..48b385ddeb 100644 --- a/src/main/java/com/lambdaworks/redis/RedisCommandBuilder.java +++ b/src/main/java/com/lambdaworks/redis/RedisCommandBuilder.java @@ -5,6 +5,11 @@ import static com.lambdaworks.redis.protocol.CommandType.*; import java.util.*; +import java.nio.ByteBuffer; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.Set; import com.lambdaworks.redis.codec.RedisCodec; import com.lambdaworks.redis.internal.LettuceAssert; @@ -27,6 +32,9 @@ class RedisCommandBuilder extends BaseRedisCommandBuilder { static final String MUST_NOT_BE_EMPTY = "must not be empty"; static final String MUST_NOT_BE_NULL = "must not be null"; + private static final byte[] MINUS_BYTES = {'-'}; + private static final byte[] PLUS_BYTES = {'+'}; + public RedisCommandBuilder(RedisCodec codec) { super(codec); } @@ -1508,6 +1516,14 @@ public Command zcount(K key, String min, String max) { return createCommand(ZCOUNT, new IntegerOutput(codec), args); } + public Command zcount(K key, Range range) { + notNullKey(key); + notNullRange(range); + + CommandArgs args = new CommandArgs(codec).addKey(key).add(min(range)).add(max(range)); + return createCommand(ZCOUNT, new IntegerOutput(codec), args); + } + public Command zincrby(K key, double amount, K member) { notNullKey(key); @@ -1571,6 +1587,19 @@ public Command> zrangebyscore(K key, String min, String max, long return createCommand(ZRANGEBYSCORE, new ValueListOutput(codec), args); } + public Command> zrangebyscore(K key, Range range, Limit limit) { + notNullKey(key); + notNullRange(range); + + CommandArgs args = new CommandArgs(codec); + args.addKey(key).add(min(range)).add(max(range)); + + if(limit.isLimited()) { + args.add(LIMIT).add(limit.getOffset()).add(limit.getCount()); + } + return createCommand(ZRANGEBYSCORE, new ValueListOutput(codec), args); + } + public Command>> zrangebyscoreWithScores(K key, double min, double max) { return zrangebyscoreWithScores(key, string(min), string(max)); } @@ -1593,7 +1622,17 @@ public Command>> zrangebyscoreWithScores(K key, String notNullMinMax(min, max); CommandArgs args = new CommandArgs(codec); - args.addKey(key).add(min).add(max).add(WITHSCORES).add(LIMIT).add(offset).add(count); + addLimit(args.addKey(key).add(min).add(max).add(WITHSCORES), Limit.create(offset, count)); + return createCommand(ZRANGEBYSCORE, new ScoredValueListOutput(codec), args); + } + + public Command>> zrangebyscoreWithScores(K key, Range range, Limit limit) { + notNullKey(key); + notNullRange(range); + notNullLimit(limit); + + CommandArgs args = new CommandArgs(codec); + addLimit(args.addKey(key).add(min(range)).add(max(range)).add(WITHSCORES), limit); return createCommand(ZRANGEBYSCORE, new ScoredValueListOutput(codec), args); } @@ -1636,7 +1675,18 @@ public Command zrangebyscore(ValueStreamingChannel channel, K key LettuceAssert.notNull(channel, "ScoredValueStreamingChannel " + MUST_NOT_BE_NULL); CommandArgs args = new CommandArgs(codec); - args.addKey(key).add(min).add(max).add(LIMIT).add(offset).add(count); + addLimit(args.addKey(key).add(min).add(max), Limit.create(offset, count)); + return createCommand(ZRANGEBYSCORE, new ValueStreamingOutput(codec, channel), args); + } + + public Command zrangebyscore(ValueStreamingChannel channel, K key, Range range, Limit limit) { + notNullKey(key); + notNullRange(range); + notNullLimit(limit); + LettuceAssert.notNull(channel, "ScoredValueStreamingChannel " + MUST_NOT_BE_NULL); + + CommandArgs args = new CommandArgs(codec); + addLimit(args.addKey(key).add(min(range)).add(max(range)), limit); return createCommand(ZRANGEBYSCORE, new ValueStreamingOutput(codec, channel), args); } @@ -1666,7 +1716,18 @@ public Command zrangebyscoreWithScores(ScoredValueStreamingChannel args = new CommandArgs(codec); - args.addKey(key).add(min).add(max).add(WITHSCORES).add(LIMIT).add(offset).add(count); + addLimit(args.addKey(key).add(min).add(max).add(WITHSCORES), Limit.create(offset, count)); + return createCommand(ZRANGEBYSCORE, new ScoredValueStreamingOutput(codec, channel), args); + } + + public Command zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, Range range, Limit limit) { + notNullKey(key); + notNullRange(range); + notNullLimit(limit); + notNull(channel); + + CommandArgs args = new CommandArgs(codec); + addLimit(args.addKey(key).add(min(range)).add(max(range)).add(WITHSCORES), limit); return createCommand(ZRANGEBYSCORE, new ScoredValueStreamingOutput(codec, channel), args); } @@ -1703,6 +1764,14 @@ public Command zremrangebyscore(K key, String min, String max) { return createCommand(ZREMRANGEBYSCORE, new IntegerOutput(codec), args); } + public Command zremrangebyscore(K key, Range range) { + notNullKey(key); + notNullRange(range); + + CommandArgs args = new CommandArgs(codec).addKey(key).add(min(range)).add(max(range)); + return createCommand(ZREMRANGEBYSCORE, new IntegerOutput(codec), args); + } + public Command> zrevrange(K key, long start, long stop) { notNullKey(key); @@ -1739,7 +1808,17 @@ public Command> zrevrangebyscore(K key, String max, String min, lo notNullMinMax(min, max); CommandArgs args = new CommandArgs(codec); - args.addKey(key).add(max).add(min).add(LIMIT).add(offset).add(count); + addLimit(args.addKey(key).add(max).add(min), Limit.create(offset, count)); + return createCommand(ZREVRANGEBYSCORE, new ValueListOutput(codec), args); + } + + public Command> zrevrangebyscore(K key, Range range, Limit limit) { + notNullKey(key); + notNullRange(range); + notNullLimit(limit); + + CommandArgs args = new CommandArgs(codec); + addLimit(args.addKey(key).add(max(range)).add(min(range)), limit); return createCommand(ZREVRANGEBYSCORE, new ValueListOutput(codec), args); } @@ -1767,7 +1846,17 @@ public Command>> zrevrangebyscoreWithScores(K key, Str notNullMinMax(min, max); CommandArgs args = new CommandArgs(codec); - args.addKey(key).add(max).add(min).add(WITHSCORES).add(LIMIT).add(offset).add(count); + addLimit(args.addKey(key).add(max).add(min).add(WITHSCORES), Limit.create(offset, count)); + return createCommand(ZREVRANGEBYSCORE, new ScoredValueListOutput(codec), args); + } + + public Command>> zrevrangebyscoreWithScores(K key, Range range, Limit limit) { + notNullKey(key); + notNullRange(range); + notNullLimit(limit); + + CommandArgs args = new CommandArgs(codec); + addLimit(args.addKey(key).add(max(range)).add(min(range)).add(WITHSCORES), limit); return createCommand(ZREVRANGEBYSCORE, new ScoredValueListOutput(codec), args); } @@ -1813,7 +1902,18 @@ public Command zrevrangebyscore(ValueStreamingChannel channel, K notNull(channel); CommandArgs args = new CommandArgs(codec); - args.addKey(key).add(max).add(min).add(LIMIT).add(offset).add(count); + addLimit(args.addKey(key).add(max).add(min), Limit.create(offset, count)); + return createCommand(ZREVRANGEBYSCORE, new ValueStreamingOutput(codec, channel), args); + } + + public Command zrevrangebyscore(ValueStreamingChannel channel, K key, Range range, Limit limit) { + notNullKey(key); + notNullRange(range); + notNullLimit(limit); + notNull(channel); + + CommandArgs args = new CommandArgs(codec); + addLimit(args.addKey(key).add(max(range)).add(min(range)), limit); return createCommand(ZREVRANGEBYSCORE, new ValueStreamingOutput(codec, channel), args); } @@ -1849,7 +1949,19 @@ public Command zrevrangebyscoreWithScores(ScoredValueStreamingChanne notNull(channel); CommandArgs args = new CommandArgs(codec); - args.addKey(key).add(max).add(min).add(WITHSCORES).add(LIMIT).add(offset).add(count); + addLimit(args.addKey(key).add(max).add(min).add(WITHSCORES), Limit.create(offset, count)); + return createCommand(ZREVRANGEBYSCORE, new ScoredValueStreamingOutput(codec, channel), args); + } + + public Command zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, Range range, + Limit limit) { + notNullKey(key); + notNullRange(range); + notNullLimit(limit); + notNull(channel); + + CommandArgs args = new CommandArgs(codec); + addLimit(args.addKey(key).add(max(range)).add(min(range)).add(WITHSCORES), limit); return createCommand(ZREVRANGEBYSCORE, new ScoredValueStreamingOutput(codec, channel), args); } @@ -1890,6 +2002,15 @@ public RedisCommand zlexcount(K key, String min, String max) { return createCommand(ZLEXCOUNT, new IntegerOutput(codec), args); } + public RedisCommand zlexcount(K key, Range range) { + notNullKey(key); + notNullRange(range); + + CommandArgs args = new CommandArgs(codec); + args.addKey(key).add(minValue(range)).add(maxValue(range)); + return createCommand(ZLEXCOUNT, new IntegerOutput(codec), args); + } + public RedisCommand zremrangebylex(K key, String min, String max) { notNullKey(key); notNullMinMax(min, max); @@ -1899,6 +2020,15 @@ public RedisCommand zremrangebylex(K key, String min, String max) { return createCommand(ZREMRANGEBYLEX, new IntegerOutput(codec), args); } + public RedisCommand zremrangebylex(K key, Range range) { + notNullKey(key); + notNullRange(range); + + CommandArgs args = new CommandArgs(codec); + args.addKey(key).add(minValue(range)).add(maxValue(range)); + return createCommand(ZREMRANGEBYLEX, new IntegerOutput(codec), args); + } + public RedisCommand> zrangebylex(K key, String min, String max) { notNullKey(key); notNullMinMax(min, max); @@ -1913,7 +2043,17 @@ public RedisCommand> zrangebylex(K key, String min, String max, lo notNullMinMax(min, max); CommandArgs args = new CommandArgs(codec); - args.addKey(key).add(min).add(max).add(LIMIT).add(offset).add(count); + addLimit(args.addKey(key).add(min).add(max), Limit.create(offset, count)); + return createCommand(ZRANGEBYLEX, new ValueListOutput(codec), args); + } + + public RedisCommand> zrangebylex(K key, Range range, Limit limit) { + notNullKey(key); + notNullRange(range); + notNullLimit(limit); + + CommandArgs args = new CommandArgs(codec); + addLimit(args.addKey(key).add(minValue(range)).add(maxValue(range)), limit); return createCommand(ZRANGEBYLEX, new ValueListOutput(codec), args); } @@ -2580,6 +2720,14 @@ private void notNullKey(K key) { LettuceAssert.notNull(key, "Key " + MUST_NOT_BE_NULL); } + private void notNullRange(Range range) { + LettuceAssert.notNull(range, "Range " + MUST_NOT_BE_NULL); + } + + private void notNullLimit(Limit limit) { + LettuceAssert.notNull(limit, "Limit " + MUST_NOT_BE_NULL); + } + public void notNullMinMax(String min, String max) { LettuceAssert.notNull(min, "Min " + MUST_NOT_BE_NULL); LettuceAssert.notNull(max, "Max " + MUST_NOT_BE_NULL); @@ -2604,4 +2752,71 @@ private void notEmptySlots(int[] slots) { LettuceAssert.notNull(slots, "Slots " + MUST_NOT_BE_NULL); LettuceAssert.notEmpty(slots, "Slots " + MUST_NOT_BE_EMPTY); } + + private void addLimit(CommandArgs args, Limit limit) { + + if(limit.isLimited()){ + args.add(LIMIT).add(limit.getOffset()).add(limit.getCount()); + } + } + + private String min(Range range) { + + Range.Boundary lower = range.getLower(); + + if(lower.getValue() == null || lower.getValue() instanceof Double && lower.getValue().doubleValue() == Double.NEGATIVE_INFINITY){ + return "-inf"; + } + + if(!lower.isIncluding()){ + return "(" + lower.getValue(); + } + + return lower.getValue().toString(); + } + + private String max(Range range) { + + Range.Boundary upper = range.getUpper(); + + if(upper.getValue() == null || upper.getValue() instanceof Double && upper.getValue().doubleValue() == Double.POSITIVE_INFINITY){ + return "+inf"; + } + + if(!upper.isIncluding()){ + return "(" + upper.getValue(); + } + + return upper.getValue().toString(); + } + + private byte[] minValue(Range range) { + + Range.Boundary lower = range.getLower(); + + if(lower.getValue() == null){ + return MINUS_BYTES; + } + + ByteBuffer encoded = codec.encodeValue(lower.getValue()); + ByteBuffer allocated = ByteBuffer.allocate(encoded.remaining() + 1); + allocated.put(lower.isIncluding() ? (byte) '[' : (byte) '(').put(encoded); + + return allocated.array(); + } + + private byte[] maxValue(Range range) { + + Range.Boundary upper = range.getUpper(); + + if(upper.getValue() == null){ + return PLUS_BYTES; + } + + ByteBuffer encoded = codec.encodeValue(upper.getValue()); + ByteBuffer allocated = ByteBuffer.allocate(encoded.remaining() + 1); + allocated.put(upper.isIncluding() ? (byte) '[' : (byte) '(').put(encoded); + + return allocated.array(); + } } diff --git a/src/main/java/com/lambdaworks/redis/api/async/RedisSortedSetAsyncCommands.java b/src/main/java/com/lambdaworks/redis/api/async/RedisSortedSetAsyncCommands.java index 27c3285e38..b02bb9314a 100644 --- a/src/main/java/com/lambdaworks/redis/api/async/RedisSortedSetAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/async/RedisSortedSetAsyncCommands.java @@ -1,6 +1,8 @@ package com.lambdaworks.redis.api.async; import java.util.List; +import com.lambdaworks.redis.Limit; +import com.lambdaworks.redis.Range; import com.lambdaworks.redis.ScanArgs; import com.lambdaworks.redis.ScanCursor; import com.lambdaworks.redis.ScoredValue; @@ -131,7 +133,9 @@ public interface RedisSortedSetAsyncCommands { * @param min min score * @param max max score * @return Long integer-reply the number of elements in the specified score range. + * @deprecated Use {@link #zcount(java.lang.Object, Range)} */ + @Deprecated RedisFuture zcount(K key, double min, double max); /** @@ -141,9 +145,21 @@ public interface RedisSortedSetAsyncCommands { * @param min min score * @param max max score * @return Long integer-reply the number of elements in the specified score range. + * @deprecated Use {@link #zcount(java.lang.Object, Range)} */ + @Deprecated RedisFuture zcount(K key, String min, String max); + /** + * Count the members in a sorted set with scores within the given {@link Range}. + * + * @param key the key + * @param range the range + * @return Long integer-reply the number of elements in the specified score range. + * @since 4.3 + */ + RedisFuture zcount(K key, Range range); + /** * Increment the score of a member in a sorted set. * @@ -201,7 +217,9 @@ public interface RedisSortedSetAsyncCommands { * @param min min score * @param max max score * @return List<V> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebyscore(java.lang.Object, Range)} */ + @Deprecated RedisFuture> zrangebyscore(K key, double min, double max); /** @@ -211,9 +229,21 @@ public interface RedisSortedSetAsyncCommands { * @param min min score * @param max max score * @return List<V> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebyscore(java.lang.Object, Range)} */ + @Deprecated RedisFuture> zrangebyscore(K key, String min, String max); + /** + * Return a range of members in a sorted set, by score. + * + * @param key the key + * @param range the range + * @return List<V> array-reply list of elements in the specified score range. + * @since 4.3 + */ + RedisFuture> zrangebyscore(K key, Range range); + /** * Return a range of members in a sorted set, by score. * @@ -223,7 +253,9 @@ public interface RedisSortedSetAsyncCommands { * @param offset the offset * @param count the count * @return List<V> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebyscore(java.lang.Object, Range, Limit)} */ + @Deprecated RedisFuture> zrangebyscore(K key, double min, double max, long offset, long count); /** @@ -235,9 +267,22 @@ public interface RedisSortedSetAsyncCommands { * @param offset the offset * @param count the count * @return List<V> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebyscore(java.lang.Object, Range, Limit)} */ + @Deprecated RedisFuture> zrangebyscore(K key, String min, String max, long offset, long count); + /** + * Return a range of members in a sorted set, by score. + * + * @param key the key + * @param range the range + * @param limit the limit + * @return List<V> array-reply list of elements in the specified score range. + * @since 4.3 + */ + RedisFuture> zrangebyscore(K key, Range range, Limit limit); + /** * Return a range of members with score in a sorted set, by score. * @@ -245,7 +290,9 @@ public interface RedisSortedSetAsyncCommands { * @param min min score * @param max max score * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range)} */ + @Deprecated RedisFuture>> zrangebyscoreWithScores(K key, double min, double max); /** @@ -255,9 +302,21 @@ public interface RedisSortedSetAsyncCommands { * @param min min score * @param max max score * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range)} */ + @Deprecated RedisFuture>> zrangebyscoreWithScores(K key, String min, String max); + /** + * Return a range of members with score in a sorted set, by score. + * + * @param key the key + * @param range the range + * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @since 4.3 + */ + RedisFuture>> zrangebyscoreWithScores(K key, Range range); + /** * Return a range of members with score in a sorted set, by score. * @@ -267,6 +326,7 @@ public interface RedisSortedSetAsyncCommands { * @param offset the offset * @param count the count * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range, Limit limit)} */ RedisFuture>> zrangebyscoreWithScores(K key, double min, double max, long offset, long count); @@ -279,9 +339,22 @@ public interface RedisSortedSetAsyncCommands { * @param offset the offset * @param count the count * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range, Limit)} */ + @Deprecated RedisFuture>> zrangebyscoreWithScores(K key, String min, String max, long offset, long count); + /** + * Return a range of members with score in a sorted set, by score. + * + * @param key the key + * @param range the range + * @param limit the limit + * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @since 4.3 + */ + RedisFuture>> zrangebyscoreWithScores(K key, Range range, Limit limit); + /** * Return a range of members in a sorted set, by index. * @@ -312,7 +385,9 @@ public interface RedisSortedSetAsyncCommands { * @param min min score * @param max max score * @return Long count of elements in the specified score range. + * @deprecated Use {@link #zrangebyscore(ValueStreamingChannel, java.lang.Object, Range)} */ + @Deprecated RedisFuture zrangebyscore(ValueStreamingChannel channel, K key, double min, double max); /** @@ -323,9 +398,22 @@ public interface RedisSortedSetAsyncCommands { * @param min min score * @param max max score * @return Long count of elements in the specified score range. + * @deprecated Use {@link #zrangebyscore(ValueStreamingChannel, java.lang.Object, Range)} */ + @Deprecated RedisFuture zrangebyscore(ValueStreamingChannel channel, K key, String min, String max); + /** + * Stream over a range of members in a sorted set, by score. + * + * @param channel streaming channel that receives a call for every value + * @param key the key + * @param range the range + * @return Long count of elements in the specified score range. + * @since 4.3 + */ + RedisFuture zrangebyscore(ValueStreamingChannel channel, K key, Range range); + /** * Stream over range of members in a sorted set, by score. * @@ -336,7 +424,9 @@ public interface RedisSortedSetAsyncCommands { * @param offset the offset * @param count the count * @return Long count of elements in the specified score range. + * @deprecated Use {@link #zrangebyscore(ValueStreamingChannel, java.lang.Object, Range, Limit limit)} */ + @Deprecated RedisFuture zrangebyscore(ValueStreamingChannel channel, K key, double min, double max, long offset, long count); /** @@ -349,9 +439,23 @@ public interface RedisSortedSetAsyncCommands { * @param offset the offset * @param count the count * @return Long count of elements in the specified score range. + * @deprecated Use {@link #zrangebyscore(ValueStreamingChannel, java.lang.Object, Range, Limit limit)} */ + @Deprecated RedisFuture zrangebyscore(ValueStreamingChannel channel, K key, String min, String max, long offset, long count); + /** + * Stream over a range of members in a sorted set, by score. + * + * @param channel streaming channel that receives a call for every value + * @param key the key + * @param range the range + * @param limit the limit + * @return Long count of elements in the specified score range. + * @since 4.3 + */ + RedisFuture zrangebyscore(ValueStreamingChannel channel, K key, Range range, Limit limit); + /** * Stream over a range of members with scores in a sorted set, by score. * @@ -360,7 +464,9 @@ public interface RedisSortedSetAsyncCommands { * @param min min score * @param max max score * @return Long count of elements in the specified score range. + * @deprecated Use {@link #zrangebyscoreWithScores(ScoredValueStreamingChannel, java.lang.Object, Range)} */ + @Deprecated RedisFuture zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, double min, double max); /** @@ -371,9 +477,22 @@ public interface RedisSortedSetAsyncCommands { * @param min min score * @param max max score * @return Long count of elements in the specified score range. + * @deprecated Use {@link #zrangebyscoreWithScores(ScoredValueStreamingChannel, java.lang.Object, Range)} */ + @Deprecated RedisFuture zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, String min, String max); + /** + * Stream over a range of members with scores in a sorted set, by score. + * + * @param channel streaming channel that receives a call for every scored value + * @param key the key + * @param range the range + * @return Long count of elements in the specified score range. + * @since 4.3 + */ + RedisFuture zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, Range range); + /** * Stream over a range of members with scores in a sorted set, by score. * @@ -384,7 +503,9 @@ public interface RedisSortedSetAsyncCommands { * @param offset the offset * @param count the count * @return Long count of elements in the specified score range. + * @deprecated Use {@link #zrangebyscoreWithScores(ScoredValueStreamingChannel, java.lang.Object, Range, Limit limit)} */ + @Deprecated RedisFuture zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, double min, double max, long offset, long count); /** @@ -397,9 +518,23 @@ public interface RedisSortedSetAsyncCommands { * @param offset the offset * @param count the count * @return Long count of elements in the specified score range. + * @deprecated Use {@link #zrangebyscoreWithScores(ScoredValueStreamingChannel, java.lang.Object, Range, Limit limit)} */ + @Deprecated RedisFuture zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, String min, String max, long offset, long count); + /** + * Stream over a range of members with scores in a sorted set, by score. + * + * @param channel streaming channel that receives a call for every scored value + * @param key the key + * @param range the range + * @param limit the limit + * @return Long count of elements in the specified score range. + * @since 4.3 + */ + RedisFuture zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, Range range, Limit limit); + /** * Determine the index of a member in a sorted set. * @@ -438,7 +573,9 @@ public interface RedisSortedSetAsyncCommands { * @param min min score * @param max max score * @return Long integer-reply the number of elements removed. + * @deprecated Use {@link #zremrangebyscore(java.lang.Object, Range)} */ + @Deprecated RedisFuture zremrangebyscore(K key, double min, double max); /** @@ -448,9 +585,21 @@ public interface RedisSortedSetAsyncCommands { * @param min min score * @param max max score * @return Long integer-reply the number of elements removed. + * @deprecated Use {@link #zremrangebyscore(java.lang.Object, Range)} */ + @Deprecated RedisFuture zremrangebyscore(K key, String min, String max); + /** + * Remove all members in a sorted set within the given scores. + * + * @param key the key + * @param range the range + * @return Long integer-reply the number of elements removed. + * @since 4.3 + */ + RedisFuture zremrangebyscore(K key, Range range); + /** * Return a range of members in a sorted set, by index, with scores ordered from high to low. * @@ -478,7 +627,9 @@ public interface RedisSortedSetAsyncCommands { * @param min min score * @param max max score * @return List<V> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrevrangebyscore(java.lang.Object, Range)} */ + @Deprecated RedisFuture> zrevrangebyscore(K key, double max, double min); /** @@ -488,9 +639,21 @@ public interface RedisSortedSetAsyncCommands { * @param min min score * @param max max score * @return List<V> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrevrangebyscore(java.lang.Object, Range)} */ + @Deprecated RedisFuture> zrevrangebyscore(K key, String max, String min); + /** + * Return a range of members in a sorted set, by score, with scores ordered from high to low. + * + * @param key the key + * @param range the range + * @return List<V> array-reply list of elements in the specified score range. + * @since 4.3 + */ + RedisFuture> zrevrangebyscore(K key, Range range); + /** * Return a range of members in a sorted set, by score, with scores ordered from high to low. * @@ -500,7 +663,9 @@ public interface RedisSortedSetAsyncCommands { * @param offset the withscores * @param count the null * @return List<V> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrevrangebyscore(java.lang.Object, Range, Limit)} */ + @Deprecated RedisFuture> zrevrangebyscore(K key, double max, double min, long offset, long count); /** @@ -512,9 +677,22 @@ public interface RedisSortedSetAsyncCommands { * @param offset the offset * @param count the count * @return List<V> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrevrangebyscore(java.lang.Object, Range, Limit)} */ + @Deprecated RedisFuture> zrevrangebyscore(K key, String max, String min, long offset, long count); + /** + * Return a range of members in a sorted set, by score, with scores ordered from high to low. + * + * @param key the key + * @param range the range + * @param limit the limit + * @return List<V> array-reply list of elements in the specified score range. + * @since 4.3 + */ + RedisFuture> zrevrangebyscore(K key, Range range, Limit limit); + /** * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. * @@ -522,7 +700,9 @@ public interface RedisSortedSetAsyncCommands { * @param max max score * @param min min score * @return List<V> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range)} */ + @Deprecated RedisFuture>> zrevrangebyscoreWithScores(K key, double max, double min); /** @@ -532,9 +712,21 @@ public interface RedisSortedSetAsyncCommands { * @param max max score * @param min min score * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range)} */ + @Deprecated RedisFuture>> zrevrangebyscoreWithScores(K key, String max, String min); + /** + * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. + * + * @param key the key + * @param range the range + * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @since 4.3 + */ + RedisFuture>> zrevrangebyscoreWithScores(K key, Range range); + /** * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. * @@ -544,7 +736,9 @@ public interface RedisSortedSetAsyncCommands { * @param offset the offset * @param count the count * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range, Limit)} */ + @Deprecated RedisFuture>> zrevrangebyscoreWithScores(K key, double max, double min, long offset, long count); /** @@ -556,9 +750,22 @@ public interface RedisSortedSetAsyncCommands { * @param offset the offset * @param count the count * @return List<V> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range, Limit)} */ + @Deprecated RedisFuture>> zrevrangebyscoreWithScores(K key, String max, String min, long offset, long count); + /** + * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. + * + * @param key the key + * @param range the range + * @param limit limit + * @return List<V> array-reply list of elements in the specified score range. + * @since 4.3 + */ + RedisFuture>> zrevrangebyscoreWithScores(K key, Range range, Limit limit); + /** * Stream over a range of members in a sorted set, by index, with scores ordered from high to low. * @@ -589,7 +796,9 @@ public interface RedisSortedSetAsyncCommands { * @param max max score * @param min min score * @return Long count of elements in the specified range. + * @deprecated Use {@link #zrevrangebyscore(java.lang.Object, Range)} */ + @Deprecated RedisFuture zrevrangebyscore(ValueStreamingChannel channel, K key, double max, double min); /** @@ -600,9 +809,22 @@ public interface RedisSortedSetAsyncCommands { * @param min min score * @param max max score * @return Long count of elements in the specified range. + * @deprecated Use {@link #zrevrangebyscore(java.lang.Object, Range)} */ + @Deprecated RedisFuture zrevrangebyscore(ValueStreamingChannel channel, K key, String max, String min); + /** + * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. + * + * @param channel streaming channel that receives a call for every value + * @param key the key + * @param range the range + * @return Long count of elements in the specified range. + * @since 4.3 + */ + RedisFuture zrevrangebyscore(ValueStreamingChannel channel, K key, Range range); + /** * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. * @@ -613,7 +835,9 @@ public interface RedisSortedSetAsyncCommands { * @param offset the offset * @param count the count * @return Long count of elements in the specified range. + * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range, Limit)} */ + @Deprecated RedisFuture zrevrangebyscore(ValueStreamingChannel channel, K key, double max, double min, long offset, long count); /** @@ -626,9 +850,23 @@ public interface RedisSortedSetAsyncCommands { * @param offset the offset * @param count the count * @return Long count of elements in the specified range. + * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range, Limit)} */ + @Deprecated RedisFuture zrevrangebyscore(ValueStreamingChannel channel, K key, String max, String min, long offset, long count); + /** + * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. + * + * @param channel streaming channel that receives a call for every value + * @param key the key + * @param range the range + * @param limit the limit + * @return Long count of elements in the specified range. + * @since 4.3 + */ + RedisFuture zrevrangebyscore(ValueStreamingChannel channel, K key, Range range, Limit limit); + /** * Stream over a range of members with scores in a sorted set, by score, with scores ordered from high to low. * @@ -637,7 +875,9 @@ public interface RedisSortedSetAsyncCommands { * @param min min score * @param max max score * @return Long count of elements in the specified range. + * @deprecated Use {@link #zrevrangebyscoreWithScores(ScoredValueStreamingChannel, java.lang.Object, Range)} */ + @Deprecated RedisFuture zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, double max, double min); /** @@ -648,9 +888,21 @@ public interface RedisSortedSetAsyncCommands { * @param min min score * @param max max score * @return Long count of elements in the specified range. + * @deprecated Use {@link #zrevrangebyscoreWithScores(ScoredValueStreamingChannel, java.lang.Object, Range)} */ + @Deprecated RedisFuture zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, String max, String min); + /** + * Stream over a range of members with scores in a sorted set, by score, with scores ordered from high to low. + * + * @param channel streaming channel that receives a call for every scored value + * @param key the key + * @param range the range + * @return Long count of elements in the specified range. + */ + RedisFuture zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, Range range); + /** * Stream over a range of members with scores in a sorted set, by score, with scores ordered from high to low. * @@ -661,7 +913,9 @@ public interface RedisSortedSetAsyncCommands { * @param offset the offset * @param count the count * @return Long count of elements in the specified range. + * @deprecated Use {@link #zrevrangebyscoreWithScores(ScoredValueStreamingChannel, java.lang.Object, Range, Limit)} */ + @Deprecated RedisFuture zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, double max, double min, long offset, long count); /** @@ -674,9 +928,23 @@ public interface RedisSortedSetAsyncCommands { * @param offset the offset * @param count the count * @return Long count of elements in the specified range. + * @deprecated Use {@link #zrevrangebyscoreWithScores(ScoredValueStreamingChannel, java.lang.Object, Range, Limit)} */ + @Deprecated RedisFuture zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, String max, String min, long offset, long count); + /** + * Stream over a range of members with scores in a sorted set, by score, with scores ordered from high to low. + * + * @param channel streaming channel that receives a call for every scored value + * @param key the key + * @param range the range + * @param limit the limit + * @return Long count of elements in the specified range. + * @since 4.3 + */ + RedisFuture zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, Range range, Limit limit); + /** * Determine the index of a member in a sorted set, with scores ordered from high to low. * @@ -799,9 +1067,21 @@ public interface RedisSortedSetAsyncCommands { * @param min min score * @param max max score * @return Long integer-reply the number of elements in the specified score range. + * @deprecated Use {@link #zlexcount(java.lang.Object, Range)} */ + @Deprecated RedisFuture zlexcount(K key, String min, String max); + /** + * Count the number of members in a sorted set between a given lexicographical range. + * + * @param key the key + * @param range the range + * @return Long integer-reply the number of elements in the specified score range. + * @since 4.3 + */ + RedisFuture zlexcount(K key, Range range); + /** * Remove all members in a sorted set between the given lexicographical range. * @@ -809,9 +1089,21 @@ public interface RedisSortedSetAsyncCommands { * @param min min score * @param max max score * @return Long integer-reply the number of elements removed. + * @deprecated Use {@link #zremrangebylex(java.lang.Object, Range)} */ + @Deprecated RedisFuture zremrangebylex(K key, String min, String max); + /** + * Remove all members in a sorted set between the given lexicographical range. + * + * @param key the key + * @param range the range + * @return Long integer-reply the number of elements removed. + * @since 4.3 + */ + RedisFuture zremrangebylex(K key, Range range); + /** * Return a range of members in a sorted set, by lexicographical range. * @@ -819,9 +1111,21 @@ public interface RedisSortedSetAsyncCommands { * @param min min score * @param max max score * @return List<V> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebylex(java.lang.Object, Range)} */ + @Deprecated RedisFuture> zrangebylex(K key, String min, String max); + /** + * Return a range of members in a sorted set, by lexicographical range. + * + * @param key the key + * @param range the range + * @return List<V> array-reply list of elements in the specified score range. + * @since 4.3 + */ + RedisFuture> zrangebylex(K key, Range range); + /** * Return a range of members in a sorted set, by lexicographical range. * @@ -831,6 +1135,19 @@ public interface RedisSortedSetAsyncCommands { * @param offset the offset * @param count the count * @return List<V> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebylex(java.lang.Object, Range)} */ + @Deprecated RedisFuture> zrangebylex(K key, String min, String max, long offset, long count); + + /** + * Return a range of members in a sorted set, by lexicographical range. + * + * @param key the key + * @param range the range + * @param limit the limit + * @return List<V> array-reply list of elements in the specified score range. + * @since 4.3 + */ + RedisFuture> zrangebylex(K key, Range range, Limit limit); } diff --git a/src/main/java/com/lambdaworks/redis/api/reactive/RedisSortedSetReactiveCommands.java b/src/main/java/com/lambdaworks/redis/api/reactive/RedisSortedSetReactiveCommands.java index ca9c6ca24c..3acd9a8a97 100644 --- a/src/main/java/com/lambdaworks/redis/api/reactive/RedisSortedSetReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/reactive/RedisSortedSetReactiveCommands.java @@ -1,6 +1,8 @@ package com.lambdaworks.redis.api.reactive; import java.util.List; +import com.lambdaworks.redis.Limit; +import com.lambdaworks.redis.Range; import com.lambdaworks.redis.ScanArgs; import com.lambdaworks.redis.ScanCursor; import com.lambdaworks.redis.ScoredValue; @@ -132,7 +134,9 @@ public interface RedisSortedSetReactiveCommands { * @param min min score * @param max max score * @return Long integer-reply the number of elements in the specified score range. + * @deprecated Use {@link #zcount(java.lang.Object, Range)} */ + @Deprecated Mono zcount(K key, double min, double max); /** @@ -142,9 +146,21 @@ public interface RedisSortedSetReactiveCommands { * @param min min score * @param max max score * @return Long integer-reply the number of elements in the specified score range. + * @deprecated Use {@link #zcount(java.lang.Object, Range)} */ + @Deprecated Mono zcount(K key, String min, String max); + /** + * Count the members in a sorted set with scores within the given {@link Range}. + * + * @param key the key + * @param range the range + * @return Long integer-reply the number of elements in the specified score range. + * @since 4.3 + */ + Mono zcount(K key, Range range); + /** * Increment the score of a member in a sorted set. * @@ -202,7 +218,9 @@ public interface RedisSortedSetReactiveCommands { * @param min min score * @param max max score * @return V array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebyscore(java.lang.Object, Range)} */ + @Deprecated Flux zrangebyscore(K key, double min, double max); /** @@ -212,9 +230,21 @@ public interface RedisSortedSetReactiveCommands { * @param min min score * @param max max score * @return V array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebyscore(java.lang.Object, Range)} */ + @Deprecated Flux zrangebyscore(K key, String min, String max); + /** + * Return a range of members in a sorted set, by score. + * + * @param key the key + * @param range the range + * @return V array-reply list of elements in the specified score range. + * @since 4.3 + */ + Flux zrangebyscore(K key, Range range); + /** * Return a range of members in a sorted set, by score. * @@ -224,7 +254,9 @@ public interface RedisSortedSetReactiveCommands { * @param offset the offset * @param count the count * @return V array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebyscore(java.lang.Object, Range, Limit)} */ + @Deprecated Flux zrangebyscore(K key, double min, double max, long offset, long count); /** @@ -236,9 +268,22 @@ public interface RedisSortedSetReactiveCommands { * @param offset the offset * @param count the count * @return V array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebyscore(java.lang.Object, Range, Limit)} */ + @Deprecated Flux zrangebyscore(K key, String min, String max, long offset, long count); + /** + * Return a range of members in a sorted set, by score. + * + * @param key the key + * @param range the range + * @param limit the limit + * @return V array-reply list of elements in the specified score range. + * @since 4.3 + */ + Flux zrangebyscore(K key, Range range, Limit limit); + /** * Return a range of members with score in a sorted set, by score. * @@ -246,7 +291,9 @@ public interface RedisSortedSetReactiveCommands { * @param min min score * @param max max score * @return ScoredValue<V> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range)} */ + @Deprecated Flux> zrangebyscoreWithScores(K key, double min, double max); /** @@ -256,9 +303,21 @@ public interface RedisSortedSetReactiveCommands { * @param min min score * @param max max score * @return ScoredValue<V> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range)} */ + @Deprecated Flux> zrangebyscoreWithScores(K key, String min, String max); + /** + * Return a range of members with score in a sorted set, by score. + * + * @param key the key + * @param range the range + * @return ScoredValue<V> array-reply list of elements in the specified score range. + * @since 4.3 + */ + Flux> zrangebyscoreWithScores(K key, Range range); + /** * Return a range of members with score in a sorted set, by score. * @@ -268,6 +327,7 @@ public interface RedisSortedSetReactiveCommands { * @param offset the offset * @param count the count * @return ScoredValue<V> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range, Limit limit)} */ Flux> zrangebyscoreWithScores(K key, double min, double max, long offset, long count); @@ -280,9 +340,22 @@ public interface RedisSortedSetReactiveCommands { * @param offset the offset * @param count the count * @return ScoredValue<V> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range, Limit)} */ + @Deprecated Flux> zrangebyscoreWithScores(K key, String min, String max, long offset, long count); + /** + * Return a range of members with score in a sorted set, by score. + * + * @param key the key + * @param range the range + * @param limit the limit + * @return ScoredValue<V> array-reply list of elements in the specified score range. + * @since 4.3 + */ + Flux> zrangebyscoreWithScores(K key, Range range, Limit limit); + /** * Return a range of members in a sorted set, by index. * @@ -313,7 +386,9 @@ public interface RedisSortedSetReactiveCommands { * @param min min score * @param max max score * @return Long count of elements in the specified score range. + * @deprecated Use {@link #zrangebyscore(ValueStreamingChannel, java.lang.Object, Range)} */ + @Deprecated Mono zrangebyscore(ValueStreamingChannel channel, K key, double min, double max); /** @@ -324,9 +399,22 @@ public interface RedisSortedSetReactiveCommands { * @param min min score * @param max max score * @return Long count of elements in the specified score range. + * @deprecated Use {@link #zrangebyscore(ValueStreamingChannel, java.lang.Object, Range)} */ + @Deprecated Mono zrangebyscore(ValueStreamingChannel channel, K key, String min, String max); + /** + * Stream over a range of members in a sorted set, by score. + * + * @param channel streaming channel that receives a call for every value + * @param key the key + * @param range the range + * @return Long count of elements in the specified score range. + * @since 4.3 + */ + Mono zrangebyscore(ValueStreamingChannel channel, K key, Range range); + /** * Stream over range of members in a sorted set, by score. * @@ -337,7 +425,9 @@ public interface RedisSortedSetReactiveCommands { * @param offset the offset * @param count the count * @return Long count of elements in the specified score range. + * @deprecated Use {@link #zrangebyscore(ValueStreamingChannel, java.lang.Object, Range, Limit limit)} */ + @Deprecated Mono zrangebyscore(ValueStreamingChannel channel, K key, double min, double max, long offset, long count); /** @@ -350,9 +440,23 @@ public interface RedisSortedSetReactiveCommands { * @param offset the offset * @param count the count * @return Long count of elements in the specified score range. + * @deprecated Use {@link #zrangebyscore(ValueStreamingChannel, java.lang.Object, Range, Limit limit)} */ + @Deprecated Mono zrangebyscore(ValueStreamingChannel channel, K key, String min, String max, long offset, long count); + /** + * Stream over a range of members in a sorted set, by score. + * + * @param channel streaming channel that receives a call for every value + * @param key the key + * @param range the range + * @param limit the limit + * @return Long count of elements in the specified score range. + * @since 4.3 + */ + Mono zrangebyscore(ValueStreamingChannel channel, K key, Range range, Limit limit); + /** * Stream over a range of members with scores in a sorted set, by score. * @@ -361,7 +465,9 @@ public interface RedisSortedSetReactiveCommands { * @param min min score * @param max max score * @return Long count of elements in the specified score range. + * @deprecated Use {@link #zrangebyscoreWithScores(ScoredValueStreamingChannel, java.lang.Object, Range)} */ + @Deprecated Mono zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, double min, double max); /** @@ -372,9 +478,22 @@ public interface RedisSortedSetReactiveCommands { * @param min min score * @param max max score * @return Long count of elements in the specified score range. + * @deprecated Use {@link #zrangebyscoreWithScores(ScoredValueStreamingChannel, java.lang.Object, Range)} */ + @Deprecated Mono zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, String min, String max); + /** + * Stream over a range of members with scores in a sorted set, by score. + * + * @param channel streaming channel that receives a call for every scored value + * @param key the key + * @param range the range + * @return Long count of elements in the specified score range. + * @since 4.3 + */ + Mono zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, Range range); + /** * Stream over a range of members with scores in a sorted set, by score. * @@ -385,7 +504,9 @@ public interface RedisSortedSetReactiveCommands { * @param offset the offset * @param count the count * @return Long count of elements in the specified score range. + * @deprecated Use {@link #zrangebyscoreWithScores(ScoredValueStreamingChannel, java.lang.Object, Range, Limit limit)} */ + @Deprecated Mono zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, double min, double max, long offset, long count); /** @@ -398,9 +519,23 @@ public interface RedisSortedSetReactiveCommands { * @param offset the offset * @param count the count * @return Long count of elements in the specified score range. + * @deprecated Use {@link #zrangebyscoreWithScores(ScoredValueStreamingChannel, java.lang.Object, Range, Limit limit)} */ + @Deprecated Mono zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, String min, String max, long offset, long count); + /** + * Stream over a range of members with scores in a sorted set, by score. + * + * @param channel streaming channel that receives a call for every scored value + * @param key the key + * @param range the range + * @param limit the limit + * @return Long count of elements in the specified score range. + * @since 4.3 + */ + Mono zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, Range range, Limit limit); + /** * Determine the index of a member in a sorted set. * @@ -439,7 +574,9 @@ public interface RedisSortedSetReactiveCommands { * @param min min score * @param max max score * @return Long integer-reply the number of elements removed. + * @deprecated Use {@link #zremrangebyscore(java.lang.Object, Range)} */ + @Deprecated Mono zremrangebyscore(K key, double min, double max); /** @@ -449,9 +586,21 @@ public interface RedisSortedSetReactiveCommands { * @param min min score * @param max max score * @return Long integer-reply the number of elements removed. + * @deprecated Use {@link #zremrangebyscore(java.lang.Object, Range)} */ + @Deprecated Mono zremrangebyscore(K key, String min, String max); + /** + * Remove all members in a sorted set within the given scores. + * + * @param key the key + * @param range the range + * @return Long integer-reply the number of elements removed. + * @since 4.3 + */ + Mono zremrangebyscore(K key, Range range); + /** * Return a range of members in a sorted set, by index, with scores ordered from high to low. * @@ -479,7 +628,9 @@ public interface RedisSortedSetReactiveCommands { * @param min min score * @param max max score * @return V array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrevrangebyscore(java.lang.Object, Range)} */ + @Deprecated Flux zrevrangebyscore(K key, double max, double min); /** @@ -489,9 +640,21 @@ public interface RedisSortedSetReactiveCommands { * @param min min score * @param max max score * @return V array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrevrangebyscore(java.lang.Object, Range)} */ + @Deprecated Flux zrevrangebyscore(K key, String max, String min); + /** + * Return a range of members in a sorted set, by score, with scores ordered from high to low. + * + * @param key the key + * @param range the range + * @return V array-reply list of elements in the specified score range. + * @since 4.3 + */ + Flux zrevrangebyscore(K key, Range range); + /** * Return a range of members in a sorted set, by score, with scores ordered from high to low. * @@ -501,7 +664,9 @@ public interface RedisSortedSetReactiveCommands { * @param offset the withscores * @param count the null * @return V array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrevrangebyscore(java.lang.Object, Range, Limit)} */ + @Deprecated Flux zrevrangebyscore(K key, double max, double min, long offset, long count); /** @@ -513,9 +678,22 @@ public interface RedisSortedSetReactiveCommands { * @param offset the offset * @param count the count * @return V array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrevrangebyscore(java.lang.Object, Range, Limit)} */ + @Deprecated Flux zrevrangebyscore(K key, String max, String min, long offset, long count); + /** + * Return a range of members in a sorted set, by score, with scores ordered from high to low. + * + * @param key the key + * @param range the range + * @param limit the limit + * @return V array-reply list of elements in the specified score range. + * @since 4.3 + */ + Flux zrevrangebyscore(K key, Range range, Limit limit); + /** * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. * @@ -523,7 +701,9 @@ public interface RedisSortedSetReactiveCommands { * @param max max score * @param min min score * @return V array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range)} */ + @Deprecated Flux> zrevrangebyscoreWithScores(K key, double max, double min); /** @@ -533,9 +713,21 @@ public interface RedisSortedSetReactiveCommands { * @param max max score * @param min min score * @return ScoredValue<V> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range)} */ + @Deprecated Flux> zrevrangebyscoreWithScores(K key, String max, String min); + /** + * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. + * + * @param key the key + * @param range the range + * @return ScoredValue<V> array-reply list of elements in the specified score range. + * @since 4.3 + */ + Flux> zrevrangebyscoreWithScores(K key, Range range); + /** * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. * @@ -545,7 +737,9 @@ public interface RedisSortedSetReactiveCommands { * @param offset the offset * @param count the count * @return ScoredValue<V> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range, Limit)} */ + @Deprecated Flux> zrevrangebyscoreWithScores(K key, double max, double min, long offset, long count); /** @@ -557,9 +751,22 @@ public interface RedisSortedSetReactiveCommands { * @param offset the offset * @param count the count * @return V array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range, Limit)} */ + @Deprecated Flux> zrevrangebyscoreWithScores(K key, String max, String min, long offset, long count); + /** + * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. + * + * @param key the key + * @param range the range + * @param limit limit + * @return V array-reply list of elements in the specified score range. + * @since 4.3 + */ + Flux> zrevrangebyscoreWithScores(K key, Range range, Limit limit); + /** * Stream over a range of members in a sorted set, by index, with scores ordered from high to low. * @@ -590,7 +797,9 @@ public interface RedisSortedSetReactiveCommands { * @param max max score * @param min min score * @return Long count of elements in the specified range. + * @deprecated Use {@link #zrevrangebyscore(java.lang.Object, Range)} */ + @Deprecated Mono zrevrangebyscore(ValueStreamingChannel channel, K key, double max, double min); /** @@ -601,9 +810,22 @@ public interface RedisSortedSetReactiveCommands { * @param min min score * @param max max score * @return Long count of elements in the specified range. + * @deprecated Use {@link #zrevrangebyscore(java.lang.Object, Range)} */ + @Deprecated Mono zrevrangebyscore(ValueStreamingChannel channel, K key, String max, String min); + /** + * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. + * + * @param channel streaming channel that receives a call for every value + * @param key the key + * @param range the range + * @return Long count of elements in the specified range. + * @since 4.3 + */ + Mono zrevrangebyscore(ValueStreamingChannel channel, K key, Range range); + /** * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. * @@ -614,7 +836,9 @@ public interface RedisSortedSetReactiveCommands { * @param offset the offset * @param count the count * @return Long count of elements in the specified range. + * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range, Limit)} */ + @Deprecated Mono zrevrangebyscore(ValueStreamingChannel channel, K key, double max, double min, long offset, long count); /** @@ -627,9 +851,23 @@ public interface RedisSortedSetReactiveCommands { * @param offset the offset * @param count the count * @return Long count of elements in the specified range. + * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range, Limit)} */ + @Deprecated Mono zrevrangebyscore(ValueStreamingChannel channel, K key, String max, String min, long offset, long count); + /** + * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. + * + * @param channel streaming channel that receives a call for every value + * @param key the key + * @param range the range + * @param limit the limit + * @return Long count of elements in the specified range. + * @since 4.3 + */ + Mono zrevrangebyscore(ValueStreamingChannel channel, K key, Range range, Limit limit); + /** * Stream over a range of members with scores in a sorted set, by score, with scores ordered from high to low. * @@ -638,7 +876,9 @@ public interface RedisSortedSetReactiveCommands { * @param min min score * @param max max score * @return Long count of elements in the specified range. + * @deprecated Use {@link #zrevrangebyscoreWithScores(ScoredValueStreamingChannel, java.lang.Object, Range)} */ + @Deprecated Mono zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, double max, double min); /** @@ -649,9 +889,21 @@ public interface RedisSortedSetReactiveCommands { * @param min min score * @param max max score * @return Long count of elements in the specified range. + * @deprecated Use {@link #zrevrangebyscoreWithScores(ScoredValueStreamingChannel, java.lang.Object, Range)} */ + @Deprecated Mono zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, String max, String min); + /** + * Stream over a range of members with scores in a sorted set, by score, with scores ordered from high to low. + * + * @param channel streaming channel that receives a call for every scored value + * @param key the key + * @param range the range + * @return Long count of elements in the specified range. + */ + Mono zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, Range range); + /** * Stream over a range of members with scores in a sorted set, by score, with scores ordered from high to low. * @@ -662,7 +914,9 @@ public interface RedisSortedSetReactiveCommands { * @param offset the offset * @param count the count * @return Long count of elements in the specified range. + * @deprecated Use {@link #zrevrangebyscoreWithScores(ScoredValueStreamingChannel, java.lang.Object, Range, Limit)} */ + @Deprecated Mono zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, double max, double min, long offset, long count); /** @@ -675,9 +929,23 @@ public interface RedisSortedSetReactiveCommands { * @param offset the offset * @param count the count * @return Long count of elements in the specified range. + * @deprecated Use {@link #zrevrangebyscoreWithScores(ScoredValueStreamingChannel, java.lang.Object, Range, Limit)} */ + @Deprecated Mono zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, String max, String min, long offset, long count); + /** + * Stream over a range of members with scores in a sorted set, by score, with scores ordered from high to low. + * + * @param channel streaming channel that receives a call for every scored value + * @param key the key + * @param range the range + * @param limit the limit + * @return Long count of elements in the specified range. + * @since 4.3 + */ + Mono zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, Range range, Limit limit); + /** * Determine the index of a member in a sorted set, with scores ordered from high to low. * @@ -800,9 +1068,21 @@ public interface RedisSortedSetReactiveCommands { * @param min min score * @param max max score * @return Long integer-reply the number of elements in the specified score range. + * @deprecated Use {@link #zlexcount(java.lang.Object, Range)} */ + @Deprecated Mono zlexcount(K key, String min, String max); + /** + * Count the number of members in a sorted set between a given lexicographical range. + * + * @param key the key + * @param range the range + * @return Long integer-reply the number of elements in the specified score range. + * @since 4.3 + */ + Mono zlexcount(K key, Range range); + /** * Remove all members in a sorted set between the given lexicographical range. * @@ -810,9 +1090,21 @@ public interface RedisSortedSetReactiveCommands { * @param min min score * @param max max score * @return Long integer-reply the number of elements removed. + * @deprecated Use {@link #zremrangebylex(java.lang.Object, Range)} */ + @Deprecated Mono zremrangebylex(K key, String min, String max); + /** + * Remove all members in a sorted set between the given lexicographical range. + * + * @param key the key + * @param range the range + * @return Long integer-reply the number of elements removed. + * @since 4.3 + */ + Mono zremrangebylex(K key, Range range); + /** * Return a range of members in a sorted set, by lexicographical range. * @@ -820,9 +1112,21 @@ public interface RedisSortedSetReactiveCommands { * @param min min score * @param max max score * @return V array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebylex(java.lang.Object, Range)} */ + @Deprecated Flux zrangebylex(K key, String min, String max); + /** + * Return a range of members in a sorted set, by lexicographical range. + * + * @param key the key + * @param range the range + * @return V array-reply list of elements in the specified score range. + * @since 4.3 + */ + Flux zrangebylex(K key, Range range); + /** * Return a range of members in a sorted set, by lexicographical range. * @@ -832,6 +1136,19 @@ public interface RedisSortedSetReactiveCommands { * @param offset the offset * @param count the count * @return V array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebylex(java.lang.Object, Range)} */ + @Deprecated Flux zrangebylex(K key, String min, String max, long offset, long count); + + /** + * Return a range of members in a sorted set, by lexicographical range. + * + * @param key the key + * @param range the range + * @param limit the limit + * @return V array-reply list of elements in the specified score range. + * @since 4.3 + */ + Flux zrangebylex(K key, Range range, Limit limit); } diff --git a/src/main/java/com/lambdaworks/redis/api/sync/RedisSortedSetCommands.java b/src/main/java/com/lambdaworks/redis/api/sync/RedisSortedSetCommands.java index 00062b93b0..d484e1ef94 100644 --- a/src/main/java/com/lambdaworks/redis/api/sync/RedisSortedSetCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/sync/RedisSortedSetCommands.java @@ -1,6 +1,8 @@ package com.lambdaworks.redis.api.sync; import java.util.List; +import com.lambdaworks.redis.Limit; +import com.lambdaworks.redis.Range; import com.lambdaworks.redis.ScanArgs; import com.lambdaworks.redis.ScanCursor; import com.lambdaworks.redis.ScoredValue; @@ -130,7 +132,9 @@ public interface RedisSortedSetCommands { * @param min min score * @param max max score * @return Long integer-reply the number of elements in the specified score range. + * @deprecated Use {@link #zcount(java.lang.Object, Range)} */ + @Deprecated Long zcount(K key, double min, double max); /** @@ -140,9 +144,21 @@ public interface RedisSortedSetCommands { * @param min min score * @param max max score * @return Long integer-reply the number of elements in the specified score range. + * @deprecated Use {@link #zcount(java.lang.Object, Range)} */ + @Deprecated Long zcount(K key, String min, String max); + /** + * Count the members in a sorted set with scores within the given {@link Range}. + * + * @param key the key + * @param range the range + * @return Long integer-reply the number of elements in the specified score range. + * @since 4.3 + */ + Long zcount(K key, Range range); + /** * Increment the score of a member in a sorted set. * @@ -200,7 +216,9 @@ public interface RedisSortedSetCommands { * @param min min score * @param max max score * @return List<V> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebyscore(java.lang.Object, Range)} */ + @Deprecated List zrangebyscore(K key, double min, double max); /** @@ -210,9 +228,21 @@ public interface RedisSortedSetCommands { * @param min min score * @param max max score * @return List<V> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebyscore(java.lang.Object, Range)} */ + @Deprecated List zrangebyscore(K key, String min, String max); + /** + * Return a range of members in a sorted set, by score. + * + * @param key the key + * @param range the range + * @return List<V> array-reply list of elements in the specified score range. + * @since 4.3 + */ + List zrangebyscore(K key, Range range); + /** * Return a range of members in a sorted set, by score. * @@ -222,7 +252,9 @@ public interface RedisSortedSetCommands { * @param offset the offset * @param count the count * @return List<V> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebyscore(java.lang.Object, Range, Limit)} */ + @Deprecated List zrangebyscore(K key, double min, double max, long offset, long count); /** @@ -234,9 +266,22 @@ public interface RedisSortedSetCommands { * @param offset the offset * @param count the count * @return List<V> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebyscore(java.lang.Object, Range, Limit)} */ + @Deprecated List zrangebyscore(K key, String min, String max, long offset, long count); + /** + * Return a range of members in a sorted set, by score. + * + * @param key the key + * @param range the range + * @param limit the limit + * @return List<V> array-reply list of elements in the specified score range. + * @since 4.3 + */ + List zrangebyscore(K key, Range range, Limit limit); + /** * Return a range of members with score in a sorted set, by score. * @@ -244,7 +289,9 @@ public interface RedisSortedSetCommands { * @param min min score * @param max max score * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range)} */ + @Deprecated List> zrangebyscoreWithScores(K key, double min, double max); /** @@ -254,9 +301,21 @@ public interface RedisSortedSetCommands { * @param min min score * @param max max score * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range)} */ + @Deprecated List> zrangebyscoreWithScores(K key, String min, String max); + /** + * Return a range of members with score in a sorted set, by score. + * + * @param key the key + * @param range the range + * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @since 4.3 + */ + List> zrangebyscoreWithScores(K key, Range range); + /** * Return a range of members with score in a sorted set, by score. * @@ -266,6 +325,7 @@ public interface RedisSortedSetCommands { * @param offset the offset * @param count the count * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range, Limit limit)} */ List> zrangebyscoreWithScores(K key, double min, double max, long offset, long count); @@ -278,9 +338,22 @@ public interface RedisSortedSetCommands { * @param offset the offset * @param count the count * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range, Limit)} */ + @Deprecated List> zrangebyscoreWithScores(K key, String min, String max, long offset, long count); + /** + * Return a range of members with score in a sorted set, by score. + * + * @param key the key + * @param range the range + * @param limit the limit + * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @since 4.3 + */ + List> zrangebyscoreWithScores(K key, Range range, Limit limit); + /** * Return a range of members in a sorted set, by index. * @@ -311,7 +384,9 @@ public interface RedisSortedSetCommands { * @param min min score * @param max max score * @return Long count of elements in the specified score range. + * @deprecated Use {@link #zrangebyscore(ValueStreamingChannel, java.lang.Object, Range)} */ + @Deprecated Long zrangebyscore(ValueStreamingChannel channel, K key, double min, double max); /** @@ -322,9 +397,22 @@ public interface RedisSortedSetCommands { * @param min min score * @param max max score * @return Long count of elements in the specified score range. + * @deprecated Use {@link #zrangebyscore(ValueStreamingChannel, java.lang.Object, Range)} */ + @Deprecated Long zrangebyscore(ValueStreamingChannel channel, K key, String min, String max); + /** + * Stream over a range of members in a sorted set, by score. + * + * @param channel streaming channel that receives a call for every value + * @param key the key + * @param range the range + * @return Long count of elements in the specified score range. + * @since 4.3 + */ + Long zrangebyscore(ValueStreamingChannel channel, K key, Range range); + /** * Stream over range of members in a sorted set, by score. * @@ -335,7 +423,9 @@ public interface RedisSortedSetCommands { * @param offset the offset * @param count the count * @return Long count of elements in the specified score range. + * @deprecated Use {@link #zrangebyscore(ValueStreamingChannel, java.lang.Object, Range, Limit limit)} */ + @Deprecated Long zrangebyscore(ValueStreamingChannel channel, K key, double min, double max, long offset, long count); /** @@ -348,9 +438,23 @@ public interface RedisSortedSetCommands { * @param offset the offset * @param count the count * @return Long count of elements in the specified score range. + * @deprecated Use {@link #zrangebyscore(ValueStreamingChannel, java.lang.Object, Range, Limit limit)} */ + @Deprecated Long zrangebyscore(ValueStreamingChannel channel, K key, String min, String max, long offset, long count); + /** + * Stream over a range of members in a sorted set, by score. + * + * @param channel streaming channel that receives a call for every value + * @param key the key + * @param range the range + * @param limit the limit + * @return Long count of elements in the specified score range. + * @since 4.3 + */ + Long zrangebyscore(ValueStreamingChannel channel, K key, Range range, Limit limit); + /** * Stream over a range of members with scores in a sorted set, by score. * @@ -359,7 +463,9 @@ public interface RedisSortedSetCommands { * @param min min score * @param max max score * @return Long count of elements in the specified score range. + * @deprecated Use {@link #zrangebyscoreWithScores(ScoredValueStreamingChannel, java.lang.Object, Range)} */ + @Deprecated Long zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, double min, double max); /** @@ -370,9 +476,22 @@ public interface RedisSortedSetCommands { * @param min min score * @param max max score * @return Long count of elements in the specified score range. + * @deprecated Use {@link #zrangebyscoreWithScores(ScoredValueStreamingChannel, java.lang.Object, Range)} */ + @Deprecated Long zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, String min, String max); + /** + * Stream over a range of members with scores in a sorted set, by score. + * + * @param channel streaming channel that receives a call for every scored value + * @param key the key + * @param range the range + * @return Long count of elements in the specified score range. + * @since 4.3 + */ + Long zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, Range range); + /** * Stream over a range of members with scores in a sorted set, by score. * @@ -383,7 +502,9 @@ public interface RedisSortedSetCommands { * @param offset the offset * @param count the count * @return Long count of elements in the specified score range. + * @deprecated Use {@link #zrangebyscoreWithScores(ScoredValueStreamingChannel, java.lang.Object, Range, Limit limit)} */ + @Deprecated Long zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, double min, double max, long offset, long count); /** @@ -396,9 +517,23 @@ public interface RedisSortedSetCommands { * @param offset the offset * @param count the count * @return Long count of elements in the specified score range. + * @deprecated Use {@link #zrangebyscoreWithScores(ScoredValueStreamingChannel, java.lang.Object, Range, Limit limit)} */ + @Deprecated Long zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, String min, String max, long offset, long count); + /** + * Stream over a range of members with scores in a sorted set, by score. + * + * @param channel streaming channel that receives a call for every scored value + * @param key the key + * @param range the range + * @param limit the limit + * @return Long count of elements in the specified score range. + * @since 4.3 + */ + Long zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, Range range, Limit limit); + /** * Determine the index of a member in a sorted set. * @@ -437,7 +572,9 @@ public interface RedisSortedSetCommands { * @param min min score * @param max max score * @return Long integer-reply the number of elements removed. + * @deprecated Use {@link #zremrangebyscore(java.lang.Object, Range)} */ + @Deprecated Long zremrangebyscore(K key, double min, double max); /** @@ -447,9 +584,21 @@ public interface RedisSortedSetCommands { * @param min min score * @param max max score * @return Long integer-reply the number of elements removed. + * @deprecated Use {@link #zremrangebyscore(java.lang.Object, Range)} */ + @Deprecated Long zremrangebyscore(K key, String min, String max); + /** + * Remove all members in a sorted set within the given scores. + * + * @param key the key + * @param range the range + * @return Long integer-reply the number of elements removed. + * @since 4.3 + */ + Long zremrangebyscore(K key, Range range); + /** * Return a range of members in a sorted set, by index, with scores ordered from high to low. * @@ -477,7 +626,9 @@ public interface RedisSortedSetCommands { * @param min min score * @param max max score * @return List<V> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrevrangebyscore(java.lang.Object, Range)} */ + @Deprecated List zrevrangebyscore(K key, double max, double min); /** @@ -487,9 +638,21 @@ public interface RedisSortedSetCommands { * @param min min score * @param max max score * @return List<V> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrevrangebyscore(java.lang.Object, Range)} */ + @Deprecated List zrevrangebyscore(K key, String max, String min); + /** + * Return a range of members in a sorted set, by score, with scores ordered from high to low. + * + * @param key the key + * @param range the range + * @return List<V> array-reply list of elements in the specified score range. + * @since 4.3 + */ + List zrevrangebyscore(K key, Range range); + /** * Return a range of members in a sorted set, by score, with scores ordered from high to low. * @@ -499,7 +662,9 @@ public interface RedisSortedSetCommands { * @param offset the withscores * @param count the null * @return List<V> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrevrangebyscore(java.lang.Object, Range, Limit)} */ + @Deprecated List zrevrangebyscore(K key, double max, double min, long offset, long count); /** @@ -511,9 +676,22 @@ public interface RedisSortedSetCommands { * @param offset the offset * @param count the count * @return List<V> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrevrangebyscore(java.lang.Object, Range, Limit)} */ + @Deprecated List zrevrangebyscore(K key, String max, String min, long offset, long count); + /** + * Return a range of members in a sorted set, by score, with scores ordered from high to low. + * + * @param key the key + * @param range the range + * @param limit the limit + * @return List<V> array-reply list of elements in the specified score range. + * @since 4.3 + */ + List zrevrangebyscore(K key, Range range, Limit limit); + /** * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. * @@ -521,7 +699,9 @@ public interface RedisSortedSetCommands { * @param max max score * @param min min score * @return List<V> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range)} */ + @Deprecated List> zrevrangebyscoreWithScores(K key, double max, double min); /** @@ -531,9 +711,21 @@ public interface RedisSortedSetCommands { * @param max max score * @param min min score * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range)} */ + @Deprecated List> zrevrangebyscoreWithScores(K key, String max, String min); + /** + * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. + * + * @param key the key + * @param range the range + * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @since 4.3 + */ + List> zrevrangebyscoreWithScores(K key, Range range); + /** * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. * @@ -543,7 +735,9 @@ public interface RedisSortedSetCommands { * @param offset the offset * @param count the count * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range, Limit)} */ + @Deprecated List> zrevrangebyscoreWithScores(K key, double max, double min, long offset, long count); /** @@ -555,9 +749,22 @@ public interface RedisSortedSetCommands { * @param offset the offset * @param count the count * @return List<V> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range, Limit)} */ + @Deprecated List> zrevrangebyscoreWithScores(K key, String max, String min, long offset, long count); + /** + * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. + * + * @param key the key + * @param range the range + * @param limit limit + * @return List<V> array-reply list of elements in the specified score range. + * @since 4.3 + */ + List> zrevrangebyscoreWithScores(K key, Range range, Limit limit); + /** * Stream over a range of members in a sorted set, by index, with scores ordered from high to low. * @@ -588,7 +795,9 @@ public interface RedisSortedSetCommands { * @param max max score * @param min min score * @return Long count of elements in the specified range. + * @deprecated Use {@link #zrevrangebyscore(java.lang.Object, Range)} */ + @Deprecated Long zrevrangebyscore(ValueStreamingChannel channel, K key, double max, double min); /** @@ -599,9 +808,22 @@ public interface RedisSortedSetCommands { * @param min min score * @param max max score * @return Long count of elements in the specified range. + * @deprecated Use {@link #zrevrangebyscore(java.lang.Object, Range)} */ + @Deprecated Long zrevrangebyscore(ValueStreamingChannel channel, K key, String max, String min); + /** + * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. + * + * @param channel streaming channel that receives a call for every value + * @param key the key + * @param range the range + * @return Long count of elements in the specified range. + * @since 4.3 + */ + Long zrevrangebyscore(ValueStreamingChannel channel, K key, Range range); + /** * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. * @@ -612,7 +834,9 @@ public interface RedisSortedSetCommands { * @param offset the offset * @param count the count * @return Long count of elements in the specified range. + * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range, Limit)} */ + @Deprecated Long zrevrangebyscore(ValueStreamingChannel channel, K key, double max, double min, long offset, long count); /** @@ -625,9 +849,23 @@ public interface RedisSortedSetCommands { * @param offset the offset * @param count the count * @return Long count of elements in the specified range. + * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range, Limit)} */ + @Deprecated Long zrevrangebyscore(ValueStreamingChannel channel, K key, String max, String min, long offset, long count); + /** + * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. + * + * @param channel streaming channel that receives a call for every value + * @param key the key + * @param range the range + * @param limit the limit + * @return Long count of elements in the specified range. + * @since 4.3 + */ + Long zrevrangebyscore(ValueStreamingChannel channel, K key, Range range, Limit limit); + /** * Stream over a range of members with scores in a sorted set, by score, with scores ordered from high to low. * @@ -636,7 +874,9 @@ public interface RedisSortedSetCommands { * @param min min score * @param max max score * @return Long count of elements in the specified range. + * @deprecated Use {@link #zrevrangebyscoreWithScores(ScoredValueStreamingChannel, java.lang.Object, Range)} */ + @Deprecated Long zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, double max, double min); /** @@ -647,9 +887,21 @@ public interface RedisSortedSetCommands { * @param min min score * @param max max score * @return Long count of elements in the specified range. + * @deprecated Use {@link #zrevrangebyscoreWithScores(ScoredValueStreamingChannel, java.lang.Object, Range)} */ + @Deprecated Long zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, String max, String min); + /** + * Stream over a range of members with scores in a sorted set, by score, with scores ordered from high to low. + * + * @param channel streaming channel that receives a call for every scored value + * @param key the key + * @param range the range + * @return Long count of elements in the specified range. + */ + Long zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, Range range); + /** * Stream over a range of members with scores in a sorted set, by score, with scores ordered from high to low. * @@ -660,7 +912,9 @@ public interface RedisSortedSetCommands { * @param offset the offset * @param count the count * @return Long count of elements in the specified range. + * @deprecated Use {@link #zrevrangebyscoreWithScores(ScoredValueStreamingChannel, java.lang.Object, Range, Limit)} */ + @Deprecated Long zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, double max, double min, long offset, long count); /** @@ -673,9 +927,23 @@ public interface RedisSortedSetCommands { * @param offset the offset * @param count the count * @return Long count of elements in the specified range. + * @deprecated Use {@link #zrevrangebyscoreWithScores(ScoredValueStreamingChannel, java.lang.Object, Range, Limit)} */ + @Deprecated Long zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, String max, String min, long offset, long count); + /** + * Stream over a range of members with scores in a sorted set, by score, with scores ordered from high to low. + * + * @param channel streaming channel that receives a call for every scored value + * @param key the key + * @param range the range + * @param limit the limit + * @return Long count of elements in the specified range. + * @since 4.3 + */ + Long zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, Range range, Limit limit); + /** * Determine the index of a member in a sorted set, with scores ordered from high to low. * @@ -798,9 +1066,21 @@ public interface RedisSortedSetCommands { * @param min min score * @param max max score * @return Long integer-reply the number of elements in the specified score range. + * @deprecated Use {@link #zlexcount(java.lang.Object, Range)} */ + @Deprecated Long zlexcount(K key, String min, String max); + /** + * Count the number of members in a sorted set between a given lexicographical range. + * + * @param key the key + * @param range the range + * @return Long integer-reply the number of elements in the specified score range. + * @since 4.3 + */ + Long zlexcount(K key, Range range); + /** * Remove all members in a sorted set between the given lexicographical range. * @@ -808,9 +1088,21 @@ public interface RedisSortedSetCommands { * @param min min score * @param max max score * @return Long integer-reply the number of elements removed. + * @deprecated Use {@link #zremrangebylex(java.lang.Object, Range)} */ + @Deprecated Long zremrangebylex(K key, String min, String max); + /** + * Remove all members in a sorted set between the given lexicographical range. + * + * @param key the key + * @param range the range + * @return Long integer-reply the number of elements removed. + * @since 4.3 + */ + Long zremrangebylex(K key, Range range); + /** * Return a range of members in a sorted set, by lexicographical range. * @@ -818,9 +1110,21 @@ public interface RedisSortedSetCommands { * @param min min score * @param max max score * @return List<V> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebylex(java.lang.Object, Range)} */ + @Deprecated List zrangebylex(K key, String min, String max); + /** + * Return a range of members in a sorted set, by lexicographical range. + * + * @param key the key + * @param range the range + * @return List<V> array-reply list of elements in the specified score range. + * @since 4.3 + */ + List zrangebylex(K key, Range range); + /** * Return a range of members in a sorted set, by lexicographical range. * @@ -830,6 +1134,19 @@ public interface RedisSortedSetCommands { * @param offset the offset * @param count the count * @return List<V> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebylex(java.lang.Object, Range)} */ + @Deprecated List zrangebylex(K key, String min, String max, long offset, long count); + + /** + * Return a range of members in a sorted set, by lexicographical range. + * + * @param key the key + * @param range the range + * @param limit the limit + * @return List<V> array-reply list of elements in the specified score range. + * @since 4.3 + */ + List zrangebylex(K key, Range range, Limit limit); } diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionSortedSetAsyncCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionSortedSetAsyncCommands.java index 489f704428..100e83dc7b 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionSortedSetAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionSortedSetAsyncCommands.java @@ -1,6 +1,8 @@ package com.lambdaworks.redis.cluster.api.async; import java.util.List; +import com.lambdaworks.redis.Limit; +import com.lambdaworks.redis.Range; import com.lambdaworks.redis.ScanArgs; import com.lambdaworks.redis.ScanCursor; import com.lambdaworks.redis.ScoredValue; @@ -131,7 +133,9 @@ public interface NodeSelectionSortedSetAsyncCommands { * @param min min score * @param max max score * @return Long integer-reply the number of elements in the specified score range. + * @deprecated Use {@link #zcount(java.lang.Object, Range)} */ + @Deprecated AsyncExecutions zcount(K key, double min, double max); /** @@ -141,9 +145,21 @@ public interface NodeSelectionSortedSetAsyncCommands { * @param min min score * @param max max score * @return Long integer-reply the number of elements in the specified score range. + * @deprecated Use {@link #zcount(java.lang.Object, Range)} */ + @Deprecated AsyncExecutions zcount(K key, String min, String max); + /** + * Count the members in a sorted set with scores within the given {@link Range}. + * + * @param key the key + * @param range the range + * @return Long integer-reply the number of elements in the specified score range. + * @since 4.3 + */ + AsyncExecutions zcount(K key, Range range); + /** * Increment the score of a member in a sorted set. * @@ -201,7 +217,9 @@ public interface NodeSelectionSortedSetAsyncCommands { * @param min min score * @param max max score * @return List<V> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebyscore(java.lang.Object, Range)} */ + @Deprecated AsyncExecutions> zrangebyscore(K key, double min, double max); /** @@ -211,9 +229,21 @@ public interface NodeSelectionSortedSetAsyncCommands { * @param min min score * @param max max score * @return List<V> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebyscore(java.lang.Object, Range)} */ + @Deprecated AsyncExecutions> zrangebyscore(K key, String min, String max); + /** + * Return a range of members in a sorted set, by score. + * + * @param key the key + * @param range the range + * @return List<V> array-reply list of elements in the specified score range. + * @since 4.3 + */ + AsyncExecutions> zrangebyscore(K key, Range range); + /** * Return a range of members in a sorted set, by score. * @@ -223,7 +253,9 @@ public interface NodeSelectionSortedSetAsyncCommands { * @param offset the offset * @param count the count * @return List<V> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebyscore(java.lang.Object, Range, Limit)} */ + @Deprecated AsyncExecutions> zrangebyscore(K key, double min, double max, long offset, long count); /** @@ -235,9 +267,22 @@ public interface NodeSelectionSortedSetAsyncCommands { * @param offset the offset * @param count the count * @return List<V> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebyscore(java.lang.Object, Range, Limit)} */ + @Deprecated AsyncExecutions> zrangebyscore(K key, String min, String max, long offset, long count); + /** + * Return a range of members in a sorted set, by score. + * + * @param key the key + * @param range the range + * @param limit the limit + * @return List<V> array-reply list of elements in the specified score range. + * @since 4.3 + */ + AsyncExecutions> zrangebyscore(K key, Range range, Limit limit); + /** * Return a range of members with score in a sorted set, by score. * @@ -245,7 +290,9 @@ public interface NodeSelectionSortedSetAsyncCommands { * @param min min score * @param max max score * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range)} */ + @Deprecated AsyncExecutions>> zrangebyscoreWithScores(K key, double min, double max); /** @@ -255,9 +302,21 @@ public interface NodeSelectionSortedSetAsyncCommands { * @param min min score * @param max max score * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range)} */ + @Deprecated AsyncExecutions>> zrangebyscoreWithScores(K key, String min, String max); + /** + * Return a range of members with score in a sorted set, by score. + * + * @param key the key + * @param range the range + * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @since 4.3 + */ + AsyncExecutions>> zrangebyscoreWithScores(K key, Range range); + /** * Return a range of members with score in a sorted set, by score. * @@ -267,6 +326,7 @@ public interface NodeSelectionSortedSetAsyncCommands { * @param offset the offset * @param count the count * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range, Limit limit)} */ AsyncExecutions>> zrangebyscoreWithScores(K key, double min, double max, long offset, long count); @@ -279,9 +339,22 @@ public interface NodeSelectionSortedSetAsyncCommands { * @param offset the offset * @param count the count * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range, Limit)} */ + @Deprecated AsyncExecutions>> zrangebyscoreWithScores(K key, String min, String max, long offset, long count); + /** + * Return a range of members with score in a sorted set, by score. + * + * @param key the key + * @param range the range + * @param limit the limit + * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @since 4.3 + */ + AsyncExecutions>> zrangebyscoreWithScores(K key, Range range, Limit limit); + /** * Return a range of members in a sorted set, by index. * @@ -312,7 +385,9 @@ public interface NodeSelectionSortedSetAsyncCommands { * @param min min score * @param max max score * @return Long count of elements in the specified score range. + * @deprecated Use {@link #zrangebyscore(ValueStreamingChannel, java.lang.Object, Range)} */ + @Deprecated AsyncExecutions zrangebyscore(ValueStreamingChannel channel, K key, double min, double max); /** @@ -323,9 +398,22 @@ public interface NodeSelectionSortedSetAsyncCommands { * @param min min score * @param max max score * @return Long count of elements in the specified score range. + * @deprecated Use {@link #zrangebyscore(ValueStreamingChannel, java.lang.Object, Range)} */ + @Deprecated AsyncExecutions zrangebyscore(ValueStreamingChannel channel, K key, String min, String max); + /** + * Stream over a range of members in a sorted set, by score. + * + * @param channel streaming channel that receives a call for every value + * @param key the key + * @param range the range + * @return Long count of elements in the specified score range. + * @since 4.3 + */ + AsyncExecutions zrangebyscore(ValueStreamingChannel channel, K key, Range range); + /** * Stream over range of members in a sorted set, by score. * @@ -336,7 +424,9 @@ public interface NodeSelectionSortedSetAsyncCommands { * @param offset the offset * @param count the count * @return Long count of elements in the specified score range. + * @deprecated Use {@link #zrangebyscore(ValueStreamingChannel, java.lang.Object, Range, Limit limit)} */ + @Deprecated AsyncExecutions zrangebyscore(ValueStreamingChannel channel, K key, double min, double max, long offset, long count); /** @@ -349,9 +439,23 @@ public interface NodeSelectionSortedSetAsyncCommands { * @param offset the offset * @param count the count * @return Long count of elements in the specified score range. + * @deprecated Use {@link #zrangebyscore(ValueStreamingChannel, java.lang.Object, Range, Limit limit)} */ + @Deprecated AsyncExecutions zrangebyscore(ValueStreamingChannel channel, K key, String min, String max, long offset, long count); + /** + * Stream over a range of members in a sorted set, by score. + * + * @param channel streaming channel that receives a call for every value + * @param key the key + * @param range the range + * @param limit the limit + * @return Long count of elements in the specified score range. + * @since 4.3 + */ + AsyncExecutions zrangebyscore(ValueStreamingChannel channel, K key, Range range, Limit limit); + /** * Stream over a range of members with scores in a sorted set, by score. * @@ -360,7 +464,9 @@ public interface NodeSelectionSortedSetAsyncCommands { * @param min min score * @param max max score * @return Long count of elements in the specified score range. + * @deprecated Use {@link #zrangebyscoreWithScores(ScoredValueStreamingChannel, java.lang.Object, Range)} */ + @Deprecated AsyncExecutions zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, double min, double max); /** @@ -371,9 +477,22 @@ public interface NodeSelectionSortedSetAsyncCommands { * @param min min score * @param max max score * @return Long count of elements in the specified score range. + * @deprecated Use {@link #zrangebyscoreWithScores(ScoredValueStreamingChannel, java.lang.Object, Range)} */ + @Deprecated AsyncExecutions zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, String min, String max); + /** + * Stream over a range of members with scores in a sorted set, by score. + * + * @param channel streaming channel that receives a call for every scored value + * @param key the key + * @param range the range + * @return Long count of elements in the specified score range. + * @since 4.3 + */ + AsyncExecutions zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, Range range); + /** * Stream over a range of members with scores in a sorted set, by score. * @@ -384,7 +503,9 @@ public interface NodeSelectionSortedSetAsyncCommands { * @param offset the offset * @param count the count * @return Long count of elements in the specified score range. + * @deprecated Use {@link #zrangebyscoreWithScores(ScoredValueStreamingChannel, java.lang.Object, Range, Limit limit)} */ + @Deprecated AsyncExecutions zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, double min, double max, long offset, long count); /** @@ -397,9 +518,23 @@ public interface NodeSelectionSortedSetAsyncCommands { * @param offset the offset * @param count the count * @return Long count of elements in the specified score range. + * @deprecated Use {@link #zrangebyscoreWithScores(ScoredValueStreamingChannel, java.lang.Object, Range, Limit limit)} */ + @Deprecated AsyncExecutions zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, String min, String max, long offset, long count); + /** + * Stream over a range of members with scores in a sorted set, by score. + * + * @param channel streaming channel that receives a call for every scored value + * @param key the key + * @param range the range + * @param limit the limit + * @return Long count of elements in the specified score range. + * @since 4.3 + */ + AsyncExecutions zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, Range range, Limit limit); + /** * Determine the index of a member in a sorted set. * @@ -438,7 +573,9 @@ public interface NodeSelectionSortedSetAsyncCommands { * @param min min score * @param max max score * @return Long integer-reply the number of elements removed. + * @deprecated Use {@link #zremrangebyscore(java.lang.Object, Range)} */ + @Deprecated AsyncExecutions zremrangebyscore(K key, double min, double max); /** @@ -448,9 +585,21 @@ public interface NodeSelectionSortedSetAsyncCommands { * @param min min score * @param max max score * @return Long integer-reply the number of elements removed. + * @deprecated Use {@link #zremrangebyscore(java.lang.Object, Range)} */ + @Deprecated AsyncExecutions zremrangebyscore(K key, String min, String max); + /** + * Remove all members in a sorted set within the given scores. + * + * @param key the key + * @param range the range + * @return Long integer-reply the number of elements removed. + * @since 4.3 + */ + AsyncExecutions zremrangebyscore(K key, Range range); + /** * Return a range of members in a sorted set, by index, with scores ordered from high to low. * @@ -478,7 +627,9 @@ public interface NodeSelectionSortedSetAsyncCommands { * @param min min score * @param max max score * @return List<V> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrevrangebyscore(java.lang.Object, Range)} */ + @Deprecated AsyncExecutions> zrevrangebyscore(K key, double max, double min); /** @@ -488,9 +639,21 @@ public interface NodeSelectionSortedSetAsyncCommands { * @param min min score * @param max max score * @return List<V> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrevrangebyscore(java.lang.Object, Range)} */ + @Deprecated AsyncExecutions> zrevrangebyscore(K key, String max, String min); + /** + * Return a range of members in a sorted set, by score, with scores ordered from high to low. + * + * @param key the key + * @param range the range + * @return List<V> array-reply list of elements in the specified score range. + * @since 4.3 + */ + AsyncExecutions> zrevrangebyscore(K key, Range range); + /** * Return a range of members in a sorted set, by score, with scores ordered from high to low. * @@ -500,7 +663,9 @@ public interface NodeSelectionSortedSetAsyncCommands { * @param offset the withscores * @param count the null * @return List<V> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrevrangebyscore(java.lang.Object, Range, Limit)} */ + @Deprecated AsyncExecutions> zrevrangebyscore(K key, double max, double min, long offset, long count); /** @@ -512,9 +677,22 @@ public interface NodeSelectionSortedSetAsyncCommands { * @param offset the offset * @param count the count * @return List<V> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrevrangebyscore(java.lang.Object, Range, Limit)} */ + @Deprecated AsyncExecutions> zrevrangebyscore(K key, String max, String min, long offset, long count); + /** + * Return a range of members in a sorted set, by score, with scores ordered from high to low. + * + * @param key the key + * @param range the range + * @param limit the limit + * @return List<V> array-reply list of elements in the specified score range. + * @since 4.3 + */ + AsyncExecutions> zrevrangebyscore(K key, Range range, Limit limit); + /** * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. * @@ -522,7 +700,9 @@ public interface NodeSelectionSortedSetAsyncCommands { * @param max max score * @param min min score * @return List<V> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range)} */ + @Deprecated AsyncExecutions>> zrevrangebyscoreWithScores(K key, double max, double min); /** @@ -532,9 +712,21 @@ public interface NodeSelectionSortedSetAsyncCommands { * @param max max score * @param min min score * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range)} */ + @Deprecated AsyncExecutions>> zrevrangebyscoreWithScores(K key, String max, String min); + /** + * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. + * + * @param key the key + * @param range the range + * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @since 4.3 + */ + AsyncExecutions>> zrevrangebyscoreWithScores(K key, Range range); + /** * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. * @@ -544,7 +736,9 @@ public interface NodeSelectionSortedSetAsyncCommands { * @param offset the offset * @param count the count * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range, Limit)} */ + @Deprecated AsyncExecutions>> zrevrangebyscoreWithScores(K key, double max, double min, long offset, long count); /** @@ -556,9 +750,22 @@ public interface NodeSelectionSortedSetAsyncCommands { * @param offset the offset * @param count the count * @return List<V> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range, Limit)} */ + @Deprecated AsyncExecutions>> zrevrangebyscoreWithScores(K key, String max, String min, long offset, long count); + /** + * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. + * + * @param key the key + * @param range the range + * @param limit limit + * @return List<V> array-reply list of elements in the specified score range. + * @since 4.3 + */ + AsyncExecutions>> zrevrangebyscoreWithScores(K key, Range range, Limit limit); + /** * Stream over a range of members in a sorted set, by index, with scores ordered from high to low. * @@ -589,7 +796,9 @@ public interface NodeSelectionSortedSetAsyncCommands { * @param max max score * @param min min score * @return Long count of elements in the specified range. + * @deprecated Use {@link #zrevrangebyscore(java.lang.Object, Range)} */ + @Deprecated AsyncExecutions zrevrangebyscore(ValueStreamingChannel channel, K key, double max, double min); /** @@ -600,9 +809,22 @@ public interface NodeSelectionSortedSetAsyncCommands { * @param min min score * @param max max score * @return Long count of elements in the specified range. + * @deprecated Use {@link #zrevrangebyscore(java.lang.Object, Range)} */ + @Deprecated AsyncExecutions zrevrangebyscore(ValueStreamingChannel channel, K key, String max, String min); + /** + * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. + * + * @param channel streaming channel that receives a call for every value + * @param key the key + * @param range the range + * @return Long count of elements in the specified range. + * @since 4.3 + */ + AsyncExecutions zrevrangebyscore(ValueStreamingChannel channel, K key, Range range); + /** * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. * @@ -613,7 +835,9 @@ public interface NodeSelectionSortedSetAsyncCommands { * @param offset the offset * @param count the count * @return Long count of elements in the specified range. + * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range, Limit)} */ + @Deprecated AsyncExecutions zrevrangebyscore(ValueStreamingChannel channel, K key, double max, double min, long offset, long count); /** @@ -626,9 +850,23 @@ public interface NodeSelectionSortedSetAsyncCommands { * @param offset the offset * @param count the count * @return Long count of elements in the specified range. + * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range, Limit)} */ + @Deprecated AsyncExecutions zrevrangebyscore(ValueStreamingChannel channel, K key, String max, String min, long offset, long count); + /** + * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. + * + * @param channel streaming channel that receives a call for every value + * @param key the key + * @param range the range + * @param limit the limit + * @return Long count of elements in the specified range. + * @since 4.3 + */ + AsyncExecutions zrevrangebyscore(ValueStreamingChannel channel, K key, Range range, Limit limit); + /** * Stream over a range of members with scores in a sorted set, by score, with scores ordered from high to low. * @@ -637,7 +875,9 @@ public interface NodeSelectionSortedSetAsyncCommands { * @param min min score * @param max max score * @return Long count of elements in the specified range. + * @deprecated Use {@link #zrevrangebyscoreWithScores(ScoredValueStreamingChannel, java.lang.Object, Range)} */ + @Deprecated AsyncExecutions zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, double max, double min); /** @@ -648,9 +888,21 @@ public interface NodeSelectionSortedSetAsyncCommands { * @param min min score * @param max max score * @return Long count of elements in the specified range. + * @deprecated Use {@link #zrevrangebyscoreWithScores(ScoredValueStreamingChannel, java.lang.Object, Range)} */ + @Deprecated AsyncExecutions zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, String max, String min); + /** + * Stream over a range of members with scores in a sorted set, by score, with scores ordered from high to low. + * + * @param channel streaming channel that receives a call for every scored value + * @param key the key + * @param range the range + * @return Long count of elements in the specified range. + */ + AsyncExecutions zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, Range range); + /** * Stream over a range of members with scores in a sorted set, by score, with scores ordered from high to low. * @@ -661,7 +913,9 @@ public interface NodeSelectionSortedSetAsyncCommands { * @param offset the offset * @param count the count * @return Long count of elements in the specified range. + * @deprecated Use {@link #zrevrangebyscoreWithScores(ScoredValueStreamingChannel, java.lang.Object, Range, Limit)} */ + @Deprecated AsyncExecutions zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, double max, double min, long offset, long count); /** @@ -674,9 +928,23 @@ public interface NodeSelectionSortedSetAsyncCommands { * @param offset the offset * @param count the count * @return Long count of elements in the specified range. + * @deprecated Use {@link #zrevrangebyscoreWithScores(ScoredValueStreamingChannel, java.lang.Object, Range, Limit)} */ + @Deprecated AsyncExecutions zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, String max, String min, long offset, long count); + /** + * Stream over a range of members with scores in a sorted set, by score, with scores ordered from high to low. + * + * @param channel streaming channel that receives a call for every scored value + * @param key the key + * @param range the range + * @param limit the limit + * @return Long count of elements in the specified range. + * @since 4.3 + */ + AsyncExecutions zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, Range range, Limit limit); + /** * Determine the index of a member in a sorted set, with scores ordered from high to low. * @@ -799,9 +1067,21 @@ public interface NodeSelectionSortedSetAsyncCommands { * @param min min score * @param max max score * @return Long integer-reply the number of elements in the specified score range. + * @deprecated Use {@link #zlexcount(java.lang.Object, Range)} */ + @Deprecated AsyncExecutions zlexcount(K key, String min, String max); + /** + * Count the number of members in a sorted set between a given lexicographical range. + * + * @param key the key + * @param range the range + * @return Long integer-reply the number of elements in the specified score range. + * @since 4.3 + */ + AsyncExecutions zlexcount(K key, Range range); + /** * Remove all members in a sorted set between the given lexicographical range. * @@ -809,9 +1089,21 @@ public interface NodeSelectionSortedSetAsyncCommands { * @param min min score * @param max max score * @return Long integer-reply the number of elements removed. + * @deprecated Use {@link #zremrangebylex(java.lang.Object, Range)} */ + @Deprecated AsyncExecutions zremrangebylex(K key, String min, String max); + /** + * Remove all members in a sorted set between the given lexicographical range. + * + * @param key the key + * @param range the range + * @return Long integer-reply the number of elements removed. + * @since 4.3 + */ + AsyncExecutions zremrangebylex(K key, Range range); + /** * Return a range of members in a sorted set, by lexicographical range. * @@ -819,9 +1111,21 @@ public interface NodeSelectionSortedSetAsyncCommands { * @param min min score * @param max max score * @return List<V> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebylex(java.lang.Object, Range)} */ + @Deprecated AsyncExecutions> zrangebylex(K key, String min, String max); + /** + * Return a range of members in a sorted set, by lexicographical range. + * + * @param key the key + * @param range the range + * @return List<V> array-reply list of elements in the specified score range. + * @since 4.3 + */ + AsyncExecutions> zrangebylex(K key, Range range); + /** * Return a range of members in a sorted set, by lexicographical range. * @@ -831,6 +1135,19 @@ public interface NodeSelectionSortedSetAsyncCommands { * @param offset the offset * @param count the count * @return List<V> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebylex(java.lang.Object, Range)} */ + @Deprecated AsyncExecutions> zrangebylex(K key, String min, String max, long offset, long count); + + /** + * Return a range of members in a sorted set, by lexicographical range. + * + * @param key the key + * @param range the range + * @param limit the limit + * @return List<V> array-reply list of elements in the specified score range. + * @since 4.3 + */ + AsyncExecutions> zrangebylex(K key, Range range, Limit limit); } diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionSortedSetCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionSortedSetCommands.java index 288961a928..0aeeaee2a6 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionSortedSetCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionSortedSetCommands.java @@ -1,6 +1,8 @@ package com.lambdaworks.redis.cluster.api.sync; import java.util.List; +import com.lambdaworks.redis.Limit; +import com.lambdaworks.redis.Range; import com.lambdaworks.redis.ScanArgs; import com.lambdaworks.redis.ScanCursor; import com.lambdaworks.redis.ScoredValue; @@ -130,7 +132,9 @@ public interface NodeSelectionSortedSetCommands { * @param min min score * @param max max score * @return Long integer-reply the number of elements in the specified score range. + * @deprecated Use {@link #zcount(java.lang.Object, Range)} */ + @Deprecated Executions zcount(K key, double min, double max); /** @@ -140,9 +144,21 @@ public interface NodeSelectionSortedSetCommands { * @param min min score * @param max max score * @return Long integer-reply the number of elements in the specified score range. + * @deprecated Use {@link #zcount(java.lang.Object, Range)} */ + @Deprecated Executions zcount(K key, String min, String max); + /** + * Count the members in a sorted set with scores within the given {@link Range}. + * + * @param key the key + * @param range the range + * @return Long integer-reply the number of elements in the specified score range. + * @since 4.3 + */ + Executions zcount(K key, Range range); + /** * Increment the score of a member in a sorted set. * @@ -200,7 +216,9 @@ public interface NodeSelectionSortedSetCommands { * @param min min score * @param max max score * @return List<V> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebyscore(java.lang.Object, Range)} */ + @Deprecated Executions> zrangebyscore(K key, double min, double max); /** @@ -210,9 +228,21 @@ public interface NodeSelectionSortedSetCommands { * @param min min score * @param max max score * @return List<V> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebyscore(java.lang.Object, Range)} */ + @Deprecated Executions> zrangebyscore(K key, String min, String max); + /** + * Return a range of members in a sorted set, by score. + * + * @param key the key + * @param range the range + * @return List<V> array-reply list of elements in the specified score range. + * @since 4.3 + */ + Executions> zrangebyscore(K key, Range range); + /** * Return a range of members in a sorted set, by score. * @@ -222,7 +252,9 @@ public interface NodeSelectionSortedSetCommands { * @param offset the offset * @param count the count * @return List<V> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebyscore(java.lang.Object, Range, Limit)} */ + @Deprecated Executions> zrangebyscore(K key, double min, double max, long offset, long count); /** @@ -234,9 +266,22 @@ public interface NodeSelectionSortedSetCommands { * @param offset the offset * @param count the count * @return List<V> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebyscore(java.lang.Object, Range, Limit)} */ + @Deprecated Executions> zrangebyscore(K key, String min, String max, long offset, long count); + /** + * Return a range of members in a sorted set, by score. + * + * @param key the key + * @param range the range + * @param limit the limit + * @return List<V> array-reply list of elements in the specified score range. + * @since 4.3 + */ + Executions> zrangebyscore(K key, Range range, Limit limit); + /** * Return a range of members with score in a sorted set, by score. * @@ -244,7 +289,9 @@ public interface NodeSelectionSortedSetCommands { * @param min min score * @param max max score * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range)} */ + @Deprecated Executions>> zrangebyscoreWithScores(K key, double min, double max); /** @@ -254,9 +301,21 @@ public interface NodeSelectionSortedSetCommands { * @param min min score * @param max max score * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range)} */ + @Deprecated Executions>> zrangebyscoreWithScores(K key, String min, String max); + /** + * Return a range of members with score in a sorted set, by score. + * + * @param key the key + * @param range the range + * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @since 4.3 + */ + Executions>> zrangebyscoreWithScores(K key, Range range); + /** * Return a range of members with score in a sorted set, by score. * @@ -266,6 +325,7 @@ public interface NodeSelectionSortedSetCommands { * @param offset the offset * @param count the count * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range, Limit limit)} */ Executions>> zrangebyscoreWithScores(K key, double min, double max, long offset, long count); @@ -278,9 +338,22 @@ public interface NodeSelectionSortedSetCommands { * @param offset the offset * @param count the count * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range, Limit)} */ + @Deprecated Executions>> zrangebyscoreWithScores(K key, String min, String max, long offset, long count); + /** + * Return a range of members with score in a sorted set, by score. + * + * @param key the key + * @param range the range + * @param limit the limit + * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @since 4.3 + */ + Executions>> zrangebyscoreWithScores(K key, Range range, Limit limit); + /** * Return a range of members in a sorted set, by index. * @@ -311,7 +384,9 @@ public interface NodeSelectionSortedSetCommands { * @param min min score * @param max max score * @return Long count of elements in the specified score range. + * @deprecated Use {@link #zrangebyscore(ValueStreamingChannel, java.lang.Object, Range)} */ + @Deprecated Executions zrangebyscore(ValueStreamingChannel channel, K key, double min, double max); /** @@ -322,9 +397,22 @@ public interface NodeSelectionSortedSetCommands { * @param min min score * @param max max score * @return Long count of elements in the specified score range. + * @deprecated Use {@link #zrangebyscore(ValueStreamingChannel, java.lang.Object, Range)} */ + @Deprecated Executions zrangebyscore(ValueStreamingChannel channel, K key, String min, String max); + /** + * Stream over a range of members in a sorted set, by score. + * + * @param channel streaming channel that receives a call for every value + * @param key the key + * @param range the range + * @return Long count of elements in the specified score range. + * @since 4.3 + */ + Executions zrangebyscore(ValueStreamingChannel channel, K key, Range range); + /** * Stream over range of members in a sorted set, by score. * @@ -335,7 +423,9 @@ public interface NodeSelectionSortedSetCommands { * @param offset the offset * @param count the count * @return Long count of elements in the specified score range. + * @deprecated Use {@link #zrangebyscore(ValueStreamingChannel, java.lang.Object, Range, Limit limit)} */ + @Deprecated Executions zrangebyscore(ValueStreamingChannel channel, K key, double min, double max, long offset, long count); /** @@ -348,9 +438,23 @@ public interface NodeSelectionSortedSetCommands { * @param offset the offset * @param count the count * @return Long count of elements in the specified score range. + * @deprecated Use {@link #zrangebyscore(ValueStreamingChannel, java.lang.Object, Range, Limit limit)} */ + @Deprecated Executions zrangebyscore(ValueStreamingChannel channel, K key, String min, String max, long offset, long count); + /** + * Stream over a range of members in a sorted set, by score. + * + * @param channel streaming channel that receives a call for every value + * @param key the key + * @param range the range + * @param limit the limit + * @return Long count of elements in the specified score range. + * @since 4.3 + */ + Executions zrangebyscore(ValueStreamingChannel channel, K key, Range range, Limit limit); + /** * Stream over a range of members with scores in a sorted set, by score. * @@ -359,7 +463,9 @@ public interface NodeSelectionSortedSetCommands { * @param min min score * @param max max score * @return Long count of elements in the specified score range. + * @deprecated Use {@link #zrangebyscoreWithScores(ScoredValueStreamingChannel, java.lang.Object, Range)} */ + @Deprecated Executions zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, double min, double max); /** @@ -370,9 +476,22 @@ public interface NodeSelectionSortedSetCommands { * @param min min score * @param max max score * @return Long count of elements in the specified score range. + * @deprecated Use {@link #zrangebyscoreWithScores(ScoredValueStreamingChannel, java.lang.Object, Range)} */ + @Deprecated Executions zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, String min, String max); + /** + * Stream over a range of members with scores in a sorted set, by score. + * + * @param channel streaming channel that receives a call for every scored value + * @param key the key + * @param range the range + * @return Long count of elements in the specified score range. + * @since 4.3 + */ + Executions zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, Range range); + /** * Stream over a range of members with scores in a sorted set, by score. * @@ -383,7 +502,9 @@ public interface NodeSelectionSortedSetCommands { * @param offset the offset * @param count the count * @return Long count of elements in the specified score range. + * @deprecated Use {@link #zrangebyscoreWithScores(ScoredValueStreamingChannel, java.lang.Object, Range, Limit limit)} */ + @Deprecated Executions zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, double min, double max, long offset, long count); /** @@ -396,9 +517,23 @@ public interface NodeSelectionSortedSetCommands { * @param offset the offset * @param count the count * @return Long count of elements in the specified score range. + * @deprecated Use {@link #zrangebyscoreWithScores(ScoredValueStreamingChannel, java.lang.Object, Range, Limit limit)} */ + @Deprecated Executions zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, String min, String max, long offset, long count); + /** + * Stream over a range of members with scores in a sorted set, by score. + * + * @param channel streaming channel that receives a call for every scored value + * @param key the key + * @param range the range + * @param limit the limit + * @return Long count of elements in the specified score range. + * @since 4.3 + */ + Executions zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, Range range, Limit limit); + /** * Determine the index of a member in a sorted set. * @@ -437,7 +572,9 @@ public interface NodeSelectionSortedSetCommands { * @param min min score * @param max max score * @return Long integer-reply the number of elements removed. + * @deprecated Use {@link #zremrangebyscore(java.lang.Object, Range)} */ + @Deprecated Executions zremrangebyscore(K key, double min, double max); /** @@ -447,9 +584,21 @@ public interface NodeSelectionSortedSetCommands { * @param min min score * @param max max score * @return Long integer-reply the number of elements removed. + * @deprecated Use {@link #zremrangebyscore(java.lang.Object, Range)} */ + @Deprecated Executions zremrangebyscore(K key, String min, String max); + /** + * Remove all members in a sorted set within the given scores. + * + * @param key the key + * @param range the range + * @return Long integer-reply the number of elements removed. + * @since 4.3 + */ + Executions zremrangebyscore(K key, Range range); + /** * Return a range of members in a sorted set, by index, with scores ordered from high to low. * @@ -477,7 +626,9 @@ public interface NodeSelectionSortedSetCommands { * @param min min score * @param max max score * @return List<V> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrevrangebyscore(java.lang.Object, Range)} */ + @Deprecated Executions> zrevrangebyscore(K key, double max, double min); /** @@ -487,9 +638,21 @@ public interface NodeSelectionSortedSetCommands { * @param min min score * @param max max score * @return List<V> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrevrangebyscore(java.lang.Object, Range)} */ + @Deprecated Executions> zrevrangebyscore(K key, String max, String min); + /** + * Return a range of members in a sorted set, by score, with scores ordered from high to low. + * + * @param key the key + * @param range the range + * @return List<V> array-reply list of elements in the specified score range. + * @since 4.3 + */ + Executions> zrevrangebyscore(K key, Range range); + /** * Return a range of members in a sorted set, by score, with scores ordered from high to low. * @@ -499,7 +662,9 @@ public interface NodeSelectionSortedSetCommands { * @param offset the withscores * @param count the null * @return List<V> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrevrangebyscore(java.lang.Object, Range, Limit)} */ + @Deprecated Executions> zrevrangebyscore(K key, double max, double min, long offset, long count); /** @@ -511,9 +676,22 @@ public interface NodeSelectionSortedSetCommands { * @param offset the offset * @param count the count * @return List<V> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrevrangebyscore(java.lang.Object, Range, Limit)} */ + @Deprecated Executions> zrevrangebyscore(K key, String max, String min, long offset, long count); + /** + * Return a range of members in a sorted set, by score, with scores ordered from high to low. + * + * @param key the key + * @param range the range + * @param limit the limit + * @return List<V> array-reply list of elements in the specified score range. + * @since 4.3 + */ + Executions> zrevrangebyscore(K key, Range range, Limit limit); + /** * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. * @@ -521,7 +699,9 @@ public interface NodeSelectionSortedSetCommands { * @param max max score * @param min min score * @return List<V> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range)} */ + @Deprecated Executions>> zrevrangebyscoreWithScores(K key, double max, double min); /** @@ -531,9 +711,21 @@ public interface NodeSelectionSortedSetCommands { * @param max max score * @param min min score * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range)} */ + @Deprecated Executions>> zrevrangebyscoreWithScores(K key, String max, String min); + /** + * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. + * + * @param key the key + * @param range the range + * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @since 4.3 + */ + Executions>> zrevrangebyscoreWithScores(K key, Range range); + /** * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. * @@ -543,7 +735,9 @@ public interface NodeSelectionSortedSetCommands { * @param offset the offset * @param count the count * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range, Limit)} */ + @Deprecated Executions>> zrevrangebyscoreWithScores(K key, double max, double min, long offset, long count); /** @@ -555,9 +749,22 @@ public interface NodeSelectionSortedSetCommands { * @param offset the offset * @param count the count * @return List<V> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range, Limit)} */ + @Deprecated Executions>> zrevrangebyscoreWithScores(K key, String max, String min, long offset, long count); + /** + * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. + * + * @param key the key + * @param range the range + * @param limit limit + * @return List<V> array-reply list of elements in the specified score range. + * @since 4.3 + */ + Executions>> zrevrangebyscoreWithScores(K key, Range range, Limit limit); + /** * Stream over a range of members in a sorted set, by index, with scores ordered from high to low. * @@ -588,7 +795,9 @@ public interface NodeSelectionSortedSetCommands { * @param max max score * @param min min score * @return Long count of elements in the specified range. + * @deprecated Use {@link #zrevrangebyscore(java.lang.Object, Range)} */ + @Deprecated Executions zrevrangebyscore(ValueStreamingChannel channel, K key, double max, double min); /** @@ -599,9 +808,22 @@ public interface NodeSelectionSortedSetCommands { * @param min min score * @param max max score * @return Long count of elements in the specified range. + * @deprecated Use {@link #zrevrangebyscore(java.lang.Object, Range)} */ + @Deprecated Executions zrevrangebyscore(ValueStreamingChannel channel, K key, String max, String min); + /** + * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. + * + * @param channel streaming channel that receives a call for every value + * @param key the key + * @param range the range + * @return Long count of elements in the specified range. + * @since 4.3 + */ + Executions zrevrangebyscore(ValueStreamingChannel channel, K key, Range range); + /** * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. * @@ -612,7 +834,9 @@ public interface NodeSelectionSortedSetCommands { * @param offset the offset * @param count the count * @return Long count of elements in the specified range. + * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range, Limit)} */ + @Deprecated Executions zrevrangebyscore(ValueStreamingChannel channel, K key, double max, double min, long offset, long count); /** @@ -625,9 +849,23 @@ public interface NodeSelectionSortedSetCommands { * @param offset the offset * @param count the count * @return Long count of elements in the specified range. + * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range, Limit)} */ + @Deprecated Executions zrevrangebyscore(ValueStreamingChannel channel, K key, String max, String min, long offset, long count); + /** + * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. + * + * @param channel streaming channel that receives a call for every value + * @param key the key + * @param range the range + * @param limit the limit + * @return Long count of elements in the specified range. + * @since 4.3 + */ + Executions zrevrangebyscore(ValueStreamingChannel channel, K key, Range range, Limit limit); + /** * Stream over a range of members with scores in a sorted set, by score, with scores ordered from high to low. * @@ -636,7 +874,9 @@ public interface NodeSelectionSortedSetCommands { * @param min min score * @param max max score * @return Long count of elements in the specified range. + * @deprecated Use {@link #zrevrangebyscoreWithScores(ScoredValueStreamingChannel, java.lang.Object, Range)} */ + @Deprecated Executions zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, double max, double min); /** @@ -647,9 +887,21 @@ public interface NodeSelectionSortedSetCommands { * @param min min score * @param max max score * @return Long count of elements in the specified range. + * @deprecated Use {@link #zrevrangebyscoreWithScores(ScoredValueStreamingChannel, java.lang.Object, Range)} */ + @Deprecated Executions zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, String max, String min); + /** + * Stream over a range of members with scores in a sorted set, by score, with scores ordered from high to low. + * + * @param channel streaming channel that receives a call for every scored value + * @param key the key + * @param range the range + * @return Long count of elements in the specified range. + */ + Executions zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, Range range); + /** * Stream over a range of members with scores in a sorted set, by score, with scores ordered from high to low. * @@ -660,7 +912,9 @@ public interface NodeSelectionSortedSetCommands { * @param offset the offset * @param count the count * @return Long count of elements in the specified range. + * @deprecated Use {@link #zrevrangebyscoreWithScores(ScoredValueStreamingChannel, java.lang.Object, Range, Limit)} */ + @Deprecated Executions zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, double max, double min, long offset, long count); /** @@ -673,9 +927,23 @@ public interface NodeSelectionSortedSetCommands { * @param offset the offset * @param count the count * @return Long count of elements in the specified range. + * @deprecated Use {@link #zrevrangebyscoreWithScores(ScoredValueStreamingChannel, java.lang.Object, Range, Limit)} */ + @Deprecated Executions zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, String max, String min, long offset, long count); + /** + * Stream over a range of members with scores in a sorted set, by score, with scores ordered from high to low. + * + * @param channel streaming channel that receives a call for every scored value + * @param key the key + * @param range the range + * @param limit the limit + * @return Long count of elements in the specified range. + * @since 4.3 + */ + Executions zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, Range range, Limit limit); + /** * Determine the index of a member in a sorted set, with scores ordered from high to low. * @@ -798,9 +1066,21 @@ public interface NodeSelectionSortedSetCommands { * @param min min score * @param max max score * @return Long integer-reply the number of elements in the specified score range. + * @deprecated Use {@link #zlexcount(java.lang.Object, Range)} */ + @Deprecated Executions zlexcount(K key, String min, String max); + /** + * Count the number of members in a sorted set between a given lexicographical range. + * + * @param key the key + * @param range the range + * @return Long integer-reply the number of elements in the specified score range. + * @since 4.3 + */ + Executions zlexcount(K key, Range range); + /** * Remove all members in a sorted set between the given lexicographical range. * @@ -808,9 +1088,21 @@ public interface NodeSelectionSortedSetCommands { * @param min min score * @param max max score * @return Long integer-reply the number of elements removed. + * @deprecated Use {@link #zremrangebylex(java.lang.Object, Range)} */ + @Deprecated Executions zremrangebylex(K key, String min, String max); + /** + * Remove all members in a sorted set between the given lexicographical range. + * + * @param key the key + * @param range the range + * @return Long integer-reply the number of elements removed. + * @since 4.3 + */ + Executions zremrangebylex(K key, Range range); + /** * Return a range of members in a sorted set, by lexicographical range. * @@ -818,9 +1110,21 @@ public interface NodeSelectionSortedSetCommands { * @param min min score * @param max max score * @return List<V> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebylex(java.lang.Object, Range)} */ + @Deprecated Executions> zrangebylex(K key, String min, String max); + /** + * Return a range of members in a sorted set, by lexicographical range. + * + * @param key the key + * @param range the range + * @return List<V> array-reply list of elements in the specified score range. + * @since 4.3 + */ + Executions> zrangebylex(K key, Range range); + /** * Return a range of members in a sorted set, by lexicographical range. * @@ -830,6 +1134,19 @@ public interface NodeSelectionSortedSetCommands { * @param offset the offset * @param count the count * @return List<V> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebylex(java.lang.Object, Range)} */ + @Deprecated Executions> zrangebylex(K key, String min, String max, long offset, long count); + + /** + * Return a range of members in a sorted set, by lexicographical range. + * + * @param key the key + * @param range the range + * @param limit the limit + * @return List<V> array-reply list of elements in the specified score range. + * @since 4.3 + */ + Executions> zrangebylex(K key, Range range, Limit limit); } diff --git a/src/main/templates/com/lambdaworks/redis/api/RedisSortedSetCommands.java b/src/main/templates/com/lambdaworks/redis/api/RedisSortedSetCommands.java index 251a69dc4c..653e5762dc 100644 --- a/src/main/templates/com/lambdaworks/redis/api/RedisSortedSetCommands.java +++ b/src/main/templates/com/lambdaworks/redis/api/RedisSortedSetCommands.java @@ -2,6 +2,8 @@ import java.util.List; +import com.lambdaworks.redis.Limit; +import com.lambdaworks.redis.Range; import com.lambdaworks.redis.ScanArgs; import com.lambdaworks.redis.ScanCursor; import com.lambdaworks.redis.ScoredValue; @@ -130,7 +132,9 @@ public interface RedisSortedSetCommands { * @param min min score * @param max max score * @return Long integer-reply the number of elements in the specified score range. + * @deprecated Use {@link #zcount(java.lang.Object, Range)} */ + @Deprecated Long zcount(K key, double min, double max); /** @@ -140,9 +144,21 @@ public interface RedisSortedSetCommands { * @param min min score * @param max max score * @return Long integer-reply the number of elements in the specified score range. + * @deprecated Use {@link #zcount(java.lang.Object, Range)} */ + @Deprecated Long zcount(K key, String min, String max); + /** + * Count the members in a sorted set with scores within the given {@link Range}. + * + * @param key the key + * @param range the range + * @return Long integer-reply the number of elements in the specified score range. + * @since 4.3 + */ + Long zcount(K key, Range range); + /** * Increment the score of a member in a sorted set. * @@ -200,7 +216,9 @@ public interface RedisSortedSetCommands { * @param min min score * @param max max score * @return List<V> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebyscore(java.lang.Object, Range)} */ + @Deprecated List zrangebyscore(K key, double min, double max); /** @@ -210,9 +228,21 @@ public interface RedisSortedSetCommands { * @param min min score * @param max max score * @return List<V> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebyscore(java.lang.Object, Range)} */ + @Deprecated List zrangebyscore(K key, String min, String max); + /** + * Return a range of members in a sorted set, by score. + * + * @param key the key + * @param range the range + * @return List<V> array-reply list of elements in the specified score range. + * @since 4.3 + */ + List zrangebyscore(K key, Range range); + /** * Return a range of members in a sorted set, by score. * @@ -222,7 +252,9 @@ public interface RedisSortedSetCommands { * @param offset the offset * @param count the count * @return List<V> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebyscore(java.lang.Object, Range, Limit)} */ + @Deprecated List zrangebyscore(K key, double min, double max, long offset, long count); /** @@ -234,9 +266,22 @@ public interface RedisSortedSetCommands { * @param offset the offset * @param count the count * @return List<V> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebyscore(java.lang.Object, Range, Limit)} */ + @Deprecated List zrangebyscore(K key, String min, String max, long offset, long count); + /** + * Return a range of members in a sorted set, by score. + * + * @param key the key + * @param range the range + * @param limit the limit + * @return List<V> array-reply list of elements in the specified score range. + * @since 4.3 + */ + List zrangebyscore(K key, Range range, Limit limit); + /** * Return a range of members with score in a sorted set, by score. * @@ -244,7 +289,9 @@ public interface RedisSortedSetCommands { * @param min min score * @param max max score * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range)} */ + @Deprecated List> zrangebyscoreWithScores(K key, double min, double max); /** @@ -254,9 +301,21 @@ public interface RedisSortedSetCommands { * @param min min score * @param max max score * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range)} */ + @Deprecated List> zrangebyscoreWithScores(K key, String min, String max); + /** + * Return a range of members with score in a sorted set, by score. + * + * @param key the key + * @param range the range + * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @since 4.3 + */ + List> zrangebyscoreWithScores(K key, Range range); + /** * Return a range of members with score in a sorted set, by score. * @@ -266,6 +325,7 @@ public interface RedisSortedSetCommands { * @param offset the offset * @param count the count * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range, Limit limit)} */ List> zrangebyscoreWithScores(K key, double min, double max, long offset, long count); @@ -278,9 +338,22 @@ public interface RedisSortedSetCommands { * @param offset the offset * @param count the count * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range, Limit)} */ + @Deprecated List> zrangebyscoreWithScores(K key, String min, String max, long offset, long count); + /** + * Return a range of members with score in a sorted set, by score. + * + * @param key the key + * @param range the range + * @param limit the limit + * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @since 4.3 + */ + List> zrangebyscoreWithScores(K key, Range range, Limit limit); + /** * Return a range of members in a sorted set, by index. * @@ -311,7 +384,9 @@ public interface RedisSortedSetCommands { * @param min min score * @param max max score * @return Long count of elements in the specified score range. + * @deprecated Use {@link #zrangebyscore(ValueStreamingChannel, java.lang.Object, Range)} */ + @Deprecated Long zrangebyscore(ValueStreamingChannel channel, K key, double min, double max); /** @@ -322,9 +397,22 @@ public interface RedisSortedSetCommands { * @param min min score * @param max max score * @return Long count of elements in the specified score range. + * @deprecated Use {@link #zrangebyscore(ValueStreamingChannel, java.lang.Object, Range)} */ + @Deprecated Long zrangebyscore(ValueStreamingChannel channel, K key, String min, String max); + /** + * Stream over a range of members in a sorted set, by score. + * + * @param channel streaming channel that receives a call for every value + * @param key the key + * @param range the range + * @return Long count of elements in the specified score range. + * @since 4.3 + */ + Long zrangebyscore(ValueStreamingChannel channel, K key, Range range); + /** * Stream over range of members in a sorted set, by score. * @@ -335,7 +423,9 @@ public interface RedisSortedSetCommands { * @param offset the offset * @param count the count * @return Long count of elements in the specified score range. + * @deprecated Use {@link #zrangebyscore(ValueStreamingChannel, java.lang.Object, Range, Limit limit)} */ + @Deprecated Long zrangebyscore(ValueStreamingChannel channel, K key, double min, double max, long offset, long count); /** @@ -348,9 +438,23 @@ public interface RedisSortedSetCommands { * @param offset the offset * @param count the count * @return Long count of elements in the specified score range. + * @deprecated Use {@link #zrangebyscore(ValueStreamingChannel, java.lang.Object, Range, Limit limit)} */ + @Deprecated Long zrangebyscore(ValueStreamingChannel channel, K key, String min, String max, long offset, long count); + /** + * Stream over a range of members in a sorted set, by score. + * + * @param channel streaming channel that receives a call for every value + * @param key the key + * @param range the range + * @param limit the limit + * @return Long count of elements in the specified score range. + * @since 4.3 + */ + Long zrangebyscore(ValueStreamingChannel channel, K key, Range range, Limit limit); + /** * Stream over a range of members with scores in a sorted set, by score. * @@ -359,7 +463,9 @@ public interface RedisSortedSetCommands { * @param min min score * @param max max score * @return Long count of elements in the specified score range. + * @deprecated Use {@link #zrangebyscoreWithScores(ScoredValueStreamingChannel, java.lang.Object, Range)} */ + @Deprecated Long zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, double min, double max); /** @@ -370,9 +476,22 @@ public interface RedisSortedSetCommands { * @param min min score * @param max max score * @return Long count of elements in the specified score range. + * @deprecated Use {@link #zrangebyscoreWithScores(ScoredValueStreamingChannel, java.lang.Object, Range)} */ + @Deprecated Long zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, String min, String max); + /** + * Stream over a range of members with scores in a sorted set, by score. + * + * @param channel streaming channel that receives a call for every scored value + * @param key the key + * @param range the range + * @return Long count of elements in the specified score range. + * @since 4.3 + */ + Long zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, Range range); + /** * Stream over a range of members with scores in a sorted set, by score. * @@ -383,7 +502,9 @@ public interface RedisSortedSetCommands { * @param offset the offset * @param count the count * @return Long count of elements in the specified score range. + * @deprecated Use {@link #zrangebyscoreWithScores(ScoredValueStreamingChannel, java.lang.Object, Range, Limit limit)} */ + @Deprecated Long zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, double min, double max, long offset, long count); /** @@ -396,9 +517,23 @@ public interface RedisSortedSetCommands { * @param offset the offset * @param count the count * @return Long count of elements in the specified score range. + * @deprecated Use {@link #zrangebyscoreWithScores(ScoredValueStreamingChannel, java.lang.Object, Range, Limit limit)} */ + @Deprecated Long zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, String min, String max, long offset, long count); + /** + * Stream over a range of members with scores in a sorted set, by score. + * + * @param channel streaming channel that receives a call for every scored value + * @param key the key + * @param range the range + * @param limit the limit + * @return Long count of elements in the specified score range. + * @since 4.3 + */ + Long zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, Range range, Limit limit); + /** * Determine the index of a member in a sorted set. * @@ -437,7 +572,9 @@ public interface RedisSortedSetCommands { * @param min min score * @param max max score * @return Long integer-reply the number of elements removed. + * @deprecated Use {@link #zremrangebyscore(java.lang.Object, Range)} */ + @Deprecated Long zremrangebyscore(K key, double min, double max); /** @@ -447,9 +584,21 @@ public interface RedisSortedSetCommands { * @param min min score * @param max max score * @return Long integer-reply the number of elements removed. + * @deprecated Use {@link #zremrangebyscore(java.lang.Object, Range)} */ + @Deprecated Long zremrangebyscore(K key, String min, String max); + /** + * Remove all members in a sorted set within the given scores. + * + * @param key the key + * @param range the range + * @return Long integer-reply the number of elements removed. + * @since 4.3 + */ + Long zremrangebyscore(K key, Range range); + /** * Return a range of members in a sorted set, by index, with scores ordered from high to low. * @@ -477,7 +626,9 @@ public interface RedisSortedSetCommands { * @param min min score * @param max max score * @return List<V> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrevrangebyscore(java.lang.Object, Range)} */ + @Deprecated List zrevrangebyscore(K key, double max, double min); /** @@ -487,9 +638,21 @@ public interface RedisSortedSetCommands { * @param min min score * @param max max score * @return List<V> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrevrangebyscore(java.lang.Object, Range)} */ + @Deprecated List zrevrangebyscore(K key, String max, String min); + /** + * Return a range of members in a sorted set, by score, with scores ordered from high to low. + * + * @param key the key + * @param range the range + * @return List<V> array-reply list of elements in the specified score range. + * @since 4.3 + */ + List zrevrangebyscore(K key, Range range); + /** * Return a range of members in a sorted set, by score, with scores ordered from high to low. * @@ -499,7 +662,9 @@ public interface RedisSortedSetCommands { * @param offset the withscores * @param count the null * @return List<V> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrevrangebyscore(java.lang.Object, Range, Limit)} */ + @Deprecated List zrevrangebyscore(K key, double max, double min, long offset, long count); /** @@ -511,9 +676,22 @@ public interface RedisSortedSetCommands { * @param offset the offset * @param count the count * @return List<V> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrevrangebyscore(java.lang.Object, Range, Limit)} */ + @Deprecated List zrevrangebyscore(K key, String max, String min, long offset, long count); + /** + * Return a range of members in a sorted set, by score, with scores ordered from high to low. + * + * @param key the key + * @param range the range + * @param limit the limit + * @return List<V> array-reply list of elements in the specified score range. + * @since 4.3 + */ + List zrevrangebyscore(K key, Range range, Limit limit); + /** * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. * @@ -521,7 +699,9 @@ public interface RedisSortedSetCommands { * @param max max score * @param min min score * @return List<V> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range)} */ + @Deprecated List> zrevrangebyscoreWithScores(K key, double max, double min); /** @@ -531,9 +711,21 @@ public interface RedisSortedSetCommands { * @param max max score * @param min min score * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range)} */ + @Deprecated List> zrevrangebyscoreWithScores(K key, String max, String min); + /** + * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. + * + * @param key the key + * @param range the range + * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @since 4.3 + */ + List> zrevrangebyscoreWithScores(K key, Range range); + /** * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. * @@ -543,7 +735,9 @@ public interface RedisSortedSetCommands { * @param offset the offset * @param count the count * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range, Limit)} */ + @Deprecated List> zrevrangebyscoreWithScores(K key, double max, double min, long offset, long count); /** @@ -555,9 +749,22 @@ public interface RedisSortedSetCommands { * @param offset the offset * @param count the count * @return List<V> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range, Limit)} */ + @Deprecated List> zrevrangebyscoreWithScores(K key, String max, String min, long offset, long count); + /** + * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. + * + * @param key the key + * @param range the range + * @param limit limit + * @return List<V> array-reply list of elements in the specified score range. + * @since 4.3 + */ + List> zrevrangebyscoreWithScores(K key, Range range, Limit limit); + /** * Stream over a range of members in a sorted set, by index, with scores ordered from high to low. * @@ -588,7 +795,9 @@ public interface RedisSortedSetCommands { * @param max max score * @param min min score * @return Long count of elements in the specified range. + * @deprecated Use {@link #zrevrangebyscore(java.lang.Object, Range)} */ + @Deprecated Long zrevrangebyscore(ValueStreamingChannel channel, K key, double max, double min); /** @@ -599,9 +808,22 @@ public interface RedisSortedSetCommands { * @param min min score * @param max max score * @return Long count of elements in the specified range. + * @deprecated Use {@link #zrevrangebyscore(java.lang.Object, Range)} */ + @Deprecated Long zrevrangebyscore(ValueStreamingChannel channel, K key, String max, String min); + /** + * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. + * + * @param channel streaming channel that receives a call for every value + * @param key the key + * @param range the range + * @return Long count of elements in the specified range. + * @since 4.3 + */ + Long zrevrangebyscore(ValueStreamingChannel channel, K key, Range range); + /** * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. * @@ -612,7 +834,9 @@ public interface RedisSortedSetCommands { * @param offset the offset * @param count the count * @return Long count of elements in the specified range. + * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range, Limit)} */ + @Deprecated Long zrevrangebyscore(ValueStreamingChannel channel, K key, double max, double min, long offset, long count); /** @@ -625,9 +849,23 @@ public interface RedisSortedSetCommands { * @param offset the offset * @param count the count * @return Long count of elements in the specified range. + * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range, Limit)} */ + @Deprecated Long zrevrangebyscore(ValueStreamingChannel channel, K key, String max, String min, long offset, long count); + /** + * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. + * + * @param channel streaming channel that receives a call for every value + * @param key the key + * @param range the range + * @param limit the limit + * @return Long count of elements in the specified range. + * @since 4.3 + */ + Long zrevrangebyscore(ValueStreamingChannel channel, K key, Range range, Limit limit); + /** * Stream over a range of members with scores in a sorted set, by score, with scores ordered from high to low. * @@ -636,7 +874,9 @@ public interface RedisSortedSetCommands { * @param min min score * @param max max score * @return Long count of elements in the specified range. + * @deprecated Use {@link #zrevrangebyscoreWithScores(ScoredValueStreamingChannel, java.lang.Object, Range)} */ + @Deprecated Long zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, double max, double min); /** @@ -647,9 +887,21 @@ public interface RedisSortedSetCommands { * @param min min score * @param max max score * @return Long count of elements in the specified range. + * @deprecated Use {@link #zrevrangebyscoreWithScores(ScoredValueStreamingChannel, java.lang.Object, Range)} */ + @Deprecated Long zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, String max, String min); + /** + * Stream over a range of members with scores in a sorted set, by score, with scores ordered from high to low. + * + * @param channel streaming channel that receives a call for every scored value + * @param key the key + * @param range the range + * @return Long count of elements in the specified range. + */ + Long zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, Range range); + /** * Stream over a range of members with scores in a sorted set, by score, with scores ordered from high to low. * @@ -660,7 +912,9 @@ public interface RedisSortedSetCommands { * @param offset the offset * @param count the count * @return Long count of elements in the specified range. + * @deprecated Use {@link #zrevrangebyscoreWithScores(ScoredValueStreamingChannel, java.lang.Object, Range, Limit)} */ + @Deprecated Long zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, double max, double min, long offset, long count); @@ -674,10 +928,24 @@ Long zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, d * @param offset the offset * @param count the count * @return Long count of elements in the specified range. + * @deprecated Use {@link #zrevrangebyscoreWithScores(ScoredValueStreamingChannel, java.lang.Object, Range, Limit)} */ + @Deprecated Long zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, String max, String min, long offset, long count); + /** + * Stream over a range of members with scores in a sorted set, by score, with scores ordered from high to low. + * + * @param channel streaming channel that receives a call for every scored value + * @param key the key + * @param range the range + * @param limit the limit + * @return Long count of elements in the specified range. + * @since 4.3 + */ + Long zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, Range range, Limit limit); + /** * Determine the index of a member in a sorted set, with scores ordered from high to low. * @@ -800,9 +1068,21 @@ Long zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, S * @param min min score * @param max max score * @return Long integer-reply the number of elements in the specified score range. + * @deprecated Use {@link #zlexcount(java.lang.Object, Range)} */ + @Deprecated Long zlexcount(K key, String min, String max); + /** + * Count the number of members in a sorted set between a given lexicographical range. + * + * @param key the key + * @param range the range + * @return Long integer-reply the number of elements in the specified score range. + * @since 4.3 + */ + Long zlexcount(K key, Range range); + /** * Remove all members in a sorted set between the given lexicographical range. * @@ -810,9 +1090,21 @@ Long zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, S * @param min min score * @param max max score * @return Long integer-reply the number of elements removed. + * @deprecated Use {@link #zremrangebylex(java.lang.Object, Range)} */ + @Deprecated Long zremrangebylex(K key, String min, String max); + /** + * Remove all members in a sorted set between the given lexicographical range. + * + * @param key the key + * @param range the range + * @return Long integer-reply the number of elements removed. + * @since 4.3 + */ + Long zremrangebylex(K key, Range range); + /** * Return a range of members in a sorted set, by lexicographical range. * @@ -820,9 +1112,21 @@ Long zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, S * @param min min score * @param max max score * @return List<V> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebylex(java.lang.Object, Range)} */ + @Deprecated List zrangebylex(K key, String min, String max); + /** + * Return a range of members in a sorted set, by lexicographical range. + * + * @param key the key + * @param range the range + * @return List<V> array-reply list of elements in the specified score range. + * @since 4.3 + */ + List zrangebylex(K key, Range range); + /** * Return a range of members in a sorted set, by lexicographical range. * @@ -832,6 +1136,19 @@ Long zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, S * @param offset the offset * @param count the count * @return List<V> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebylex(java.lang.Object, Range)} */ + @Deprecated List zrangebylex(K key, String min, String max, long offset, long count); + + /** + * Return a range of members in a sorted set, by lexicographical range. + * + * @param key the key + * @param range the range + * @param limit the limit + * @return List<V> array-reply list of elements in the specified score range. + * @since 4.3 + */ + List zrangebylex(K key, Range range, Limit limit); } diff --git a/src/test/java/com/lambdaworks/apigenerator/CompilationUnitFactory.java b/src/test/java/com/lambdaworks/apigenerator/CompilationUnitFactory.java index efc4e934f0..fdb6225951 100644 --- a/src/test/java/com/lambdaworks/apigenerator/CompilationUnitFactory.java +++ b/src/test/java/com/lambdaworks/apigenerator/CompilationUnitFactory.java @@ -49,11 +49,9 @@ public class CompilationUnitFactory { ClassOrInterfaceDeclaration resultType; public CompilationUnitFactory(File templateFile, File sources, String targetPackage, String targetName, - Function typeDocFunction, - Function methodReturnTypeFunction, - Predicate methodFilter, Supplier> importSupplier, - Consumer typeMutator, - Function methodCommentMutator) { + Function typeDocFunction, Function methodReturnTypeFunction, + Predicate methodFilter, Supplier> importSupplier, + Consumer typeMutator, Function methodCommentMutator) { this.templateFile = templateFile; this.sources = sources; @@ -132,9 +130,9 @@ public void visit(MethodDeclaration n, Object arg) { MethodDeclaration method = new MethodDeclaration(n.getModifiers(), methodReturnTypeFunction.apply(n), n.getName()); - if(methodCommentMutator != null){ + if (methodCommentMutator != null) { method.setComment(methodCommentMutator.apply(n.getComment())); - }else { + } else { method.setComment(n.getComment()); } @@ -150,9 +148,11 @@ public void visit(MethodDeclaration n, Object arg) { method.getTypeParameters().addAll(n.getTypeParameters()); } - ASTHelper.addMember(resultType, method); + if (n.getAnnotations() != null) { + method.setAnnotations(n.getAnnotations()); + } + ASTHelper.addMember(resultType, method); } } - } diff --git a/src/test/java/com/lambdaworks/apigenerator/Constants.java b/src/test/java/com/lambdaworks/apigenerator/Constants.java index 3f60c1dceb..8d61b69e43 100644 --- a/src/test/java/com/lambdaworks/apigenerator/Constants.java +++ b/src/test/java/com/lambdaworks/apigenerator/Constants.java @@ -7,8 +7,7 @@ */ class Constants { - public final static String[] TEMPLATE_NAMES = { "RedisHashCommands", "RedisHLLCommands", "RedisKeyCommands", - "RedisListCommands", "RedisScriptingCommands", "RedisServerCommands", "RedisSetCommands", "RedisSortedSetCommands", + public final static String[] TEMPLATE_NAMES = { "RedisSortedSetCommands", "RedisStringCommands", "RedisTransactionalCommands", "RedisSentinelCommands", "BaseRedisCommands", "RedisGeoCommands" }; diff --git a/src/test/java/com/lambdaworks/redis/LimitTest.java b/src/test/java/com/lambdaworks/redis/LimitTest.java new file mode 100644 index 0000000000..a5e1595219 --- /dev/null +++ b/src/test/java/com/lambdaworks/redis/LimitTest.java @@ -0,0 +1,31 @@ +package com.lambdaworks.redis; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.Test; + +/** + * @author Mark Paluch + */ +public class LimitTest { + + @Test + public void create() { + + Limit limit = Limit.create(1, 2); + + assertThat(limit.getOffset()).isEqualTo(1); + assertThat(limit.getCount()).isEqualTo(2); + assertThat(limit.isLimited()).isTrue(); + } + + @Test + public void unlimited() { + + Limit limit = Limit.unlimited(); + + assertThat(limit.getOffset()).isEqualTo(-1); + assertThat(limit.getCount()).isEqualTo(-1); + assertThat(limit.isLimited()).isFalse(); + } +} diff --git a/src/test/java/com/lambdaworks/redis/RangeTest.java b/src/test/java/com/lambdaworks/redis/RangeTest.java new file mode 100644 index 0000000000..d250338145 --- /dev/null +++ b/src/test/java/com/lambdaworks/redis/RangeTest.java @@ -0,0 +1,92 @@ +package com.lambdaworks.redis; + +import static com.lambdaworks.redis.Range.Boundary.excluding; +import static com.lambdaworks.redis.Range.Boundary.including; +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.Test; + +/** + * @author Mark Paluch + */ +public class RangeTest { + + @Test + public void unbounded() { + + Range unbounded = Range.unbounded(); + + assertThat(unbounded.getLower().isIncluding()).isTrue(); + assertThat(unbounded.getLower().getValue()).isNull(); + assertThat(unbounded.getUpper().isIncluding()).isTrue(); + assertThat(unbounded.getUpper().getValue()).isNull(); + } + + @Test + public void createIncluded() { + + Range range = Range.create("ze", "ro"); + + assertThat(range.getLower().isIncluding()).isTrue(); + assertThat(range.getLower().getValue()).isEqualTo("ze"); + assertThat(range.getUpper().isIncluding()).isTrue(); + assertThat(range.getUpper().getValue()).isEqualTo("ro"); + } + + @Test + public void fromBoundaries() { + + Range range = Range.from(including("ze"), excluding("ro")); + + assertThat(range.getLower().isIncluding()).isTrue(); + assertThat(range.getLower().getValue()).isEqualTo("ze"); + assertThat(range.getUpper().isIncluding()).isFalse(); + assertThat(range.getUpper().getValue()).isEqualTo("ro"); + } + + @Test + public void greater() { + + Range gt = Range.unbounded().gt("zero"); + + assertThat(gt.getLower().isIncluding()).isFalse(); + assertThat(gt.getLower().getValue()).isEqualTo("zero"); + assertThat(gt.getUpper().isIncluding()).isTrue(); + assertThat(gt.getUpper().getValue()).isNull(); + } + + @Test + public void greaterOrEquals() { + + Range gte = Range.unbounded().gte("zero"); + + assertThat(gte.getLower().isIncluding()).isTrue(); + assertThat(gte.getLower().getValue()).isEqualTo("zero"); + assertThat(gte.getUpper().isIncluding()).isTrue(); + assertThat(gte.getUpper().getValue()).isNull(); + } + + @Test + public void less() { + + Range lt = Range.unbounded().lt("zero"); + + assertThat(lt.getLower().isIncluding()).isTrue(); + assertThat(lt.getLower().getValue()).isNull(); + assertThat(lt.getUpper().isIncluding()).isFalse(); + assertThat(lt.getUpper().getValue()).isEqualTo("zero"); + assertThat(lt.toString()).isEqualTo("Range [[unbounded] to (zero]"); + } + + @Test + public void lessOrEquals() { + + Range lte = Range.unbounded().lte("zero"); + + assertThat(lte.getLower().isIncluding()).isTrue(); + assertThat(lte.getLower().getValue()).isNull(); + assertThat(lte.getUpper().isIncluding()).isTrue(); + assertThat(lte.getUpper().getValue()).isEqualTo("zero"); + assertThat(lte.toString()).isEqualTo("Range [[unbounded] to [zero]"); + } +} diff --git a/src/test/java/com/lambdaworks/redis/commands/CustomCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/CustomCommandTest.java index e92e3c5a3c..da084f63a9 100644 --- a/src/test/java/com/lambdaworks/redis/commands/CustomCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/CustomCommandTest.java @@ -1,8 +1,12 @@ package com.lambdaworks.redis.commands; +import static com.lambdaworks.redis.protocol.CommandType.ZRANGEBYLEX; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assume.assumeTrue; +import java.nio.charset.StandardCharsets; +import java.util.List; + import org.junit.Test; import com.lambdaworks.redis.AbstractRedisClientTest; @@ -11,6 +15,7 @@ import com.lambdaworks.redis.api.StatefulRedisConnection; import com.lambdaworks.redis.codec.Utf8StringCodec; import com.lambdaworks.redis.output.StatusOutput; +import com.lambdaworks.redis.output.ValueListOutput; import com.lambdaworks.redis.protocol.*; /** diff --git a/src/test/java/com/lambdaworks/redis/commands/SortedSetCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/SortedSetCommandTest.java index a8b872e667..da4d4f6068 100644 --- a/src/test/java/com/lambdaworks/redis/commands/SortedSetCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/SortedSetCommandTest.java @@ -12,9 +12,9 @@ import static org.assertj.core.data.Offset.offset; import java.util.HashSet; -import java.util.List; import java.util.Set; +import com.lambdaworks.redis.Range.Boundary; import org.junit.Test; import com.lambdaworks.redis.*; @@ -112,6 +112,13 @@ public void zcount() throws Exception { assertThat(redis.zcount(key, "(1.0", "3.0")).isEqualTo(2); assertThat(redis.zcount(key, "-inf", "+inf")).isEqualTo(3); + + assertThat(redis.zcount(key, Range.create(1.0, 3.0))).isEqualTo(3); + assertThat(redis.zcount(key, Range.create(1.0, 2.0))).isEqualTo(2); + assertThat(redis.zcount(key, Range.create(NEGATIVE_INFINITY, POSITIVE_INFINITY))).isEqualTo(3); + + assertThat(redis.zcount(key, Range.from(Boundary.excluding(1.0), Boundary.including(3.0)))).isEqualTo(2); + assertThat(redis.zcount(key, Range.unbounded())).isEqualTo(3); } @Test @@ -142,7 +149,7 @@ public void zrange() throws Exception { public void zrangeStreaming() throws Exception { setup(); - ListStreamingAdapter streamingAdapter = new ListStreamingAdapter(); + ListStreamingAdapter streamingAdapter = new ListStreamingAdapter<>(); Long count = redis.zrange(streamingAdapter, key, 0, -1); assertThat(count.longValue()).isEqualTo(3); @@ -164,7 +171,7 @@ public void zrangeWithScores() throws Exception { @SuppressWarnings({ "unchecked" }) public void zrangeWithScoresStreaming() throws Exception { setup(); - ScoredValueStreamingAdapter streamingAdapter = new ScoredValueStreamingAdapter(); + ScoredValueStreamingAdapter streamingAdapter = new ScoredValueStreamingAdapter<>(); Long count = redis.zrangeWithScores(streamingAdapter, key, 0, -1); assertThat(count.longValue()).isEqualTo(3); assertThat(streamingAdapter.getList()).isEqualTo(svlist(sv(1.0, "a"), sv(2.0, "b"), sv(3.0, "c"))); @@ -172,19 +179,27 @@ public void zrangeWithScoresStreaming() throws Exception { @Test public void zrangebyscore() throws Exception { + redis.zadd(key, 1.0, "a", 2.0, "b", 3.0, "c", 4.0, "d"); + assertThat(redis.zrangebyscore(key, 2.0, 3.0)).isEqualTo(list("b", "c")); assertThat(redis.zrangebyscore(key, "(1.0", "(4.0")).isEqualTo(list("b", "c")); assertThat(redis.zrangebyscore(key, NEGATIVE_INFINITY, POSITIVE_INFINITY)).isEqualTo(list("a", "b", "c", "d")); assertThat(redis.zrangebyscore(key, "-inf", "+inf")).isEqualTo(list("a", "b", "c", "d")); assertThat(redis.zrangebyscore(key, 0.0, 4.0, 1, 3)).isEqualTo(list("b", "c", "d")); assertThat(redis.zrangebyscore(key, "-inf", "+inf", 2, 2)).isEqualTo(list("c", "d")); + + assertThat(redis.zrangebyscore(key, Range.create(2.0, 3.0))).isEqualTo(list("b", "c")); + assertThat(redis.zrangebyscore(key, Range.from(Boundary.excluding(1.0), Boundary.excluding(4.0)))).isEqualTo(list("b", "c")); + assertThat(redis.zrangebyscore(key, Range.unbounded())).isEqualTo(list("a", "b", "c", "d")); + assertThat(redis.zrangebyscore(key, Range.create(0.0, 4.0), Limit.create(1, 3))).isEqualTo(list("b", "c", "d")); + assertThat(redis.zrangebyscore(key, Range.unbounded(), Limit.create(2, 2))).isEqualTo(list("c", "d")); } @Test public void zrangebyscoreStreaming() throws Exception { redis.zadd(key, 1.0, "a", 2.0, "b", 3.0, "c", 4.0, "d"); - ListStreamingAdapter streamingAdapter = new ListStreamingAdapter(); + ListStreamingAdapter streamingAdapter = new ListStreamingAdapter<>(); assertThat(redis.zrangebyscore(streamingAdapter, key, 2.0, 3.0)).isEqualTo(2); assertThat(redis.zrangebyscore(streamingAdapter, key, "(1.0", "(4.0")).isEqualTo(2); @@ -194,12 +209,19 @@ public void zrangebyscoreStreaming() throws Exception { assertThat(redis.zrangebyscore(streamingAdapter, key, 0.0, 4.0, 1, 3)).isEqualTo(3); assertThat(redis.zrangebyscore(streamingAdapter, key, "-inf", "+inf", 2, 2)).isEqualTo(2); + assertThat(redis.zrangebyscore(streamingAdapter, key, Range.create(2.0, 3.0))).isEqualTo(2); + assertThat(redis.zrangebyscore(streamingAdapter, key, Range.from(Boundary.excluding(1.0), Boundary.excluding(4.0)))).isEqualTo(2); + assertThat(redis.zrangebyscore(streamingAdapter, key, Range.unbounded())).isEqualTo(4); + assertThat(redis.zrangebyscore(streamingAdapter, key, Range.create(0.0, 4.0), Limit.create(1, 3))).isEqualTo(3); + assertThat(redis.zrangebyscore(streamingAdapter, key, Range.unbounded(), Limit.create(2, 2))).isEqualTo(2); } @Test @SuppressWarnings({ "unchecked" }) public void zrangebyscoreWithScores() throws Exception { + redis.zadd(key, 1.0, "a", 2.0, "b", 3.0, "c", 4.0, "d"); + assertThat(redis.zrangebyscoreWithScores(key, 2.0, 3.0)).isEqualTo(svlist(sv(2.0, "b"), sv(3.0, "c"))); assertThat(redis.zrangebyscoreWithScores(key, "(1.0", "(4.0")).isEqualTo(svlist(sv(2.0, "b"), sv(3.0, "c"))); assertThat(redis.zrangebyscoreWithScores(key, NEGATIVE_INFINITY, POSITIVE_INFINITY)).isEqualTo( @@ -209,12 +231,20 @@ public void zrangebyscoreWithScores() throws Exception { assertThat(redis.zrangebyscoreWithScores(key, 0.0, 4.0, 1, 3)).isEqualTo( svlist(sv(2.0, "b"), sv(3.0, "c"), sv(4.0, "d"))); assertThat(redis.zrangebyscoreWithScores(key, "-inf", "+inf", 2, 2)).isEqualTo(svlist(sv(3.0, "c"), sv(4.0, "d"))); + + assertThat(redis.zrangebyscoreWithScores(key, Range.create(2.0, 3.0))).isEqualTo(svlist(sv(2.0, "b"), sv(3.0, "c"))); + assertThat(redis.zrangebyscoreWithScores(key, Range.from(Boundary.excluding(1.0), Boundary.excluding(4.0)))).isEqualTo(svlist(sv(2.0, "b"), sv(3.0, "c"))); + assertThat(redis.zrangebyscoreWithScores(key, Range.unbounded())).isEqualTo( + svlist(sv(1.0, "a"), sv(2.0, "b"), sv(3.0, "c"), sv(4.0, "d"))); + assertThat(redis.zrangebyscoreWithScores(key, Range.create(0.0, 4.0), Limit.create(1, 3))).isEqualTo( + svlist(sv(2.0, "b"), sv(3.0, "c"), sv(4.0, "d"))); + assertThat(redis.zrangebyscoreWithScores(key, Range.unbounded(), Limit.create(2, 2))).isEqualTo(svlist(sv(3.0, "c"), sv(4.0, "d"))); } @Test public void zrangebyscoreWithScoresStreaming() throws Exception { redis.zadd(key, 1.0, "a", 2.0, "b", 3.0, "c", 4.0, "d"); - ListStreamingAdapter streamingAdapter = new ListStreamingAdapter(); + ListStreamingAdapter streamingAdapter = new ListStreamingAdapter<>(); assertThat(redis.zrangebyscoreWithScores(streamingAdapter, key, 2.0, 3.0).longValue()).isEqualTo(2); assertThat(redis.zrangebyscoreWithScores(streamingAdapter, key, "(1.0", "(4.0").longValue()).isEqualTo(2); @@ -225,6 +255,12 @@ public void zrangebyscoreWithScoresStreaming() throws Exception { assertThat(redis.zrangebyscoreWithScores(streamingAdapter, key, 0.0, 4.0, 1, 3).longValue()).isEqualTo(3); assertThat(redis.zrangebyscoreWithScores(streamingAdapter, key, "-inf", "+inf", 2, 2).longValue()).isEqualTo(2); + assertThat(redis.zrangebyscoreWithScores(streamingAdapter,key, Range.create(2.0, 3.0))).isEqualTo(2); + assertThat(redis.zrangebyscoreWithScores(streamingAdapter,key, Range.from(Boundary.excluding(1.0), Boundary.excluding(4.0)))).isEqualTo(2); + assertThat(redis.zrangebyscoreWithScores(streamingAdapter,key, Range.unbounded())).isEqualTo(4); + assertThat(redis.zrangebyscoreWithScores(streamingAdapter,key, Range.create(0.0, 4.0), Limit.create(1, 3))).isEqualTo(3); + assertThat(redis.zrangebyscoreWithScores(streamingAdapter,key, Range.unbounded(), Limit.create(2, 2))).isEqualTo(2); + } @Test @@ -247,13 +283,22 @@ public void zrem() throws Exception { @Test public void zremrangebyscore() throws Exception { + setup(); assertThat(redis.zremrangebyscore(key, 1.0, 2.0)).isEqualTo(2); assertThat(redis.zrange(key, 0, -1)).isEqualTo(list("c")); + setup(); + assertThat(redis.zremrangebyscore(key, Range.create(1.0, 2.0))).isEqualTo(2); + assertThat(redis.zrange(key, 0, -1)).isEqualTo(list("c")); + setup(); assertThat(redis.zremrangebyscore(key, "(1.0", "(3.0")).isEqualTo(1); assertThat(redis.zrange(key, 0, -1)).isEqualTo(list("a", "c")); + + setup(); + assertThat(redis.zremrangebyscore(key, Range.from(Boundary.excluding(1.0), Boundary.excluding(3.0)))).isEqualTo(1); + assertThat(redis.zrange(key, 0, -1)).isEqualTo(list("a", "c")); } @Test @@ -283,7 +328,7 @@ public void zrevrangeWithScores() throws Exception { @Test public void zrevrangeStreaming() throws Exception { setup(); - ListStreamingAdapter streamingAdapter = new ListStreamingAdapter(); + ListStreamingAdapter streamingAdapter = new ListStreamingAdapter<>(); Long count = redis.zrevrange(streamingAdapter, key, 0, -1); assertThat(count).isEqualTo(3); assertThat(streamingAdapter.getList()).isEqualTo(list("c", "b", "a")); @@ -293,7 +338,7 @@ public void zrevrangeStreaming() throws Exception { @SuppressWarnings({ "unchecked" }) public void zrevrangeWithScoresStreaming() throws Exception { setup(); - ScoredValueStreamingAdapter streamingAdapter = new ScoredValueStreamingAdapter(); + ScoredValueStreamingAdapter streamingAdapter = new ScoredValueStreamingAdapter<>(); Long count = redis.zrevrangeWithScores(streamingAdapter, key, 0, -1); assertThat(count).isEqualTo(3); assertThat(streamingAdapter.getList()).isEqualTo(svlist(sv(3.0, "c"), sv(2.0, "b"), sv(1.0, "a"))); @@ -301,19 +346,28 @@ public void zrevrangeWithScoresStreaming() throws Exception { @Test public void zrevrangebyscore() throws Exception { + redis.zadd(key, 1.0, "a", 2.0, "b", 3.0, "c", 4.0, "d"); + assertThat(redis.zrevrangebyscore(key, 3.0, 2.0)).isEqualTo(list("c", "b")); assertThat(redis.zrevrangebyscore(key, "(4.0", "(1.0")).isEqualTo(list("c", "b")); assertThat(redis.zrevrangebyscore(key, POSITIVE_INFINITY, NEGATIVE_INFINITY)).isEqualTo(list("d", "c", "b", "a")); assertThat(redis.zrevrangebyscore(key, "+inf", "-inf")).isEqualTo(list("d", "c", "b", "a")); assertThat(redis.zrevrangebyscore(key, 4.0, 0.0, 1, 3)).isEqualTo(list("c", "b", "a")); assertThat(redis.zrevrangebyscore(key, "+inf", "-inf", 2, 2)).isEqualTo(list("b", "a")); + + assertThat(redis.zrevrangebyscore(key, Range.create(2.0, 3.0))).isEqualTo(list("c", "b")); + assertThat(redis.zrevrangebyscore(key, Range.from(Boundary.excluding(1.0), Boundary.excluding(4.0)))).isEqualTo(list("c", "b")); + assertThat(redis.zrevrangebyscore(key, Range.unbounded())).isEqualTo(list("d", "c", "b", "a")); + assertThat(redis.zrevrangebyscore(key, Range.create(0.0, 4.0), Limit.create(1, 3))).isEqualTo(list("c", "b", "a")); + assertThat(redis.zrevrangebyscore(key, Range.unbounded(), Limit.create(2, 2))).isEqualTo(list("b", "a")); } @Test @SuppressWarnings({ "unchecked" }) public void zrevrangebyscoreWithScores() throws Exception { redis.zadd(key, 1.0, "a", 2.0, "b", 3.0, "c", 4.0, "d"); + assertThat(redis.zrevrangebyscoreWithScores(key, 3.0, 2.0)).isEqualTo(svlist(sv(3.0, "c"), sv(2.0, "b"))); assertThat(redis.zrevrangebyscoreWithScores(key, "(4.0", "(1.0")).isEqualTo(svlist(sv(3.0, "c"), sv(2.0, "b"))); assertThat(redis.zrevrangebyscoreWithScores(key, POSITIVE_INFINITY, NEGATIVE_INFINITY)).isEqualTo( @@ -323,12 +377,20 @@ public void zrevrangebyscoreWithScores() throws Exception { assertThat(redis.zrevrangebyscoreWithScores(key, 4.0, 0.0, 1, 3)).isEqualTo( svlist(sv(3.0, "c"), sv(2.0, "b"), sv(1.0, "a"))); assertThat(redis.zrevrangebyscoreWithScores(key, "+inf", "-inf", 2, 2)).isEqualTo(svlist(sv(2.0, "b"), sv(1.0, "a"))); + + assertThat(redis.zrevrangebyscoreWithScores(key, Range.create(2.0, 3.0))).isEqualTo(svlist(sv(3.0, "c"), sv(2.0, "b"))); + assertThat(redis.zrevrangebyscoreWithScores(key, Range.from(Boundary.excluding(1.0), Boundary.excluding(4.0)))).isEqualTo(svlist(sv(3.0, "c"), sv(2.0, "b"))); + assertThat(redis.zrevrangebyscoreWithScores(key, Range.unbounded())).isEqualTo( + svlist(sv(4.0, "d"), sv(3.0, "c"), sv(2.0, "b"), sv(1.0, "a"))); + assertThat(redis.zrevrangebyscoreWithScores(key, Range.create(0.0, 4.0), Limit.create(1, 3))).isEqualTo( + svlist(sv(3.0, "c"), sv(2.0, "b"), sv(1.0, "a"))); + assertThat(redis.zrevrangebyscoreWithScores(key, Range.unbounded(), Limit.create(2, 2))).isEqualTo(svlist(sv(2.0, "b"), sv(1.0, "a"))); } @Test public void zrevrangebyscoreStreaming() throws Exception { redis.zadd(key, 1.0, "a", 2.0, "b", 3.0, "c", 4.0, "d"); - ListStreamingAdapter streamingAdapter = new ListStreamingAdapter(); + ListStreamingAdapter streamingAdapter = new ListStreamingAdapter<>(); assertThat(redis.zrevrangebyscore(streamingAdapter, key, 3.0, 2.0).longValue()).isEqualTo(2); assertThat(redis.zrevrangebyscore(streamingAdapter, key, "(4.0", "(1.0").longValue()).isEqualTo(2); @@ -337,6 +399,12 @@ public void zrevrangebyscoreStreaming() throws Exception { assertThat(redis.zrevrangebyscore(streamingAdapter, key, "+inf", "-inf").longValue()).isEqualTo(4); assertThat(redis.zrevrangebyscore(streamingAdapter, key, 4.0, 0.0, 1, 3).longValue()).isEqualTo(3); assertThat(redis.zrevrangebyscore(streamingAdapter, key, "+inf", "-inf", 2, 2).longValue()).isEqualTo(2); + + assertThat(redis.zrevrangebyscore(streamingAdapter, key, Range.create(2.0, 3.0)).longValue()).isEqualTo(2); + assertThat(redis.zrevrangebyscore(streamingAdapter, key, Range.from(Boundary.excluding(1.0), Boundary.excluding(4.0))).longValue()).isEqualTo(2); + assertThat(redis.zrevrangebyscore(streamingAdapter, key, Range.unbounded()).longValue()).isEqualTo(4); + assertThat(redis.zrevrangebyscore(streamingAdapter, key, Range.create(0.0, 4.0), Limit.create(1, 3)).longValue()).isEqualTo(3); + assertThat(redis.zrevrangebyscore(streamingAdapter, key, Range.unbounded(), Limit.create(2, 2)).longValue()).isEqualTo(2); } @Test @@ -344,7 +412,7 @@ public void zrevrangebyscoreStreaming() throws Exception { public void zrevrangebyscoreWithScoresStreaming() throws Exception { redis.zadd(key, 1.0, "a", 2.0, "b", 3.0, "c", 4.0, "d"); - ScoredValueStreamingAdapter streamingAdapter = new ScoredValueStreamingAdapter(); + ScoredValueStreamingAdapter streamingAdapter = new ScoredValueStreamingAdapter<>(); assertThat(redis.zrevrangebyscoreWithScores(streamingAdapter, key, 3.0, 2.0)).isEqualTo(2); assertThat(redis.zrevrangebyscoreWithScores(streamingAdapter, key, "(4.0", "(1.0")).isEqualTo(2); @@ -352,6 +420,12 @@ public void zrevrangebyscoreWithScoresStreaming() throws Exception { assertThat(redis.zrevrangebyscoreWithScores(streamingAdapter, key, "+inf", "-inf")).isEqualTo(4); assertThat(redis.zrevrangebyscoreWithScores(streamingAdapter, key, 4.0, 0.0, 1, 3)).isEqualTo(3); assertThat(redis.zrevrangebyscoreWithScores(streamingAdapter, key, "+inf", "-inf", 2, 2)).isEqualTo(2); + + assertThat(redis.zrevrangebyscoreWithScores(streamingAdapter, key, Range.create(2.0, 3.0)).longValue()).isEqualTo(2); + assertThat(redis.zrevrangebyscoreWithScores(streamingAdapter, key, Range.from(Boundary.excluding(1.0), Boundary.excluding(4.0))).longValue()).isEqualTo(2); + assertThat(redis.zrevrangebyscoreWithScores(streamingAdapter, key, Range.unbounded()).longValue()).isEqualTo(4); + assertThat(redis.zrevrangebyscoreWithScores(streamingAdapter, key, Range.create(0.0, 4.0), Limit.create(1, 3)).longValue()).isEqualTo(3); + assertThat(redis.zrevrangebyscoreWithScores(streamingAdapter, key, Range.unbounded(), Limit.create(2, 2)).longValue()).isEqualTo(2); } @Test @@ -454,7 +528,7 @@ public void zsscanWithCursorAndArgs() throws Exception { @Test public void zscanStreaming() throws Exception { redis.zadd(key, 1, value); - ListStreamingAdapter adapter = new ListStreamingAdapter(); + ListStreamingAdapter adapter = new ListStreamingAdapter<>(); StreamScanCursor cursor = redis.zscan(adapter, key); @@ -467,7 +541,7 @@ public void zscanStreaming() throws Exception { @Test public void zscanStreamingWithCursor() throws Exception { redis.zadd(key, 1, value); - ListStreamingAdapter adapter = new ListStreamingAdapter(); + ListStreamingAdapter adapter = new ListStreamingAdapter<>(); StreamScanCursor cursor = redis.zscan(adapter, key, ScanCursor.INITIAL); @@ -479,7 +553,7 @@ public void zscanStreamingWithCursor() throws Exception { @Test public void zscanStreamingWithCursorAndArgs() throws Exception { redis.zadd(key, 1, value); - ListStreamingAdapter adapter = new ListStreamingAdapter(); + ListStreamingAdapter adapter = new ListStreamingAdapter<>(); StreamScanCursor cursor = redis.zscan(adapter, key, ScanCursor.INITIAL, ScanArgs.Builder.matches("*").limit(100)); @@ -491,7 +565,7 @@ public void zscanStreamingWithCursorAndArgs() throws Exception { @Test public void zscanStreamingWithArgs() throws Exception { redis.zadd(key, 1, value); - ListStreamingAdapter adapter = new ListStreamingAdapter(); + ListStreamingAdapter adapter = new ListStreamingAdapter<>(); StreamScanCursor cursor = redis.zscan(adapter, key, ScanArgs.Builder.limit(100).match("*")); @@ -533,33 +607,39 @@ public void zscanMatch() throws Exception { @Test public void zlexcount() throws Exception { + setup100KeyValues(new HashSet<>()); - Long result = redis.zlexcount(key, "-", "+"); - assertThat(result.longValue()).isEqualTo(100); + assertThat(redis.zlexcount(key, "-", "+")).isEqualTo(100); + assertThat(redis.zlexcount(key, "[value", "[zzz")).isEqualTo(100); - Long resultFromTo = redis.zlexcount(key, "[value", "[zzz"); - assertThat(resultFromTo.longValue()).isEqualTo(100); + assertThat(redis.zlexcount(key, Range.unbounded())).isEqualTo(100); + assertThat(redis.zlexcount(key, Range.create("value", "zzz"))).isEqualTo(100); + assertThat(redis.zlexcount(key, Range.from(Boundary.including("value99"), Boundary.unbounded()))).isEqualTo(1); + assertThat(redis.zlexcount(key, Range.from(Boundary.excluding("value99"), Boundary.unbounded()))).isEqualTo(0); } @Test public void zrangebylex() throws Exception { setup100KeyValues(new HashSet<>()); - List result = redis.zrangebylex(key, "-", "+"); - assertThat(result).hasSize(100); + assertThat(redis.zrangebylex(key, "-", "+")).hasSize(100); + assertThat(redis.zrangebylex(key, "-", "+", 10, 10)).hasSize(10); - List result2 = redis.zrangebylex(key, "-", "+", 10, 10); - - assertThat(result2).hasSize(10); + assertThat(redis.zrangebylex(key, Range.unbounded())).hasSize(100); + assertThat(redis.zrangebylex(key, Range.create("value", "zzz"))).hasSize(100); + assertThat(redis.zrangebylex(key, Range.from(Boundary.including("value99"), Boundary.unbounded()))).hasSize(1); + assertThat(redis.zrangebylex(key, Range.from(Boundary.excluding("value99"), Boundary.unbounded()))).hasSize(0); } @Test public void zremrangebylex() throws Exception { + setup100KeyValues(new HashSet<>()); - Long result = redis.zremrangebylex(key, "(aaa", "[zzz"); + assertThat(redis.zremrangebylex(key, "(aaa", "[zzz")).isEqualTo(100); - assertThat(result.longValue()).isEqualTo(100); + setup100KeyValues(new HashSet<>()); + assertThat(redis.zremrangebylex(key, Range.create("value", "zzz"))).isEqualTo(100); } @@ -569,6 +649,5 @@ protected void setup100KeyValues(Set expect) { redis.zadd(key, i, value + i); expect.add(value + i); } - } } From 8420915a87edfa7674cc39a1497a3a7d1d3f524f Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Thu, 22 Sep 2016 21:34:59 +0200 Subject: [PATCH 030/808] Use Limit in SortArgs #364 --- .../java/com/lambdaworks/redis/SortArgs.java | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/lambdaworks/redis/SortArgs.java b/src/main/java/com/lambdaworks/redis/SortArgs.java index 87b6a08942..1545c51268 100644 --- a/src/main/java/com/lambdaworks/redis/SortArgs.java +++ b/src/main/java/com/lambdaworks/redis/SortArgs.java @@ -8,6 +8,7 @@ import java.util.ArrayList; import java.util.List; +import com.lambdaworks.redis.internal.LettuceAssert; import com.lambdaworks.redis.protocol.CommandArgs; import com.lambdaworks.redis.protocol.CommandKeyword; @@ -20,7 +21,7 @@ public class SortArgs { private String by; - private Long offset, count; + private Limit limit = Limit.unlimited(); private List get; private CommandKeyword order; private boolean alpha; @@ -67,8 +68,14 @@ public SortArgs by(String pattern) { } public SortArgs limit(long offset, long count) { - this.offset = offset; - this.count = count; + return limit(Limit.create(offset, count)); + } + + public SortArgs limit(Limit limit) { + + LettuceAssert.notNull(limit, "Limit must not be null"); + + this.limit = limit; return this; } @@ -109,10 +116,10 @@ void build(CommandArgs args, K store) { } } - if (offset != null) { + if (limit != null && limit.isLimited()) { args.add(LIMIT); - args.add(offset); - args.add(count); + args.add(limit.getOffset()); + args.add(limit.getCount()); } if (order != null) { From 7676035300bffe25c84938952e85be1e6dbce47a Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Thu, 22 Sep 2016 22:30:13 +0200 Subject: [PATCH 031/808] Fix RedisClusterSetupTest. Prevent usage of orphaned node when splitting the cluster. --- .../redis/cluster/RedisClusterSetupTest.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/test/java/com/lambdaworks/redis/cluster/RedisClusterSetupTest.java b/src/test/java/com/lambdaworks/redis/cluster/RedisClusterSetupTest.java index f9866abfe1..92fd365343 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/RedisClusterSetupTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/RedisClusterSetupTest.java @@ -13,18 +13,18 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; -import com.lambdaworks.TestClientResources; -import com.lambdaworks.redis.api.sync.RedisCommands; import org.junit.*; import com.google.code.tempusfugit.temporal.Condition; import com.google.code.tempusfugit.temporal.WaitFor; import com.lambdaworks.ConnectionTestUtil; import com.lambdaworks.Futures; +import com.lambdaworks.TestClientResources; import com.lambdaworks.Wait; import com.lambdaworks.category.SlowTests; import com.lambdaworks.redis.*; import com.lambdaworks.redis.api.async.RedisAsyncCommands; +import com.lambdaworks.redis.api.sync.RedisCommands; import com.lambdaworks.redis.cluster.api.StatefulRedisClusterConnection; import com.lambdaworks.redis.cluster.api.async.RedisAdvancedClusterAsyncCommands; import com.lambdaworks.redis.cluster.api.async.RedisClusterAsyncCommands; @@ -47,7 +47,7 @@ public class RedisClusterSetupTest extends AbstractTest { private static final String host = TestSettings.hostAddr(); private static final ClusterTopologyRefreshOptions PERIODIC_REFRESH_ENABLED = ClusterTopologyRefreshOptions.builder() - .enablePeriodicRefresh(1, TimeUnit.SECONDS).build(); + .enablePeriodicRefresh(1, TimeUnit.SECONDS).dynamicRefreshSources(false).build(); private static RedisClusterClient clusterClient; private static RedisClient client = DefaultRedisClient.get(); @@ -60,8 +60,8 @@ public class RedisClusterSetupTest extends AbstractTest { @BeforeClass public static void setupClient() { - clusterClient = RedisClusterClient.create( - TestClientResources.get(), RedisURI.Builder.redis(host, AbstractClusterTest.port5).build()); + clusterClient = RedisClusterClient.create(TestClientResources.get(), + RedisURI.Builder.redis(host, AbstractClusterTest.port5).build()); } @AfterClass From 61fa45be1266c562f2d8ad8f7c5f5e9c837b0922 Mon Sep 17 00:00:00 2001 From: Aaron Miller Date: Thu, 22 Sep 2016 10:50:44 -0400 Subject: [PATCH 032/808] Add EVAL and EVALSHA to ReadOnlyCommands #366 --- .../java/com/lambdaworks/redis/cluster/ReadOnlyCommands.java | 2 +- .../com/lambdaworks/redis/masterslave/ReadOnlyCommands.java | 2 +- .../com/lambdaworks/redis/cluster/ReadOnlyCommandsTest.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/lambdaworks/redis/cluster/ReadOnlyCommands.java b/src/main/java/com/lambdaworks/redis/cluster/ReadOnlyCommands.java index 95088c4c89..b11515a47a 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/ReadOnlyCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/ReadOnlyCommands.java @@ -27,7 +27,7 @@ class ReadOnlyCommands { } enum CommandName { - ASKING, BITCOUNT, BITPOS, CLIENT, COMMAND, DUMP, ECHO, EXISTS, // + ASKING, BITCOUNT, BITPOS, CLIENT, COMMAND, DUMP, ECHO, EVAL, EVALSHA, EXISTS, // GEODIST, GEOPOS, GEORADIUS, GEORADIUSBYMEMBER, GEOHASH, GET, GETBIT, // GETRANGE, HEXISTS, HGET, HGETALL, HKEYS, HLEN, HMGET, HSCAN, HSTRLEN, // HVALS, INFO, KEYS, LINDEX, LLEN, LRANGE, MGET, MULTI, PFCOUNT, PTTL, // diff --git a/src/main/java/com/lambdaworks/redis/masterslave/ReadOnlyCommands.java b/src/main/java/com/lambdaworks/redis/masterslave/ReadOnlyCommands.java index ee67adb9ad..791660ea90 100644 --- a/src/main/java/com/lambdaworks/redis/masterslave/ReadOnlyCommands.java +++ b/src/main/java/com/lambdaworks/redis/masterslave/ReadOnlyCommands.java @@ -27,7 +27,7 @@ class ReadOnlyCommands { } enum CommandName { - ASKING, BITCOUNT, BITPOS, CLIENT, COMMAND, DUMP, ECHO, EXISTS, + ASKING, BITCOUNT, BITPOS, CLIENT, COMMAND, DUMP, ECHO, EVAL, EVALSHA, EXISTS, /**/GEODIST, GEOPOS, GEORADIUS, GEORADIUSBYMEMBER, GEOHASH, GET, GETBIT, /**/GETRANGE, HEXISTS, HGET, HGETALL, HKEYS, HLEN, HMGET, HSCAN, HSTRLEN, /**/HVALS, INFO, KEYS, LINDEX, LLEN, LRANGE, MGET, MULTI, PFCOUNT, PTTL, diff --git a/src/test/java/com/lambdaworks/redis/cluster/ReadOnlyCommandsTest.java b/src/test/java/com/lambdaworks/redis/cluster/ReadOnlyCommandsTest.java index 447074e19d..bd9f16c5db 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/ReadOnlyCommandsTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/ReadOnlyCommandsTest.java @@ -13,7 +13,7 @@ public class ReadOnlyCommandsTest { @Test public void testCount() throws Exception { - assertThat(ReadOnlyCommands.READ_ONLY_COMMANDS).hasSize(69); + assertThat(ReadOnlyCommands.READ_ONLY_COMMANDS).hasSize(71); } @Test From 63947c9d7559cd7de3ffb04b535b8e2f31362544 Mon Sep 17 00:00:00 2001 From: Jongyeol Choi Date: Fri, 23 Sep 2016 12:46:23 +0900 Subject: [PATCH 033/808] Add jitter backoff strategies for spreading reconnection timing #365 When users use exponential backoff streategy and connection pool with more than thousands of application servers, sometimes connection bursting hits Redis servers. This issue is because of same timings when Redis is slow/drops connections or due to network partitions. This change will addresses the problem using well known jitter backoff strategies. Equal Jitter sleep = random_between(0, min(cap, base * 2 ** attempt)) Full Jitter temp = min(cap, base * 2 ** attempt) sleep = temp / 2 + random_between(0, temp / 2) Decorrelated Jitter sleep = min(cap, random_between(base, sleep * 3)) Rerenrence: https://www.awsarchitectureblog.com/2015/03/backoff.html --- .../redis/protocol/ConnectionWatchdog.java | 9 ++ .../resource/DecorrelatedJitterDelay.java | 44 ++++++ .../resource/DefaultClientResources.java | 26 +++- .../com/lambdaworks/redis/resource/Delay.java | 126 +++++++++++++++++- .../redis/resource/EqualJitterDelay.java | 29 ++++ .../redis/resource/ExponentialDelay.java | 33 ++--- .../redis/resource/FullJitterDelay.java | 31 +++++ .../resource/DecorrelatedJitterDelayTest.java | 59 ++++++++ .../redis/resource/EqualJitterDelayTest.java | 63 +++++++++ .../redis/resource/FullJitterDelayTest.java | 63 +++++++++ 10 files changed, 452 insertions(+), 31 deletions(-) create mode 100644 src/main/java/com/lambdaworks/redis/resource/DecorrelatedJitterDelay.java create mode 100644 src/main/java/com/lambdaworks/redis/resource/EqualJitterDelay.java create mode 100644 src/main/java/com/lambdaworks/redis/resource/FullJitterDelay.java create mode 100644 src/test/java/com/lambdaworks/redis/resource/DecorrelatedJitterDelayTest.java create mode 100644 src/test/java/com/lambdaworks/redis/resource/EqualJitterDelayTest.java create mode 100644 src/test/java/com/lambdaworks/redis/resource/FullJitterDelayTest.java diff --git a/src/main/java/com/lambdaworks/redis/protocol/ConnectionWatchdog.java b/src/main/java/com/lambdaworks/redis/protocol/ConnectionWatchdog.java index 59d96e0497..b9112254c0 100644 --- a/src/main/java/com/lambdaworks/redis/protocol/ConnectionWatchdog.java +++ b/src/main/java/com/lambdaworks/redis/protocol/ConnectionWatchdog.java @@ -10,6 +10,7 @@ import com.lambdaworks.redis.ConnectionEvents; import com.lambdaworks.redis.internal.LettuceAssert; import com.lambdaworks.redis.resource.Delay; +import com.lambdaworks.redis.resource.Delay.StatefulDelay; import io.netty.bootstrap.Bootstrap; import io.netty.channel.*; @@ -77,6 +78,7 @@ public ConnectionWatchdog(Delay reconnectDelay, ClientOptions clientOptions, Boo LettuceAssert.notNull(connectionFacade, "ConnectionFacade must not be null"); this.reconnectDelay = reconnectDelay; + resetReconnectDelay(); this.bootstrap = bootstrap; this.timer = timer; this.reconnectWorkers = reconnectWorkers; @@ -103,6 +105,12 @@ public SocketAddress get() { connectionFacade); } + private void resetReconnectDelay() { + if (reconnectDelay instanceof StatefulDelay) { + ((StatefulDelay) reconnectDelay).reset(); + } + } + @Override public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { @@ -129,6 +137,7 @@ public void channelActive(ChannelHandlerContext ctx) throws Exception { channel = ctx.channel(); reconnectScheduleTimeout = null; remoteAddress = channel.remoteAddress(); + resetReconnectDelay(); logPrefix = null; logger.debug("{} channelActive()", logPrefix()); diff --git a/src/main/java/com/lambdaworks/redis/resource/DecorrelatedJitterDelay.java b/src/main/java/com/lambdaworks/redis/resource/DecorrelatedJitterDelay.java new file mode 100644 index 0000000000..eba55a82b9 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/resource/DecorrelatedJitterDelay.java @@ -0,0 +1,44 @@ +package com.lambdaworks.redis.resource; + +import java.util.concurrent.TimeUnit; + +import com.lambdaworks.redis.resource.Delay.StatefulDelay; + +/** + * Delay that increases using decorrelated jitter strategy. + * + *

    + * Considering retry attempts start at 1, attempt 0 would be the initial call and will always yield 0 (or the lower). + * Then, each retry step will by default yield min(cap, randomBetween(base, prevDelay * 3)). + * + * This strategy is based on Exponential Backoff And Jitter. + *

    + */ +class DecorrelatedJitterDelay extends Delay implements StatefulDelay { + + private final long lower; + private final long upper; + private final long base; + private long prevDelay; + + DecorrelatedJitterDelay(long lower, long upper, long base, TimeUnit unit) { + super(unit); + this.lower = lower; + this.upper = upper; + this.base = base; + reset(); + } + + @Override + public long createDelay(long attempt) { + long value = randomBetween(base, Math.max(base, prevDelay * 3)); + long delay = applyBounds(value, lower, upper); + prevDelay = delay; + return delay; + } + + @Override + public void reset() { + prevDelay = 0L; + } +} diff --git a/src/main/java/com/lambdaworks/redis/resource/DefaultClientResources.java b/src/main/java/com/lambdaworks/redis/resource/DefaultClientResources.java index cd193c49f4..56184472a3 100644 --- a/src/main/java/com/lambdaworks/redis/resource/DefaultClientResources.java +++ b/src/main/java/com/lambdaworks/redis/resource/DefaultClientResources.java @@ -3,6 +3,7 @@ import static com.lambdaworks.redis.resource.Futures.toBooleanPromise; import java.util.concurrent.TimeUnit; +import java.util.function.Supplier; import com.lambdaworks.redis.event.DefaultEventBus; import com.lambdaworks.redis.event.DefaultEventPublisherOptions; @@ -16,6 +17,7 @@ import com.lambdaworks.redis.metrics.CommandLatencyCollectorOptions; import com.lambdaworks.redis.metrics.DefaultCommandLatencyCollector; import com.lambdaworks.redis.metrics.DefaultCommandLatencyCollectorOptions; +import com.lambdaworks.redis.resource.Delay.StatefulDelay; import io.netty.util.concurrent.*; import io.netty.util.internal.SystemPropertyUtil; @@ -55,7 +57,7 @@ public class DefaultClientResources implements ClientResources { public static final int DEFAULT_IO_THREADS; public static final int DEFAULT_COMPUTATION_THREADS; - public static final Delay DEFAULT_RECONNECT_DELAY = Delay.exponential(); + public static final Supplier DEFAULT_RECONNECT_DELAY = () -> Delay.exponential(); static { int threads = Math.max(1, SystemPropertyUtil.getInt("io.netty.eventLoopThreads", @@ -78,7 +80,7 @@ public class DefaultClientResources implements ClientResources { private final EventPublisherOptions commandLatencyPublisherOptions; private final MetricEventPublisher metricEventPublisher; private final DnsResolver dnsResolver; - private final Delay reconnectDelay; + private final Supplier reconnectDelay; private volatile boolean shutdownCalled = false; @@ -194,7 +196,7 @@ public static class Builder { private CommandLatencyCollector commandLatencyCollector; private EventPublisherOptions commandLatencyPublisherOptions = DefaultEventPublisherOptions.create(); private DnsResolver dnsResolver = DnsResolvers.JVM_DEFAULT; - private Delay reconnectDelay = DEFAULT_RECONNECT_DELAY; + private Supplier reconnectDelay = DEFAULT_RECONNECT_DELAY; private Builder() { } @@ -313,13 +315,27 @@ public Builder dnsResolver(DnsResolver dnsResolver) { } /** - * Sets the reconnect {@link Delay} to delay reconnect attempts. Defaults to binary exponential delay capped at + * Sets the stateless reconnect {@link Delay} to delay reconnect attempts. Defaults to binary exponential delay capped at * {@literal 30 SECONDS}. * * @param reconnectDelay the reconnect delay, must not be {@literal null}. * @return this */ public Builder reconnectDelay(Delay reconnectDelay) { + if (reconnectDelay instanceof StatefulDelay) { + throw new IllegalArgumentException("Delay must be a stateless instance."); + } + return reconnectDelay(() -> reconnectDelay); + } + + /** + * Sets the stateful reconnect {@link Supplier} to delay reconnect attempts. Defaults to binary exponential delay capped at + * {@literal 30 SECONDS}. + * + * @param reconnectDelay the reconnect delay, must not be {@literal null}. + * @return this + */ + public Builder reconnectDelay(Supplier reconnectDelay) { LettuceAssert.notNull(reconnectDelay, "Delay must not be null"); @@ -455,6 +471,6 @@ public DnsResolver dnsResolver() { @Override public Delay reconnectDelay() { - return reconnectDelay; + return reconnectDelay.get(); } } diff --git a/src/main/java/com/lambdaworks/redis/resource/Delay.java b/src/main/java/com/lambdaworks/redis/resource/Delay.java index 61627931de..bf93d707f0 100644 --- a/src/main/java/com/lambdaworks/redis/resource/Delay.java +++ b/src/main/java/com/lambdaworks/redis/resource/Delay.java @@ -1,6 +1,8 @@ package com.lambdaworks.redis.resource; +import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.TimeUnit; +import java.util.function.Supplier; import com.lambdaworks.redis.internal.LettuceAssert; @@ -13,6 +15,24 @@ */ public abstract class Delay { + private static long DEFAULT_LOWER_BOUND = 0; + private static long DEFAULT_UPPER_BOUND = TimeUnit.SECONDS.toMillis(30); + private static int DEFAULT_POWER_OF = 2; + private static TimeUnit DEFAULT_TIMEUNIT = TimeUnit.MILLISECONDS; + + /** + * Additional interface for stateful {@link Delay}. + */ + public interface StatefulDelay { + + /** + * Reset this delay. + * + * This method is to be implemented by the implementations. + */ + void reset(); + } + /** * The time unit of the delay. */ @@ -23,7 +43,7 @@ public abstract class Delay { * * @param timeUnit the time unit. */ - Delay(TimeUnit timeUnit) { + protected Delay(TimeUnit timeUnit) { LettuceAssert.notNull(timeUnit, "TimeUnit must not be null"); @@ -55,7 +75,7 @@ public TimeUnit getTimeUnit() { * * @param delay the delay, must be greater or equal to 0 * @param timeUnit the unit of the delay. - * @return a created {@link ExponentialDelay}. + * @return a created {@link ConstantDelay}. */ public static Delay constant(int delay, TimeUnit timeUnit) { @@ -71,7 +91,7 @@ public static Delay constant(int delay, TimeUnit timeUnit) { * @return a created {@link ExponentialDelay}. */ public static Delay exponential() { - return exponential(0, TimeUnit.SECONDS.toMillis(30), TimeUnit.MILLISECONDS, 2); + return exponential(DEFAULT_LOWER_BOUND, DEFAULT_UPPER_BOUND, DEFAULT_TIMEUNIT, DEFAULT_POWER_OF); } /** @@ -93,4 +113,104 @@ public static Delay exponential(long lower, long upper, TimeUnit unit, int power return new ExponentialDelay(lower, upper, unit, powersOf); } + + /** + * Creates a new {@link EqualJitterDelay} with default boundaries. + * + * @return a created {@link EqualJitterDelay}. + */ + public static Delay equalJitter() { + return equalJitter(DEFAULT_LOWER_BOUND, DEFAULT_UPPER_BOUND, 1L, DEFAULT_TIMEUNIT); + } + + /** + * Creates a new {@link EqualJitterDelay}. + * + * @param lower the lower boundary, must be non-negative + * @param upper the upper boundary, must be greater than the lower boundary + * @param base the base, must be greater or equal to 1 + * @param unit the unit of the delay. + * @return a created {@link EqualJitterDelay}. + */ + public static Delay equalJitter(long lower, long upper, long base, TimeUnit unit) { + + LettuceAssert.isTrue(lower >= 0, "Lower boundary must be greater or equal to 0"); + LettuceAssert.isTrue(upper > lower, "Upper boundary must be greater than the lower boundary"); + LettuceAssert.isTrue(base >= 1, "Base must be greater or equal to 1"); + + return new EqualJitterDelay(lower, upper, base, unit); + } + + /** + * Creates a new {@link FullJitterDelay} with default boundaries. + * + * @return a created {@link FullJitterDelay}. + */ + public static Delay fullJitter() { + return fullJitter(DEFAULT_LOWER_BOUND, DEFAULT_UPPER_BOUND, 1L, DEFAULT_TIMEUNIT); + } + + /** + * Creates a new {@link FullJitterDelay}. + * + * @param lower the lower boundary, must be non-negative + * @param upper the upper boundary, must be greater than the lower boundary + * @param base the base, must be greater or equal to 1 + * @param unit the unit of the delay. + * @return a created {@link FullJitterDelay}. + */ + public static Delay fullJitter(long lower, long upper, long base, TimeUnit unit) { + + LettuceAssert.isTrue(lower >= 0, "Lower boundary must be greater or equal to 0"); + LettuceAssert.isTrue(upper > lower, "Upper boundary must be greater than the lower boundary"); + LettuceAssert.isTrue(base >= 1, "Base must be greater or equal to 1"); + + return new FullJitterDelay(lower, upper, base, unit); + } + + /** + * Creates a new {@link DecorrelatedJitterDelay} supplier with default boundaries. + * + * @return a created {@link Supplier}. + */ + public static Supplier decorrelatedJitter() { + return decorrelatedJitter(DEFAULT_LOWER_BOUND, DEFAULT_UPPER_BOUND, 0L, DEFAULT_TIMEUNIT); + } + + /** + * Creates a new {@link DecorrelatedJitterDelay} supplier. + * + * @param lower the lower boundary, must be non-negative + * @param upper the upper boundary, must be greater than the lower boundary + * @param base the base, must be greater or equal to 0 + * @param unit the unit of the delay. + * @return a created {@link Supplier}. + */ + public static Supplier decorrelatedJitter(long lower, long upper, long base, TimeUnit unit) { + + LettuceAssert.isTrue(lower >= 0, "Lower boundary must be greater or equal to 0"); + LettuceAssert.isTrue(upper > lower, "Upper boundary must be greater than the lower boundary"); + LettuceAssert.isTrue(base >= 0, "Base must be greater or equal to 0"); + + // It'll create new Delay everytime because it has state. + return () -> new DecorrelatedJitterDelay(lower, upper, base, unit); + } + + protected static long randomBetween(long min, long max) { + if (min == max) { + return min; + } + return ThreadLocalRandom.current().nextLong(min, max); + } + + protected static long applyBounds(long calculatedValue, long lower, long upper) { + + if (calculatedValue < lower) { + return lower; + } + if (calculatedValue > upper) { + return upper; + } + return calculatedValue; + } } diff --git a/src/main/java/com/lambdaworks/redis/resource/EqualJitterDelay.java b/src/main/java/com/lambdaworks/redis/resource/EqualJitterDelay.java new file mode 100644 index 0000000000..c9067d3bf9 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/resource/EqualJitterDelay.java @@ -0,0 +1,29 @@ +package com.lambdaworks.redis.resource; + +import java.util.concurrent.TimeUnit; + +/** + * Delay that increases using equal jitter strategy. + * + *

    + * Considering retry attempts start at 1, attempt 0 would be the initial call and will always yield 0 (or the lower). + * Then, each retry step will by default yield randomBetween(0, base * 2 ^ (attempt - 1)). + * + * This strategy is based on Exponential Backoff And Jitter. + *

    + */ +class EqualJitterDelay extends ExponentialDelay { + + private final long base; + + EqualJitterDelay(long lower, long upper, long base, TimeUnit unit) { + super(lower, upper, unit, 2); + this.base = base; + } + + @Override + public long createDelay(long attempt) { + long value = randomBetween(0, base * calculatePowerOfTwo(attempt)); + return applyBounds(value, lower, upper); + } +} diff --git a/src/main/java/com/lambdaworks/redis/resource/ExponentialDelay.java b/src/main/java/com/lambdaworks/redis/resource/ExponentialDelay.java index 5485a06929..e47d8691c1 100644 --- a/src/main/java/com/lambdaworks/redis/resource/ExponentialDelay.java +++ b/src/main/java/com/lambdaworks/redis/resource/ExponentialDelay.java @@ -19,8 +19,8 @@ */ class ExponentialDelay extends Delay { - private final long lower; - private final long upper; + protected final long lower; + protected final long upper; private final int powersOf; ExponentialDelay(long lower, long upper, TimeUnit unit, int powersOf) { @@ -43,37 +43,24 @@ public long createDelay(long attempt) { delay = calculateAlternatePower(attempt); } - return applyBounds(delay); + return applyBounds(delay, lower, upper); } private long calculateAlternatePower(long attempt) { // round will cap at Long.MAX_VALUE and pow should prevent overflows - double step = Math.pow(this.powersOf, attempt - 1); // attempt > 0 + double step = Math.pow(powersOf, attempt - 1); // attempt > 0 return Math.round(step); } // fastpath with bitwise operator - private long calculatePowerOfTwo(long attempt) { - - long step; - if (attempt >= 64) { // safeguard against overflow in the bitshift operation - step = Long.MAX_VALUE; + protected static long calculatePowerOfTwo(long attempt) { + if (attempt <= 0) { // safeguard against underflow + return 0L; + } else if (attempt >= 64) { // safeguard against overflow in the bitshift operation + return Long.MAX_VALUE; } else { - step = (1L << (attempt - 1)); - } - // round will cap at Long.MAX_VALUE - return Math.round(step); - } - - private long applyBounds(long calculatedValue) { - - if (calculatedValue < lower) { - return lower; - } - if (calculatedValue > upper) { - return upper; + return 1L << (attempt - 1); } - return calculatedValue; } } diff --git a/src/main/java/com/lambdaworks/redis/resource/FullJitterDelay.java b/src/main/java/com/lambdaworks/redis/resource/FullJitterDelay.java new file mode 100644 index 0000000000..2dab7128c7 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/resource/FullJitterDelay.java @@ -0,0 +1,31 @@ +package com.lambdaworks.redis.resource; + +import java.util.concurrent.TimeUnit; + +/** + * Delay that increases using full jitter strategy. + * + *

    + * Considering retry attempts start at 1, attempt 0 would be the initial call and will always yield 0 (or the lower). + * Then, each retry step will by default yield temp / 2 + random_between(0, temp / 2) and temp + * is temp = min(upper, base * 2 ** attempt). + * + * This strategy is based on Exponential Backoff And Jitter. + *

    + */ +class FullJitterDelay extends ExponentialDelay { + + private final long base; + + FullJitterDelay(long lower, long upper, long base, TimeUnit unit) { + super(lower, upper, unit, 2); + this.base = base; + } + + @Override + public long createDelay(long attempt) { + long temp = Math.min(upper, base * calculatePowerOfTwo(attempt)); + long delay = temp / 2 + randomBetween(0, temp / 2); + return applyBounds(delay, lower, upper); + } +} diff --git a/src/test/java/com/lambdaworks/redis/resource/DecorrelatedJitterDelayTest.java b/src/test/java/com/lambdaworks/redis/resource/DecorrelatedJitterDelayTest.java new file mode 100644 index 0000000000..2075022e3e --- /dev/null +++ b/src/test/java/com/lambdaworks/redis/resource/DecorrelatedJitterDelayTest.java @@ -0,0 +1,59 @@ +package com.lambdaworks.redis.resource; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.concurrent.TimeUnit; + +import org.junit.Test; + +public class DecorrelatedJitterDelayTest { + + @Test(expected = IllegalArgumentException.class) + public void shouldNotCreateIfLowerBoundIsNegative() throws Exception { + Delay.decorrelatedJitter(-1, 100, 0, TimeUnit.MILLISECONDS); + } + + @Test(expected = IllegalArgumentException.class) + public void shouldNotCreateIfLowerBoundIsSameAsUpperBound() throws Exception { + Delay.decorrelatedJitter(100, 100, 1, TimeUnit.MILLISECONDS); + } + + @Test + public void negativeAttemptShouldReturnZero() throws Exception { + + Delay delay = Delay.decorrelatedJitter().get(); + + assertThat(delay.createDelay(-1)).isEqualTo(0); + } + + @Test + public void zeroShouldReturnZero() throws Exception { + + Delay delay = Delay.decorrelatedJitter().get(); + + assertThat(delay.createDelay(0)).isEqualTo(0); + } + + @Test + public void testDefaultDelays() throws Exception { + + Delay delay = Delay.decorrelatedJitter().get(); + + assertThat(delay.getTimeUnit()).isEqualTo(TimeUnit.MILLISECONDS); + + for (int i = 0; i < 1000; i++) { + assertThat(delay.createDelay(1)).isBetween(0L, 1L); + assertThat(delay.createDelay(2)).isBetween(0L, 3L); + assertThat(delay.createDelay(3)).isBetween(0L, 9L); + assertThat(delay.createDelay(4)).isBetween(0L, 27L); + assertThat(delay.createDelay(5)).isBetween(0L, 81L); + assertThat(delay.createDelay(6)).isBetween(0L, 243L); + assertThat(delay.createDelay(7)).isBetween(0L, 729L); + assertThat(delay.createDelay(8)).isBetween(0L, 2187L); + assertThat(delay.createDelay(9)).isBetween(0L, 6561L); + assertThat(delay.createDelay(10)).isBetween(0L, 19683L); + assertThat(delay.createDelay(11)).isBetween(0L, 30000L); + assertThat(delay.createDelay(Integer.MAX_VALUE)).isBetween(0L, 30000L); + } + } +} diff --git a/src/test/java/com/lambdaworks/redis/resource/EqualJitterDelayTest.java b/src/test/java/com/lambdaworks/redis/resource/EqualJitterDelayTest.java new file mode 100644 index 0000000000..f3660d3043 --- /dev/null +++ b/src/test/java/com/lambdaworks/redis/resource/EqualJitterDelayTest.java @@ -0,0 +1,63 @@ +package com.lambdaworks.redis.resource; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.concurrent.TimeUnit; + +import org.junit.Test; + +public class EqualJitterDelayTest { + + @Test(expected = IllegalArgumentException.class) + public void shouldNotCreateIfLowerBoundIsNegative() throws Exception { + Delay.equalJitter(-1, 100, 1, TimeUnit.MILLISECONDS); + } + + @Test(expected = IllegalArgumentException.class) + public void shouldNotCreateIfLowerBoundIsSameAsUpperBound() throws Exception { + Delay.equalJitter(100, 100, 1, TimeUnit.MILLISECONDS); + } + + @Test + public void negativeAttemptShouldReturnZero() throws Exception { + + Delay delay = Delay.equalJitter(); + + assertThat(delay.createDelay(-1)).isEqualTo(0); + } + + @Test + public void zeroShouldReturnZero() throws Exception { + + Delay delay = Delay.equalJitter(); + + assertThat(delay.createDelay(0)).isEqualTo(0); + } + + @Test + public void testDefaultDelays() throws Exception { + + Delay delay = Delay.equalJitter(); + + assertThat(delay.getTimeUnit()).isEqualTo(TimeUnit.MILLISECONDS); + + assertThat(delay.createDelay(1)).isBetween(0L, 1L); + assertThat(delay.createDelay(2)).isBetween(0L, 2L); + assertThat(delay.createDelay(3)).isBetween(0L, 4L); + assertThat(delay.createDelay(4)).isBetween(0L, 8L); + assertThat(delay.createDelay(5)).isBetween(0L, 16L); + assertThat(delay.createDelay(6)).isBetween(0L, 32L); + assertThat(delay.createDelay(7)).isBetween(0L, 64L); + assertThat(delay.createDelay(8)).isBetween(0L, 128L); + assertThat(delay.createDelay(9)).isBetween(0L, 256L); + assertThat(delay.createDelay(10)).isBetween(0L, 512L); + assertThat(delay.createDelay(11)).isBetween(0L, 1024L); + assertThat(delay.createDelay(12)).isBetween(0L, 2048L); + assertThat(delay.createDelay(13)).isBetween(0L, 4096L); + assertThat(delay.createDelay(14)).isBetween(0L, 8192L); + assertThat(delay.createDelay(15)).isBetween(0L, 16384L); + assertThat(delay.createDelay(16)).isBetween(0L, 30000L); + assertThat(delay.createDelay(17)).isBetween(0L, 30000L); + assertThat(delay.createDelay(Integer.MAX_VALUE)).isBetween(0L, 30000L); + } +} diff --git a/src/test/java/com/lambdaworks/redis/resource/FullJitterDelayTest.java b/src/test/java/com/lambdaworks/redis/resource/FullJitterDelayTest.java new file mode 100644 index 0000000000..8d1542db46 --- /dev/null +++ b/src/test/java/com/lambdaworks/redis/resource/FullJitterDelayTest.java @@ -0,0 +1,63 @@ +package com.lambdaworks.redis.resource; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.concurrent.TimeUnit; + +import org.junit.Test; + +public class FullJitterDelayTest { + + @Test(expected = IllegalArgumentException.class) + public void shouldNotCreateIfLowerBoundIsNegative() throws Exception { + Delay.fullJitter(-1, 100, 1, TimeUnit.MILLISECONDS); + } + + @Test(expected = IllegalArgumentException.class) + public void shouldNotCreateIfLowerBoundIsSameAsUpperBound() throws Exception { + Delay.fullJitter(100, 100, 1, TimeUnit.MILLISECONDS); + } + + @Test + public void negativeAttemptShouldReturnZero() throws Exception { + + Delay delay = Delay.fullJitter(); + + assertThat(delay.createDelay(-1)).isEqualTo(0); + } + + @Test + public void zeroShouldReturnZero() throws Exception { + + Delay delay = Delay.fullJitter(); + + assertThat(delay.createDelay(0)).isEqualTo(0); + } + + @Test + public void testDefaultDelays() throws Exception { + + Delay delay = Delay.fullJitter(); + + assertThat(delay.getTimeUnit()).isEqualTo(TimeUnit.MILLISECONDS); + + assertThat(delay.createDelay(1)).isBetween(0L, 1L); + assertThat(delay.createDelay(2)).isBetween(1L, 2L); + assertThat(delay.createDelay(3)).isBetween(2L, 4L); + assertThat(delay.createDelay(4)).isBetween(4L, 8L); + assertThat(delay.createDelay(5)).isBetween(8L, 16L); + assertThat(delay.createDelay(6)).isBetween(16L, 32L); + assertThat(delay.createDelay(7)).isBetween(32L, 64L); + assertThat(delay.createDelay(8)).isBetween(64L, 128L); + assertThat(delay.createDelay(9)).isBetween(128L, 256L); + assertThat(delay.createDelay(10)).isBetween(256L, 512L); + assertThat(delay.createDelay(11)).isBetween(512L, 1024L); + assertThat(delay.createDelay(12)).isBetween(1024L, 2048L); + assertThat(delay.createDelay(13)).isBetween(2048L, 4096L); + assertThat(delay.createDelay(14)).isBetween(4096L, 8192L); + assertThat(delay.createDelay(15)).isBetween(8192L, 16384L); + assertThat(delay.createDelay(16)).isBetween(15000L, 30000L); + assertThat(delay.createDelay(17)).isBetween(15000L, 30000L); + assertThat(delay.createDelay(Integer.MAX_VALUE)).isBetween(15000L, 30000L); + } +} From bfee76eefa77e0fe9051e53302f13834ba0e7677 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Tue, 27 Sep 2016 21:24:00 +0200 Subject: [PATCH 034/808] Polishing #365 --- .../redis/protocol/ConnectionWatchdog.java | 15 +++---- .../redis/resource/ClientResources.java | 3 +- .../resource/DecorrelatedJitterDelay.java | 19 ++++++--- .../resource/DefaultClientResources.java | 9 +++-- .../com/lambdaworks/redis/resource/Delay.java | 39 ++++++++++++++----- .../redis/resource/EqualJitterDelay.java | 12 ++++-- .../redis/resource/ExponentialDelay.java | 30 ++++++++++---- .../redis/resource/FullJitterDelay.java | 16 +++++--- .../resource/DecorrelatedJitterDelayTest.java | 3 ++ .../resource/DefaultClientResourcesTest.java | 34 +++++++++++++++- .../redis/resource/EqualJitterDelayTest.java | 3 ++ .../redis/resource/FullJitterDelayTest.java | 3 ++ 12 files changed, 140 insertions(+), 46 deletions(-) diff --git a/src/main/java/com/lambdaworks/redis/protocol/ConnectionWatchdog.java b/src/main/java/com/lambdaworks/redis/protocol/ConnectionWatchdog.java index b9112254c0..254367a555 100644 --- a/src/main/java/com/lambdaworks/redis/protocol/ConnectionWatchdog.java +++ b/src/main/java/com/lambdaworks/redis/protocol/ConnectionWatchdog.java @@ -78,7 +78,6 @@ public ConnectionWatchdog(Delay reconnectDelay, ClientOptions clientOptions, Boo LettuceAssert.notNull(connectionFacade, "ConnectionFacade must not be null"); this.reconnectDelay = reconnectDelay; - resetReconnectDelay(); this.bootstrap = bootstrap; this.timer = timer; this.reconnectWorkers = reconnectWorkers; @@ -103,12 +102,8 @@ public SocketAddress get() { this.reconnectionHandler = new ReconnectionHandler(clientOptions, bootstrap, wrappedSocketAddressSupplier, connectionFacade); - } - private void resetReconnectDelay() { - if (reconnectDelay instanceof StatefulDelay) { - ((StatefulDelay) reconnectDelay).reset(); - } + resetReconnectDelay(); } @Override @@ -118,6 +113,7 @@ public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exc if (evt instanceof ConnectionEvents.Activated) { attempts = 0; + resetReconnectDelay(); } super.userEventTriggered(ctx, evt); @@ -137,7 +133,6 @@ public void channelActive(ChannelHandlerContext ctx) throws Exception { channel = ctx.channel(); reconnectScheduleTimeout = null; remoteAddress = channel.remoteAddress(); - resetReconnectDelay(); logPrefix = null; logger.debug("{} channelActive()", logPrefix()); @@ -318,6 +313,12 @@ ReconnectionHandler getReconnectionHandler() { return reconnectionHandler; } + private void resetReconnectDelay() { + if (reconnectDelay instanceof StatefulDelay) { + ((StatefulDelay) reconnectDelay).reset(); + } + } + private String logPrefix() { if (logPrefix != null) { diff --git a/src/main/java/com/lambdaworks/redis/resource/ClientResources.java b/src/main/java/com/lambdaworks/redis/resource/ClientResources.java index d8516f0ea8..1ee05ac66f 100644 --- a/src/main/java/com/lambdaworks/redis/resource/ClientResources.java +++ b/src/main/java/com/lambdaworks/redis/resource/ClientResources.java @@ -115,10 +115,9 @@ public interface ClientResources { DnsResolver dnsResolver(); /** - * Returns the {@link Delay} for reconnect attempts. Each connection uses its own attempt counter. + * Returns the {@link Delay} for reconnect attempts. May return a different instance on each call. * * @return the reconnect {@link Delay}. */ Delay reconnectDelay(); - } diff --git a/src/main/java/com/lambdaworks/redis/resource/DecorrelatedJitterDelay.java b/src/main/java/com/lambdaworks/redis/resource/DecorrelatedJitterDelay.java index eba55a82b9..370ae51bd9 100644 --- a/src/main/java/com/lambdaworks/redis/resource/DecorrelatedJitterDelay.java +++ b/src/main/java/com/lambdaworks/redis/resource/DecorrelatedJitterDelay.java @@ -5,21 +5,30 @@ import com.lambdaworks.redis.resource.Delay.StatefulDelay; /** - * Delay that increases using decorrelated jitter strategy. + * Stateful delay that increases using decorrelated jitter strategy. * *

    - * Considering retry attempts start at 1, attempt 0 would be the initial call and will always yield 0 (or the lower). - * Then, each retry step will by default yield min(cap, randomBetween(base, prevDelay * 3)). + * Considering retry attempts start at 1, attempt 0 would be the initial call and will always yield 0 (or the lower). Then, each + * retry step will by default yield {@code min(cap, randomBetween(base, prevDelay * 3))}. * - * This strategy is based on Exponential Backoff And Jitter. + * This strategy is based on Exponential Backoff and + * Jitter. *

    + * + * @author Jongyeol Choi + * @since 4.2 + * @see StatefulDelay */ class DecorrelatedJitterDelay extends Delay implements StatefulDelay { private final long lower; private final long upper; private final long base; - private long prevDelay; + + /* + * Delays may be used by different threads, this one is volatile to prevent visibility issues + */ + private volatile long prevDelay; DecorrelatedJitterDelay(long lower, long upper, long base, TimeUnit unit) { super(unit); diff --git a/src/main/java/com/lambdaworks/redis/resource/DefaultClientResources.java b/src/main/java/com/lambdaworks/redis/resource/DefaultClientResources.java index 56184472a3..544f4aa41a 100644 --- a/src/main/java/com/lambdaworks/redis/resource/DefaultClientResources.java +++ b/src/main/java/com/lambdaworks/redis/resource/DefaultClientResources.java @@ -316,15 +316,16 @@ public Builder dnsResolver(DnsResolver dnsResolver) { /** * Sets the stateless reconnect {@link Delay} to delay reconnect attempts. Defaults to binary exponential delay capped at - * {@literal 30 SECONDS}. + * {@literal 30 SECONDS}. {@code reconnectDelay} must be a stateless {@link Delay}. * * @param reconnectDelay the reconnect delay, must not be {@literal null}. * @return this */ public Builder reconnectDelay(Delay reconnectDelay) { - if (reconnectDelay instanceof StatefulDelay) { - throw new IllegalArgumentException("Delay must be a stateless instance."); - } + + LettuceAssert.notNull(reconnectDelay, "Delay must not be null"); + LettuceAssert.isTrue(!(reconnectDelay instanceof StatefulDelay), "Delay must be a stateless instance."); + return reconnectDelay(() -> reconnectDelay); } diff --git a/src/main/java/com/lambdaworks/redis/resource/Delay.java b/src/main/java/com/lambdaworks/redis/resource/Delay.java index bf93d707f0..4d7ee3e5f9 100644 --- a/src/main/java/com/lambdaworks/redis/resource/Delay.java +++ b/src/main/java/com/lambdaworks/redis/resource/Delay.java @@ -8,10 +8,16 @@ /** * Base class for delays and factory class to create particular instances. {@link Delay} can be subclassed to create custom - * delay implementations based on attempts. Attempts start with {@value 1}. + * delay implementations based on attempts. Attempts start with {@code 1}. + *

    + * Delays are usually stateless instances that can be shared amongst multiple users (such as connections). Stateful + * {@link Delay} implementations must implement {@link StatefulDelay} to reset their internal state after the delay is not + * required anymore. * * @author Mark Paluch + * @author Jongyeol Choi * @since 4.2 + * @see StatefulDelay */ public abstract class Delay { @@ -21,14 +27,17 @@ public abstract class Delay { private static TimeUnit DEFAULT_TIMEUNIT = TimeUnit.MILLISECONDS; /** - * Additional interface for stateful {@link Delay}. + * Interface to be implemented by stateful {@link Delay}s. Stateful delays can get reset once a condition (such as + * successful reconnect) is met. Stateful delays should not be shared by multiple connections but each connection should use + * its own instance. + * + * @see Supplier + * @see com.lambdaworks.redis.resource.DefaultClientResources.Builder#reconnectDelay(Supplier) */ public interface StatefulDelay { /** - * Reset this delay. - * - * This method is to be implemented by the implementations. + * Reset this delay state. Resetting prepares a stateful delay for its next usage. */ void reset(); } @@ -169,22 +178,22 @@ public static Delay fullJitter(long lower, long upper, long base, TimeUnit unit) } /** - * Creates a new {@link DecorrelatedJitterDelay} supplier with default boundaries. + * Creates a {@link Supplier} that constructs new {@link DecorrelatedJitterDelay} instances with default boundaries. * - * @return a created {@link Supplier}. + * @return a {@link Supplier} of {@link DecorrelatedJitterDelay}. */ public static Supplier decorrelatedJitter() { return decorrelatedJitter(DEFAULT_LOWER_BOUND, DEFAULT_UPPER_BOUND, 0L, DEFAULT_TIMEUNIT); } /** - * Creates a new {@link DecorrelatedJitterDelay} supplier. + * Creates a {@link Supplier} that constructs new {@link DecorrelatedJitterDelay} instances. * * @param lower the lower boundary, must be non-negative * @param upper the upper boundary, must be greater than the lower boundary * @param base the base, must be greater or equal to 0 * @param unit the unit of the delay. - * @return a created {@link Supplier}. + * @return a new {@link Supplier} of {@link DecorrelatedJitterDelay}. */ public static Supplier decorrelatedJitter(long lower, long upper, long base, TimeUnit unit) { @@ -192,10 +201,18 @@ public static Supplier decorrelatedJitter(long lower, long upper, long ba LettuceAssert.isTrue(upper > lower, "Upper boundary must be greater than the lower boundary"); LettuceAssert.isTrue(base >= 0, "Base must be greater or equal to 0"); - // It'll create new Delay everytime because it has state. + // Create new Delay because it has state. return () -> new DecorrelatedJitterDelay(lower, upper, base, unit); } + /** + * Generates a random long value within {@code min} and {@code max} boundaries. + * + * @param min + * @param max + * @return a random value + * @see ThreadLocalRandom#nextLong(long, long) + */ protected static long randomBetween(long min, long max) { if (min == max) { return min; @@ -208,9 +225,11 @@ protected static long applyBounds(long calculatedValue, long lower, long upper) if (calculatedValue < lower) { return lower; } + if (calculatedValue > upper) { return upper; } + return calculatedValue; } } diff --git a/src/main/java/com/lambdaworks/redis/resource/EqualJitterDelay.java b/src/main/java/com/lambdaworks/redis/resource/EqualJitterDelay.java index c9067d3bf9..500200dc5a 100644 --- a/src/main/java/com/lambdaworks/redis/resource/EqualJitterDelay.java +++ b/src/main/java/com/lambdaworks/redis/resource/EqualJitterDelay.java @@ -6,11 +6,15 @@ * Delay that increases using equal jitter strategy. * *

    - * Considering retry attempts start at 1, attempt 0 would be the initial call and will always yield 0 (or the lower). - * Then, each retry step will by default yield randomBetween(0, base * 2 ^ (attempt - 1)). + * Considering retry attempts start at 1, attempt 0 would be the initial call and will always yield 0 (or the lower). Then, each + * retry step will by default yield {@code randomBetween(0, base * 2 ^ (attempt - 1))}. * - * This strategy is based on Exponential Backoff And Jitter. + * This strategy is based on Exponential Backoff and + * Jitter. *

    + * + * @author Jongyeol Choi + * @since 4.2 */ class EqualJitterDelay extends ExponentialDelay { @@ -24,6 +28,6 @@ class EqualJitterDelay extends ExponentialDelay { @Override public long createDelay(long attempt) { long value = randomBetween(0, base * calculatePowerOfTwo(attempt)); - return applyBounds(value, lower, upper); + return applyBounds(value); } } diff --git a/src/main/java/com/lambdaworks/redis/resource/ExponentialDelay.java b/src/main/java/com/lambdaworks/redis/resource/ExponentialDelay.java index e47d8691c1..87449415bd 100644 --- a/src/main/java/com/lambdaworks/redis/resource/ExponentialDelay.java +++ b/src/main/java/com/lambdaworks/redis/resource/ExponentialDelay.java @@ -7,20 +7,23 @@ * *

    * Considering retry attempts start at 1, attempt 0 would be the initial call and will always yield 0 (or the lower bound). Then - * each retry step will by default yield 1 * 2 ^ (attemptNumber-1). Actually each step can be based on a different - * number than 1 unit of time using the growBy parameter: growBy * 2 ^ (attemptNumber-1). + * each retry step will by default yield {@code 2 ^ (attemptNumber-1)}. By default this gives us 0 (initial attempt), 1, 2, 4, + * 8, 16, 32, ... *

    - * By default with growBy = 1 this gives us 0 (initial attempt), 1, 2, 4, 8, 16, 32... - * - * Each of the resulting values that is below the lowerBound will be replaced by the lower bound, and each value - * over the upperBound will be replaced by the upper bound. + * {@link ExponentialDelay} can also apply different {@code powersBy}, such as power of 10 that would apply + * {@code 10 ^ (attemptNumber-1)} which would give 0, 10, 100, 1000, ... + *

    + * Each of the resulting values that is below the {@code lowerBound} will be replaced by the lower bound, and each value over + * the {@code upperBound} will be replaced by the upper bound. * * @author Mark Paluch + * @author Jongyeol Choi + * @since 4.1 */ class ExponentialDelay extends Delay { - protected final long lower; - protected final long upper; + private final long lower; + private final long upper; private final int powersOf; ExponentialDelay(long lower, long upper, TimeUnit unit, int powersOf) { @@ -43,6 +46,16 @@ public long createDelay(long attempt) { delay = calculateAlternatePower(attempt); } + return applyBounds(delay); + } + + /** + * Apply bounds to the given {@code delay}. + * + * @param delay the delay + * @return the delay normalized to its lower and upper bounds. + */ + protected long applyBounds(long delay) { return applyBounds(delay, lower, upper); } @@ -55,6 +68,7 @@ private long calculateAlternatePower(long attempt) { // fastpath with bitwise operator protected static long calculatePowerOfTwo(long attempt) { + if (attempt <= 0) { // safeguard against underflow return 0L; } else if (attempt >= 64) { // safeguard against overflow in the bitshift operation diff --git a/src/main/java/com/lambdaworks/redis/resource/FullJitterDelay.java b/src/main/java/com/lambdaworks/redis/resource/FullJitterDelay.java index 2dab7128c7..c1843360cc 100644 --- a/src/main/java/com/lambdaworks/redis/resource/FullJitterDelay.java +++ b/src/main/java/com/lambdaworks/redis/resource/FullJitterDelay.java @@ -6,19 +6,25 @@ * Delay that increases using full jitter strategy. * *

    - * Considering retry attempts start at 1, attempt 0 would be the initial call and will always yield 0 (or the lower). - * Then, each retry step will by default yield temp / 2 + random_between(0, temp / 2) and temp - * is temp = min(upper, base * 2 ** attempt). + * Considering retry attempts start at 1, attempt 0 would be the initial call and will always yield 0 (or the lower). Then, each + * retry step will by default yield {@code temp / 2 + random_between(0, temp / 2)} and temp is + * {@code temp = min(upper, base * 2 ** attempt)}. * - * This strategy is based on Exponential Backoff And Jitter. + * This strategy is based on Exponential Backoff and + * Jitter. *

    + * + * @author Jongyeol Choi + * @since 4.2 */ class FullJitterDelay extends ExponentialDelay { private final long base; + private final long upper; FullJitterDelay(long lower, long upper, long base, TimeUnit unit) { super(lower, upper, unit, 2); + this.upper = upper; this.base = base; } @@ -26,6 +32,6 @@ class FullJitterDelay extends ExponentialDelay { public long createDelay(long attempt) { long temp = Math.min(upper, base * calculatePowerOfTwo(attempt)); long delay = temp / 2 + randomBetween(0, temp / 2); - return applyBounds(delay, lower, upper); + return applyBounds(delay); } } diff --git a/src/test/java/com/lambdaworks/redis/resource/DecorrelatedJitterDelayTest.java b/src/test/java/com/lambdaworks/redis/resource/DecorrelatedJitterDelayTest.java index 2075022e3e..3a09ff59c3 100644 --- a/src/test/java/com/lambdaworks/redis/resource/DecorrelatedJitterDelayTest.java +++ b/src/test/java/com/lambdaworks/redis/resource/DecorrelatedJitterDelayTest.java @@ -6,6 +6,9 @@ import org.junit.Test; +/** + * @author Jongyeol Choi + */ public class DecorrelatedJitterDelayTest { @Test(expected = IllegalArgumentException.class) diff --git a/src/test/java/com/lambdaworks/redis/resource/DefaultClientResourcesTest.java b/src/test/java/com/lambdaworks/redis/resource/DefaultClientResourcesTest.java index 05ed927233..4148f8c57f 100644 --- a/src/test/java/com/lambdaworks/redis/resource/DefaultClientResourcesTest.java +++ b/src/test/java/com/lambdaworks/redis/resource/DefaultClientResourcesTest.java @@ -8,13 +8,14 @@ import java.util.concurrent.TimeUnit; -import com.lambdaworks.redis.reactive.TestSubscriber; import org.junit.Test; +import com.lambdaworks.redis.FastShutdown; import com.lambdaworks.redis.event.Event; import com.lambdaworks.redis.event.EventBus; import com.lambdaworks.redis.metrics.CommandLatencyCollector; import com.lambdaworks.redis.metrics.DefaultCommandLatencyCollectorOptions; +import com.lambdaworks.redis.reactive.TestSubscriber; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.util.concurrent.EventExecutorGroup; @@ -138,4 +139,35 @@ public void testEventBus() throws Exception { assertThat(sut.shutdown(0, 0, TimeUnit.MILLISECONDS).get()).isTrue(); } + @Test(expected = IllegalArgumentException.class) + public void delayInstanceShouldRejectStatefulDelay() throws Exception { + + DefaultClientResources.builder().reconnectDelay(Delay.decorrelatedJitter().get()); + } + + @Test + public void reconnectDelayCreatesNewForStatefulDelays() throws Exception { + + DefaultClientResources resources = DefaultClientResources.builder().reconnectDelay(Delay.decorrelatedJitter()).build(); + + Delay delay1 = resources.reconnectDelay(); + Delay delay2 = resources.reconnectDelay(); + + assertThat(delay1).isNotSameAs(delay2); + + FastShutdown.shutdown(resources); + } + + @Test + public void reconnectDelayReturnsSameInstanceForStatelessDelays() throws Exception { + + DefaultClientResources resources = DefaultClientResources.builder().reconnectDelay(Delay.exponential()).build(); + + Delay delay1 = resources.reconnectDelay(); + Delay delay2 = resources.reconnectDelay(); + + assertThat(delay1).isSameAs(delay2); + + FastShutdown.shutdown(resources); + } } diff --git a/src/test/java/com/lambdaworks/redis/resource/EqualJitterDelayTest.java b/src/test/java/com/lambdaworks/redis/resource/EqualJitterDelayTest.java index f3660d3043..8a77969593 100644 --- a/src/test/java/com/lambdaworks/redis/resource/EqualJitterDelayTest.java +++ b/src/test/java/com/lambdaworks/redis/resource/EqualJitterDelayTest.java @@ -6,6 +6,9 @@ import org.junit.Test; +/** + * @author Jongyeol Choi + */ public class EqualJitterDelayTest { @Test(expected = IllegalArgumentException.class) diff --git a/src/test/java/com/lambdaworks/redis/resource/FullJitterDelayTest.java b/src/test/java/com/lambdaworks/redis/resource/FullJitterDelayTest.java index 8d1542db46..5a01edd06b 100644 --- a/src/test/java/com/lambdaworks/redis/resource/FullJitterDelayTest.java +++ b/src/test/java/com/lambdaworks/redis/resource/FullJitterDelayTest.java @@ -6,6 +6,9 @@ import org.junit.Test; +/** + * @author Jongyeol Choi + */ public class FullJitterDelayTest { @Test(expected = IllegalArgumentException.class) From dc78fde9bfabceb0fdc11d683627b3bdb0c4af91 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Tue, 27 Sep 2016 22:07:13 +0200 Subject: [PATCH 035/808] Add support for ZADD INCR with ZAddArgs #367 --- .../redis/AbstractRedisAsyncCommands.java | 7 +++- .../redis/AbstractRedisReactiveCommands.java | 8 +++-- .../redis/RedisCommandBuilder.java | 7 +++- .../java/com/lambdaworks/redis/ZAddArgs.java | 7 ++-- .../async/RedisSortedSetAsyncCommands.java | 21 ++++++++--- .../RedisSortedSetReactiveCommands.java | 21 ++++++++--- .../api/sync/RedisSortedSetCommands.java | 21 ++++++++--- .../NodeSelectionSortedSetAsyncCommands.java | 21 ++++++++--- .../sync/NodeSelectionSortedSetCommands.java | 21 ++++++++--- .../redis/api/RedisSortedSetCommands.java | 35 +++++++++++++------ .../redis/commands/SortedSetCommandTest.java | 17 +++++++-- 11 files changed, 141 insertions(+), 45 deletions(-) diff --git a/src/main/java/com/lambdaworks/redis/AbstractRedisAsyncCommands.java b/src/main/java/com/lambdaworks/redis/AbstractRedisAsyncCommands.java index a8f102d1e7..c9278d6097 100644 --- a/src/main/java/com/lambdaworks/redis/AbstractRedisAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/AbstractRedisAsyncCommands.java @@ -1056,7 +1056,12 @@ public RedisFuture zadd(K key, ZAddArgs zAddArgs, ScoredValue... scored @Override public RedisFuture zaddincr(K key, double score, V member) { - return dispatch(commandBuilder.zaddincr(key, score, member)); + return dispatch(commandBuilder.zaddincr(key, null, score, member)); + } + + @Override + public RedisFuture zaddincr(K key, ZAddArgs zAddArgs, double score, V member) { + return dispatch(commandBuilder.zaddincr(key, zAddArgs, score, member)); } @Override diff --git a/src/main/java/com/lambdaworks/redis/AbstractRedisReactiveCommands.java b/src/main/java/com/lambdaworks/redis/AbstractRedisReactiveCommands.java index a34dc499ca..d3408daf64 100644 --- a/src/main/java/com/lambdaworks/redis/AbstractRedisReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/AbstractRedisReactiveCommands.java @@ -1052,7 +1052,12 @@ public Mono zadd(K key, ZAddArgs zAddArgs, ScoredValue... scoredValues) @Override public Mono zaddincr(K key, double score, V member) { - return createMono(() -> commandBuilder.zaddincr(key, score, member)); + return createMono(() -> commandBuilder.zaddincr(key, null, score, member)); + } + + @Override + public Mono zaddincr(K key, ZAddArgs zAddArgs, double score, V member) { + return createMono(() -> commandBuilder.zaddincr(key, zAddArgs, score, member)); } @Override @@ -1060,7 +1065,6 @@ public Mono zcard(K key) { return createMono(() -> commandBuilder.zcard(key)); } - @Override public Mono zcount(K key, double min, double max) { return createMono(() -> commandBuilder.zcount(key, min, max)); } diff --git a/src/main/java/com/lambdaworks/redis/RedisCommandBuilder.java b/src/main/java/com/lambdaworks/redis/RedisCommandBuilder.java index 48b385ddeb..1c82156a52 100644 --- a/src/main/java/com/lambdaworks/redis/RedisCommandBuilder.java +++ b/src/main/java/com/lambdaworks/redis/RedisCommandBuilder.java @@ -1441,10 +1441,15 @@ public Command zadd(K key, ZAddArgs zAddArgs, double score, V member return createCommand(ZADD, new IntegerOutput(codec), args); } - public Command zaddincr(K key, double score, V member) { + public Command zaddincr(K key, ZAddArgs zAddArgs, double score, V member) { notNullKey(key); CommandArgs args = new CommandArgs(codec).addKey(key); + + if (zAddArgs != null) { + zAddArgs.build(args); + } + args.add(INCR); args.add(score).addValue(member); diff --git a/src/main/java/com/lambdaworks/redis/ZAddArgs.java b/src/main/java/com/lambdaworks/redis/ZAddArgs.java index 1a5fd103b8..8864e1026f 100644 --- a/src/main/java/com/lambdaworks/redis/ZAddArgs.java +++ b/src/main/java/com/lambdaworks/redis/ZAddArgs.java @@ -15,6 +15,7 @@ public class ZAddArgs { private boolean ch = false; public static class Builder { + /** * Utility constructor. */ @@ -35,17 +36,17 @@ public static ZAddArgs ch() { } } - private ZAddArgs nx() { + public ZAddArgs nx() { this.nx = true; return this; } - private ZAddArgs ch() { + public ZAddArgs ch() { this.ch = true; return this; } - private ZAddArgs xx() { + public ZAddArgs xx() { this.xx = true; return this; } diff --git a/src/main/java/com/lambdaworks/redis/api/async/RedisSortedSetAsyncCommands.java b/src/main/java/com/lambdaworks/redis/api/async/RedisSortedSetAsyncCommands.java index b02bb9314a..4aebb7a0d5 100644 --- a/src/main/java/com/lambdaworks/redis/api/async/RedisSortedSetAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/async/RedisSortedSetAsyncCommands.java @@ -105,18 +105,29 @@ public interface RedisSortedSetAsyncCommands { RedisFuture zadd(K key, ZAddArgs zAddArgs, ScoredValue... scoredValues); /** - * ZADD acts like ZINCRBY + * Add one or more members to a sorted set, or update its score if it already exists applying the {@code INCR} option. ZADD + * acts like ZINCRBY. * * @param key the key * @param score the score * @param member the member - * - * @return Long integer-reply specifically: - * - * The total number of elements changed + * @return Long integer-reply specifically: The total number of elements changed */ RedisFuture zaddincr(K key, double score, V member); + /** + * Add one or more members to a sorted set, or update its score if it already exists applying the {@code INCR} option. ZADD + * acts like ZINCRBY. + * + * @param key the key + * @param zAddArgs arguments for zadd + * @param score the score + * @param member the member + * @return Long integer-reply specifically: The total number of elements changed + * @since 4.3 + */ + RedisFuture zaddincr(K key, ZAddArgs zAddArgs, double score, V member); + /** * Get the number of members in a sorted set. * diff --git a/src/main/java/com/lambdaworks/redis/api/reactive/RedisSortedSetReactiveCommands.java b/src/main/java/com/lambdaworks/redis/api/reactive/RedisSortedSetReactiveCommands.java index 3acd9a8a97..4e5a31658d 100644 --- a/src/main/java/com/lambdaworks/redis/api/reactive/RedisSortedSetReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/reactive/RedisSortedSetReactiveCommands.java @@ -106,18 +106,29 @@ public interface RedisSortedSetReactiveCommands { Mono zadd(K key, ZAddArgs zAddArgs, ScoredValue... scoredValues); /** - * ZADD acts like ZINCRBY + * Add one or more members to a sorted set, or update its score if it already exists applying the {@code INCR} option. ZADD + * acts like ZINCRBY. * * @param key the key * @param score the score * @param member the member - * - * @return Long integer-reply specifically: - * - * The total number of elements changed + * @return Long integer-reply specifically: The total number of elements changed */ Mono zaddincr(K key, double score, V member); + /** + * Add one or more members to a sorted set, or update its score if it already exists applying the {@code INCR} option. ZADD + * acts like ZINCRBY. + * + * @param key the key + * @param zAddArgs arguments for zadd + * @param score the score + * @param member the member + * @return Long integer-reply specifically: The total number of elements changed + * @since 4.3 + */ + Mono zaddincr(K key, ZAddArgs zAddArgs, double score, V member); + /** * Get the number of members in a sorted set. * diff --git a/src/main/java/com/lambdaworks/redis/api/sync/RedisSortedSetCommands.java b/src/main/java/com/lambdaworks/redis/api/sync/RedisSortedSetCommands.java index d484e1ef94..96d966a1a4 100644 --- a/src/main/java/com/lambdaworks/redis/api/sync/RedisSortedSetCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/sync/RedisSortedSetCommands.java @@ -104,18 +104,29 @@ public interface RedisSortedSetCommands { Long zadd(K key, ZAddArgs zAddArgs, ScoredValue... scoredValues); /** - * ZADD acts like ZINCRBY + * Add one or more members to a sorted set, or update its score if it already exists applying the {@code INCR} option. ZADD + * acts like ZINCRBY. * * @param key the key * @param score the score * @param member the member - * - * @return Long integer-reply specifically: - * - * The total number of elements changed + * @return Long integer-reply specifically: The total number of elements changed */ Double zaddincr(K key, double score, V member); + /** + * Add one or more members to a sorted set, or update its score if it already exists applying the {@code INCR} option. ZADD + * acts like ZINCRBY. + * + * @param key the key + * @param zAddArgs arguments for zadd + * @param score the score + * @param member the member + * @return Long integer-reply specifically: The total number of elements changed + * @since 4.3 + */ + Double zaddincr(K key, ZAddArgs zAddArgs, double score, V member); + /** * Get the number of members in a sorted set. * diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionSortedSetAsyncCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionSortedSetAsyncCommands.java index 100e83dc7b..8da750bf81 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionSortedSetAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionSortedSetAsyncCommands.java @@ -105,18 +105,29 @@ public interface NodeSelectionSortedSetAsyncCommands { AsyncExecutions zadd(K key, ZAddArgs zAddArgs, ScoredValue... scoredValues); /** - * ZADD acts like ZINCRBY + * Add one or more members to a sorted set, or update its score if it already exists applying the {@code INCR} option. ZADD + * acts like ZINCRBY. * * @param key the key * @param score the score * @param member the member - * - * @return Long integer-reply specifically: - * - * The total number of elements changed + * @return Long integer-reply specifically: The total number of elements changed */ AsyncExecutions zaddincr(K key, double score, V member); + /** + * Add one or more members to a sorted set, or update its score if it already exists applying the {@code INCR} option. ZADD + * acts like ZINCRBY. + * + * @param key the key + * @param zAddArgs arguments for zadd + * @param score the score + * @param member the member + * @return Long integer-reply specifically: The total number of elements changed + * @since 4.3 + */ + AsyncExecutions zaddincr(K key, ZAddArgs zAddArgs, double score, V member); + /** * Get the number of members in a sorted set. * diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionSortedSetCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionSortedSetCommands.java index 0aeeaee2a6..2768ed7098 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionSortedSetCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionSortedSetCommands.java @@ -104,18 +104,29 @@ public interface NodeSelectionSortedSetCommands { Executions zadd(K key, ZAddArgs zAddArgs, ScoredValue... scoredValues); /** - * ZADD acts like ZINCRBY + * Add one or more members to a sorted set, or update its score if it already exists applying the {@code INCR} option. ZADD + * acts like ZINCRBY. * * @param key the key * @param score the score * @param member the member - * - * @return Long integer-reply specifically: - * - * The total number of elements changed + * @return Long integer-reply specifically: The total number of elements changed */ Executions zaddincr(K key, double score, V member); + /** + * Add one or more members to a sorted set, or update its score if it already exists applying the {@code INCR} option. ZADD + * acts like ZINCRBY. + * + * @param key the key + * @param zAddArgs arguments for zadd + * @param score the score + * @param member the member + * @return Long integer-reply specifically: The total number of elements changed + * @since 4.3 + */ + Executions zaddincr(K key, ZAddArgs zAddArgs, double score, V member); + /** * Get the number of members in a sorted set. * diff --git a/src/main/templates/com/lambdaworks/redis/api/RedisSortedSetCommands.java b/src/main/templates/com/lambdaworks/redis/api/RedisSortedSetCommands.java index 653e5762dc..20b571778c 100644 --- a/src/main/templates/com/lambdaworks/redis/api/RedisSortedSetCommands.java +++ b/src/main/templates/com/lambdaworks/redis/api/RedisSortedSetCommands.java @@ -49,7 +49,7 @@ public interface RedisSortedSetCommands { * updated. */ Long zadd(K key, Object... scoresAndValues); - + /** * Add one or more members to a sorted set, or update its score if it already exists. * @@ -89,7 +89,7 @@ public interface RedisSortedSetCommands { * updated. */ Long zadd(K key, ZAddArgs zAddArgs, Object... scoresAndValues); - + /** * Add one or more members to a sorted set, or update its score if it already exists. * @@ -104,18 +104,29 @@ public interface RedisSortedSetCommands { Long zadd(K key, ZAddArgs zAddArgs, ScoredValue... scoredValues); /** - * ZADD acts like ZINCRBY + * Add one or more members to a sorted set, or update its score if it already exists applying the {@code INCR} option. ZADD + * acts like ZINCRBY. * * @param key the key * @param score the score * @param member the member - * - * @return Long integer-reply specifically: - * - * The total number of elements changed + * @return Long integer-reply specifically: The total number of elements changed */ Double zaddincr(K key, double score, V member); + /** + * Add one or more members to a sorted set, or update its score if it already exists applying the {@code INCR} option. ZADD + * acts like ZINCRBY. + * + * @param key the key + * @param zAddArgs arguments for zadd + * @param score the score + * @param member the member + * @return Long integer-reply specifically: The total number of elements changed + * @since 4.3 + */ + Double zaddincr(K key, ZAddArgs zAddArgs, double score, V member); + /** * Get the number of members in a sorted set. * @@ -505,7 +516,8 @@ public interface RedisSortedSetCommands { * @deprecated Use {@link #zrangebyscoreWithScores(ScoredValueStreamingChannel, java.lang.Object, Range, Limit limit)} */ @Deprecated - Long zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, double min, double max, long offset, long count); + Long zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, double min, double max, long offset, + long count); /** * Stream over a range of members with scores in a sorted set, by score. @@ -520,7 +532,8 @@ public interface RedisSortedSetCommands { * @deprecated Use {@link #zrangebyscoreWithScores(ScoredValueStreamingChannel, java.lang.Object, Range, Limit limit)} */ @Deprecated - Long zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, String min, String max, long offset, long count); + Long zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, String min, String max, long offset, + long count); /** * Stream over a range of members with scores in a sorted set, by score. @@ -916,7 +929,7 @@ public interface RedisSortedSetCommands { */ @Deprecated Long zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, double max, double min, long offset, - long count); + long count); /** * Stream over a range of members with scores in a sorted set, by score, with scores ordered from high to low. @@ -932,7 +945,7 @@ Long zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, d */ @Deprecated Long zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, String max, String min, long offset, - long count); + long count); /** * Stream over a range of members with scores in a sorted set, by score, with scores ordered from high to low. diff --git a/src/test/java/com/lambdaworks/redis/commands/SortedSetCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/SortedSetCommandTest.java index da4d4f6068..bddf66e576 100644 --- a/src/test/java/com/lambdaworks/redis/commands/SortedSetCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/SortedSetCommandTest.java @@ -10,6 +10,7 @@ import static java.lang.Double.POSITIVE_INFINITY; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.data.Offset.offset; +import static sun.security.krb5.Confounder.longValue; import java.util.HashSet; import java.util.Set; @@ -76,8 +77,7 @@ public void zaddxx() throws Exception { @Test public void zaddch() throws Exception { assertThat(redis.zadd(key, 1.0, "a")).isEqualTo(1); - assertThat(redis.zadd(key, ZAddArgs.Builder.ch(), 2.0, "a")).isEqualTo(1); - + assertThat(redis.zadd(key, ZAddArgs.Builder.ch().xx(), 2.0, "a")).isEqualTo(1); assertThat(redis.zadd(key, ZAddArgs.Builder.ch(), 2.0, "b")).isEqualTo(1); assertThat(redis.zrangeWithScores(key, 0, -1)).isEqualTo(svlist(sv(2.0, "a"), sv(2.0, "b"))); @@ -93,6 +93,19 @@ public void zaddincr() throws Exception { assertThat(redis.zrangeWithScores(key, 0, -1)).isEqualTo(svlist(sv(2.0, "b"), sv(3.0, "a"))); } + @Test + public void zaddincrnx() throws Exception { + assertThat(redis.zaddincr(key, ZAddArgs.Builder.nx(), 2.0, "a").longValue()).isEqualTo(2); + assertThat(redis.zaddincr(key, ZAddArgs.Builder.nx(), 2.0, "a")).isNull(); + } + + @Test + public void zaddincrxx() throws Exception { + assertThat(redis.zaddincr(key, ZAddArgs.Builder.xx(), 2.0, "a")).isNull(); + assertThat(redis.zaddincr(key, ZAddArgs.Builder.nx(), 2.0, "a").longValue()).isEqualTo(2); + assertThat(redis.zaddincr(key, ZAddArgs.Builder.xx(), 2.0, "a").longValue()).isEqualTo(4); + } + @Test public void zcard() throws Exception { assertThat(redis.zcard(key)).isEqualTo(0); From 14606101d171a8252efd36e447f1e9566f7c1798 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Thu, 29 Sep 2016 14:40:20 +0200 Subject: [PATCH 036/808] Accept double in ZStoreArgs.weights #368 --- .../com/lambdaworks/redis/ZStoreArgs.java | 35 +++++++++++++++---- .../redis/commands/SortedSetCommandTest.java | 7 ++-- 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/lambdaworks/redis/ZStoreArgs.java b/src/main/java/com/lambdaworks/redis/ZStoreArgs.java index a0d74629c8..5a7d85c9e8 100644 --- a/src/main/java/com/lambdaworks/redis/ZStoreArgs.java +++ b/src/main/java/com/lambdaworks/redis/ZStoreArgs.java @@ -10,8 +10,8 @@ import com.lambdaworks.redis.protocol.CommandArgs; /** - * Argument list builder for the redis ZUNIONSTORE and ZINTERSTORE commands. Static import the methods from {@link Builder} and + * Argument list builder for the redis ZUNIONSTORE and + * ZINTERSTORE commands. Static import the methods from {@link Builder} and * chain the method calls: {@code weights(1, 2).max()}. * * @author Will Glozer @@ -22,7 +22,7 @@ private static enum Aggregate { SUM, MIN, MAX } - private List weights; + private List weights; private Aggregate aggregate; /** @@ -37,7 +37,12 @@ private Builder() { } - public static ZStoreArgs weights(long... weights) { + @Deprecated + public static ZStoreArgs weights(long[] weights) { + return new ZStoreArgs().weights(toDoubleArray(weights)); + } + + public static ZStoreArgs weights(double... weights) { return new ZStoreArgs().weights(weights); } @@ -54,9 +59,15 @@ public static ZStoreArgs max() { } } - public ZStoreArgs weights(long... weights) { + @Deprecated + public static ZStoreArgs weights(long[] weights) { + return new ZStoreArgs().weights(toDoubleArray(weights)); + } + + public ZStoreArgs weights(double... weights) { this.weights = new ArrayList<>(weights.length); - for (long weight : weights) { + + for (double weight : weights) { this.weights.add(weight); } return this; @@ -77,10 +88,20 @@ public ZStoreArgs max() { return this; } + private static double[] toDoubleArray(long[] weights) { + double result[] = new double[weights.length]; + for (int i = 0; i < weights.length; i++) { + result[i] = weights[i]; + } + return result; + } + void build(CommandArgs args) { + if (weights != null) { + args.add(WEIGHTS); - for (long weight : weights) { + for (double weight : weights) { args.add(weight); } } diff --git a/src/test/java/com/lambdaworks/redis/commands/SortedSetCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/SortedSetCommandTest.java index bddf66e576..b17e040050 100644 --- a/src/test/java/com/lambdaworks/redis/commands/SortedSetCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/SortedSetCommandTest.java @@ -10,15 +10,14 @@ import static java.lang.Double.POSITIVE_INFINITY; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.data.Offset.offset; -import static sun.security.krb5.Confounder.longValue; import java.util.HashSet; import java.util.Set; -import com.lambdaworks.redis.Range.Boundary; import org.junit.Test; import com.lambdaworks.redis.*; +import com.lambdaworks.redis.Range.Boundary; public class SortedSetCommandTest extends AbstractRedisClientTest { @@ -465,7 +464,7 @@ public void zunionstore() throws Exception { assertThat(redis.zrange(key, 0, -1)).isEqualTo(list("a", "c", "b")); assertThat(redis.zrangeWithScores(key, 0, -1)).isEqualTo(svlist(sv(3.0, "a"), sv(4.0, "c"), sv(5.0, "b"))); - assertThat(redis.zunionstore(key, weights(2, 3), "zset1", "zset2")).isEqualTo(3); + assertThat(redis.zunionstore(key, weights(new long[] { 2, 3 }), "zset1", "zset2")).isEqualTo(3); assertThat(redis.zrangeWithScores(key, 0, -1)).isEqualTo(svlist(sv(8.0, "a"), sv(12.0, "c"), sv(13.0, "b"))); assertThat(redis.zunionstore(key, weights(2, 3).sum(), "zset1", "zset2")).isEqualTo(3); @@ -493,7 +492,7 @@ public void zStoreArgs() throws Exception { assertThat(redis.zinterstore(key, max(), "zset1", "zset2")).isEqualTo(2); assertThat(redis.zrangeWithScores(key, 0, -1)).isEqualTo(svlist(sv(2.0, "a"), sv(3.0, "b"))); - assertThat(redis.zinterstore(key, weights(2, 3), "zset1", "zset2")).isEqualTo(2); + assertThat(redis.zinterstore(key, weights(new long[] { 2, 3 }), "zset1", "zset2")).isEqualTo(2); assertThat(redis.zrangeWithScores(key, 0, -1)).isEqualTo(svlist(sv(8.0, "a"), sv(13.0, "b"))); assertThat(redis.zinterstore(key, weights(2, 3).sum(), "zset1", "zset2")).isEqualTo(2); From 544c0452054a21415dda2309c9b88fff109bfaa9 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Thu, 29 Sep 2016 14:58:47 +0200 Subject: [PATCH 037/808] Add support for ZREVRANGEBYLEX command #369 --- .../redis/AbstractRedisAsyncCommands.java | 10 ++++ .../redis/AbstractRedisReactiveCommands.java | 10 ++++ .../redis/RedisCommandBuilder.java | 48 ++++++++++++------- .../async/RedisSortedSetAsyncCommands.java | 29 +++++++++-- .../RedisSortedSetReactiveCommands.java | 29 +++++++++-- .../api/sync/RedisSortedSetCommands.java | 29 +++++++++-- .../redis/cluster/ReadOnlyCommands.java | 4 +- .../NodeSelectionSortedSetAsyncCommands.java | 29 +++++++++-- .../sync/NodeSelectionSortedSetCommands.java | 29 +++++++++-- .../redis/masterslave/ReadOnlyCommands.java | 4 +- .../redis/protocol/CommandType.java | 2 +- .../redis/api/RedisSortedSetCommands.java | 29 +++++++++-- .../redis/cluster/ReadOnlyCommandsTest.java | 2 +- .../redis/commands/SortedSetCommandTest.java | 15 +++++- 14 files changed, 219 insertions(+), 50 deletions(-) diff --git a/src/main/java/com/lambdaworks/redis/AbstractRedisAsyncCommands.java b/src/main/java/com/lambdaworks/redis/AbstractRedisAsyncCommands.java index c9278d6097..7fed0dabf7 100644 --- a/src/main/java/com/lambdaworks/redis/AbstractRedisAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/AbstractRedisAsyncCommands.java @@ -1284,6 +1284,16 @@ public RedisFuture>> zrevrangeWithScores(K key, long start, return dispatch(commandBuilder.zrevrangeWithScores(key, start, stop)); } + @Override + public RedisFuture> zrevrangebylex(K key, Range range) { + return dispatch(commandBuilder.zrevrangebylex(key, range, Limit.unlimited())); + } + + @Override + public RedisFuture> zrevrangebylex(K key, Range range, Limit limit) { + return dispatch(commandBuilder.zrevrangebylex(key, range, limit)); + } + @Override public RedisFuture> zrevrangebyscore(K key, double max, double min) { return dispatch(commandBuilder.zrevrangebyscore(key, max, min)); diff --git a/src/main/java/com/lambdaworks/redis/AbstractRedisReactiveCommands.java b/src/main/java/com/lambdaworks/redis/AbstractRedisReactiveCommands.java index d3408daf64..704bf74645 100644 --- a/src/main/java/com/lambdaworks/redis/AbstractRedisReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/AbstractRedisReactiveCommands.java @@ -1279,6 +1279,16 @@ public Flux> zrevrangeWithScores(K key, long start, long stop) { return createDissolvingFlux(() -> commandBuilder.zrevrangeWithScores(key, start, stop)); } + @Override + public Flux zrevrangebylex(K key, Range range) { + return createDissolvingFlux(() -> commandBuilder.zrevrangebylex(key, range, Limit.unlimited())); + } + + @Override + public Flux zrevrangebylex(K key, Range range, Limit limit) { + return createDissolvingFlux(() -> commandBuilder.zrevrangebylex(key, range, limit)); + } + @Override public Flux zrevrangebyscore(K key, double max, double min) { return createDissolvingFlux(() -> commandBuilder.zrevrangebyscore(key, max, min)); diff --git a/src/main/java/com/lambdaworks/redis/RedisCommandBuilder.java b/src/main/java/com/lambdaworks/redis/RedisCommandBuilder.java index 1c82156a52..af599bd073 100644 --- a/src/main/java/com/lambdaworks/redis/RedisCommandBuilder.java +++ b/src/main/java/com/lambdaworks/redis/RedisCommandBuilder.java @@ -25,15 +25,15 @@ * @param * @author Mark Paluch */ -@SuppressWarnings({"unchecked", "Convert2Diamond", "WeakerAccess", "varargs"}) +@SuppressWarnings({ "unchecked", "Convert2Diamond", "WeakerAccess", "varargs" }) class RedisCommandBuilder extends BaseRedisCommandBuilder { static final String MUST_NOT_CONTAIN_NULL_ELEMENTS = "must not contain null elements"; static final String MUST_NOT_BE_EMPTY = "must not be empty"; static final String MUST_NOT_BE_NULL = "must not be null"; - private static final byte[] MINUS_BYTES = {'-'}; - private static final byte[] PLUS_BYTES = {'+'}; + private static final byte[] MINUS_BYTES = { '-' }; + private static final byte[] PLUS_BYTES = { '+' }; public RedisCommandBuilder(RedisCodec codec) { super(codec); @@ -1059,7 +1059,6 @@ public Command rpushx(K key, V... values) { return createCommand(RPUSHX, new IntegerOutput(codec), args); } - public Command sadd(K key, V... members) { notNullKey(key); LettuceAssert.notNull(members, "Members " + MUST_NOT_BE_NULL); @@ -1599,7 +1598,7 @@ public Command> zrangebyscore(K key, Range range CommandArgs args = new CommandArgs(codec); args.addKey(key).add(min(range)).add(max(range)); - if(limit.isLimited()) { + if (limit.isLimited()) { args.add(LIMIT).add(limit.getOffset()).add(limit.getCount()); } return createCommand(ZRANGEBYSCORE, new ValueListOutput(codec), args); @@ -1684,7 +1683,8 @@ public Command zrangebyscore(ValueStreamingChannel channel, K key return createCommand(ZRANGEBYSCORE, new ValueStreamingOutput(codec, channel), args); } - public Command zrangebyscore(ValueStreamingChannel channel, K key, Range range, Limit limit) { + public Command zrangebyscore(ValueStreamingChannel channel, K key, Range range, + Limit limit) { notNullKey(key); notNullRange(range); notNullLimit(limit); @@ -1725,7 +1725,8 @@ public Command zrangebyscoreWithScores(ScoredValueStreamingChannel(codec, channel), args); } - public Command zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, Range range, Limit limit) { + public Command zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, + Range range, Limit limit) { notNullKey(key); notNullRange(range); notNullLimit(limit); @@ -1784,6 +1785,16 @@ public Command> zrevrange(K key, long start, long stop) { return createCommand(ZREVRANGE, new ValueListOutput(codec), args); } + public Command> zrevrangebylex(K key, Range range, Limit limit) { + notNullKey(key); + notNullRange(range); + notNullLimit(limit); + + CommandArgs args = new CommandArgs(codec); + addLimit(args.addKey(key).add(maxValue(range)).add(minValue(range)), limit); + return createCommand(ZREVRANGEBYLEX, new ValueListOutput(codec), args); + } + public Command>> zrevrangeWithScores(K key, long start, long stop) { notNullKey(key); @@ -1911,7 +1922,8 @@ public Command zrevrangebyscore(ValueStreamingChannel channel, K return createCommand(ZREVRANGEBYSCORE, new ValueStreamingOutput(codec, channel), args); } - public Command zrevrangebyscore(ValueStreamingChannel channel, K key, Range range, Limit limit) { + public Command zrevrangebyscore(ValueStreamingChannel channel, K key, Range range, + Limit limit) { notNullKey(key); notNullRange(range); notNullLimit(limit); @@ -1958,8 +1970,8 @@ public Command zrevrangebyscoreWithScores(ScoredValueStreamingChanne return createCommand(ZREVRANGEBYSCORE, new ScoredValueStreamingOutput(codec, channel), args); } - public Command zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, Range range, - Limit limit) { + public Command zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, + Range range, Limit limit) { notNullKey(key); notNullRange(range); notNullLimit(limit); @@ -2760,7 +2772,7 @@ private void notEmptySlots(int[] slots) { private void addLimit(CommandArgs args, Limit limit) { - if(limit.isLimited()){ + if (limit.isLimited()) { args.add(LIMIT).add(limit.getOffset()).add(limit.getCount()); } } @@ -2769,11 +2781,12 @@ private String min(Range range) { Range.Boundary lower = range.getLower(); - if(lower.getValue() == null || lower.getValue() instanceof Double && lower.getValue().doubleValue() == Double.NEGATIVE_INFINITY){ + if (lower.getValue() == null + || lower.getValue() instanceof Double && lower.getValue().doubleValue() == Double.NEGATIVE_INFINITY) { return "-inf"; } - if(!lower.isIncluding()){ + if (!lower.isIncluding()) { return "(" + lower.getValue(); } @@ -2784,11 +2797,12 @@ private String max(Range range) { Range.Boundary upper = range.getUpper(); - if(upper.getValue() == null || upper.getValue() instanceof Double && upper.getValue().doubleValue() == Double.POSITIVE_INFINITY){ + if (upper.getValue() == null + || upper.getValue() instanceof Double && upper.getValue().doubleValue() == Double.POSITIVE_INFINITY) { return "+inf"; } - if(!upper.isIncluding()){ + if (!upper.isIncluding()) { return "(" + upper.getValue(); } @@ -2799,7 +2813,7 @@ private byte[] minValue(Range range) { Range.Boundary lower = range.getLower(); - if(lower.getValue() == null){ + if (lower.getValue() == null) { return MINUS_BYTES; } @@ -2814,7 +2828,7 @@ private byte[] maxValue(Range range) { Range.Boundary upper = range.getUpper(); - if(upper.getValue() == null){ + if (upper.getValue() == null) { return PLUS_BYTES; } diff --git a/src/main/java/com/lambdaworks/redis/api/async/RedisSortedSetAsyncCommands.java b/src/main/java/com/lambdaworks/redis/api/async/RedisSortedSetAsyncCommands.java index 4aebb7a0d5..046b57fb54 100644 --- a/src/main/java/com/lambdaworks/redis/api/async/RedisSortedSetAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/async/RedisSortedSetAsyncCommands.java @@ -631,6 +631,27 @@ public interface RedisSortedSetAsyncCommands { */ RedisFuture>> zrevrangeWithScores(K key, long start, long stop); + /** + * Return a range of members in a sorted set, by lexicographical range ordered from high to low. + * + * @param key the key + * @param range the range + * @return List<V> array-reply list of elements in the specified score range. + * @since 4.3 + */ + RedisFuture> zrevrangebylex(K key, Range range); + + /** + * Return a range of members in a sorted set, by lexicographical range ordered from high to low. + * + * @param key the key + * @param range the range + * @param limit the limit + * @return List<V> array-reply list of elements in the specified score range. + * @since 4.3 + */ + RedisFuture> zrevrangebylex(K key, Range range, Limit limit); + /** * Return a range of members in a sorted set, by score, with scores ordered from high to low. * @@ -1121,7 +1142,7 @@ public interface RedisSortedSetAsyncCommands { * @param key the key * @param min min score * @param max max score - * @return List<V> array-reply list of elements in the specified score range. + * @return List<V> array-reply list of elements in the specified range. * @deprecated Use {@link #zrangebylex(java.lang.Object, Range)} */ @Deprecated @@ -1132,7 +1153,7 @@ public interface RedisSortedSetAsyncCommands { * * @param key the key * @param range the range - * @return List<V> array-reply list of elements in the specified score range. + * @return List<V> array-reply list of elements in the specified range. * @since 4.3 */ RedisFuture> zrangebylex(K key, Range range); @@ -1145,7 +1166,7 @@ public interface RedisSortedSetAsyncCommands { * @param max max score * @param offset the offset * @param count the count - * @return List<V> array-reply list of elements in the specified score range. + * @return List<V> array-reply list of elements in the specified range. * @deprecated Use {@link #zrangebylex(java.lang.Object, Range)} */ @Deprecated @@ -1157,7 +1178,7 @@ public interface RedisSortedSetAsyncCommands { * @param key the key * @param range the range * @param limit the limit - * @return List<V> array-reply list of elements in the specified score range. + * @return List<V> array-reply list of elements in the specified range. * @since 4.3 */ RedisFuture> zrangebylex(K key, Range range, Limit limit); diff --git a/src/main/java/com/lambdaworks/redis/api/reactive/RedisSortedSetReactiveCommands.java b/src/main/java/com/lambdaworks/redis/api/reactive/RedisSortedSetReactiveCommands.java index 4e5a31658d..7e9e988890 100644 --- a/src/main/java/com/lambdaworks/redis/api/reactive/RedisSortedSetReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/reactive/RedisSortedSetReactiveCommands.java @@ -632,6 +632,27 @@ public interface RedisSortedSetReactiveCommands { */ Flux> zrevrangeWithScores(K key, long start, long stop); + /** + * Return a range of members in a sorted set, by lexicographical range ordered from high to low. + * + * @param key the key + * @param range the range + * @return V array-reply list of elements in the specified score range. + * @since 4.3 + */ + Flux zrevrangebylex(K key, Range range); + + /** + * Return a range of members in a sorted set, by lexicographical range ordered from high to low. + * + * @param key the key + * @param range the range + * @param limit the limit + * @return V array-reply list of elements in the specified score range. + * @since 4.3 + */ + Flux zrevrangebylex(K key, Range range, Limit limit); + /** * Return a range of members in a sorted set, by score, with scores ordered from high to low. * @@ -1122,7 +1143,7 @@ public interface RedisSortedSetReactiveCommands { * @param key the key * @param min min score * @param max max score - * @return V array-reply list of elements in the specified score range. + * @return V array-reply list of elements in the specified range. * @deprecated Use {@link #zrangebylex(java.lang.Object, Range)} */ @Deprecated @@ -1133,7 +1154,7 @@ public interface RedisSortedSetReactiveCommands { * * @param key the key * @param range the range - * @return V array-reply list of elements in the specified score range. + * @return V array-reply list of elements in the specified range. * @since 4.3 */ Flux zrangebylex(K key, Range range); @@ -1146,7 +1167,7 @@ public interface RedisSortedSetReactiveCommands { * @param max max score * @param offset the offset * @param count the count - * @return V array-reply list of elements in the specified score range. + * @return V array-reply list of elements in the specified range. * @deprecated Use {@link #zrangebylex(java.lang.Object, Range)} */ @Deprecated @@ -1158,7 +1179,7 @@ public interface RedisSortedSetReactiveCommands { * @param key the key * @param range the range * @param limit the limit - * @return V array-reply list of elements in the specified score range. + * @return V array-reply list of elements in the specified range. * @since 4.3 */ Flux zrangebylex(K key, Range range, Limit limit); diff --git a/src/main/java/com/lambdaworks/redis/api/sync/RedisSortedSetCommands.java b/src/main/java/com/lambdaworks/redis/api/sync/RedisSortedSetCommands.java index 96d966a1a4..b40b2d8dcc 100644 --- a/src/main/java/com/lambdaworks/redis/api/sync/RedisSortedSetCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/sync/RedisSortedSetCommands.java @@ -630,6 +630,27 @@ public interface RedisSortedSetCommands { */ List> zrevrangeWithScores(K key, long start, long stop); + /** + * Return a range of members in a sorted set, by lexicographical range ordered from high to low. + * + * @param key the key + * @param range the range + * @return List<V> array-reply list of elements in the specified score range. + * @since 4.3 + */ + List zrevrangebylex(K key, Range range); + + /** + * Return a range of members in a sorted set, by lexicographical range ordered from high to low. + * + * @param key the key + * @param range the range + * @param limit the limit + * @return List<V> array-reply list of elements in the specified score range. + * @since 4.3 + */ + List zrevrangebylex(K key, Range range, Limit limit); + /** * Return a range of members in a sorted set, by score, with scores ordered from high to low. * @@ -1120,7 +1141,7 @@ public interface RedisSortedSetCommands { * @param key the key * @param min min score * @param max max score - * @return List<V> array-reply list of elements in the specified score range. + * @return List<V> array-reply list of elements in the specified range. * @deprecated Use {@link #zrangebylex(java.lang.Object, Range)} */ @Deprecated @@ -1131,7 +1152,7 @@ public interface RedisSortedSetCommands { * * @param key the key * @param range the range - * @return List<V> array-reply list of elements in the specified score range. + * @return List<V> array-reply list of elements in the specified range. * @since 4.3 */ List zrangebylex(K key, Range range); @@ -1144,7 +1165,7 @@ public interface RedisSortedSetCommands { * @param max max score * @param offset the offset * @param count the count - * @return List<V> array-reply list of elements in the specified score range. + * @return List<V> array-reply list of elements in the specified range. * @deprecated Use {@link #zrangebylex(java.lang.Object, Range)} */ @Deprecated @@ -1156,7 +1177,7 @@ public interface RedisSortedSetCommands { * @param key the key * @param range the range * @param limit the limit - * @return List<V> array-reply list of elements in the specified score range. + * @return List<V> array-reply list of elements in the specified range. * @since 4.3 */ List zrangebylex(K key, Range range, Limit limit); diff --git a/src/main/java/com/lambdaworks/redis/cluster/ReadOnlyCommands.java b/src/main/java/com/lambdaworks/redis/cluster/ReadOnlyCommands.java index b11515a47a..92d5a2ad8e 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/ReadOnlyCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/ReadOnlyCommands.java @@ -34,11 +34,9 @@ enum CommandName { RANDOMKEY, READWRITE, SCAN, SCARD, SCRIPT, // SDIFF, SINTER, SISMEMBER, SMEMBERS, SRANDMEMBER, SSCAN, STRLEN, // SUNION, TIME, TTL, TYPE, WAIT, ZCARD, ZCOUNT, ZLEXCOUNT, ZRANGE, // - ZRANGEBYLEX, ZRANGEBYSCORE, ZRANK, ZREVRANGE, /* ZREVRANGEBYLEX , */ZREVRANGEBYSCORE, ZREVRANK, ZSCAN, ZSCORE, // + ZRANGEBYLEX, ZRANGEBYSCORE, ZRANK, ZREVRANGE, ZREVRANGEBYLEX, ZREVRANGEBYSCORE, ZREVRANK, ZSCAN, ZSCORE, // // Pub/Sub commands are no key-space commands so they are safe to execute on slave nodes PUBLISH, PUBSUB, PSUBSCRIBE, PUNSUBSCRIBE, SUBSCRIBE, UNSUBSCRIBE - } - } diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionSortedSetAsyncCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionSortedSetAsyncCommands.java index 8da750bf81..2d5b1ff749 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionSortedSetAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionSortedSetAsyncCommands.java @@ -631,6 +631,27 @@ public interface NodeSelectionSortedSetAsyncCommands { */ AsyncExecutions>> zrevrangeWithScores(K key, long start, long stop); + /** + * Return a range of members in a sorted set, by lexicographical range ordered from high to low. + * + * @param key the key + * @param range the range + * @return List<V> array-reply list of elements in the specified score range. + * @since 4.3 + */ + AsyncExecutions> zrevrangebylex(K key, Range range); + + /** + * Return a range of members in a sorted set, by lexicographical range ordered from high to low. + * + * @param key the key + * @param range the range + * @param limit the limit + * @return List<V> array-reply list of elements in the specified score range. + * @since 4.3 + */ + AsyncExecutions> zrevrangebylex(K key, Range range, Limit limit); + /** * Return a range of members in a sorted set, by score, with scores ordered from high to low. * @@ -1121,7 +1142,7 @@ public interface NodeSelectionSortedSetAsyncCommands { * @param key the key * @param min min score * @param max max score - * @return List<V> array-reply list of elements in the specified score range. + * @return List<V> array-reply list of elements in the specified range. * @deprecated Use {@link #zrangebylex(java.lang.Object, Range)} */ @Deprecated @@ -1132,7 +1153,7 @@ public interface NodeSelectionSortedSetAsyncCommands { * * @param key the key * @param range the range - * @return List<V> array-reply list of elements in the specified score range. + * @return List<V> array-reply list of elements in the specified range. * @since 4.3 */ AsyncExecutions> zrangebylex(K key, Range range); @@ -1145,7 +1166,7 @@ public interface NodeSelectionSortedSetAsyncCommands { * @param max max score * @param offset the offset * @param count the count - * @return List<V> array-reply list of elements in the specified score range. + * @return List<V> array-reply list of elements in the specified range. * @deprecated Use {@link #zrangebylex(java.lang.Object, Range)} */ @Deprecated @@ -1157,7 +1178,7 @@ public interface NodeSelectionSortedSetAsyncCommands { * @param key the key * @param range the range * @param limit the limit - * @return List<V> array-reply list of elements in the specified score range. + * @return List<V> array-reply list of elements in the specified range. * @since 4.3 */ AsyncExecutions> zrangebylex(K key, Range range, Limit limit); diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionSortedSetCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionSortedSetCommands.java index 2768ed7098..0fb61752cd 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionSortedSetCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionSortedSetCommands.java @@ -630,6 +630,27 @@ public interface NodeSelectionSortedSetCommands { */ Executions>> zrevrangeWithScores(K key, long start, long stop); + /** + * Return a range of members in a sorted set, by lexicographical range ordered from high to low. + * + * @param key the key + * @param range the range + * @return List<V> array-reply list of elements in the specified score range. + * @since 4.3 + */ + Executions> zrevrangebylex(K key, Range range); + + /** + * Return a range of members in a sorted set, by lexicographical range ordered from high to low. + * + * @param key the key + * @param range the range + * @param limit the limit + * @return List<V> array-reply list of elements in the specified score range. + * @since 4.3 + */ + Executions> zrevrangebylex(K key, Range range, Limit limit); + /** * Return a range of members in a sorted set, by score, with scores ordered from high to low. * @@ -1120,7 +1141,7 @@ public interface NodeSelectionSortedSetCommands { * @param key the key * @param min min score * @param max max score - * @return List<V> array-reply list of elements in the specified score range. + * @return List<V> array-reply list of elements in the specified range. * @deprecated Use {@link #zrangebylex(java.lang.Object, Range)} */ @Deprecated @@ -1131,7 +1152,7 @@ public interface NodeSelectionSortedSetCommands { * * @param key the key * @param range the range - * @return List<V> array-reply list of elements in the specified score range. + * @return List<V> array-reply list of elements in the specified range. * @since 4.3 */ Executions> zrangebylex(K key, Range range); @@ -1144,7 +1165,7 @@ public interface NodeSelectionSortedSetCommands { * @param max max score * @param offset the offset * @param count the count - * @return List<V> array-reply list of elements in the specified score range. + * @return List<V> array-reply list of elements in the specified range. * @deprecated Use {@link #zrangebylex(java.lang.Object, Range)} */ @Deprecated @@ -1156,7 +1177,7 @@ public interface NodeSelectionSortedSetCommands { * @param key the key * @param range the range * @param limit the limit - * @return List<V> array-reply list of elements in the specified score range. + * @return List<V> array-reply list of elements in the specified range. * @since 4.3 */ Executions> zrangebylex(K key, Range range, Limit limit); diff --git a/src/main/java/com/lambdaworks/redis/masterslave/ReadOnlyCommands.java b/src/main/java/com/lambdaworks/redis/masterslave/ReadOnlyCommands.java index 791660ea90..a1ffbe5fc4 100644 --- a/src/main/java/com/lambdaworks/redis/masterslave/ReadOnlyCommands.java +++ b/src/main/java/com/lambdaworks/redis/masterslave/ReadOnlyCommands.java @@ -34,8 +34,6 @@ enum CommandName { /**/RANDOMKEY, READWRITE, SCAN, SCARD, SCRIPT, /**/SDIFF, SINTER, SISMEMBER, SMEMBERS, SRANDMEMBER, SSCAN, STRLEN, /**/SUNION, TIME, TTL, TYPE, WAIT, ZCARD, ZCOUNT, ZLEXCOUNT, ZRANGE, - /**/ZRANGEBYLEX, ZRANGEBYSCORE, ZRANK, ZREVRANGE, /* ZREVRANGEBYLEX , */ZREVRANGEBYSCORE, ZREVRANK, ZSCAN, ZSCORE, - + /**/ZRANGEBYLEX, ZRANGEBYSCORE, ZRANK, ZREVRANGE, ZREVRANGEBYLEX, ZREVRANGEBYSCORE, ZREVRANK, ZSCAN, ZSCORE, } - } diff --git a/src/main/java/com/lambdaworks/redis/protocol/CommandType.java b/src/main/java/com/lambdaworks/redis/protocol/CommandType.java index 90ffebafc0..77e76f8c94 100644 --- a/src/main/java/com/lambdaworks/redis/protocol/CommandType.java +++ b/src/main/java/com/lambdaworks/redis/protocol/CommandType.java @@ -54,7 +54,7 @@ public enum CommandType implements ProtocolKeyword { // Sorted Set - ZADD, ZCARD, ZCOUNT, ZINCRBY, ZINTERSTORE, ZRANGE, ZRANGEBYSCORE, ZRANK, ZREM, ZREMRANGEBYRANK, ZREMRANGEBYSCORE, ZREVRANGE, ZREVRANGEBYSCORE, ZREVRANK, ZSCORE, ZUNIONSTORE, ZSCAN, ZLEXCOUNT, ZREMRANGEBYLEX, ZRANGEBYLEX, + ZADD, ZCARD, ZCOUNT, ZINCRBY, ZINTERSTORE, ZRANGE, ZRANGEBYSCORE, ZRANK, ZREM, ZREMRANGEBYRANK, ZREMRANGEBYSCORE, ZREVRANGE, ZREVRANGEBYLEX, ZREVRANGEBYSCORE, ZREVRANK, ZSCORE, ZUNIONSTORE, ZSCAN, ZLEXCOUNT, ZREMRANGEBYLEX, ZRANGEBYLEX, // Scripting diff --git a/src/main/templates/com/lambdaworks/redis/api/RedisSortedSetCommands.java b/src/main/templates/com/lambdaworks/redis/api/RedisSortedSetCommands.java index 20b571778c..fe674fdcfc 100644 --- a/src/main/templates/com/lambdaworks/redis/api/RedisSortedSetCommands.java +++ b/src/main/templates/com/lambdaworks/redis/api/RedisSortedSetCommands.java @@ -632,6 +632,27 @@ Long zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, Stri */ List> zrevrangeWithScores(K key, long start, long stop); + /** + * Return a range of members in a sorted set, by lexicographical range ordered from high to low. + * + * @param key the key + * @param range the range + * @return List<V> array-reply list of elements in the specified score range. + * @since 4.3 + */ + List zrevrangebylex(K key, Range range); + + /** + * Return a range of members in a sorted set, by lexicographical range ordered from high to low. + * + * @param key the key + * @param range the range + * @param limit the limit + * @return List<V> array-reply list of elements in the specified score range. + * @since 4.3 + */ + List zrevrangebylex(K key, Range range, Limit limit); + /** * Return a range of members in a sorted set, by score, with scores ordered from high to low. * @@ -1124,7 +1145,7 @@ Long zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, S * @param key the key * @param min min score * @param max max score - * @return List<V> array-reply list of elements in the specified score range. + * @return List<V> array-reply list of elements in the specified range. * @deprecated Use {@link #zrangebylex(java.lang.Object, Range)} */ @Deprecated @@ -1135,7 +1156,7 @@ Long zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, S * * @param key the key * @param range the range - * @return List<V> array-reply list of elements in the specified score range. + * @return List<V> array-reply list of elements in the specified range. * @since 4.3 */ List zrangebylex(K key, Range range); @@ -1148,7 +1169,7 @@ Long zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, S * @param max max score * @param offset the offset * @param count the count - * @return List<V> array-reply list of elements in the specified score range. + * @return List<V> array-reply list of elements in the specified range. * @deprecated Use {@link #zrangebylex(java.lang.Object, Range)} */ @Deprecated @@ -1160,7 +1181,7 @@ Long zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, S * @param key the key * @param range the range * @param limit the limit - * @return List<V> array-reply list of elements in the specified score range. + * @return List<V> array-reply list of elements in the specified range. * @since 4.3 */ List zrangebylex(K key, Range range, Limit limit); diff --git a/src/test/java/com/lambdaworks/redis/cluster/ReadOnlyCommandsTest.java b/src/test/java/com/lambdaworks/redis/cluster/ReadOnlyCommandsTest.java index bd9f16c5db..2922439042 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/ReadOnlyCommandsTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/ReadOnlyCommandsTest.java @@ -13,7 +13,7 @@ public class ReadOnlyCommandsTest { @Test public void testCount() throws Exception { - assertThat(ReadOnlyCommands.READ_ONLY_COMMANDS).hasSize(71); + assertThat(ReadOnlyCommands.READ_ONLY_COMMANDS).hasSize(72); } @Test diff --git a/src/test/java/com/lambdaworks/redis/commands/SortedSetCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/SortedSetCommandTest.java index b17e040050..08f08b53c7 100644 --- a/src/test/java/com/lambdaworks/redis/commands/SortedSetCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/SortedSetCommandTest.java @@ -30,7 +30,7 @@ public void zadd() throws Exception { assertThat(redis.zadd(key, 2.0, "b", 3.0, "c")).isEqualTo(2); assertThat(redis.zrange(key, 0, -1)).isEqualTo(list("a", "b", "c")); } - + @Test public void zaddScoredValue() throws Exception { assertThat(redis.zadd(key, ScoredValue.fromNullable(1.0, "a"))).isEqualTo(1); @@ -356,6 +356,18 @@ public void zrevrangeWithScoresStreaming() throws Exception { assertThat(streamingAdapter.getList()).isEqualTo(svlist(sv(3.0, "c"), sv(2.0, "b"), sv(1.0, "a"))); } + @Test + public void zrevrangebylex() throws Exception { + + setup100KeyValues(new HashSet<>()); + + assertThat(redis.zrevrangebylex(key, Range.unbounded())).hasSize(100); + assertThat(redis.zrevrangebylex(key, Range.create("value", "zzz"))).hasSize(100); + assertThat(redis.zrevrangebylex(key, Range.from(Boundary.including("value98"), Boundary.including("value99")))).containsSequence("value99", "value98"); + assertThat(redis.zrevrangebylex(key, Range.from(Boundary.including("value99"), Boundary.unbounded()))).hasSize(1); + assertThat(redis.zrevrangebylex(key, Range.from(Boundary.excluding("value99"), Boundary.unbounded()))).hasSize(0); + } + @Test public void zrevrangebyscore() throws Exception { @@ -640,6 +652,7 @@ public void zrangebylex() throws Exception { assertThat(redis.zrangebylex(key, Range.unbounded())).hasSize(100); assertThat(redis.zrangebylex(key, Range.create("value", "zzz"))).hasSize(100); + assertThat(redis.zrangebylex(key, Range.from(Boundary.including("value98"), Boundary.including("value99")))).containsSequence("value98", "value99"); assertThat(redis.zrangebylex(key, Range.from(Boundary.including("value99"), Boundary.unbounded()))).hasSize(1); assertThat(redis.zrangebylex(key, Range.from(Boundary.excluding("value99"), Boundary.unbounded()))).hasSize(0); } From 372ad6814f304c91ab1ba380d8d1da34c9b918cf Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Thu, 29 Sep 2016 15:30:41 +0200 Subject: [PATCH 038/808] Polishing Order sorted set methods alphabetically. Fix typos. Rename API generator entrypoint to GenerateCommandInterfaces. --- .../async/RedisSortedSetAsyncCommands.java | 600 +++++++++--------- .../RedisSortedSetReactiveCommands.java | 600 +++++++++--------- .../api/sync/RedisSortedSetCommands.java | 600 +++++++++--------- .../NodeSelectionSortedSetAsyncCommands.java | 600 +++++++++--------- .../sync/NodeSelectionSortedSetCommands.java | 600 +++++++++--------- .../redis/masterslave/ReadOnlyCommands.java | 16 +- .../redis/api/RedisSortedSetCommands.java | 600 +++++++++--------- .../lambdaworks/apigenerator/Constants.java | 3 +- .../apigenerator/CreateAsyncApi.java | 2 +- .../CreateAsyncNodeSelectionClusterApi.java | 2 +- .../apigenerator/CreateSyncApi.java | 2 +- .../CreateSyncNodeSelectionClusterApi.java | 2 +- ...is.java => GenerateCommandInterfaces.java} | 4 +- 13 files changed, 1817 insertions(+), 1814 deletions(-) rename src/test/java/com/lambdaworks/apigenerator/{CreateSyncAsyncRxApis.java => GenerateCommandInterfaces.java} (72%) diff --git a/src/main/java/com/lambdaworks/redis/api/async/RedisSortedSetAsyncCommands.java b/src/main/java/com/lambdaworks/redis/api/async/RedisSortedSetAsyncCommands.java index 046b57fb54..5d86c3ec7a 100644 --- a/src/main/java/com/lambdaworks/redis/api/async/RedisSortedSetAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/async/RedisSortedSetAsyncCommands.java @@ -201,9 +201,31 @@ public interface RedisSortedSetAsyncCommands { */ RedisFuture zinterstore(K destination, ZStoreArgs storeArgs, K... keys); + /** + * Count the number of members in a sorted set between a given lexicographical range. + * + * @param key the key + * @param min min score + * @param max max score + * @return Long integer-reply the number of elements in the specified score range. + * @deprecated Use {@link #zlexcount(java.lang.Object, Range)} + */ + @Deprecated + RedisFuture zlexcount(K key, String min, String max); + + /** + * Count the number of members in a sorted set between a given lexicographical range. + * + * @param key the key + * @param range the range + * @return Long integer-reply the number of elements in the specified score range. + * @since 4.3 + */ + RedisFuture zlexcount(K key, Range range); + /** * Return a range of members in a sorted set, by index. - * + * * @param key the key * @param start the start * @param stop the stop @@ -211,9 +233,20 @@ public interface RedisSortedSetAsyncCommands { */ RedisFuture> zrange(K key, long start, long stop); + /** + * Return a range of members in a sorted set, by index. + * + * @param channel streaming channel that receives a call for every value + * @param key the key + * @param start the start + * @param stop the stop + * @return Long count of elements in the specified range. + */ + RedisFuture zrange(ValueStreamingChannel channel, K key, long start, long stop); + /** * Return a range of members with scores in a sorted set, by index. - * + * * @param key the key * @param start the start * @param stop the stop @@ -221,9 +254,67 @@ public interface RedisSortedSetAsyncCommands { */ RedisFuture>> zrangeWithScores(K key, long start, long stop); + /** + * Stream over a range of members with scores in a sorted set, by index. + * + * @param channel streaming channel that receives a call for every value + * @param key the key + * @param start the start + * @param stop the stop + * @return Long count of elements in the specified range. + */ + RedisFuture zrangeWithScores(ScoredValueStreamingChannel channel, K key, long start, long stop); + + /** + * Return a range of members in a sorted set, by lexicographical range. + * + * @param key the key + * @param min min score + * @param max max score + * @return List<V> array-reply list of elements in the specified range. + * @deprecated Use {@link #zrangebylex(java.lang.Object, Range)} + */ + @Deprecated + RedisFuture> zrangebylex(K key, String min, String max); + + /** + * Return a range of members in a sorted set, by lexicographical range. + * + * @param key the key + * @param range the range + * @return List<V> array-reply list of elements in the specified range. + * @since 4.3 + */ + RedisFuture> zrangebylex(K key, Range range); + + /** + * Return a range of members in a sorted set, by lexicographical range. + * + * @param key the key + * @param min min score + * @param max max score + * @param offset the offset + * @param count the count + * @return List<V> array-reply list of elements in the specified range. + * @deprecated Use {@link #zrangebylex(java.lang.Object, Range)} + */ + @Deprecated + RedisFuture> zrangebylex(K key, String min, String max, long offset, long count); + + /** + * Return a range of members in a sorted set, by lexicographical range. + * + * @param key the key + * @param range the range + * @param limit the limit + * @return List<V> array-reply list of elements in the specified range. + * @since 4.3 + */ + RedisFuture> zrangebylex(K key, Range range, Limit limit); + /** * Return a range of members in a sorted set, by score. - * + * * @param key the key * @param min min score * @param max max score @@ -235,7 +326,7 @@ public interface RedisSortedSetAsyncCommands { /** * Return a range of members in a sorted set, by score. - * + * * @param key the key * @param min min score * @param max max score @@ -257,7 +348,7 @@ public interface RedisSortedSetAsyncCommands { /** * Return a range of members in a sorted set, by score. - * + * * @param key the key * @param min min score * @param max max score @@ -271,7 +362,7 @@ public interface RedisSortedSetAsyncCommands { /** * Return a range of members in a sorted set, by score. - * + * * @param key the key * @param min min score * @param max max score @@ -295,181 +386,159 @@ public interface RedisSortedSetAsyncCommands { RedisFuture> zrangebyscore(K key, Range range, Limit limit); /** - * Return a range of members with score in a sorted set, by score. + * Stream over a range of members in a sorted set, by score. * + * @param channel streaming channel that receives a call for every value * @param key the key * @param min min score * @param max max score - * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. - * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range)} + * @return Long count of elements in the specified score range. + * @deprecated Use {@link #zrangebyscore(ValueStreamingChannel, java.lang.Object, Range)} */ @Deprecated - RedisFuture>> zrangebyscoreWithScores(K key, double min, double max); + RedisFuture zrangebyscore(ValueStreamingChannel channel, K key, double min, double max); /** - * Return a range of members with score in a sorted set, by score. + * Stream over a range of members in a sorted set, by score. * + * @param channel streaming channel that receives a call for every value * @param key the key * @param min min score * @param max max score - * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. - * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range)} + * @return Long count of elements in the specified score range. + * @deprecated Use {@link #zrangebyscore(ValueStreamingChannel, java.lang.Object, Range)} */ @Deprecated - RedisFuture>> zrangebyscoreWithScores(K key, String min, String max); + RedisFuture zrangebyscore(ValueStreamingChannel channel, K key, String min, String max); /** - * Return a range of members with score in a sorted set, by score. + * Stream over a range of members in a sorted set, by score. * + * @param channel streaming channel that receives a call for every value * @param key the key * @param range the range - * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @return Long count of elements in the specified score range. * @since 4.3 */ - RedisFuture>> zrangebyscoreWithScores(K key, Range range); + RedisFuture zrangebyscore(ValueStreamingChannel channel, K key, Range range); /** - * Return a range of members with score in a sorted set, by score. + * Stream over range of members in a sorted set, by score. * + * @param channel streaming channel that receives a call for every value * @param key the key * @param min min score * @param max max score * @param offset the offset * @param count the count - * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. - * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range, Limit limit)} + * @return Long count of elements in the specified score range. + * @deprecated Use {@link #zrangebyscore(ValueStreamingChannel, java.lang.Object, Range, Limit limit)} */ - RedisFuture>> zrangebyscoreWithScores(K key, double min, double max, long offset, long count); + @Deprecated + RedisFuture zrangebyscore(ValueStreamingChannel channel, K key, double min, double max, long offset, long count); /** - * Return a range of members with score in a sorted set, by score. + * Stream over a range of members in a sorted set, by score. * + * @param channel streaming channel that receives a call for every value * @param key the key * @param min min score * @param max max score * @param offset the offset * @param count the count - * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. - * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range, Limit)} + * @return Long count of elements in the specified score range. + * @deprecated Use {@link #zrangebyscore(ValueStreamingChannel, java.lang.Object, Range, Limit limit)} */ @Deprecated - RedisFuture>> zrangebyscoreWithScores(K key, String min, String max, long offset, long count); + RedisFuture zrangebyscore(ValueStreamingChannel channel, K key, String min, String max, long offset, long count); /** - * Return a range of members with score in a sorted set, by score. + * Stream over a range of members in a sorted set, by score. * + * @param channel streaming channel that receives a call for every value * @param key the key * @param range the range * @param limit the limit - * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @return Long count of elements in the specified score range. * @since 4.3 */ - RedisFuture>> zrangebyscoreWithScores(K key, Range range, Limit limit); - - /** - * Return a range of members in a sorted set, by index. - * - * @param channel streaming channel that receives a call for every value - * @param key the key - * @param start the start - * @param stop the stop - * @return Long count of elements in the specified range. - */ - RedisFuture zrange(ValueStreamingChannel channel, K key, long start, long stop); - - /** - * Stream over a range of members with scores in a sorted set, by index. - * - * @param channel streaming channel that receives a call for every value - * @param key the key - * @param start the start - * @param stop the stop - * @return Long count of elements in the specified range. - */ - RedisFuture zrangeWithScores(ScoredValueStreamingChannel channel, K key, long start, long stop); + RedisFuture zrangebyscore(ValueStreamingChannel channel, K key, Range range, Limit limit); /** - * Stream over a range of members in a sorted set, by score. - * - * @param channel streaming channel that receives a call for every value + * Return a range of members with score in a sorted set, by score. + * * @param key the key * @param min min score * @param max max score - * @return Long count of elements in the specified score range. - * @deprecated Use {@link #zrangebyscore(ValueStreamingChannel, java.lang.Object, Range)} + * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range)} */ @Deprecated - RedisFuture zrangebyscore(ValueStreamingChannel channel, K key, double min, double max); + RedisFuture>> zrangebyscoreWithScores(K key, double min, double max); /** - * Stream over a range of members in a sorted set, by score. - * - * @param channel streaming channel that receives a call for every value + * Return a range of members with score in a sorted set, by score. + * * @param key the key * @param min min score * @param max max score - * @return Long count of elements in the specified score range. - * @deprecated Use {@link #zrangebyscore(ValueStreamingChannel, java.lang.Object, Range)} + * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range)} */ @Deprecated - RedisFuture zrangebyscore(ValueStreamingChannel channel, K key, String min, String max); + RedisFuture>> zrangebyscoreWithScores(K key, String min, String max); /** - * Stream over a range of members in a sorted set, by score. + * Return a range of members with score in a sorted set, by score. * - * @param channel streaming channel that receives a call for every value * @param key the key * @param range the range - * @return Long count of elements in the specified score range. + * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. * @since 4.3 */ - RedisFuture zrangebyscore(ValueStreamingChannel channel, K key, Range range); + RedisFuture>> zrangebyscoreWithScores(K key, Range range); /** - * Stream over range of members in a sorted set, by score. - * - * @param channel streaming channel that receives a call for every value + * Return a range of members with score in a sorted set, by score. + * * @param key the key * @param min min score * @param max max score * @param offset the offset * @param count the count - * @return Long count of elements in the specified score range. - * @deprecated Use {@link #zrangebyscore(ValueStreamingChannel, java.lang.Object, Range, Limit limit)} + * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range, Limit limit)} */ - @Deprecated - RedisFuture zrangebyscore(ValueStreamingChannel channel, K key, double min, double max, long offset, long count); + RedisFuture>> zrangebyscoreWithScores(K key, double min, double max, long offset, long count); /** - * Stream over a range of members in a sorted set, by score. - * - * @param channel streaming channel that receives a call for every value + * Return a range of members with score in a sorted set, by score. + * * @param key the key * @param min min score * @param max max score * @param offset the offset * @param count the count - * @return Long count of elements in the specified score range. - * @deprecated Use {@link #zrangebyscore(ValueStreamingChannel, java.lang.Object, Range, Limit limit)} + * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range, Limit)} */ @Deprecated - RedisFuture zrangebyscore(ValueStreamingChannel channel, K key, String min, String max, long offset, long count); + RedisFuture>> zrangebyscoreWithScores(K key, String min, String max, long offset, long count); /** - * Stream over a range of members in a sorted set, by score. + * Return a range of members with score in a sorted set, by score. * - * @param channel streaming channel that receives a call for every value * @param key the key * @param range the range * @param limit the limit - * @return Long count of elements in the specified score range. + * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. * @since 4.3 */ - RedisFuture zrangebyscore(ValueStreamingChannel channel, K key, Range range, Limit limit); + RedisFuture>> zrangebyscoreWithScores(K key, Range range, Limit limit); /** * Stream over a range of members with scores in a sorted set, by score. - * + * * @param channel streaming channel that receives a call for every scored value * @param key the key * @param min min score @@ -482,7 +551,7 @@ public interface RedisSortedSetAsyncCommands { /** * Stream over a range of members with scores in a sorted set, by score. - * + * * @param channel streaming channel that receives a call for every scored value * @param key the key * @param min min score @@ -506,7 +575,7 @@ public interface RedisSortedSetAsyncCommands { /** * Stream over a range of members with scores in a sorted set, by score. - * + * * @param channel streaming channel that receives a call for every scored value * @param key the key * @param min min score @@ -521,7 +590,7 @@ public interface RedisSortedSetAsyncCommands { /** * Stream over a range of members with scores in a sorted set, by score. - * + * * @param channel streaming channel that receives a call for every scored value * @param key the key * @param min min score @@ -548,7 +617,7 @@ public interface RedisSortedSetAsyncCommands { /** * Determine the index of a member in a sorted set. - * + * * @param key the key * @param member the member type: value * @return Long integer-reply the rank of {@code member}. If {@code member} does not exist in the sorted set or {@code key} @@ -558,28 +627,50 @@ public interface RedisSortedSetAsyncCommands { /** * Remove one or more members from a sorted set. - * + * * @param key the key * @param members the member type: value * @return Long integer-reply specifically: - * + * * The number of members removed from the sorted set, not including non existing members. */ RedisFuture zrem(K key, V... members); /** - * Remove all members in a sorted set within the given indexes. - * + * Remove all members in a sorted set between the given lexicographical range. + * * @param key the key - * @param start the start type: long - * @param stop the stop type: long - * @return Long integer-reply the number of elements removed. + * @param min min score + * @param max max score + * @return Long integer-reply the number of elements removed. + * @deprecated Use {@link #zremrangebylex(java.lang.Object, Range)} + */ + @Deprecated + RedisFuture zremrangebylex(K key, String min, String max); + + /** + * Remove all members in a sorted set between the given lexicographical range. + * + * @param key the key + * @param range the range + * @return Long integer-reply the number of elements removed. + * @since 4.3 + */ + RedisFuture zremrangebylex(K key, Range range); + + /** + * Remove all members in a sorted set within the given indexes. + * + * @param key the key + * @param start the start type: long + * @param stop the stop type: long + * @return Long integer-reply the number of elements removed. */ RedisFuture zremrangebyrank(K key, long start, long stop); /** * Remove all members in a sorted set within the given scores. - * + * * @param key the key * @param min min score * @param max max score @@ -591,7 +682,7 @@ public interface RedisSortedSetAsyncCommands { /** * Remove all members in a sorted set within the given scores. - * + * * @param key the key * @param min min score * @param max max score @@ -613,7 +704,7 @@ public interface RedisSortedSetAsyncCommands { /** * Return a range of members in a sorted set, by index, with scores ordered from high to low. - * + * * @param key the key * @param start the start * @param stop the stop @@ -621,9 +712,20 @@ public interface RedisSortedSetAsyncCommands { */ RedisFuture> zrevrange(K key, long start, long stop); + /** + * Stream over a range of members in a sorted set, by index, with scores ordered from high to low. + * + * @param channel streaming channel that receives a call for every scored value + * @param key the key + * @param start the start + * @param stop the stop + * @return Long count of elements in the specified range. + */ + RedisFuture zrevrange(ValueStreamingChannel channel, K key, long start, long stop); + /** * Return a range of members with scores in a sorted set, by index, with scores ordered from high to low. - * + * * @param key the key * @param start the start * @param stop the stop @@ -631,6 +733,17 @@ public interface RedisSortedSetAsyncCommands { */ RedisFuture>> zrevrangeWithScores(K key, long start, long stop); + /** + * Stream over a range of members with scores in a sorted set, by index, with scores ordered from high to low. + * + * @param channel streaming channel that receives a call for every scored value + * @param key the key + * @param start the start + * @param stop the stop + * @return Long count of elements in the specified range. + */ + RedisFuture zrevrangeWithScores(ScoredValueStreamingChannel channel, K key, long start, long stop); + /** * Return a range of members in a sorted set, by lexicographical range ordered from high to low. * @@ -654,7 +767,7 @@ public interface RedisSortedSetAsyncCommands { /** * Return a range of members in a sorted set, by score, with scores ordered from high to low. - * + * * @param key the key * @param min min score * @param max max score @@ -666,7 +779,7 @@ public interface RedisSortedSetAsyncCommands { /** * Return a range of members in a sorted set, by score, with scores ordered from high to low. - * + * * @param key the key * @param min min score * @param max max score @@ -688,7 +801,7 @@ public interface RedisSortedSetAsyncCommands { /** * Return a range of members in a sorted set, by score, with scores ordered from high to low. - * + * * @param key the key * @param max max score * @param min min score @@ -702,7 +815,7 @@ public interface RedisSortedSetAsyncCommands { /** * Return a range of members in a sorted set, by score, with scores ordered from high to low. - * + * * @param key the key * @param max max score * @param min min score @@ -726,182 +839,160 @@ public interface RedisSortedSetAsyncCommands { RedisFuture> zrevrangebyscore(K key, Range range, Limit limit); /** - * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. - * + * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. + * + * @param channel streaming channel that receives a call for every value * @param key the key * @param max max score * @param min min score - * @return List<V> array-reply list of elements in the specified score range. - * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range)} + * @return Long count of elements in the specified range. + * @deprecated Use {@link #zrevrangebyscore(java.lang.Object, Range)} */ @Deprecated - RedisFuture>> zrevrangebyscoreWithScores(K key, double max, double min); + RedisFuture zrevrangebyscore(ValueStreamingChannel channel, K key, double max, double min); /** - * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. - * + * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. + * + * @param channel streaming channel that receives a call for every value * @param key the key - * @param max max score * @param min min score - * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. - * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range)} + * @param max max score + * @return Long count of elements in the specified range. + * @deprecated Use {@link #zrevrangebyscore(java.lang.Object, Range)} */ @Deprecated - RedisFuture>> zrevrangebyscoreWithScores(K key, String max, String min); + RedisFuture zrevrangebyscore(ValueStreamingChannel channel, K key, String max, String min); /** - * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. + * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. * + * @param channel streaming channel that receives a call for every value * @param key the key * @param range the range - * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @return Long count of elements in the specified range. * @since 4.3 */ - RedisFuture>> zrevrangebyscoreWithScores(K key, Range range); + RedisFuture zrevrangebyscore(ValueStreamingChannel channel, K key, Range range); /** - * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. - * + * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. + * + * @param channel streaming channel that receives a call for every value * @param key the key - * @param max max score * @param min min score + * @param max max score * @param offset the offset * @param count the count - * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @return Long count of elements in the specified range. * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range, Limit)} */ @Deprecated - RedisFuture>> zrevrangebyscoreWithScores(K key, double max, double min, long offset, long count); + RedisFuture zrevrangebyscore(ValueStreamingChannel channel, K key, double max, double min, long offset, long count); /** - * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. - * + * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. + * + * @param channel streaming channel that receives a call for every value * @param key the key - * @param max max score * @param min min score + * @param max max score * @param offset the offset * @param count the count - * @return List<V> array-reply list of elements in the specified score range. + * @return Long count of elements in the specified range. * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range, Limit)} */ @Deprecated - RedisFuture>> zrevrangebyscoreWithScores(K key, String max, String min, long offset, long count); + RedisFuture zrevrangebyscore(ValueStreamingChannel channel, K key, String max, String min, long offset, long count); /** - * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. + * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. * + * @param channel streaming channel that receives a call for every value * @param key the key * @param range the range - * @param limit limit - * @return List<V> array-reply list of elements in the specified score range. - * @since 4.3 - */ - RedisFuture>> zrevrangebyscoreWithScores(K key, Range range, Limit limit); - - /** - * Stream over a range of members in a sorted set, by index, with scores ordered from high to low. - * - * @param channel streaming channel that receives a call for every scored value - * @param key the key - * @param start the start - * @param stop the stop - * @return Long count of elements in the specified range. - */ - RedisFuture zrevrange(ValueStreamingChannel channel, K key, long start, long stop); - - /** - * Stream over a range of members with scores in a sorted set, by index, with scores ordered from high to low. - * - * @param channel streaming channel that receives a call for every scored value - * @param key the key - * @param start the start - * @param stop the stop + * @param limit the limit * @return Long count of elements in the specified range. + * @since 4.3 */ - RedisFuture zrevrangeWithScores(ScoredValueStreamingChannel channel, K key, long start, long stop); + RedisFuture zrevrangebyscore(ValueStreamingChannel channel, K key, Range range, Limit limit); /** - * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. - * - * @param channel streaming channel that receives a call for every value + * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. + * * @param key the key * @param max max score * @param min min score - * @return Long count of elements in the specified range. - * @deprecated Use {@link #zrevrangebyscore(java.lang.Object, Range)} + * @return List<V> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range)} */ @Deprecated - RedisFuture zrevrangebyscore(ValueStreamingChannel channel, K key, double max, double min); + RedisFuture>> zrevrangebyscoreWithScores(K key, double max, double min); /** - * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. - * - * @param channel streaming channel that receives a call for every value + * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. + * * @param key the key - * @param min min score * @param max max score - * @return Long count of elements in the specified range. - * @deprecated Use {@link #zrevrangebyscore(java.lang.Object, Range)} + * @param min min score + * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range)} */ @Deprecated - RedisFuture zrevrangebyscore(ValueStreamingChannel channel, K key, String max, String min); + RedisFuture>> zrevrangebyscoreWithScores(K key, String max, String min); /** - * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. + * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. * - * @param channel streaming channel that receives a call for every value * @param key the key * @param range the range - * @return Long count of elements in the specified range. + * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. * @since 4.3 */ - RedisFuture zrevrangebyscore(ValueStreamingChannel channel, K key, Range range); + RedisFuture>> zrevrangebyscoreWithScores(K key, Range range); /** - * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. - * - * @param channel streaming channel that receives a call for every value + * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. + * * @param key the key - * @param min min score * @param max max score + * @param min min score * @param offset the offset * @param count the count - * @return Long count of elements in the specified range. + * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range, Limit)} */ @Deprecated - RedisFuture zrevrangebyscore(ValueStreamingChannel channel, K key, double max, double min, long offset, long count); + RedisFuture>> zrevrangebyscoreWithScores(K key, double max, double min, long offset, long count); /** - * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. - * - * @param channel streaming channel that receives a call for every value + * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. + * * @param key the key - * @param min min score * @param max max score + * @param min min score * @param offset the offset * @param count the count - * @return Long count of elements in the specified range. + * @return List<V> array-reply list of elements in the specified score range. * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range, Limit)} */ @Deprecated - RedisFuture zrevrangebyscore(ValueStreamingChannel channel, K key, String max, String min, long offset, long count); + RedisFuture>> zrevrangebyscoreWithScores(K key, String max, String min, long offset, long count); /** - * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. + * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. * - * @param channel streaming channel that receives a call for every value * @param key the key * @param range the range - * @param limit the limit - * @return Long count of elements in the specified range. + * @param limit limit + * @return List<V> array-reply list of elements in the specified score range. * @since 4.3 */ - RedisFuture zrevrangebyscore(ValueStreamingChannel channel, K key, Range range, Limit limit); + RedisFuture>> zrevrangebyscoreWithScores(K key, Range range, Limit limit); /** * Stream over a range of members with scores in a sorted set, by score, with scores ordered from high to low. - * + * * @param channel streaming channel that receives a call for every scored value * @param key the key * @param min min score @@ -914,7 +1005,7 @@ public interface RedisSortedSetAsyncCommands { /** * Stream over a range of members with scores in a sorted set, by score, with scores ordered from high to low. - * + * * @param channel streaming channel that receives a call for every scored value * @param key the key * @param min min score @@ -937,7 +1028,7 @@ public interface RedisSortedSetAsyncCommands { /** * Stream over a range of members with scores in a sorted set, by score, with scores ordered from high to low. - * + * * @param channel streaming channel that receives a call for every scored value * @param key the key * @param min min score @@ -952,7 +1043,7 @@ public interface RedisSortedSetAsyncCommands { /** * Stream over a range of members with scores in a sorted set, by score, with scores ordered from high to low. - * + * * @param channel streaming channel that receives a call for every scored value * @param key the key * @param min min score @@ -979,7 +1070,7 @@ public interface RedisSortedSetAsyncCommands { /** * Determine the index of a member in a sorted set, with scores ordered from high to low. - * + * * @param key the key * @param member the member type: value * @return Long integer-reply the rank of {@code member}. If {@code member} does not exist in the sorted set or {@code key} @@ -987,35 +1078,6 @@ public interface RedisSortedSetAsyncCommands { */ RedisFuture zrevrank(K key, V member); - /** - * Get the score associated with the given member in a sorted set. - * - * @param key the key - * @param member the member type: value - * @return Double bulk-string-reply the score of {@code member} (a double precision floating point number), represented as - * string. - */ - RedisFuture zscore(K key, V member); - - /** - * Add multiple sorted sets and store the resulting sorted set in a new key. - * - * @param destination destination key - * @param keys source keys - * @return Long integer-reply the number of elements in the resulting sorted set at {@code destination}. - */ - RedisFuture zunionstore(K destination, K... keys); - - /** - * Add multiple sorted sets and store the resulting sorted set in a new key. - * - * @param destination the destination - * @param storeArgs the storeArgs - * @param keys the keys - * @return Long integer-reply the number of elements in the resulting sorted set at {@code destination}. - */ - RedisFuture zunionstore(K destination, ZStoreArgs storeArgs, K... keys); - /** * Incrementally iterate sorted sets elements and associated scores. * @@ -1073,7 +1135,7 @@ public interface RedisSortedSetAsyncCommands { /** * Incrementally iterate sorted sets elements and associated scores. - * + * * @param channel streaming channel that receives a call for every scored value * @param key the key * @param scanCursor cursor to resume from a previous scan, must not be {@literal null} @@ -1093,93 +1155,31 @@ public interface RedisSortedSetAsyncCommands { RedisFuture zscan(ScoredValueStreamingChannel channel, K key, ScanCursor scanCursor); /** - * Count the number of members in a sorted set between a given lexicographical range. - * - * @param key the key - * @param min min score - * @param max max score - * @return Long integer-reply the number of elements in the specified score range. - * @deprecated Use {@link #zlexcount(java.lang.Object, Range)} - */ - @Deprecated - RedisFuture zlexcount(K key, String min, String max); - - /** - * Count the number of members in a sorted set between a given lexicographical range. - * - * @param key the key - * @param range the range - * @return Long integer-reply the number of elements in the specified score range. - * @since 4.3 - */ - RedisFuture zlexcount(K key, Range range); - - /** - * Remove all members in a sorted set between the given lexicographical range. - * - * @param key the key - * @param min min score - * @param max max score - * @return Long integer-reply the number of elements removed. - * @deprecated Use {@link #zremrangebylex(java.lang.Object, Range)} - */ - @Deprecated - RedisFuture zremrangebylex(K key, String min, String max); - - /** - * Remove all members in a sorted set between the given lexicographical range. + * Get the score associated with the given member in a sorted set. * * @param key the key - * @param range the range - * @return Long integer-reply the number of elements removed. - * @since 4.3 - */ - RedisFuture zremrangebylex(K key, Range range); - - /** - * Return a range of members in a sorted set, by lexicographical range. - * - * @param key the key - * @param min min score - * @param max max score - * @return List<V> array-reply list of elements in the specified range. - * @deprecated Use {@link #zrangebylex(java.lang.Object, Range)} + * @param member the member type: value + * @return Double bulk-string-reply the score of {@code member} (a double precision floating point number), represented as + * string. */ - @Deprecated - RedisFuture> zrangebylex(K key, String min, String max); + RedisFuture zscore(K key, V member); /** - * Return a range of members in a sorted set, by lexicographical range. + * Add multiple sorted sets and store the resulting sorted set in a new key. * - * @param key the key - * @param range the range - * @return List<V> array-reply list of elements in the specified range. - * @since 4.3 - */ - RedisFuture> zrangebylex(K key, Range range); - - /** - * Return a range of members in a sorted set, by lexicographical range. - * - * @param key the key - * @param min min score - * @param max max score - * @param offset the offset - * @param count the count - * @return List<V> array-reply list of elements in the specified range. - * @deprecated Use {@link #zrangebylex(java.lang.Object, Range)} + * @param destination destination key + * @param keys source keys + * @return Long integer-reply the number of elements in the resulting sorted set at {@code destination}. */ - @Deprecated - RedisFuture> zrangebylex(K key, String min, String max, long offset, long count); + RedisFuture zunionstore(K destination, K... keys); /** - * Return a range of members in a sorted set, by lexicographical range. + * Add multiple sorted sets and store the resulting sorted set in a new key. * - * @param key the key - * @param range the range - * @param limit the limit - * @return List<V> array-reply list of elements in the specified range. - * @since 4.3 + * @param destination the destination + * @param storeArgs the storeArgs + * @param keys the keys + * @return Long integer-reply the number of elements in the resulting sorted set at {@code destination}. */ - RedisFuture> zrangebylex(K key, Range range, Limit limit); + RedisFuture zunionstore(K destination, ZStoreArgs storeArgs, K... keys); } diff --git a/src/main/java/com/lambdaworks/redis/api/reactive/RedisSortedSetReactiveCommands.java b/src/main/java/com/lambdaworks/redis/api/reactive/RedisSortedSetReactiveCommands.java index 7e9e988890..5867b1a04d 100644 --- a/src/main/java/com/lambdaworks/redis/api/reactive/RedisSortedSetReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/reactive/RedisSortedSetReactiveCommands.java @@ -202,9 +202,31 @@ public interface RedisSortedSetReactiveCommands { */ Mono zinterstore(K destination, ZStoreArgs storeArgs, K... keys); + /** + * Count the number of members in a sorted set between a given lexicographical range. + * + * @param key the key + * @param min min score + * @param max max score + * @return Long integer-reply the number of elements in the specified score range. + * @deprecated Use {@link #zlexcount(java.lang.Object, Range)} + */ + @Deprecated + Mono zlexcount(K key, String min, String max); + + /** + * Count the number of members in a sorted set between a given lexicographical range. + * + * @param key the key + * @param range the range + * @return Long integer-reply the number of elements in the specified score range. + * @since 4.3 + */ + Mono zlexcount(K key, Range range); + /** * Return a range of members in a sorted set, by index. - * + * * @param key the key * @param start the start * @param stop the stop @@ -212,9 +234,20 @@ public interface RedisSortedSetReactiveCommands { */ Flux zrange(K key, long start, long stop); + /** + * Return a range of members in a sorted set, by index. + * + * @param channel streaming channel that receives a call for every value + * @param key the key + * @param start the start + * @param stop the stop + * @return Long count of elements in the specified range. + */ + Mono zrange(ValueStreamingChannel channel, K key, long start, long stop); + /** * Return a range of members with scores in a sorted set, by index. - * + * * @param key the key * @param start the start * @param stop the stop @@ -222,9 +255,67 @@ public interface RedisSortedSetReactiveCommands { */ Flux> zrangeWithScores(K key, long start, long stop); + /** + * Stream over a range of members with scores in a sorted set, by index. + * + * @param channel streaming channel that receives a call for every value + * @param key the key + * @param start the start + * @param stop the stop + * @return Long count of elements in the specified range. + */ + Mono zrangeWithScores(ScoredValueStreamingChannel channel, K key, long start, long stop); + + /** + * Return a range of members in a sorted set, by lexicographical range. + * + * @param key the key + * @param min min score + * @param max max score + * @return V array-reply list of elements in the specified range. + * @deprecated Use {@link #zrangebylex(java.lang.Object, Range)} + */ + @Deprecated + Flux zrangebylex(K key, String min, String max); + + /** + * Return a range of members in a sorted set, by lexicographical range. + * + * @param key the key + * @param range the range + * @return V array-reply list of elements in the specified range. + * @since 4.3 + */ + Flux zrangebylex(K key, Range range); + + /** + * Return a range of members in a sorted set, by lexicographical range. + * + * @param key the key + * @param min min score + * @param max max score + * @param offset the offset + * @param count the count + * @return V array-reply list of elements in the specified range. + * @deprecated Use {@link #zrangebylex(java.lang.Object, Range)} + */ + @Deprecated + Flux zrangebylex(K key, String min, String max, long offset, long count); + + /** + * Return a range of members in a sorted set, by lexicographical range. + * + * @param key the key + * @param range the range + * @param limit the limit + * @return V array-reply list of elements in the specified range. + * @since 4.3 + */ + Flux zrangebylex(K key, Range range, Limit limit); + /** * Return a range of members in a sorted set, by score. - * + * * @param key the key * @param min min score * @param max max score @@ -236,7 +327,7 @@ public interface RedisSortedSetReactiveCommands { /** * Return a range of members in a sorted set, by score. - * + * * @param key the key * @param min min score * @param max max score @@ -258,7 +349,7 @@ public interface RedisSortedSetReactiveCommands { /** * Return a range of members in a sorted set, by score. - * + * * @param key the key * @param min min score * @param max max score @@ -272,7 +363,7 @@ public interface RedisSortedSetReactiveCommands { /** * Return a range of members in a sorted set, by score. - * + * * @param key the key * @param min min score * @param max max score @@ -296,181 +387,159 @@ public interface RedisSortedSetReactiveCommands { Flux zrangebyscore(K key, Range range, Limit limit); /** - * Return a range of members with score in a sorted set, by score. + * Stream over a range of members in a sorted set, by score. * + * @param channel streaming channel that receives a call for every value * @param key the key * @param min min score * @param max max score - * @return ScoredValue<V> array-reply list of elements in the specified score range. - * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range)} + * @return Long count of elements in the specified score range. + * @deprecated Use {@link #zrangebyscore(ValueStreamingChannel, java.lang.Object, Range)} */ @Deprecated - Flux> zrangebyscoreWithScores(K key, double min, double max); + Mono zrangebyscore(ValueStreamingChannel channel, K key, double min, double max); /** - * Return a range of members with score in a sorted set, by score. + * Stream over a range of members in a sorted set, by score. * + * @param channel streaming channel that receives a call for every value * @param key the key * @param min min score * @param max max score - * @return ScoredValue<V> array-reply list of elements in the specified score range. - * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range)} + * @return Long count of elements in the specified score range. + * @deprecated Use {@link #zrangebyscore(ValueStreamingChannel, java.lang.Object, Range)} */ @Deprecated - Flux> zrangebyscoreWithScores(K key, String min, String max); + Mono zrangebyscore(ValueStreamingChannel channel, K key, String min, String max); /** - * Return a range of members with score in a sorted set, by score. + * Stream over a range of members in a sorted set, by score. * + * @param channel streaming channel that receives a call for every value * @param key the key * @param range the range - * @return ScoredValue<V> array-reply list of elements in the specified score range. + * @return Long count of elements in the specified score range. * @since 4.3 */ - Flux> zrangebyscoreWithScores(K key, Range range); + Mono zrangebyscore(ValueStreamingChannel channel, K key, Range range); /** - * Return a range of members with score in a sorted set, by score. + * Stream over range of members in a sorted set, by score. * + * @param channel streaming channel that receives a call for every value * @param key the key * @param min min score * @param max max score * @param offset the offset * @param count the count - * @return ScoredValue<V> array-reply list of elements in the specified score range. - * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range, Limit limit)} + * @return Long count of elements in the specified score range. + * @deprecated Use {@link #zrangebyscore(ValueStreamingChannel, java.lang.Object, Range, Limit limit)} */ - Flux> zrangebyscoreWithScores(K key, double min, double max, long offset, long count); + @Deprecated + Mono zrangebyscore(ValueStreamingChannel channel, K key, double min, double max, long offset, long count); /** - * Return a range of members with score in a sorted set, by score. + * Stream over a range of members in a sorted set, by score. * + * @param channel streaming channel that receives a call for every value * @param key the key * @param min min score * @param max max score * @param offset the offset * @param count the count - * @return ScoredValue<V> array-reply list of elements in the specified score range. - * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range, Limit)} + * @return Long count of elements in the specified score range. + * @deprecated Use {@link #zrangebyscore(ValueStreamingChannel, java.lang.Object, Range, Limit limit)} */ @Deprecated - Flux> zrangebyscoreWithScores(K key, String min, String max, long offset, long count); + Mono zrangebyscore(ValueStreamingChannel channel, K key, String min, String max, long offset, long count); /** - * Return a range of members with score in a sorted set, by score. + * Stream over a range of members in a sorted set, by score. * + * @param channel streaming channel that receives a call for every value * @param key the key * @param range the range * @param limit the limit - * @return ScoredValue<V> array-reply list of elements in the specified score range. + * @return Long count of elements in the specified score range. * @since 4.3 */ - Flux> zrangebyscoreWithScores(K key, Range range, Limit limit); - - /** - * Return a range of members in a sorted set, by index. - * - * @param channel streaming channel that receives a call for every value - * @param key the key - * @param start the start - * @param stop the stop - * @return Long count of elements in the specified range. - */ - Mono zrange(ValueStreamingChannel channel, K key, long start, long stop); - - /** - * Stream over a range of members with scores in a sorted set, by index. - * - * @param channel streaming channel that receives a call for every value - * @param key the key - * @param start the start - * @param stop the stop - * @return Long count of elements in the specified range. - */ - Mono zrangeWithScores(ScoredValueStreamingChannel channel, K key, long start, long stop); + Mono zrangebyscore(ValueStreamingChannel channel, K key, Range range, Limit limit); /** - * Stream over a range of members in a sorted set, by score. - * - * @param channel streaming channel that receives a call for every value + * Return a range of members with score in a sorted set, by score. + * * @param key the key * @param min min score * @param max max score - * @return Long count of elements in the specified score range. - * @deprecated Use {@link #zrangebyscore(ValueStreamingChannel, java.lang.Object, Range)} + * @return ScoredValue<V> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range)} */ @Deprecated - Mono zrangebyscore(ValueStreamingChannel channel, K key, double min, double max); + Flux> zrangebyscoreWithScores(K key, double min, double max); /** - * Stream over a range of members in a sorted set, by score. - * - * @param channel streaming channel that receives a call for every value + * Return a range of members with score in a sorted set, by score. + * * @param key the key * @param min min score * @param max max score - * @return Long count of elements in the specified score range. - * @deprecated Use {@link #zrangebyscore(ValueStreamingChannel, java.lang.Object, Range)} + * @return ScoredValue<V> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range)} */ @Deprecated - Mono zrangebyscore(ValueStreamingChannel channel, K key, String min, String max); + Flux> zrangebyscoreWithScores(K key, String min, String max); /** - * Stream over a range of members in a sorted set, by score. + * Return a range of members with score in a sorted set, by score. * - * @param channel streaming channel that receives a call for every value * @param key the key * @param range the range - * @return Long count of elements in the specified score range. + * @return ScoredValue<V> array-reply list of elements in the specified score range. * @since 4.3 */ - Mono zrangebyscore(ValueStreamingChannel channel, K key, Range range); + Flux> zrangebyscoreWithScores(K key, Range range); /** - * Stream over range of members in a sorted set, by score. - * - * @param channel streaming channel that receives a call for every value + * Return a range of members with score in a sorted set, by score. + * * @param key the key * @param min min score * @param max max score * @param offset the offset * @param count the count - * @return Long count of elements in the specified score range. - * @deprecated Use {@link #zrangebyscore(ValueStreamingChannel, java.lang.Object, Range, Limit limit)} + * @return ScoredValue<V> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range, Limit limit)} */ - @Deprecated - Mono zrangebyscore(ValueStreamingChannel channel, K key, double min, double max, long offset, long count); + Flux> zrangebyscoreWithScores(K key, double min, double max, long offset, long count); /** - * Stream over a range of members in a sorted set, by score. - * - * @param channel streaming channel that receives a call for every value + * Return a range of members with score in a sorted set, by score. + * * @param key the key * @param min min score * @param max max score * @param offset the offset * @param count the count - * @return Long count of elements in the specified score range. - * @deprecated Use {@link #zrangebyscore(ValueStreamingChannel, java.lang.Object, Range, Limit limit)} + * @return ScoredValue<V> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range, Limit)} */ @Deprecated - Mono zrangebyscore(ValueStreamingChannel channel, K key, String min, String max, long offset, long count); + Flux> zrangebyscoreWithScores(K key, String min, String max, long offset, long count); /** - * Stream over a range of members in a sorted set, by score. + * Return a range of members with score in a sorted set, by score. * - * @param channel streaming channel that receives a call for every value * @param key the key * @param range the range * @param limit the limit - * @return Long count of elements in the specified score range. + * @return ScoredValue<V> array-reply list of elements in the specified score range. * @since 4.3 */ - Mono zrangebyscore(ValueStreamingChannel channel, K key, Range range, Limit limit); + Flux> zrangebyscoreWithScores(K key, Range range, Limit limit); /** * Stream over a range of members with scores in a sorted set, by score. - * + * * @param channel streaming channel that receives a call for every scored value * @param key the key * @param min min score @@ -483,7 +552,7 @@ public interface RedisSortedSetReactiveCommands { /** * Stream over a range of members with scores in a sorted set, by score. - * + * * @param channel streaming channel that receives a call for every scored value * @param key the key * @param min min score @@ -507,7 +576,7 @@ public interface RedisSortedSetReactiveCommands { /** * Stream over a range of members with scores in a sorted set, by score. - * + * * @param channel streaming channel that receives a call for every scored value * @param key the key * @param min min score @@ -522,7 +591,7 @@ public interface RedisSortedSetReactiveCommands { /** * Stream over a range of members with scores in a sorted set, by score. - * + * * @param channel streaming channel that receives a call for every scored value * @param key the key * @param min min score @@ -549,7 +618,7 @@ public interface RedisSortedSetReactiveCommands { /** * Determine the index of a member in a sorted set. - * + * * @param key the key * @param member the member type: value * @return Long integer-reply the rank of {@code member}. If {@code member} does not exist in the sorted set or {@code key} @@ -559,28 +628,50 @@ public interface RedisSortedSetReactiveCommands { /** * Remove one or more members from a sorted set. - * + * * @param key the key * @param members the member type: value * @return Long integer-reply specifically: - * + * * The number of members removed from the sorted set, not including non existing members. */ Mono zrem(K key, V... members); /** - * Remove all members in a sorted set within the given indexes. - * + * Remove all members in a sorted set between the given lexicographical range. + * * @param key the key - * @param start the start type: long - * @param stop the stop type: long - * @return Long integer-reply the number of elements removed. + * @param min min score + * @param max max score + * @return Long integer-reply the number of elements removed. + * @deprecated Use {@link #zremrangebylex(java.lang.Object, Range)} + */ + @Deprecated + Mono zremrangebylex(K key, String min, String max); + + /** + * Remove all members in a sorted set between the given lexicographical range. + * + * @param key the key + * @param range the range + * @return Long integer-reply the number of elements removed. + * @since 4.3 + */ + Mono zremrangebylex(K key, Range range); + + /** + * Remove all members in a sorted set within the given indexes. + * + * @param key the key + * @param start the start type: long + * @param stop the stop type: long + * @return Long integer-reply the number of elements removed. */ Mono zremrangebyrank(K key, long start, long stop); /** * Remove all members in a sorted set within the given scores. - * + * * @param key the key * @param min min score * @param max max score @@ -592,7 +683,7 @@ public interface RedisSortedSetReactiveCommands { /** * Remove all members in a sorted set within the given scores. - * + * * @param key the key * @param min min score * @param max max score @@ -614,7 +705,7 @@ public interface RedisSortedSetReactiveCommands { /** * Return a range of members in a sorted set, by index, with scores ordered from high to low. - * + * * @param key the key * @param start the start * @param stop the stop @@ -622,9 +713,20 @@ public interface RedisSortedSetReactiveCommands { */ Flux zrevrange(K key, long start, long stop); + /** + * Stream over a range of members in a sorted set, by index, with scores ordered from high to low. + * + * @param channel streaming channel that receives a call for every scored value + * @param key the key + * @param start the start + * @param stop the stop + * @return Long count of elements in the specified range. + */ + Mono zrevrange(ValueStreamingChannel channel, K key, long start, long stop); + /** * Return a range of members with scores in a sorted set, by index, with scores ordered from high to low. - * + * * @param key the key * @param start the start * @param stop the stop @@ -632,6 +734,17 @@ public interface RedisSortedSetReactiveCommands { */ Flux> zrevrangeWithScores(K key, long start, long stop); + /** + * Stream over a range of members with scores in a sorted set, by index, with scores ordered from high to low. + * + * @param channel streaming channel that receives a call for every scored value + * @param key the key + * @param start the start + * @param stop the stop + * @return Long count of elements in the specified range. + */ + Mono zrevrangeWithScores(ScoredValueStreamingChannel channel, K key, long start, long stop); + /** * Return a range of members in a sorted set, by lexicographical range ordered from high to low. * @@ -655,7 +768,7 @@ public interface RedisSortedSetReactiveCommands { /** * Return a range of members in a sorted set, by score, with scores ordered from high to low. - * + * * @param key the key * @param min min score * @param max max score @@ -667,7 +780,7 @@ public interface RedisSortedSetReactiveCommands { /** * Return a range of members in a sorted set, by score, with scores ordered from high to low. - * + * * @param key the key * @param min min score * @param max max score @@ -689,7 +802,7 @@ public interface RedisSortedSetReactiveCommands { /** * Return a range of members in a sorted set, by score, with scores ordered from high to low. - * + * * @param key the key * @param max max score * @param min min score @@ -703,7 +816,7 @@ public interface RedisSortedSetReactiveCommands { /** * Return a range of members in a sorted set, by score, with scores ordered from high to low. - * + * * @param key the key * @param max max score * @param min min score @@ -727,182 +840,160 @@ public interface RedisSortedSetReactiveCommands { Flux zrevrangebyscore(K key, Range range, Limit limit); /** - * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. - * + * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. + * + * @param channel streaming channel that receives a call for every value * @param key the key * @param max max score * @param min min score - * @return V array-reply list of elements in the specified score range. - * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range)} + * @return Long count of elements in the specified range. + * @deprecated Use {@link #zrevrangebyscore(java.lang.Object, Range)} */ @Deprecated - Flux> zrevrangebyscoreWithScores(K key, double max, double min); + Mono zrevrangebyscore(ValueStreamingChannel channel, K key, double max, double min); /** - * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. - * + * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. + * + * @param channel streaming channel that receives a call for every value * @param key the key - * @param max max score * @param min min score - * @return ScoredValue<V> array-reply list of elements in the specified score range. - * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range)} + * @param max max score + * @return Long count of elements in the specified range. + * @deprecated Use {@link #zrevrangebyscore(java.lang.Object, Range)} */ @Deprecated - Flux> zrevrangebyscoreWithScores(K key, String max, String min); + Mono zrevrangebyscore(ValueStreamingChannel channel, K key, String max, String min); /** - * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. + * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. * + * @param channel streaming channel that receives a call for every value * @param key the key * @param range the range - * @return ScoredValue<V> array-reply list of elements in the specified score range. + * @return Long count of elements in the specified range. * @since 4.3 */ - Flux> zrevrangebyscoreWithScores(K key, Range range); + Mono zrevrangebyscore(ValueStreamingChannel channel, K key, Range range); /** - * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. - * + * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. + * + * @param channel streaming channel that receives a call for every value * @param key the key - * @param max max score * @param min min score + * @param max max score * @param offset the offset * @param count the count - * @return ScoredValue<V> array-reply list of elements in the specified score range. + * @return Long count of elements in the specified range. * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range, Limit)} */ @Deprecated - Flux> zrevrangebyscoreWithScores(K key, double max, double min, long offset, long count); + Mono zrevrangebyscore(ValueStreamingChannel channel, K key, double max, double min, long offset, long count); /** - * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. - * + * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. + * + * @param channel streaming channel that receives a call for every value * @param key the key - * @param max max score * @param min min score + * @param max max score * @param offset the offset * @param count the count - * @return V array-reply list of elements in the specified score range. + * @return Long count of elements in the specified range. * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range, Limit)} */ @Deprecated - Flux> zrevrangebyscoreWithScores(K key, String max, String min, long offset, long count); + Mono zrevrangebyscore(ValueStreamingChannel channel, K key, String max, String min, long offset, long count); /** - * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. + * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. * + * @param channel streaming channel that receives a call for every value * @param key the key * @param range the range - * @param limit limit - * @return V array-reply list of elements in the specified score range. - * @since 4.3 - */ - Flux> zrevrangebyscoreWithScores(K key, Range range, Limit limit); - - /** - * Stream over a range of members in a sorted set, by index, with scores ordered from high to low. - * - * @param channel streaming channel that receives a call for every scored value - * @param key the key - * @param start the start - * @param stop the stop - * @return Long count of elements in the specified range. - */ - Mono zrevrange(ValueStreamingChannel channel, K key, long start, long stop); - - /** - * Stream over a range of members with scores in a sorted set, by index, with scores ordered from high to low. - * - * @param channel streaming channel that receives a call for every scored value - * @param key the key - * @param start the start - * @param stop the stop + * @param limit the limit * @return Long count of elements in the specified range. + * @since 4.3 */ - Mono zrevrangeWithScores(ScoredValueStreamingChannel channel, K key, long start, long stop); + Mono zrevrangebyscore(ValueStreamingChannel channel, K key, Range range, Limit limit); /** - * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. - * - * @param channel streaming channel that receives a call for every value + * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. + * * @param key the key * @param max max score * @param min min score - * @return Long count of elements in the specified range. - * @deprecated Use {@link #zrevrangebyscore(java.lang.Object, Range)} + * @return V array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range)} */ @Deprecated - Mono zrevrangebyscore(ValueStreamingChannel channel, K key, double max, double min); + Flux> zrevrangebyscoreWithScores(K key, double max, double min); /** - * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. - * - * @param channel streaming channel that receives a call for every value + * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. + * * @param key the key - * @param min min score * @param max max score - * @return Long count of elements in the specified range. - * @deprecated Use {@link #zrevrangebyscore(java.lang.Object, Range)} + * @param min min score + * @return ScoredValue<V> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range)} */ @Deprecated - Mono zrevrangebyscore(ValueStreamingChannel channel, K key, String max, String min); + Flux> zrevrangebyscoreWithScores(K key, String max, String min); /** - * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. + * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. * - * @param channel streaming channel that receives a call for every value * @param key the key * @param range the range - * @return Long count of elements in the specified range. + * @return ScoredValue<V> array-reply list of elements in the specified score range. * @since 4.3 */ - Mono zrevrangebyscore(ValueStreamingChannel channel, K key, Range range); + Flux> zrevrangebyscoreWithScores(K key, Range range); /** - * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. - * - * @param channel streaming channel that receives a call for every value + * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. + * * @param key the key - * @param min min score * @param max max score + * @param min min score * @param offset the offset * @param count the count - * @return Long count of elements in the specified range. + * @return ScoredValue<V> array-reply list of elements in the specified score range. * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range, Limit)} */ @Deprecated - Mono zrevrangebyscore(ValueStreamingChannel channel, K key, double max, double min, long offset, long count); + Flux> zrevrangebyscoreWithScores(K key, double max, double min, long offset, long count); /** - * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. - * - * @param channel streaming channel that receives a call for every value + * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. + * * @param key the key - * @param min min score * @param max max score + * @param min min score * @param offset the offset * @param count the count - * @return Long count of elements in the specified range. + * @return V array-reply list of elements in the specified score range. * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range, Limit)} */ @Deprecated - Mono zrevrangebyscore(ValueStreamingChannel channel, K key, String max, String min, long offset, long count); + Flux> zrevrangebyscoreWithScores(K key, String max, String min, long offset, long count); /** - * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. + * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. * - * @param channel streaming channel that receives a call for every value * @param key the key * @param range the range - * @param limit the limit - * @return Long count of elements in the specified range. + * @param limit limit + * @return V array-reply list of elements in the specified score range. * @since 4.3 */ - Mono zrevrangebyscore(ValueStreamingChannel channel, K key, Range range, Limit limit); + Flux> zrevrangebyscoreWithScores(K key, Range range, Limit limit); /** * Stream over a range of members with scores in a sorted set, by score, with scores ordered from high to low. - * + * * @param channel streaming channel that receives a call for every scored value * @param key the key * @param min min score @@ -915,7 +1006,7 @@ public interface RedisSortedSetReactiveCommands { /** * Stream over a range of members with scores in a sorted set, by score, with scores ordered from high to low. - * + * * @param channel streaming channel that receives a call for every scored value * @param key the key * @param min min score @@ -938,7 +1029,7 @@ public interface RedisSortedSetReactiveCommands { /** * Stream over a range of members with scores in a sorted set, by score, with scores ordered from high to low. - * + * * @param channel streaming channel that receives a call for every scored value * @param key the key * @param min min score @@ -953,7 +1044,7 @@ public interface RedisSortedSetReactiveCommands { /** * Stream over a range of members with scores in a sorted set, by score, with scores ordered from high to low. - * + * * @param channel streaming channel that receives a call for every scored value * @param key the key * @param min min score @@ -980,7 +1071,7 @@ public interface RedisSortedSetReactiveCommands { /** * Determine the index of a member in a sorted set, with scores ordered from high to low. - * + * * @param key the key * @param member the member type: value * @return Long integer-reply the rank of {@code member}. If {@code member} does not exist in the sorted set or {@code key} @@ -988,35 +1079,6 @@ public interface RedisSortedSetReactiveCommands { */ Mono zrevrank(K key, V member); - /** - * Get the score associated with the given member in a sorted set. - * - * @param key the key - * @param member the member type: value - * @return Double bulk-string-reply the score of {@code member} (a double precision floating point number), represented as - * string. - */ - Mono zscore(K key, V member); - - /** - * Add multiple sorted sets and store the resulting sorted set in a new key. - * - * @param destination destination key - * @param keys source keys - * @return Long integer-reply the number of elements in the resulting sorted set at {@code destination}. - */ - Mono zunionstore(K destination, K... keys); - - /** - * Add multiple sorted sets and store the resulting sorted set in a new key. - * - * @param destination the destination - * @param storeArgs the storeArgs - * @param keys the keys - * @return Long integer-reply the number of elements in the resulting sorted set at {@code destination}. - */ - Mono zunionstore(K destination, ZStoreArgs storeArgs, K... keys); - /** * Incrementally iterate sorted sets elements and associated scores. * @@ -1074,7 +1136,7 @@ public interface RedisSortedSetReactiveCommands { /** * Incrementally iterate sorted sets elements and associated scores. - * + * * @param channel streaming channel that receives a call for every scored value * @param key the key * @param scanCursor cursor to resume from a previous scan, must not be {@literal null} @@ -1094,93 +1156,31 @@ public interface RedisSortedSetReactiveCommands { Mono zscan(ScoredValueStreamingChannel channel, K key, ScanCursor scanCursor); /** - * Count the number of members in a sorted set between a given lexicographical range. - * - * @param key the key - * @param min min score - * @param max max score - * @return Long integer-reply the number of elements in the specified score range. - * @deprecated Use {@link #zlexcount(java.lang.Object, Range)} - */ - @Deprecated - Mono zlexcount(K key, String min, String max); - - /** - * Count the number of members in a sorted set between a given lexicographical range. - * - * @param key the key - * @param range the range - * @return Long integer-reply the number of elements in the specified score range. - * @since 4.3 - */ - Mono zlexcount(K key, Range range); - - /** - * Remove all members in a sorted set between the given lexicographical range. - * - * @param key the key - * @param min min score - * @param max max score - * @return Long integer-reply the number of elements removed. - * @deprecated Use {@link #zremrangebylex(java.lang.Object, Range)} - */ - @Deprecated - Mono zremrangebylex(K key, String min, String max); - - /** - * Remove all members in a sorted set between the given lexicographical range. + * Get the score associated with the given member in a sorted set. * * @param key the key - * @param range the range - * @return Long integer-reply the number of elements removed. - * @since 4.3 - */ - Mono zremrangebylex(K key, Range range); - - /** - * Return a range of members in a sorted set, by lexicographical range. - * - * @param key the key - * @param min min score - * @param max max score - * @return V array-reply list of elements in the specified range. - * @deprecated Use {@link #zrangebylex(java.lang.Object, Range)} + * @param member the member type: value + * @return Double bulk-string-reply the score of {@code member} (a double precision floating point number), represented as + * string. */ - @Deprecated - Flux zrangebylex(K key, String min, String max); + Mono zscore(K key, V member); /** - * Return a range of members in a sorted set, by lexicographical range. + * Add multiple sorted sets and store the resulting sorted set in a new key. * - * @param key the key - * @param range the range - * @return V array-reply list of elements in the specified range. - * @since 4.3 - */ - Flux zrangebylex(K key, Range range); - - /** - * Return a range of members in a sorted set, by lexicographical range. - * - * @param key the key - * @param min min score - * @param max max score - * @param offset the offset - * @param count the count - * @return V array-reply list of elements in the specified range. - * @deprecated Use {@link #zrangebylex(java.lang.Object, Range)} + * @param destination destination key + * @param keys source keys + * @return Long integer-reply the number of elements in the resulting sorted set at {@code destination}. */ - @Deprecated - Flux zrangebylex(K key, String min, String max, long offset, long count); + Mono zunionstore(K destination, K... keys); /** - * Return a range of members in a sorted set, by lexicographical range. + * Add multiple sorted sets and store the resulting sorted set in a new key. * - * @param key the key - * @param range the range - * @param limit the limit - * @return V array-reply list of elements in the specified range. - * @since 4.3 + * @param destination the destination + * @param storeArgs the storeArgs + * @param keys the keys + * @return Long integer-reply the number of elements in the resulting sorted set at {@code destination}. */ - Flux zrangebylex(K key, Range range, Limit limit); + Mono zunionstore(K destination, ZStoreArgs storeArgs, K... keys); } diff --git a/src/main/java/com/lambdaworks/redis/api/sync/RedisSortedSetCommands.java b/src/main/java/com/lambdaworks/redis/api/sync/RedisSortedSetCommands.java index b40b2d8dcc..182926e7a8 100644 --- a/src/main/java/com/lambdaworks/redis/api/sync/RedisSortedSetCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/sync/RedisSortedSetCommands.java @@ -200,9 +200,31 @@ public interface RedisSortedSetCommands { */ Long zinterstore(K destination, ZStoreArgs storeArgs, K... keys); + /** + * Count the number of members in a sorted set between a given lexicographical range. + * + * @param key the key + * @param min min score + * @param max max score + * @return Long integer-reply the number of elements in the specified score range. + * @deprecated Use {@link #zlexcount(java.lang.Object, Range)} + */ + @Deprecated + Long zlexcount(K key, String min, String max); + + /** + * Count the number of members in a sorted set between a given lexicographical range. + * + * @param key the key + * @param range the range + * @return Long integer-reply the number of elements in the specified score range. + * @since 4.3 + */ + Long zlexcount(K key, Range range); + /** * Return a range of members in a sorted set, by index. - * + * * @param key the key * @param start the start * @param stop the stop @@ -210,9 +232,20 @@ public interface RedisSortedSetCommands { */ List zrange(K key, long start, long stop); + /** + * Return a range of members in a sorted set, by index. + * + * @param channel streaming channel that receives a call for every value + * @param key the key + * @param start the start + * @param stop the stop + * @return Long count of elements in the specified range. + */ + Long zrange(ValueStreamingChannel channel, K key, long start, long stop); + /** * Return a range of members with scores in a sorted set, by index. - * + * * @param key the key * @param start the start * @param stop the stop @@ -220,9 +253,67 @@ public interface RedisSortedSetCommands { */ List> zrangeWithScores(K key, long start, long stop); + /** + * Stream over a range of members with scores in a sorted set, by index. + * + * @param channel streaming channel that receives a call for every value + * @param key the key + * @param start the start + * @param stop the stop + * @return Long count of elements in the specified range. + */ + Long zrangeWithScores(ScoredValueStreamingChannel channel, K key, long start, long stop); + + /** + * Return a range of members in a sorted set, by lexicographical range. + * + * @param key the key + * @param min min score + * @param max max score + * @return List<V> array-reply list of elements in the specified range. + * @deprecated Use {@link #zrangebylex(java.lang.Object, Range)} + */ + @Deprecated + List zrangebylex(K key, String min, String max); + + /** + * Return a range of members in a sorted set, by lexicographical range. + * + * @param key the key + * @param range the range + * @return List<V> array-reply list of elements in the specified range. + * @since 4.3 + */ + List zrangebylex(K key, Range range); + + /** + * Return a range of members in a sorted set, by lexicographical range. + * + * @param key the key + * @param min min score + * @param max max score + * @param offset the offset + * @param count the count + * @return List<V> array-reply list of elements in the specified range. + * @deprecated Use {@link #zrangebylex(java.lang.Object, Range)} + */ + @Deprecated + List zrangebylex(K key, String min, String max, long offset, long count); + + /** + * Return a range of members in a sorted set, by lexicographical range. + * + * @param key the key + * @param range the range + * @param limit the limit + * @return List<V> array-reply list of elements in the specified range. + * @since 4.3 + */ + List zrangebylex(K key, Range range, Limit limit); + /** * Return a range of members in a sorted set, by score. - * + * * @param key the key * @param min min score * @param max max score @@ -234,7 +325,7 @@ public interface RedisSortedSetCommands { /** * Return a range of members in a sorted set, by score. - * + * * @param key the key * @param min min score * @param max max score @@ -256,7 +347,7 @@ public interface RedisSortedSetCommands { /** * Return a range of members in a sorted set, by score. - * + * * @param key the key * @param min min score * @param max max score @@ -270,7 +361,7 @@ public interface RedisSortedSetCommands { /** * Return a range of members in a sorted set, by score. - * + * * @param key the key * @param min min score * @param max max score @@ -294,181 +385,159 @@ public interface RedisSortedSetCommands { List zrangebyscore(K key, Range range, Limit limit); /** - * Return a range of members with score in a sorted set, by score. + * Stream over a range of members in a sorted set, by score. * + * @param channel streaming channel that receives a call for every value * @param key the key * @param min min score * @param max max score - * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. - * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range)} + * @return Long count of elements in the specified score range. + * @deprecated Use {@link #zrangebyscore(ValueStreamingChannel, java.lang.Object, Range)} */ @Deprecated - List> zrangebyscoreWithScores(K key, double min, double max); + Long zrangebyscore(ValueStreamingChannel channel, K key, double min, double max); /** - * Return a range of members with score in a sorted set, by score. + * Stream over a range of members in a sorted set, by score. * + * @param channel streaming channel that receives a call for every value * @param key the key * @param min min score * @param max max score - * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. - * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range)} + * @return Long count of elements in the specified score range. + * @deprecated Use {@link #zrangebyscore(ValueStreamingChannel, java.lang.Object, Range)} */ @Deprecated - List> zrangebyscoreWithScores(K key, String min, String max); + Long zrangebyscore(ValueStreamingChannel channel, K key, String min, String max); /** - * Return a range of members with score in a sorted set, by score. + * Stream over a range of members in a sorted set, by score. * + * @param channel streaming channel that receives a call for every value * @param key the key * @param range the range - * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @return Long count of elements in the specified score range. * @since 4.3 */ - List> zrangebyscoreWithScores(K key, Range range); + Long zrangebyscore(ValueStreamingChannel channel, K key, Range range); /** - * Return a range of members with score in a sorted set, by score. + * Stream over range of members in a sorted set, by score. * + * @param channel streaming channel that receives a call for every value * @param key the key * @param min min score * @param max max score * @param offset the offset * @param count the count - * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. - * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range, Limit limit)} + * @return Long count of elements in the specified score range. + * @deprecated Use {@link #zrangebyscore(ValueStreamingChannel, java.lang.Object, Range, Limit limit)} */ - List> zrangebyscoreWithScores(K key, double min, double max, long offset, long count); + @Deprecated + Long zrangebyscore(ValueStreamingChannel channel, K key, double min, double max, long offset, long count); /** - * Return a range of members with score in a sorted set, by score. + * Stream over a range of members in a sorted set, by score. * + * @param channel streaming channel that receives a call for every value * @param key the key * @param min min score * @param max max score * @param offset the offset * @param count the count - * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. - * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range, Limit)} + * @return Long count of elements in the specified score range. + * @deprecated Use {@link #zrangebyscore(ValueStreamingChannel, java.lang.Object, Range, Limit limit)} */ @Deprecated - List> zrangebyscoreWithScores(K key, String min, String max, long offset, long count); + Long zrangebyscore(ValueStreamingChannel channel, K key, String min, String max, long offset, long count); /** - * Return a range of members with score in a sorted set, by score. + * Stream over a range of members in a sorted set, by score. * + * @param channel streaming channel that receives a call for every value * @param key the key * @param range the range * @param limit the limit - * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @return Long count of elements in the specified score range. * @since 4.3 */ - List> zrangebyscoreWithScores(K key, Range range, Limit limit); - - /** - * Return a range of members in a sorted set, by index. - * - * @param channel streaming channel that receives a call for every value - * @param key the key - * @param start the start - * @param stop the stop - * @return Long count of elements in the specified range. - */ - Long zrange(ValueStreamingChannel channel, K key, long start, long stop); - - /** - * Stream over a range of members with scores in a sorted set, by index. - * - * @param channel streaming channel that receives a call for every value - * @param key the key - * @param start the start - * @param stop the stop - * @return Long count of elements in the specified range. - */ - Long zrangeWithScores(ScoredValueStreamingChannel channel, K key, long start, long stop); + Long zrangebyscore(ValueStreamingChannel channel, K key, Range range, Limit limit); /** - * Stream over a range of members in a sorted set, by score. - * - * @param channel streaming channel that receives a call for every value + * Return a range of members with score in a sorted set, by score. + * * @param key the key * @param min min score * @param max max score - * @return Long count of elements in the specified score range. - * @deprecated Use {@link #zrangebyscore(ValueStreamingChannel, java.lang.Object, Range)} + * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range)} */ @Deprecated - Long zrangebyscore(ValueStreamingChannel channel, K key, double min, double max); + List> zrangebyscoreWithScores(K key, double min, double max); /** - * Stream over a range of members in a sorted set, by score. - * - * @param channel streaming channel that receives a call for every value + * Return a range of members with score in a sorted set, by score. + * * @param key the key * @param min min score * @param max max score - * @return Long count of elements in the specified score range. - * @deprecated Use {@link #zrangebyscore(ValueStreamingChannel, java.lang.Object, Range)} + * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range)} */ @Deprecated - Long zrangebyscore(ValueStreamingChannel channel, K key, String min, String max); + List> zrangebyscoreWithScores(K key, String min, String max); /** - * Stream over a range of members in a sorted set, by score. + * Return a range of members with score in a sorted set, by score. * - * @param channel streaming channel that receives a call for every value * @param key the key * @param range the range - * @return Long count of elements in the specified score range. + * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. * @since 4.3 */ - Long zrangebyscore(ValueStreamingChannel channel, K key, Range range); + List> zrangebyscoreWithScores(K key, Range range); /** - * Stream over range of members in a sorted set, by score. - * - * @param channel streaming channel that receives a call for every value + * Return a range of members with score in a sorted set, by score. + * * @param key the key * @param min min score * @param max max score * @param offset the offset * @param count the count - * @return Long count of elements in the specified score range. - * @deprecated Use {@link #zrangebyscore(ValueStreamingChannel, java.lang.Object, Range, Limit limit)} + * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range, Limit limit)} */ - @Deprecated - Long zrangebyscore(ValueStreamingChannel channel, K key, double min, double max, long offset, long count); + List> zrangebyscoreWithScores(K key, double min, double max, long offset, long count); /** - * Stream over a range of members in a sorted set, by score. - * - * @param channel streaming channel that receives a call for every value + * Return a range of members with score in a sorted set, by score. + * * @param key the key * @param min min score * @param max max score * @param offset the offset * @param count the count - * @return Long count of elements in the specified score range. - * @deprecated Use {@link #zrangebyscore(ValueStreamingChannel, java.lang.Object, Range, Limit limit)} + * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range, Limit)} */ @Deprecated - Long zrangebyscore(ValueStreamingChannel channel, K key, String min, String max, long offset, long count); + List> zrangebyscoreWithScores(K key, String min, String max, long offset, long count); /** - * Stream over a range of members in a sorted set, by score. + * Return a range of members with score in a sorted set, by score. * - * @param channel streaming channel that receives a call for every value * @param key the key * @param range the range * @param limit the limit - * @return Long count of elements in the specified score range. + * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. * @since 4.3 */ - Long zrangebyscore(ValueStreamingChannel channel, K key, Range range, Limit limit); + List> zrangebyscoreWithScores(K key, Range range, Limit limit); /** * Stream over a range of members with scores in a sorted set, by score. - * + * * @param channel streaming channel that receives a call for every scored value * @param key the key * @param min min score @@ -481,7 +550,7 @@ public interface RedisSortedSetCommands { /** * Stream over a range of members with scores in a sorted set, by score. - * + * * @param channel streaming channel that receives a call for every scored value * @param key the key * @param min min score @@ -505,7 +574,7 @@ public interface RedisSortedSetCommands { /** * Stream over a range of members with scores in a sorted set, by score. - * + * * @param channel streaming channel that receives a call for every scored value * @param key the key * @param min min score @@ -520,7 +589,7 @@ public interface RedisSortedSetCommands { /** * Stream over a range of members with scores in a sorted set, by score. - * + * * @param channel streaming channel that receives a call for every scored value * @param key the key * @param min min score @@ -547,7 +616,7 @@ public interface RedisSortedSetCommands { /** * Determine the index of a member in a sorted set. - * + * * @param key the key * @param member the member type: value * @return Long integer-reply the rank of {@code member}. If {@code member} does not exist in the sorted set or {@code key} @@ -557,28 +626,50 @@ public interface RedisSortedSetCommands { /** * Remove one or more members from a sorted set. - * + * * @param key the key * @param members the member type: value * @return Long integer-reply specifically: - * + * * The number of members removed from the sorted set, not including non existing members. */ Long zrem(K key, V... members); /** - * Remove all members in a sorted set within the given indexes. - * + * Remove all members in a sorted set between the given lexicographical range. + * * @param key the key - * @param start the start type: long - * @param stop the stop type: long - * @return Long integer-reply the number of elements removed. + * @param min min score + * @param max max score + * @return Long integer-reply the number of elements removed. + * @deprecated Use {@link #zremrangebylex(java.lang.Object, Range)} + */ + @Deprecated + Long zremrangebylex(K key, String min, String max); + + /** + * Remove all members in a sorted set between the given lexicographical range. + * + * @param key the key + * @param range the range + * @return Long integer-reply the number of elements removed. + * @since 4.3 + */ + Long zremrangebylex(K key, Range range); + + /** + * Remove all members in a sorted set within the given indexes. + * + * @param key the key + * @param start the start type: long + * @param stop the stop type: long + * @return Long integer-reply the number of elements removed. */ Long zremrangebyrank(K key, long start, long stop); /** * Remove all members in a sorted set within the given scores. - * + * * @param key the key * @param min min score * @param max max score @@ -590,7 +681,7 @@ public interface RedisSortedSetCommands { /** * Remove all members in a sorted set within the given scores. - * + * * @param key the key * @param min min score * @param max max score @@ -612,7 +703,7 @@ public interface RedisSortedSetCommands { /** * Return a range of members in a sorted set, by index, with scores ordered from high to low. - * + * * @param key the key * @param start the start * @param stop the stop @@ -620,9 +711,20 @@ public interface RedisSortedSetCommands { */ List zrevrange(K key, long start, long stop); + /** + * Stream over a range of members in a sorted set, by index, with scores ordered from high to low. + * + * @param channel streaming channel that receives a call for every scored value + * @param key the key + * @param start the start + * @param stop the stop + * @return Long count of elements in the specified range. + */ + Long zrevrange(ValueStreamingChannel channel, K key, long start, long stop); + /** * Return a range of members with scores in a sorted set, by index, with scores ordered from high to low. - * + * * @param key the key * @param start the start * @param stop the stop @@ -630,6 +732,17 @@ public interface RedisSortedSetCommands { */ List> zrevrangeWithScores(K key, long start, long stop); + /** + * Stream over a range of members with scores in a sorted set, by index, with scores ordered from high to low. + * + * @param channel streaming channel that receives a call for every scored value + * @param key the key + * @param start the start + * @param stop the stop + * @return Long count of elements in the specified range. + */ + Long zrevrangeWithScores(ScoredValueStreamingChannel channel, K key, long start, long stop); + /** * Return a range of members in a sorted set, by lexicographical range ordered from high to low. * @@ -653,7 +766,7 @@ public interface RedisSortedSetCommands { /** * Return a range of members in a sorted set, by score, with scores ordered from high to low. - * + * * @param key the key * @param min min score * @param max max score @@ -665,7 +778,7 @@ public interface RedisSortedSetCommands { /** * Return a range of members in a sorted set, by score, with scores ordered from high to low. - * + * * @param key the key * @param min min score * @param max max score @@ -687,7 +800,7 @@ public interface RedisSortedSetCommands { /** * Return a range of members in a sorted set, by score, with scores ordered from high to low. - * + * * @param key the key * @param max max score * @param min min score @@ -701,7 +814,7 @@ public interface RedisSortedSetCommands { /** * Return a range of members in a sorted set, by score, with scores ordered from high to low. - * + * * @param key the key * @param max max score * @param min min score @@ -725,182 +838,160 @@ public interface RedisSortedSetCommands { List zrevrangebyscore(K key, Range range, Limit limit); /** - * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. - * + * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. + * + * @param channel streaming channel that receives a call for every value * @param key the key * @param max max score * @param min min score - * @return List<V> array-reply list of elements in the specified score range. - * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range)} + * @return Long count of elements in the specified range. + * @deprecated Use {@link #zrevrangebyscore(java.lang.Object, Range)} */ @Deprecated - List> zrevrangebyscoreWithScores(K key, double max, double min); + Long zrevrangebyscore(ValueStreamingChannel channel, K key, double max, double min); /** - * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. - * + * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. + * + * @param channel streaming channel that receives a call for every value * @param key the key - * @param max max score * @param min min score - * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. - * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range)} + * @param max max score + * @return Long count of elements in the specified range. + * @deprecated Use {@link #zrevrangebyscore(java.lang.Object, Range)} */ @Deprecated - List> zrevrangebyscoreWithScores(K key, String max, String min); + Long zrevrangebyscore(ValueStreamingChannel channel, K key, String max, String min); /** - * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. + * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. * + * @param channel streaming channel that receives a call for every value * @param key the key * @param range the range - * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @return Long count of elements in the specified range. * @since 4.3 */ - List> zrevrangebyscoreWithScores(K key, Range range); + Long zrevrangebyscore(ValueStreamingChannel channel, K key, Range range); /** - * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. - * + * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. + * + * @param channel streaming channel that receives a call for every value * @param key the key - * @param max max score * @param min min score + * @param max max score * @param offset the offset * @param count the count - * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @return Long count of elements in the specified range. * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range, Limit)} */ @Deprecated - List> zrevrangebyscoreWithScores(K key, double max, double min, long offset, long count); + Long zrevrangebyscore(ValueStreamingChannel channel, K key, double max, double min, long offset, long count); /** - * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. - * + * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. + * + * @param channel streaming channel that receives a call for every value * @param key the key - * @param max max score * @param min min score + * @param max max score * @param offset the offset * @param count the count - * @return List<V> array-reply list of elements in the specified score range. + * @return Long count of elements in the specified range. * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range, Limit)} */ @Deprecated - List> zrevrangebyscoreWithScores(K key, String max, String min, long offset, long count); + Long zrevrangebyscore(ValueStreamingChannel channel, K key, String max, String min, long offset, long count); /** - * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. + * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. * + * @param channel streaming channel that receives a call for every value * @param key the key * @param range the range - * @param limit limit - * @return List<V> array-reply list of elements in the specified score range. - * @since 4.3 - */ - List> zrevrangebyscoreWithScores(K key, Range range, Limit limit); - - /** - * Stream over a range of members in a sorted set, by index, with scores ordered from high to low. - * - * @param channel streaming channel that receives a call for every scored value - * @param key the key - * @param start the start - * @param stop the stop - * @return Long count of elements in the specified range. - */ - Long zrevrange(ValueStreamingChannel channel, K key, long start, long stop); - - /** - * Stream over a range of members with scores in a sorted set, by index, with scores ordered from high to low. - * - * @param channel streaming channel that receives a call for every scored value - * @param key the key - * @param start the start - * @param stop the stop + * @param limit the limit * @return Long count of elements in the specified range. + * @since 4.3 */ - Long zrevrangeWithScores(ScoredValueStreamingChannel channel, K key, long start, long stop); + Long zrevrangebyscore(ValueStreamingChannel channel, K key, Range range, Limit limit); /** - * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. - * - * @param channel streaming channel that receives a call for every value + * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. + * * @param key the key * @param max max score * @param min min score - * @return Long count of elements in the specified range. - * @deprecated Use {@link #zrevrangebyscore(java.lang.Object, Range)} + * @return List<V> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range)} */ @Deprecated - Long zrevrangebyscore(ValueStreamingChannel channel, K key, double max, double min); + List> zrevrangebyscoreWithScores(K key, double max, double min); /** - * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. - * - * @param channel streaming channel that receives a call for every value + * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. + * * @param key the key - * @param min min score * @param max max score - * @return Long count of elements in the specified range. - * @deprecated Use {@link #zrevrangebyscore(java.lang.Object, Range)} + * @param min min score + * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range)} */ @Deprecated - Long zrevrangebyscore(ValueStreamingChannel channel, K key, String max, String min); + List> zrevrangebyscoreWithScores(K key, String max, String min); /** - * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. + * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. * - * @param channel streaming channel that receives a call for every value * @param key the key * @param range the range - * @return Long count of elements in the specified range. + * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. * @since 4.3 */ - Long zrevrangebyscore(ValueStreamingChannel channel, K key, Range range); + List> zrevrangebyscoreWithScores(K key, Range range); /** - * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. - * - * @param channel streaming channel that receives a call for every value + * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. + * * @param key the key - * @param min min score * @param max max score + * @param min min score * @param offset the offset * @param count the count - * @return Long count of elements in the specified range. + * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range, Limit)} */ @Deprecated - Long zrevrangebyscore(ValueStreamingChannel channel, K key, double max, double min, long offset, long count); + List> zrevrangebyscoreWithScores(K key, double max, double min, long offset, long count); /** - * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. - * - * @param channel streaming channel that receives a call for every value + * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. + * * @param key the key - * @param min min score * @param max max score + * @param min min score * @param offset the offset * @param count the count - * @return Long count of elements in the specified range. + * @return List<V> array-reply list of elements in the specified score range. * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range, Limit)} */ @Deprecated - Long zrevrangebyscore(ValueStreamingChannel channel, K key, String max, String min, long offset, long count); + List> zrevrangebyscoreWithScores(K key, String max, String min, long offset, long count); /** - * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. + * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. * - * @param channel streaming channel that receives a call for every value * @param key the key * @param range the range - * @param limit the limit - * @return Long count of elements in the specified range. + * @param limit limit + * @return List<V> array-reply list of elements in the specified score range. * @since 4.3 */ - Long zrevrangebyscore(ValueStreamingChannel channel, K key, Range range, Limit limit); + List> zrevrangebyscoreWithScores(K key, Range range, Limit limit); /** * Stream over a range of members with scores in a sorted set, by score, with scores ordered from high to low. - * + * * @param channel streaming channel that receives a call for every scored value * @param key the key * @param min min score @@ -913,7 +1004,7 @@ public interface RedisSortedSetCommands { /** * Stream over a range of members with scores in a sorted set, by score, with scores ordered from high to low. - * + * * @param channel streaming channel that receives a call for every scored value * @param key the key * @param min min score @@ -936,7 +1027,7 @@ public interface RedisSortedSetCommands { /** * Stream over a range of members with scores in a sorted set, by score, with scores ordered from high to low. - * + * * @param channel streaming channel that receives a call for every scored value * @param key the key * @param min min score @@ -951,7 +1042,7 @@ public interface RedisSortedSetCommands { /** * Stream over a range of members with scores in a sorted set, by score, with scores ordered from high to low. - * + * * @param channel streaming channel that receives a call for every scored value * @param key the key * @param min min score @@ -978,7 +1069,7 @@ public interface RedisSortedSetCommands { /** * Determine the index of a member in a sorted set, with scores ordered from high to low. - * + * * @param key the key * @param member the member type: value * @return Long integer-reply the rank of {@code member}. If {@code member} does not exist in the sorted set or {@code key} @@ -986,35 +1077,6 @@ public interface RedisSortedSetCommands { */ Long zrevrank(K key, V member); - /** - * Get the score associated with the given member in a sorted set. - * - * @param key the key - * @param member the member type: value - * @return Double bulk-string-reply the score of {@code member} (a double precision floating point number), represented as - * string. - */ - Double zscore(K key, V member); - - /** - * Add multiple sorted sets and store the resulting sorted set in a new key. - * - * @param destination destination key - * @param keys source keys - * @return Long integer-reply the number of elements in the resulting sorted set at {@code destination}. - */ - Long zunionstore(K destination, K... keys); - - /** - * Add multiple sorted sets and store the resulting sorted set in a new key. - * - * @param destination the destination - * @param storeArgs the storeArgs - * @param keys the keys - * @return Long integer-reply the number of elements in the resulting sorted set at {@code destination}. - */ - Long zunionstore(K destination, ZStoreArgs storeArgs, K... keys); - /** * Incrementally iterate sorted sets elements and associated scores. * @@ -1072,7 +1134,7 @@ public interface RedisSortedSetCommands { /** * Incrementally iterate sorted sets elements and associated scores. - * + * * @param channel streaming channel that receives a call for every scored value * @param key the key * @param scanCursor cursor to resume from a previous scan, must not be {@literal null} @@ -1092,93 +1154,31 @@ public interface RedisSortedSetCommands { StreamScanCursor zscan(ScoredValueStreamingChannel channel, K key, ScanCursor scanCursor); /** - * Count the number of members in a sorted set between a given lexicographical range. - * - * @param key the key - * @param min min score - * @param max max score - * @return Long integer-reply the number of elements in the specified score range. - * @deprecated Use {@link #zlexcount(java.lang.Object, Range)} - */ - @Deprecated - Long zlexcount(K key, String min, String max); - - /** - * Count the number of members in a sorted set between a given lexicographical range. - * - * @param key the key - * @param range the range - * @return Long integer-reply the number of elements in the specified score range. - * @since 4.3 - */ - Long zlexcount(K key, Range range); - - /** - * Remove all members in a sorted set between the given lexicographical range. - * - * @param key the key - * @param min min score - * @param max max score - * @return Long integer-reply the number of elements removed. - * @deprecated Use {@link #zremrangebylex(java.lang.Object, Range)} - */ - @Deprecated - Long zremrangebylex(K key, String min, String max); - - /** - * Remove all members in a sorted set between the given lexicographical range. + * Get the score associated with the given member in a sorted set. * * @param key the key - * @param range the range - * @return Long integer-reply the number of elements removed. - * @since 4.3 - */ - Long zremrangebylex(K key, Range range); - - /** - * Return a range of members in a sorted set, by lexicographical range. - * - * @param key the key - * @param min min score - * @param max max score - * @return List<V> array-reply list of elements in the specified range. - * @deprecated Use {@link #zrangebylex(java.lang.Object, Range)} + * @param member the member type: value + * @return Double bulk-string-reply the score of {@code member} (a double precision floating point number), represented as + * string. */ - @Deprecated - List zrangebylex(K key, String min, String max); + Double zscore(K key, V member); /** - * Return a range of members in a sorted set, by lexicographical range. + * Add multiple sorted sets and store the resulting sorted set in a new key. * - * @param key the key - * @param range the range - * @return List<V> array-reply list of elements in the specified range. - * @since 4.3 - */ - List zrangebylex(K key, Range range); - - /** - * Return a range of members in a sorted set, by lexicographical range. - * - * @param key the key - * @param min min score - * @param max max score - * @param offset the offset - * @param count the count - * @return List<V> array-reply list of elements in the specified range. - * @deprecated Use {@link #zrangebylex(java.lang.Object, Range)} + * @param destination destination key + * @param keys source keys + * @return Long integer-reply the number of elements in the resulting sorted set at {@code destination}. */ - @Deprecated - List zrangebylex(K key, String min, String max, long offset, long count); + Long zunionstore(K destination, K... keys); /** - * Return a range of members in a sorted set, by lexicographical range. + * Add multiple sorted sets and store the resulting sorted set in a new key. * - * @param key the key - * @param range the range - * @param limit the limit - * @return List<V> array-reply list of elements in the specified range. - * @since 4.3 + * @param destination the destination + * @param storeArgs the storeArgs + * @param keys the keys + * @return Long integer-reply the number of elements in the resulting sorted set at {@code destination}. */ - List zrangebylex(K key, Range range, Limit limit); + Long zunionstore(K destination, ZStoreArgs storeArgs, K... keys); } diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionSortedSetAsyncCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionSortedSetAsyncCommands.java index 2d5b1ff749..f3579e7a21 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionSortedSetAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionSortedSetAsyncCommands.java @@ -201,9 +201,31 @@ public interface NodeSelectionSortedSetAsyncCommands { */ AsyncExecutions zinterstore(K destination, ZStoreArgs storeArgs, K... keys); + /** + * Count the number of members in a sorted set between a given lexicographical range. + * + * @param key the key + * @param min min score + * @param max max score + * @return Long integer-reply the number of elements in the specified score range. + * @deprecated Use {@link #zlexcount(java.lang.Object, Range)} + */ + @Deprecated + AsyncExecutions zlexcount(K key, String min, String max); + + /** + * Count the number of members in a sorted set between a given lexicographical range. + * + * @param key the key + * @param range the range + * @return Long integer-reply the number of elements in the specified score range. + * @since 4.3 + */ + AsyncExecutions zlexcount(K key, Range range); + /** * Return a range of members in a sorted set, by index. - * + * * @param key the key * @param start the start * @param stop the stop @@ -211,9 +233,20 @@ public interface NodeSelectionSortedSetAsyncCommands { */ AsyncExecutions> zrange(K key, long start, long stop); + /** + * Return a range of members in a sorted set, by index. + * + * @param channel streaming channel that receives a call for every value + * @param key the key + * @param start the start + * @param stop the stop + * @return Long count of elements in the specified range. + */ + AsyncExecutions zrange(ValueStreamingChannel channel, K key, long start, long stop); + /** * Return a range of members with scores in a sorted set, by index. - * + * * @param key the key * @param start the start * @param stop the stop @@ -221,9 +254,67 @@ public interface NodeSelectionSortedSetAsyncCommands { */ AsyncExecutions>> zrangeWithScores(K key, long start, long stop); + /** + * Stream over a range of members with scores in a sorted set, by index. + * + * @param channel streaming channel that receives a call for every value + * @param key the key + * @param start the start + * @param stop the stop + * @return Long count of elements in the specified range. + */ + AsyncExecutions zrangeWithScores(ScoredValueStreamingChannel channel, K key, long start, long stop); + + /** + * Return a range of members in a sorted set, by lexicographical range. + * + * @param key the key + * @param min min score + * @param max max score + * @return List<V> array-reply list of elements in the specified range. + * @deprecated Use {@link #zrangebylex(java.lang.Object, Range)} + */ + @Deprecated + AsyncExecutions> zrangebylex(K key, String min, String max); + + /** + * Return a range of members in a sorted set, by lexicographical range. + * + * @param key the key + * @param range the range + * @return List<V> array-reply list of elements in the specified range. + * @since 4.3 + */ + AsyncExecutions> zrangebylex(K key, Range range); + + /** + * Return a range of members in a sorted set, by lexicographical range. + * + * @param key the key + * @param min min score + * @param max max score + * @param offset the offset + * @param count the count + * @return List<V> array-reply list of elements in the specified range. + * @deprecated Use {@link #zrangebylex(java.lang.Object, Range)} + */ + @Deprecated + AsyncExecutions> zrangebylex(K key, String min, String max, long offset, long count); + + /** + * Return a range of members in a sorted set, by lexicographical range. + * + * @param key the key + * @param range the range + * @param limit the limit + * @return List<V> array-reply list of elements in the specified range. + * @since 4.3 + */ + AsyncExecutions> zrangebylex(K key, Range range, Limit limit); + /** * Return a range of members in a sorted set, by score. - * + * * @param key the key * @param min min score * @param max max score @@ -235,7 +326,7 @@ public interface NodeSelectionSortedSetAsyncCommands { /** * Return a range of members in a sorted set, by score. - * + * * @param key the key * @param min min score * @param max max score @@ -257,7 +348,7 @@ public interface NodeSelectionSortedSetAsyncCommands { /** * Return a range of members in a sorted set, by score. - * + * * @param key the key * @param min min score * @param max max score @@ -271,7 +362,7 @@ public interface NodeSelectionSortedSetAsyncCommands { /** * Return a range of members in a sorted set, by score. - * + * * @param key the key * @param min min score * @param max max score @@ -295,181 +386,159 @@ public interface NodeSelectionSortedSetAsyncCommands { AsyncExecutions> zrangebyscore(K key, Range range, Limit limit); /** - * Return a range of members with score in a sorted set, by score. + * Stream over a range of members in a sorted set, by score. * + * @param channel streaming channel that receives a call for every value * @param key the key * @param min min score * @param max max score - * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. - * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range)} + * @return Long count of elements in the specified score range. + * @deprecated Use {@link #zrangebyscore(ValueStreamingChannel, java.lang.Object, Range)} */ @Deprecated - AsyncExecutions>> zrangebyscoreWithScores(K key, double min, double max); + AsyncExecutions zrangebyscore(ValueStreamingChannel channel, K key, double min, double max); /** - * Return a range of members with score in a sorted set, by score. + * Stream over a range of members in a sorted set, by score. * + * @param channel streaming channel that receives a call for every value * @param key the key * @param min min score * @param max max score - * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. - * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range)} + * @return Long count of elements in the specified score range. + * @deprecated Use {@link #zrangebyscore(ValueStreamingChannel, java.lang.Object, Range)} */ @Deprecated - AsyncExecutions>> zrangebyscoreWithScores(K key, String min, String max); + AsyncExecutions zrangebyscore(ValueStreamingChannel channel, K key, String min, String max); /** - * Return a range of members with score in a sorted set, by score. + * Stream over a range of members in a sorted set, by score. * + * @param channel streaming channel that receives a call for every value * @param key the key * @param range the range - * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @return Long count of elements in the specified score range. * @since 4.3 */ - AsyncExecutions>> zrangebyscoreWithScores(K key, Range range); + AsyncExecutions zrangebyscore(ValueStreamingChannel channel, K key, Range range); /** - * Return a range of members with score in a sorted set, by score. + * Stream over range of members in a sorted set, by score. * + * @param channel streaming channel that receives a call for every value * @param key the key * @param min min score * @param max max score * @param offset the offset * @param count the count - * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. - * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range, Limit limit)} + * @return Long count of elements in the specified score range. + * @deprecated Use {@link #zrangebyscore(ValueStreamingChannel, java.lang.Object, Range, Limit limit)} */ - AsyncExecutions>> zrangebyscoreWithScores(K key, double min, double max, long offset, long count); + @Deprecated + AsyncExecutions zrangebyscore(ValueStreamingChannel channel, K key, double min, double max, long offset, long count); /** - * Return a range of members with score in a sorted set, by score. + * Stream over a range of members in a sorted set, by score. * + * @param channel streaming channel that receives a call for every value * @param key the key * @param min min score * @param max max score * @param offset the offset * @param count the count - * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. - * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range, Limit)} + * @return Long count of elements in the specified score range. + * @deprecated Use {@link #zrangebyscore(ValueStreamingChannel, java.lang.Object, Range, Limit limit)} */ @Deprecated - AsyncExecutions>> zrangebyscoreWithScores(K key, String min, String max, long offset, long count); + AsyncExecutions zrangebyscore(ValueStreamingChannel channel, K key, String min, String max, long offset, long count); /** - * Return a range of members with score in a sorted set, by score. + * Stream over a range of members in a sorted set, by score. * + * @param channel streaming channel that receives a call for every value * @param key the key * @param range the range * @param limit the limit - * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @return Long count of elements in the specified score range. * @since 4.3 */ - AsyncExecutions>> zrangebyscoreWithScores(K key, Range range, Limit limit); - - /** - * Return a range of members in a sorted set, by index. - * - * @param channel streaming channel that receives a call for every value - * @param key the key - * @param start the start - * @param stop the stop - * @return Long count of elements in the specified range. - */ - AsyncExecutions zrange(ValueStreamingChannel channel, K key, long start, long stop); - - /** - * Stream over a range of members with scores in a sorted set, by index. - * - * @param channel streaming channel that receives a call for every value - * @param key the key - * @param start the start - * @param stop the stop - * @return Long count of elements in the specified range. - */ - AsyncExecutions zrangeWithScores(ScoredValueStreamingChannel channel, K key, long start, long stop); + AsyncExecutions zrangebyscore(ValueStreamingChannel channel, K key, Range range, Limit limit); /** - * Stream over a range of members in a sorted set, by score. - * - * @param channel streaming channel that receives a call for every value + * Return a range of members with score in a sorted set, by score. + * * @param key the key * @param min min score * @param max max score - * @return Long count of elements in the specified score range. - * @deprecated Use {@link #zrangebyscore(ValueStreamingChannel, java.lang.Object, Range)} + * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range)} */ @Deprecated - AsyncExecutions zrangebyscore(ValueStreamingChannel channel, K key, double min, double max); + AsyncExecutions>> zrangebyscoreWithScores(K key, double min, double max); /** - * Stream over a range of members in a sorted set, by score. - * - * @param channel streaming channel that receives a call for every value + * Return a range of members with score in a sorted set, by score. + * * @param key the key * @param min min score * @param max max score - * @return Long count of elements in the specified score range. - * @deprecated Use {@link #zrangebyscore(ValueStreamingChannel, java.lang.Object, Range)} + * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range)} */ @Deprecated - AsyncExecutions zrangebyscore(ValueStreamingChannel channel, K key, String min, String max); + AsyncExecutions>> zrangebyscoreWithScores(K key, String min, String max); /** - * Stream over a range of members in a sorted set, by score. + * Return a range of members with score in a sorted set, by score. * - * @param channel streaming channel that receives a call for every value * @param key the key * @param range the range - * @return Long count of elements in the specified score range. + * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. * @since 4.3 */ - AsyncExecutions zrangebyscore(ValueStreamingChannel channel, K key, Range range); + AsyncExecutions>> zrangebyscoreWithScores(K key, Range range); /** - * Stream over range of members in a sorted set, by score. - * - * @param channel streaming channel that receives a call for every value + * Return a range of members with score in a sorted set, by score. + * * @param key the key * @param min min score * @param max max score * @param offset the offset * @param count the count - * @return Long count of elements in the specified score range. - * @deprecated Use {@link #zrangebyscore(ValueStreamingChannel, java.lang.Object, Range, Limit limit)} + * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range, Limit limit)} */ - @Deprecated - AsyncExecutions zrangebyscore(ValueStreamingChannel channel, K key, double min, double max, long offset, long count); + AsyncExecutions>> zrangebyscoreWithScores(K key, double min, double max, long offset, long count); /** - * Stream over a range of members in a sorted set, by score. - * - * @param channel streaming channel that receives a call for every value + * Return a range of members with score in a sorted set, by score. + * * @param key the key * @param min min score * @param max max score * @param offset the offset * @param count the count - * @return Long count of elements in the specified score range. - * @deprecated Use {@link #zrangebyscore(ValueStreamingChannel, java.lang.Object, Range, Limit limit)} + * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range, Limit)} */ @Deprecated - AsyncExecutions zrangebyscore(ValueStreamingChannel channel, K key, String min, String max, long offset, long count); + AsyncExecutions>> zrangebyscoreWithScores(K key, String min, String max, long offset, long count); /** - * Stream over a range of members in a sorted set, by score. + * Return a range of members with score in a sorted set, by score. * - * @param channel streaming channel that receives a call for every value * @param key the key * @param range the range * @param limit the limit - * @return Long count of elements in the specified score range. + * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. * @since 4.3 */ - AsyncExecutions zrangebyscore(ValueStreamingChannel channel, K key, Range range, Limit limit); + AsyncExecutions>> zrangebyscoreWithScores(K key, Range range, Limit limit); /** * Stream over a range of members with scores in a sorted set, by score. - * + * * @param channel streaming channel that receives a call for every scored value * @param key the key * @param min min score @@ -482,7 +551,7 @@ public interface NodeSelectionSortedSetAsyncCommands { /** * Stream over a range of members with scores in a sorted set, by score. - * + * * @param channel streaming channel that receives a call for every scored value * @param key the key * @param min min score @@ -506,7 +575,7 @@ public interface NodeSelectionSortedSetAsyncCommands { /** * Stream over a range of members with scores in a sorted set, by score. - * + * * @param channel streaming channel that receives a call for every scored value * @param key the key * @param min min score @@ -521,7 +590,7 @@ public interface NodeSelectionSortedSetAsyncCommands { /** * Stream over a range of members with scores in a sorted set, by score. - * + * * @param channel streaming channel that receives a call for every scored value * @param key the key * @param min min score @@ -548,7 +617,7 @@ public interface NodeSelectionSortedSetAsyncCommands { /** * Determine the index of a member in a sorted set. - * + * * @param key the key * @param member the member type: value * @return Long integer-reply the rank of {@code member}. If {@code member} does not exist in the sorted set or {@code key} @@ -558,28 +627,50 @@ public interface NodeSelectionSortedSetAsyncCommands { /** * Remove one or more members from a sorted set. - * + * * @param key the key * @param members the member type: value * @return Long integer-reply specifically: - * + * * The number of members removed from the sorted set, not including non existing members. */ AsyncExecutions zrem(K key, V... members); /** - * Remove all members in a sorted set within the given indexes. - * + * Remove all members in a sorted set between the given lexicographical range. + * * @param key the key - * @param start the start type: long - * @param stop the stop type: long - * @return Long integer-reply the number of elements removed. + * @param min min score + * @param max max score + * @return Long integer-reply the number of elements removed. + * @deprecated Use {@link #zremrangebylex(java.lang.Object, Range)} + */ + @Deprecated + AsyncExecutions zremrangebylex(K key, String min, String max); + + /** + * Remove all members in a sorted set between the given lexicographical range. + * + * @param key the key + * @param range the range + * @return Long integer-reply the number of elements removed. + * @since 4.3 + */ + AsyncExecutions zremrangebylex(K key, Range range); + + /** + * Remove all members in a sorted set within the given indexes. + * + * @param key the key + * @param start the start type: long + * @param stop the stop type: long + * @return Long integer-reply the number of elements removed. */ AsyncExecutions zremrangebyrank(K key, long start, long stop); /** * Remove all members in a sorted set within the given scores. - * + * * @param key the key * @param min min score * @param max max score @@ -591,7 +682,7 @@ public interface NodeSelectionSortedSetAsyncCommands { /** * Remove all members in a sorted set within the given scores. - * + * * @param key the key * @param min min score * @param max max score @@ -613,7 +704,7 @@ public interface NodeSelectionSortedSetAsyncCommands { /** * Return a range of members in a sorted set, by index, with scores ordered from high to low. - * + * * @param key the key * @param start the start * @param stop the stop @@ -621,9 +712,20 @@ public interface NodeSelectionSortedSetAsyncCommands { */ AsyncExecutions> zrevrange(K key, long start, long stop); + /** + * Stream over a range of members in a sorted set, by index, with scores ordered from high to low. + * + * @param channel streaming channel that receives a call for every scored value + * @param key the key + * @param start the start + * @param stop the stop + * @return Long count of elements in the specified range. + */ + AsyncExecutions zrevrange(ValueStreamingChannel channel, K key, long start, long stop); + /** * Return a range of members with scores in a sorted set, by index, with scores ordered from high to low. - * + * * @param key the key * @param start the start * @param stop the stop @@ -631,6 +733,17 @@ public interface NodeSelectionSortedSetAsyncCommands { */ AsyncExecutions>> zrevrangeWithScores(K key, long start, long stop); + /** + * Stream over a range of members with scores in a sorted set, by index, with scores ordered from high to low. + * + * @param channel streaming channel that receives a call for every scored value + * @param key the key + * @param start the start + * @param stop the stop + * @return Long count of elements in the specified range. + */ + AsyncExecutions zrevrangeWithScores(ScoredValueStreamingChannel channel, K key, long start, long stop); + /** * Return a range of members in a sorted set, by lexicographical range ordered from high to low. * @@ -654,7 +767,7 @@ public interface NodeSelectionSortedSetAsyncCommands { /** * Return a range of members in a sorted set, by score, with scores ordered from high to low. - * + * * @param key the key * @param min min score * @param max max score @@ -666,7 +779,7 @@ public interface NodeSelectionSortedSetAsyncCommands { /** * Return a range of members in a sorted set, by score, with scores ordered from high to low. - * + * * @param key the key * @param min min score * @param max max score @@ -688,7 +801,7 @@ public interface NodeSelectionSortedSetAsyncCommands { /** * Return a range of members in a sorted set, by score, with scores ordered from high to low. - * + * * @param key the key * @param max max score * @param min min score @@ -702,7 +815,7 @@ public interface NodeSelectionSortedSetAsyncCommands { /** * Return a range of members in a sorted set, by score, with scores ordered from high to low. - * + * * @param key the key * @param max max score * @param min min score @@ -726,182 +839,160 @@ public interface NodeSelectionSortedSetAsyncCommands { AsyncExecutions> zrevrangebyscore(K key, Range range, Limit limit); /** - * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. - * + * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. + * + * @param channel streaming channel that receives a call for every value * @param key the key * @param max max score * @param min min score - * @return List<V> array-reply list of elements in the specified score range. - * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range)} + * @return Long count of elements in the specified range. + * @deprecated Use {@link #zrevrangebyscore(java.lang.Object, Range)} */ @Deprecated - AsyncExecutions>> zrevrangebyscoreWithScores(K key, double max, double min); + AsyncExecutions zrevrangebyscore(ValueStreamingChannel channel, K key, double max, double min); /** - * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. - * + * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. + * + * @param channel streaming channel that receives a call for every value * @param key the key - * @param max max score * @param min min score - * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. - * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range)} + * @param max max score + * @return Long count of elements in the specified range. + * @deprecated Use {@link #zrevrangebyscore(java.lang.Object, Range)} */ @Deprecated - AsyncExecutions>> zrevrangebyscoreWithScores(K key, String max, String min); + AsyncExecutions zrevrangebyscore(ValueStreamingChannel channel, K key, String max, String min); /** - * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. + * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. * + * @param channel streaming channel that receives a call for every value * @param key the key * @param range the range - * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @return Long count of elements in the specified range. * @since 4.3 */ - AsyncExecutions>> zrevrangebyscoreWithScores(K key, Range range); + AsyncExecutions zrevrangebyscore(ValueStreamingChannel channel, K key, Range range); /** - * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. - * + * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. + * + * @param channel streaming channel that receives a call for every value * @param key the key - * @param max max score * @param min min score + * @param max max score * @param offset the offset * @param count the count - * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @return Long count of elements in the specified range. * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range, Limit)} */ @Deprecated - AsyncExecutions>> zrevrangebyscoreWithScores(K key, double max, double min, long offset, long count); + AsyncExecutions zrevrangebyscore(ValueStreamingChannel channel, K key, double max, double min, long offset, long count); /** - * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. - * + * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. + * + * @param channel streaming channel that receives a call for every value * @param key the key - * @param max max score * @param min min score + * @param max max score * @param offset the offset * @param count the count - * @return List<V> array-reply list of elements in the specified score range. + * @return Long count of elements in the specified range. * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range, Limit)} */ @Deprecated - AsyncExecutions>> zrevrangebyscoreWithScores(K key, String max, String min, long offset, long count); + AsyncExecutions zrevrangebyscore(ValueStreamingChannel channel, K key, String max, String min, long offset, long count); /** - * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. + * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. * + * @param channel streaming channel that receives a call for every value * @param key the key * @param range the range - * @param limit limit - * @return List<V> array-reply list of elements in the specified score range. - * @since 4.3 - */ - AsyncExecutions>> zrevrangebyscoreWithScores(K key, Range range, Limit limit); - - /** - * Stream over a range of members in a sorted set, by index, with scores ordered from high to low. - * - * @param channel streaming channel that receives a call for every scored value - * @param key the key - * @param start the start - * @param stop the stop - * @return Long count of elements in the specified range. - */ - AsyncExecutions zrevrange(ValueStreamingChannel channel, K key, long start, long stop); - - /** - * Stream over a range of members with scores in a sorted set, by index, with scores ordered from high to low. - * - * @param channel streaming channel that receives a call for every scored value - * @param key the key - * @param start the start - * @param stop the stop + * @param limit the limit * @return Long count of elements in the specified range. + * @since 4.3 */ - AsyncExecutions zrevrangeWithScores(ScoredValueStreamingChannel channel, K key, long start, long stop); + AsyncExecutions zrevrangebyscore(ValueStreamingChannel channel, K key, Range range, Limit limit); /** - * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. - * - * @param channel streaming channel that receives a call for every value + * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. + * * @param key the key * @param max max score * @param min min score - * @return Long count of elements in the specified range. - * @deprecated Use {@link #zrevrangebyscore(java.lang.Object, Range)} + * @return List<V> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range)} */ @Deprecated - AsyncExecutions zrevrangebyscore(ValueStreamingChannel channel, K key, double max, double min); + AsyncExecutions>> zrevrangebyscoreWithScores(K key, double max, double min); /** - * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. - * - * @param channel streaming channel that receives a call for every value + * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. + * * @param key the key - * @param min min score * @param max max score - * @return Long count of elements in the specified range. - * @deprecated Use {@link #zrevrangebyscore(java.lang.Object, Range)} + * @param min min score + * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range)} */ @Deprecated - AsyncExecutions zrevrangebyscore(ValueStreamingChannel channel, K key, String max, String min); + AsyncExecutions>> zrevrangebyscoreWithScores(K key, String max, String min); /** - * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. + * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. * - * @param channel streaming channel that receives a call for every value * @param key the key * @param range the range - * @return Long count of elements in the specified range. + * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. * @since 4.3 */ - AsyncExecutions zrevrangebyscore(ValueStreamingChannel channel, K key, Range range); + AsyncExecutions>> zrevrangebyscoreWithScores(K key, Range range); /** - * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. - * - * @param channel streaming channel that receives a call for every value + * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. + * * @param key the key - * @param min min score * @param max max score + * @param min min score * @param offset the offset * @param count the count - * @return Long count of elements in the specified range. + * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range, Limit)} */ @Deprecated - AsyncExecutions zrevrangebyscore(ValueStreamingChannel channel, K key, double max, double min, long offset, long count); + AsyncExecutions>> zrevrangebyscoreWithScores(K key, double max, double min, long offset, long count); /** - * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. - * - * @param channel streaming channel that receives a call for every value + * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. + * * @param key the key - * @param min min score * @param max max score + * @param min min score * @param offset the offset * @param count the count - * @return Long count of elements in the specified range. + * @return List<V> array-reply list of elements in the specified score range. * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range, Limit)} */ @Deprecated - AsyncExecutions zrevrangebyscore(ValueStreamingChannel channel, K key, String max, String min, long offset, long count); + AsyncExecutions>> zrevrangebyscoreWithScores(K key, String max, String min, long offset, long count); /** - * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. + * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. * - * @param channel streaming channel that receives a call for every value * @param key the key * @param range the range - * @param limit the limit - * @return Long count of elements in the specified range. + * @param limit limit + * @return List<V> array-reply list of elements in the specified score range. * @since 4.3 */ - AsyncExecutions zrevrangebyscore(ValueStreamingChannel channel, K key, Range range, Limit limit); + AsyncExecutions>> zrevrangebyscoreWithScores(K key, Range range, Limit limit); /** * Stream over a range of members with scores in a sorted set, by score, with scores ordered from high to low. - * + * * @param channel streaming channel that receives a call for every scored value * @param key the key * @param min min score @@ -914,7 +1005,7 @@ public interface NodeSelectionSortedSetAsyncCommands { /** * Stream over a range of members with scores in a sorted set, by score, with scores ordered from high to low. - * + * * @param channel streaming channel that receives a call for every scored value * @param key the key * @param min min score @@ -937,7 +1028,7 @@ public interface NodeSelectionSortedSetAsyncCommands { /** * Stream over a range of members with scores in a sorted set, by score, with scores ordered from high to low. - * + * * @param channel streaming channel that receives a call for every scored value * @param key the key * @param min min score @@ -952,7 +1043,7 @@ public interface NodeSelectionSortedSetAsyncCommands { /** * Stream over a range of members with scores in a sorted set, by score, with scores ordered from high to low. - * + * * @param channel streaming channel that receives a call for every scored value * @param key the key * @param min min score @@ -979,7 +1070,7 @@ public interface NodeSelectionSortedSetAsyncCommands { /** * Determine the index of a member in a sorted set, with scores ordered from high to low. - * + * * @param key the key * @param member the member type: value * @return Long integer-reply the rank of {@code member}. If {@code member} does not exist in the sorted set or {@code key} @@ -987,35 +1078,6 @@ public interface NodeSelectionSortedSetAsyncCommands { */ AsyncExecutions zrevrank(K key, V member); - /** - * Get the score associated with the given member in a sorted set. - * - * @param key the key - * @param member the member type: value - * @return Double bulk-string-reply the score of {@code member} (a double precision floating point number), represented as - * string. - */ - AsyncExecutions zscore(K key, V member); - - /** - * Add multiple sorted sets and store the resulting sorted set in a new key. - * - * @param destination destination key - * @param keys source keys - * @return Long integer-reply the number of elements in the resulting sorted set at {@code destination}. - */ - AsyncExecutions zunionstore(K destination, K... keys); - - /** - * Add multiple sorted sets and store the resulting sorted set in a new key. - * - * @param destination the destination - * @param storeArgs the storeArgs - * @param keys the keys - * @return Long integer-reply the number of elements in the resulting sorted set at {@code destination}. - */ - AsyncExecutions zunionstore(K destination, ZStoreArgs storeArgs, K... keys); - /** * Incrementally iterate sorted sets elements and associated scores. * @@ -1073,7 +1135,7 @@ public interface NodeSelectionSortedSetAsyncCommands { /** * Incrementally iterate sorted sets elements and associated scores. - * + * * @param channel streaming channel that receives a call for every scored value * @param key the key * @param scanCursor cursor to resume from a previous scan, must not be {@literal null} @@ -1093,93 +1155,31 @@ public interface NodeSelectionSortedSetAsyncCommands { AsyncExecutions zscan(ScoredValueStreamingChannel channel, K key, ScanCursor scanCursor); /** - * Count the number of members in a sorted set between a given lexicographical range. - * - * @param key the key - * @param min min score - * @param max max score - * @return Long integer-reply the number of elements in the specified score range. - * @deprecated Use {@link #zlexcount(java.lang.Object, Range)} - */ - @Deprecated - AsyncExecutions zlexcount(K key, String min, String max); - - /** - * Count the number of members in a sorted set between a given lexicographical range. - * - * @param key the key - * @param range the range - * @return Long integer-reply the number of elements in the specified score range. - * @since 4.3 - */ - AsyncExecutions zlexcount(K key, Range range); - - /** - * Remove all members in a sorted set between the given lexicographical range. - * - * @param key the key - * @param min min score - * @param max max score - * @return Long integer-reply the number of elements removed. - * @deprecated Use {@link #zremrangebylex(java.lang.Object, Range)} - */ - @Deprecated - AsyncExecutions zremrangebylex(K key, String min, String max); - - /** - * Remove all members in a sorted set between the given lexicographical range. + * Get the score associated with the given member in a sorted set. * * @param key the key - * @param range the range - * @return Long integer-reply the number of elements removed. - * @since 4.3 - */ - AsyncExecutions zremrangebylex(K key, Range range); - - /** - * Return a range of members in a sorted set, by lexicographical range. - * - * @param key the key - * @param min min score - * @param max max score - * @return List<V> array-reply list of elements in the specified range. - * @deprecated Use {@link #zrangebylex(java.lang.Object, Range)} + * @param member the member type: value + * @return Double bulk-string-reply the score of {@code member} (a double precision floating point number), represented as + * string. */ - @Deprecated - AsyncExecutions> zrangebylex(K key, String min, String max); + AsyncExecutions zscore(K key, V member); /** - * Return a range of members in a sorted set, by lexicographical range. + * Add multiple sorted sets and store the resulting sorted set in a new key. * - * @param key the key - * @param range the range - * @return List<V> array-reply list of elements in the specified range. - * @since 4.3 - */ - AsyncExecutions> zrangebylex(K key, Range range); - - /** - * Return a range of members in a sorted set, by lexicographical range. - * - * @param key the key - * @param min min score - * @param max max score - * @param offset the offset - * @param count the count - * @return List<V> array-reply list of elements in the specified range. - * @deprecated Use {@link #zrangebylex(java.lang.Object, Range)} + * @param destination destination key + * @param keys source keys + * @return Long integer-reply the number of elements in the resulting sorted set at {@code destination}. */ - @Deprecated - AsyncExecutions> zrangebylex(K key, String min, String max, long offset, long count); + AsyncExecutions zunionstore(K destination, K... keys); /** - * Return a range of members in a sorted set, by lexicographical range. + * Add multiple sorted sets and store the resulting sorted set in a new key. * - * @param key the key - * @param range the range - * @param limit the limit - * @return List<V> array-reply list of elements in the specified range. - * @since 4.3 + * @param destination the destination + * @param storeArgs the storeArgs + * @param keys the keys + * @return Long integer-reply the number of elements in the resulting sorted set at {@code destination}. */ - AsyncExecutions> zrangebylex(K key, Range range, Limit limit); + AsyncExecutions zunionstore(K destination, ZStoreArgs storeArgs, K... keys); } diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionSortedSetCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionSortedSetCommands.java index 0fb61752cd..30c15399f2 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionSortedSetCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionSortedSetCommands.java @@ -200,9 +200,31 @@ public interface NodeSelectionSortedSetCommands { */ Executions zinterstore(K destination, ZStoreArgs storeArgs, K... keys); + /** + * Count the number of members in a sorted set between a given lexicographical range. + * + * @param key the key + * @param min min score + * @param max max score + * @return Long integer-reply the number of elements in the specified score range. + * @deprecated Use {@link #zlexcount(java.lang.Object, Range)} + */ + @Deprecated + Executions zlexcount(K key, String min, String max); + + /** + * Count the number of members in a sorted set between a given lexicographical range. + * + * @param key the key + * @param range the range + * @return Long integer-reply the number of elements in the specified score range. + * @since 4.3 + */ + Executions zlexcount(K key, Range range); + /** * Return a range of members in a sorted set, by index. - * + * * @param key the key * @param start the start * @param stop the stop @@ -210,9 +232,20 @@ public interface NodeSelectionSortedSetCommands { */ Executions> zrange(K key, long start, long stop); + /** + * Return a range of members in a sorted set, by index. + * + * @param channel streaming channel that receives a call for every value + * @param key the key + * @param start the start + * @param stop the stop + * @return Long count of elements in the specified range. + */ + Executions zrange(ValueStreamingChannel channel, K key, long start, long stop); + /** * Return a range of members with scores in a sorted set, by index. - * + * * @param key the key * @param start the start * @param stop the stop @@ -220,9 +253,67 @@ public interface NodeSelectionSortedSetCommands { */ Executions>> zrangeWithScores(K key, long start, long stop); + /** + * Stream over a range of members with scores in a sorted set, by index. + * + * @param channel streaming channel that receives a call for every value + * @param key the key + * @param start the start + * @param stop the stop + * @return Long count of elements in the specified range. + */ + Executions zrangeWithScores(ScoredValueStreamingChannel channel, K key, long start, long stop); + + /** + * Return a range of members in a sorted set, by lexicographical range. + * + * @param key the key + * @param min min score + * @param max max score + * @return List<V> array-reply list of elements in the specified range. + * @deprecated Use {@link #zrangebylex(java.lang.Object, Range)} + */ + @Deprecated + Executions> zrangebylex(K key, String min, String max); + + /** + * Return a range of members in a sorted set, by lexicographical range. + * + * @param key the key + * @param range the range + * @return List<V> array-reply list of elements in the specified range. + * @since 4.3 + */ + Executions> zrangebylex(K key, Range range); + + /** + * Return a range of members in a sorted set, by lexicographical range. + * + * @param key the key + * @param min min score + * @param max max score + * @param offset the offset + * @param count the count + * @return List<V> array-reply list of elements in the specified range. + * @deprecated Use {@link #zrangebylex(java.lang.Object, Range)} + */ + @Deprecated + Executions> zrangebylex(K key, String min, String max, long offset, long count); + + /** + * Return a range of members in a sorted set, by lexicographical range. + * + * @param key the key + * @param range the range + * @param limit the limit + * @return List<V> array-reply list of elements in the specified range. + * @since 4.3 + */ + Executions> zrangebylex(K key, Range range, Limit limit); + /** * Return a range of members in a sorted set, by score. - * + * * @param key the key * @param min min score * @param max max score @@ -234,7 +325,7 @@ public interface NodeSelectionSortedSetCommands { /** * Return a range of members in a sorted set, by score. - * + * * @param key the key * @param min min score * @param max max score @@ -256,7 +347,7 @@ public interface NodeSelectionSortedSetCommands { /** * Return a range of members in a sorted set, by score. - * + * * @param key the key * @param min min score * @param max max score @@ -270,7 +361,7 @@ public interface NodeSelectionSortedSetCommands { /** * Return a range of members in a sorted set, by score. - * + * * @param key the key * @param min min score * @param max max score @@ -294,181 +385,159 @@ public interface NodeSelectionSortedSetCommands { Executions> zrangebyscore(K key, Range range, Limit limit); /** - * Return a range of members with score in a sorted set, by score. + * Stream over a range of members in a sorted set, by score. * + * @param channel streaming channel that receives a call for every value * @param key the key * @param min min score * @param max max score - * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. - * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range)} + * @return Long count of elements in the specified score range. + * @deprecated Use {@link #zrangebyscore(ValueStreamingChannel, java.lang.Object, Range)} */ @Deprecated - Executions>> zrangebyscoreWithScores(K key, double min, double max); + Executions zrangebyscore(ValueStreamingChannel channel, K key, double min, double max); /** - * Return a range of members with score in a sorted set, by score. + * Stream over a range of members in a sorted set, by score. * + * @param channel streaming channel that receives a call for every value * @param key the key * @param min min score * @param max max score - * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. - * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range)} + * @return Long count of elements in the specified score range. + * @deprecated Use {@link #zrangebyscore(ValueStreamingChannel, java.lang.Object, Range)} */ @Deprecated - Executions>> zrangebyscoreWithScores(K key, String min, String max); + Executions zrangebyscore(ValueStreamingChannel channel, K key, String min, String max); /** - * Return a range of members with score in a sorted set, by score. + * Stream over a range of members in a sorted set, by score. * + * @param channel streaming channel that receives a call for every value * @param key the key * @param range the range - * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @return Long count of elements in the specified score range. * @since 4.3 */ - Executions>> zrangebyscoreWithScores(K key, Range range); + Executions zrangebyscore(ValueStreamingChannel channel, K key, Range range); /** - * Return a range of members with score in a sorted set, by score. + * Stream over range of members in a sorted set, by score. * + * @param channel streaming channel that receives a call for every value * @param key the key * @param min min score * @param max max score * @param offset the offset * @param count the count - * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. - * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range, Limit limit)} + * @return Long count of elements in the specified score range. + * @deprecated Use {@link #zrangebyscore(ValueStreamingChannel, java.lang.Object, Range, Limit limit)} */ - Executions>> zrangebyscoreWithScores(K key, double min, double max, long offset, long count); + @Deprecated + Executions zrangebyscore(ValueStreamingChannel channel, K key, double min, double max, long offset, long count); /** - * Return a range of members with score in a sorted set, by score. + * Stream over a range of members in a sorted set, by score. * + * @param channel streaming channel that receives a call for every value * @param key the key * @param min min score * @param max max score * @param offset the offset * @param count the count - * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. - * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range, Limit)} + * @return Long count of elements in the specified score range. + * @deprecated Use {@link #zrangebyscore(ValueStreamingChannel, java.lang.Object, Range, Limit limit)} */ @Deprecated - Executions>> zrangebyscoreWithScores(K key, String min, String max, long offset, long count); + Executions zrangebyscore(ValueStreamingChannel channel, K key, String min, String max, long offset, long count); /** - * Return a range of members with score in a sorted set, by score. + * Stream over a range of members in a sorted set, by score. * + * @param channel streaming channel that receives a call for every value * @param key the key * @param range the range * @param limit the limit - * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @return Long count of elements in the specified score range. * @since 4.3 */ - Executions>> zrangebyscoreWithScores(K key, Range range, Limit limit); - - /** - * Return a range of members in a sorted set, by index. - * - * @param channel streaming channel that receives a call for every value - * @param key the key - * @param start the start - * @param stop the stop - * @return Long count of elements in the specified range. - */ - Executions zrange(ValueStreamingChannel channel, K key, long start, long stop); - - /** - * Stream over a range of members with scores in a sorted set, by index. - * - * @param channel streaming channel that receives a call for every value - * @param key the key - * @param start the start - * @param stop the stop - * @return Long count of elements in the specified range. - */ - Executions zrangeWithScores(ScoredValueStreamingChannel channel, K key, long start, long stop); + Executions zrangebyscore(ValueStreamingChannel channel, K key, Range range, Limit limit); /** - * Stream over a range of members in a sorted set, by score. - * - * @param channel streaming channel that receives a call for every value + * Return a range of members with score in a sorted set, by score. + * * @param key the key * @param min min score * @param max max score - * @return Long count of elements in the specified score range. - * @deprecated Use {@link #zrangebyscore(ValueStreamingChannel, java.lang.Object, Range)} + * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range)} */ @Deprecated - Executions zrangebyscore(ValueStreamingChannel channel, K key, double min, double max); + Executions>> zrangebyscoreWithScores(K key, double min, double max); /** - * Stream over a range of members in a sorted set, by score. - * - * @param channel streaming channel that receives a call for every value + * Return a range of members with score in a sorted set, by score. + * * @param key the key * @param min min score * @param max max score - * @return Long count of elements in the specified score range. - * @deprecated Use {@link #zrangebyscore(ValueStreamingChannel, java.lang.Object, Range)} + * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range)} */ @Deprecated - Executions zrangebyscore(ValueStreamingChannel channel, K key, String min, String max); + Executions>> zrangebyscoreWithScores(K key, String min, String max); /** - * Stream over a range of members in a sorted set, by score. + * Return a range of members with score in a sorted set, by score. * - * @param channel streaming channel that receives a call for every value * @param key the key * @param range the range - * @return Long count of elements in the specified score range. + * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. * @since 4.3 */ - Executions zrangebyscore(ValueStreamingChannel channel, K key, Range range); + Executions>> zrangebyscoreWithScores(K key, Range range); /** - * Stream over range of members in a sorted set, by score. - * - * @param channel streaming channel that receives a call for every value + * Return a range of members with score in a sorted set, by score. + * * @param key the key * @param min min score * @param max max score * @param offset the offset * @param count the count - * @return Long count of elements in the specified score range. - * @deprecated Use {@link #zrangebyscore(ValueStreamingChannel, java.lang.Object, Range, Limit limit)} + * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range, Limit limit)} */ - @Deprecated - Executions zrangebyscore(ValueStreamingChannel channel, K key, double min, double max, long offset, long count); + Executions>> zrangebyscoreWithScores(K key, double min, double max, long offset, long count); /** - * Stream over a range of members in a sorted set, by score. - * - * @param channel streaming channel that receives a call for every value + * Return a range of members with score in a sorted set, by score. + * * @param key the key * @param min min score * @param max max score * @param offset the offset * @param count the count - * @return Long count of elements in the specified score range. - * @deprecated Use {@link #zrangebyscore(ValueStreamingChannel, java.lang.Object, Range, Limit limit)} + * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range, Limit)} */ @Deprecated - Executions zrangebyscore(ValueStreamingChannel channel, K key, String min, String max, long offset, long count); + Executions>> zrangebyscoreWithScores(K key, String min, String max, long offset, long count); /** - * Stream over a range of members in a sorted set, by score. + * Return a range of members with score in a sorted set, by score. * - * @param channel streaming channel that receives a call for every value * @param key the key * @param range the range * @param limit the limit - * @return Long count of elements in the specified score range. + * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. * @since 4.3 */ - Executions zrangebyscore(ValueStreamingChannel channel, K key, Range range, Limit limit); + Executions>> zrangebyscoreWithScores(K key, Range range, Limit limit); /** * Stream over a range of members with scores in a sorted set, by score. - * + * * @param channel streaming channel that receives a call for every scored value * @param key the key * @param min min score @@ -481,7 +550,7 @@ public interface NodeSelectionSortedSetCommands { /** * Stream over a range of members with scores in a sorted set, by score. - * + * * @param channel streaming channel that receives a call for every scored value * @param key the key * @param min min score @@ -505,7 +574,7 @@ public interface NodeSelectionSortedSetCommands { /** * Stream over a range of members with scores in a sorted set, by score. - * + * * @param channel streaming channel that receives a call for every scored value * @param key the key * @param min min score @@ -520,7 +589,7 @@ public interface NodeSelectionSortedSetCommands { /** * Stream over a range of members with scores in a sorted set, by score. - * + * * @param channel streaming channel that receives a call for every scored value * @param key the key * @param min min score @@ -547,7 +616,7 @@ public interface NodeSelectionSortedSetCommands { /** * Determine the index of a member in a sorted set. - * + * * @param key the key * @param member the member type: value * @return Long integer-reply the rank of {@code member}. If {@code member} does not exist in the sorted set or {@code key} @@ -557,28 +626,50 @@ public interface NodeSelectionSortedSetCommands { /** * Remove one or more members from a sorted set. - * + * * @param key the key * @param members the member type: value * @return Long integer-reply specifically: - * + * * The number of members removed from the sorted set, not including non existing members. */ Executions zrem(K key, V... members); /** - * Remove all members in a sorted set within the given indexes. - * + * Remove all members in a sorted set between the given lexicographical range. + * * @param key the key - * @param start the start type: long - * @param stop the stop type: long - * @return Long integer-reply the number of elements removed. + * @param min min score + * @param max max score + * @return Long integer-reply the number of elements removed. + * @deprecated Use {@link #zremrangebylex(java.lang.Object, Range)} + */ + @Deprecated + Executions zremrangebylex(K key, String min, String max); + + /** + * Remove all members in a sorted set between the given lexicographical range. + * + * @param key the key + * @param range the range + * @return Long integer-reply the number of elements removed. + * @since 4.3 + */ + Executions zremrangebylex(K key, Range range); + + /** + * Remove all members in a sorted set within the given indexes. + * + * @param key the key + * @param start the start type: long + * @param stop the stop type: long + * @return Long integer-reply the number of elements removed. */ Executions zremrangebyrank(K key, long start, long stop); /** * Remove all members in a sorted set within the given scores. - * + * * @param key the key * @param min min score * @param max max score @@ -590,7 +681,7 @@ public interface NodeSelectionSortedSetCommands { /** * Remove all members in a sorted set within the given scores. - * + * * @param key the key * @param min min score * @param max max score @@ -612,7 +703,7 @@ public interface NodeSelectionSortedSetCommands { /** * Return a range of members in a sorted set, by index, with scores ordered from high to low. - * + * * @param key the key * @param start the start * @param stop the stop @@ -620,9 +711,20 @@ public interface NodeSelectionSortedSetCommands { */ Executions> zrevrange(K key, long start, long stop); + /** + * Stream over a range of members in a sorted set, by index, with scores ordered from high to low. + * + * @param channel streaming channel that receives a call for every scored value + * @param key the key + * @param start the start + * @param stop the stop + * @return Long count of elements in the specified range. + */ + Executions zrevrange(ValueStreamingChannel channel, K key, long start, long stop); + /** * Return a range of members with scores in a sorted set, by index, with scores ordered from high to low. - * + * * @param key the key * @param start the start * @param stop the stop @@ -630,6 +732,17 @@ public interface NodeSelectionSortedSetCommands { */ Executions>> zrevrangeWithScores(K key, long start, long stop); + /** + * Stream over a range of members with scores in a sorted set, by index, with scores ordered from high to low. + * + * @param channel streaming channel that receives a call for every scored value + * @param key the key + * @param start the start + * @param stop the stop + * @return Long count of elements in the specified range. + */ + Executions zrevrangeWithScores(ScoredValueStreamingChannel channel, K key, long start, long stop); + /** * Return a range of members in a sorted set, by lexicographical range ordered from high to low. * @@ -653,7 +766,7 @@ public interface NodeSelectionSortedSetCommands { /** * Return a range of members in a sorted set, by score, with scores ordered from high to low. - * + * * @param key the key * @param min min score * @param max max score @@ -665,7 +778,7 @@ public interface NodeSelectionSortedSetCommands { /** * Return a range of members in a sorted set, by score, with scores ordered from high to low. - * + * * @param key the key * @param min min score * @param max max score @@ -687,7 +800,7 @@ public interface NodeSelectionSortedSetCommands { /** * Return a range of members in a sorted set, by score, with scores ordered from high to low. - * + * * @param key the key * @param max max score * @param min min score @@ -701,7 +814,7 @@ public interface NodeSelectionSortedSetCommands { /** * Return a range of members in a sorted set, by score, with scores ordered from high to low. - * + * * @param key the key * @param max max score * @param min min score @@ -725,182 +838,160 @@ public interface NodeSelectionSortedSetCommands { Executions> zrevrangebyscore(K key, Range range, Limit limit); /** - * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. - * + * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. + * + * @param channel streaming channel that receives a call for every value * @param key the key * @param max max score * @param min min score - * @return List<V> array-reply list of elements in the specified score range. - * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range)} + * @return Long count of elements in the specified range. + * @deprecated Use {@link #zrevrangebyscore(java.lang.Object, Range)} */ @Deprecated - Executions>> zrevrangebyscoreWithScores(K key, double max, double min); + Executions zrevrangebyscore(ValueStreamingChannel channel, K key, double max, double min); /** - * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. - * + * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. + * + * @param channel streaming channel that receives a call for every value * @param key the key - * @param max max score * @param min min score - * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. - * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range)} + * @param max max score + * @return Long count of elements in the specified range. + * @deprecated Use {@link #zrevrangebyscore(java.lang.Object, Range)} */ @Deprecated - Executions>> zrevrangebyscoreWithScores(K key, String max, String min); + Executions zrevrangebyscore(ValueStreamingChannel channel, K key, String max, String min); /** - * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. + * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. * + * @param channel streaming channel that receives a call for every value * @param key the key * @param range the range - * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @return Long count of elements in the specified range. * @since 4.3 */ - Executions>> zrevrangebyscoreWithScores(K key, Range range); + Executions zrevrangebyscore(ValueStreamingChannel channel, K key, Range range); /** - * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. - * + * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. + * + * @param channel streaming channel that receives a call for every value * @param key the key - * @param max max score * @param min min score + * @param max max score * @param offset the offset * @param count the count - * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @return Long count of elements in the specified range. * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range, Limit)} */ @Deprecated - Executions>> zrevrangebyscoreWithScores(K key, double max, double min, long offset, long count); + Executions zrevrangebyscore(ValueStreamingChannel channel, K key, double max, double min, long offset, long count); /** - * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. - * + * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. + * + * @param channel streaming channel that receives a call for every value * @param key the key - * @param max max score * @param min min score + * @param max max score * @param offset the offset * @param count the count - * @return List<V> array-reply list of elements in the specified score range. + * @return Long count of elements in the specified range. * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range, Limit)} */ @Deprecated - Executions>> zrevrangebyscoreWithScores(K key, String max, String min, long offset, long count); + Executions zrevrangebyscore(ValueStreamingChannel channel, K key, String max, String min, long offset, long count); /** - * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. + * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. * + * @param channel streaming channel that receives a call for every value * @param key the key * @param range the range - * @param limit limit - * @return List<V> array-reply list of elements in the specified score range. - * @since 4.3 - */ - Executions>> zrevrangebyscoreWithScores(K key, Range range, Limit limit); - - /** - * Stream over a range of members in a sorted set, by index, with scores ordered from high to low. - * - * @param channel streaming channel that receives a call for every scored value - * @param key the key - * @param start the start - * @param stop the stop - * @return Long count of elements in the specified range. - */ - Executions zrevrange(ValueStreamingChannel channel, K key, long start, long stop); - - /** - * Stream over a range of members with scores in a sorted set, by index, with scores ordered from high to low. - * - * @param channel streaming channel that receives a call for every scored value - * @param key the key - * @param start the start - * @param stop the stop + * @param limit the limit * @return Long count of elements in the specified range. + * @since 4.3 */ - Executions zrevrangeWithScores(ScoredValueStreamingChannel channel, K key, long start, long stop); + Executions zrevrangebyscore(ValueStreamingChannel channel, K key, Range range, Limit limit); /** - * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. - * - * @param channel streaming channel that receives a call for every value + * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. + * * @param key the key * @param max max score * @param min min score - * @return Long count of elements in the specified range. - * @deprecated Use {@link #zrevrangebyscore(java.lang.Object, Range)} + * @return List<V> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range)} */ @Deprecated - Executions zrevrangebyscore(ValueStreamingChannel channel, K key, double max, double min); + Executions>> zrevrangebyscoreWithScores(K key, double max, double min); /** - * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. - * - * @param channel streaming channel that receives a call for every value + * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. + * * @param key the key - * @param min min score * @param max max score - * @return Long count of elements in the specified range. - * @deprecated Use {@link #zrevrangebyscore(java.lang.Object, Range)} + * @param min min score + * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range)} */ @Deprecated - Executions zrevrangebyscore(ValueStreamingChannel channel, K key, String max, String min); + Executions>> zrevrangebyscoreWithScores(K key, String max, String min); /** - * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. + * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. * - * @param channel streaming channel that receives a call for every value * @param key the key * @param range the range - * @return Long count of elements in the specified range. + * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. * @since 4.3 */ - Executions zrevrangebyscore(ValueStreamingChannel channel, K key, Range range); + Executions>> zrevrangebyscoreWithScores(K key, Range range); /** - * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. - * - * @param channel streaming channel that receives a call for every value + * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. + * * @param key the key - * @param min min score * @param max max score + * @param min min score * @param offset the offset * @param count the count - * @return Long count of elements in the specified range. + * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range, Limit)} */ @Deprecated - Executions zrevrangebyscore(ValueStreamingChannel channel, K key, double max, double min, long offset, long count); + Executions>> zrevrangebyscoreWithScores(K key, double max, double min, long offset, long count); /** - * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. - * - * @param channel streaming channel that receives a call for every value + * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. + * * @param key the key - * @param min min score * @param max max score + * @param min min score * @param offset the offset * @param count the count - * @return Long count of elements in the specified range. + * @return List<V> array-reply list of elements in the specified score range. * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range, Limit)} */ @Deprecated - Executions zrevrangebyscore(ValueStreamingChannel channel, K key, String max, String min, long offset, long count); + Executions>> zrevrangebyscoreWithScores(K key, String max, String min, long offset, long count); /** - * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. + * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. * - * @param channel streaming channel that receives a call for every value * @param key the key * @param range the range - * @param limit the limit - * @return Long count of elements in the specified range. + * @param limit limit + * @return List<V> array-reply list of elements in the specified score range. * @since 4.3 */ - Executions zrevrangebyscore(ValueStreamingChannel channel, K key, Range range, Limit limit); + Executions>> zrevrangebyscoreWithScores(K key, Range range, Limit limit); /** * Stream over a range of members with scores in a sorted set, by score, with scores ordered from high to low. - * + * * @param channel streaming channel that receives a call for every scored value * @param key the key * @param min min score @@ -913,7 +1004,7 @@ public interface NodeSelectionSortedSetCommands { /** * Stream over a range of members with scores in a sorted set, by score, with scores ordered from high to low. - * + * * @param channel streaming channel that receives a call for every scored value * @param key the key * @param min min score @@ -936,7 +1027,7 @@ public interface NodeSelectionSortedSetCommands { /** * Stream over a range of members with scores in a sorted set, by score, with scores ordered from high to low. - * + * * @param channel streaming channel that receives a call for every scored value * @param key the key * @param min min score @@ -951,7 +1042,7 @@ public interface NodeSelectionSortedSetCommands { /** * Stream over a range of members with scores in a sorted set, by score, with scores ordered from high to low. - * + * * @param channel streaming channel that receives a call for every scored value * @param key the key * @param min min score @@ -978,7 +1069,7 @@ public interface NodeSelectionSortedSetCommands { /** * Determine the index of a member in a sorted set, with scores ordered from high to low. - * + * * @param key the key * @param member the member type: value * @return Long integer-reply the rank of {@code member}. If {@code member} does not exist in the sorted set or {@code key} @@ -986,35 +1077,6 @@ public interface NodeSelectionSortedSetCommands { */ Executions zrevrank(K key, V member); - /** - * Get the score associated with the given member in a sorted set. - * - * @param key the key - * @param member the member type: value - * @return Double bulk-string-reply the score of {@code member} (a double precision floating point number), represented as - * string. - */ - Executions zscore(K key, V member); - - /** - * Add multiple sorted sets and store the resulting sorted set in a new key. - * - * @param destination destination key - * @param keys source keys - * @return Long integer-reply the number of elements in the resulting sorted set at {@code destination}. - */ - Executions zunionstore(K destination, K... keys); - - /** - * Add multiple sorted sets and store the resulting sorted set in a new key. - * - * @param destination the destination - * @param storeArgs the storeArgs - * @param keys the keys - * @return Long integer-reply the number of elements in the resulting sorted set at {@code destination}. - */ - Executions zunionstore(K destination, ZStoreArgs storeArgs, K... keys); - /** * Incrementally iterate sorted sets elements and associated scores. * @@ -1072,7 +1134,7 @@ public interface NodeSelectionSortedSetCommands { /** * Incrementally iterate sorted sets elements and associated scores. - * + * * @param channel streaming channel that receives a call for every scored value * @param key the key * @param scanCursor cursor to resume from a previous scan, must not be {@literal null} @@ -1092,93 +1154,31 @@ public interface NodeSelectionSortedSetCommands { Executions zscan(ScoredValueStreamingChannel channel, K key, ScanCursor scanCursor); /** - * Count the number of members in a sorted set between a given lexicographical range. - * - * @param key the key - * @param min min score - * @param max max score - * @return Long integer-reply the number of elements in the specified score range. - * @deprecated Use {@link #zlexcount(java.lang.Object, Range)} - */ - @Deprecated - Executions zlexcount(K key, String min, String max); - - /** - * Count the number of members in a sorted set between a given lexicographical range. - * - * @param key the key - * @param range the range - * @return Long integer-reply the number of elements in the specified score range. - * @since 4.3 - */ - Executions zlexcount(K key, Range range); - - /** - * Remove all members in a sorted set between the given lexicographical range. - * - * @param key the key - * @param min min score - * @param max max score - * @return Long integer-reply the number of elements removed. - * @deprecated Use {@link #zremrangebylex(java.lang.Object, Range)} - */ - @Deprecated - Executions zremrangebylex(K key, String min, String max); - - /** - * Remove all members in a sorted set between the given lexicographical range. + * Get the score associated with the given member in a sorted set. * * @param key the key - * @param range the range - * @return Long integer-reply the number of elements removed. - * @since 4.3 - */ - Executions zremrangebylex(K key, Range range); - - /** - * Return a range of members in a sorted set, by lexicographical range. - * - * @param key the key - * @param min min score - * @param max max score - * @return List<V> array-reply list of elements in the specified range. - * @deprecated Use {@link #zrangebylex(java.lang.Object, Range)} + * @param member the member type: value + * @return Double bulk-string-reply the score of {@code member} (a double precision floating point number), represented as + * string. */ - @Deprecated - Executions> zrangebylex(K key, String min, String max); + Executions zscore(K key, V member); /** - * Return a range of members in a sorted set, by lexicographical range. + * Add multiple sorted sets and store the resulting sorted set in a new key. * - * @param key the key - * @param range the range - * @return List<V> array-reply list of elements in the specified range. - * @since 4.3 - */ - Executions> zrangebylex(K key, Range range); - - /** - * Return a range of members in a sorted set, by lexicographical range. - * - * @param key the key - * @param min min score - * @param max max score - * @param offset the offset - * @param count the count - * @return List<V> array-reply list of elements in the specified range. - * @deprecated Use {@link #zrangebylex(java.lang.Object, Range)} + * @param destination destination key + * @param keys source keys + * @return Long integer-reply the number of elements in the resulting sorted set at {@code destination}. */ - @Deprecated - Executions> zrangebylex(K key, String min, String max, long offset, long count); + Executions zunionstore(K destination, K... keys); /** - * Return a range of members in a sorted set, by lexicographical range. + * Add multiple sorted sets and store the resulting sorted set in a new key. * - * @param key the key - * @param range the range - * @param limit the limit - * @return List<V> array-reply list of elements in the specified range. - * @since 4.3 + * @param destination the destination + * @param storeArgs the storeArgs + * @param keys the keys + * @return Long integer-reply the number of elements in the resulting sorted set at {@code destination}. */ - Executions> zrangebylex(K key, Range range, Limit limit); + Executions zunionstore(K destination, ZStoreArgs storeArgs, K... keys); } diff --git a/src/main/java/com/lambdaworks/redis/masterslave/ReadOnlyCommands.java b/src/main/java/com/lambdaworks/redis/masterslave/ReadOnlyCommands.java index a1ffbe5fc4..c48043db4c 100644 --- a/src/main/java/com/lambdaworks/redis/masterslave/ReadOnlyCommands.java +++ b/src/main/java/com/lambdaworks/redis/masterslave/ReadOnlyCommands.java @@ -27,13 +27,13 @@ class ReadOnlyCommands { } enum CommandName { - ASKING, BITCOUNT, BITPOS, CLIENT, COMMAND, DUMP, ECHO, EVAL, EVALSHA, EXISTS, - /**/GEODIST, GEOPOS, GEORADIUS, GEORADIUSBYMEMBER, GEOHASH, GET, GETBIT, - /**/GETRANGE, HEXISTS, HGET, HGETALL, HKEYS, HLEN, HMGET, HSCAN, HSTRLEN, - /**/HVALS, INFO, KEYS, LINDEX, LLEN, LRANGE, MGET, MULTI, PFCOUNT, PTTL, - /**/RANDOMKEY, READWRITE, SCAN, SCARD, SCRIPT, - /**/SDIFF, SINTER, SISMEMBER, SMEMBERS, SRANDMEMBER, SSCAN, STRLEN, - /**/SUNION, TIME, TTL, TYPE, WAIT, ZCARD, ZCOUNT, ZLEXCOUNT, ZRANGE, - /**/ZRANGEBYLEX, ZRANGEBYSCORE, ZRANK, ZREVRANGE, ZREVRANGEBYLEX, ZREVRANGEBYSCORE, ZREVRANK, ZSCAN, ZSCORE, + ASKING, BITCOUNT, BITPOS, CLIENT, COMMAND, DUMP, ECHO, EVAL, EVALSHA, EXISTS, // + GEODIST, GEOPOS, GEORADIUS, GEORADIUSBYMEMBER, GEOHASH, GET, GETBIT, // + GETRANGE, HEXISTS, HGET, HGETALL, HKEYS, HLEN, HMGET, HSCAN, HSTRLEN, // + HVALS, INFO, KEYS, LINDEX, LLEN, LRANGE, MGET, MULTI, PFCOUNT, PTTL, // + RANDOMKEY, READWRITE, SCAN, SCARD, SCRIPT, // + SDIFF, SINTER, SISMEMBER, SMEMBERS, SRANDMEMBER, SSCAN, STRLEN, // + SUNION, TIME, TTL, TYPE, WAIT, ZCARD, ZCOUNT, ZLEXCOUNT, ZRANGE, // + ZRANGEBYLEX, ZRANGEBYSCORE, ZRANK, ZREVRANGE, ZREVRANGEBYLEX, ZREVRANGEBYSCORE, ZREVRANK, ZSCAN, ZSCORE, } } diff --git a/src/main/templates/com/lambdaworks/redis/api/RedisSortedSetCommands.java b/src/main/templates/com/lambdaworks/redis/api/RedisSortedSetCommands.java index fe674fdcfc..6e26962c72 100644 --- a/src/main/templates/com/lambdaworks/redis/api/RedisSortedSetCommands.java +++ b/src/main/templates/com/lambdaworks/redis/api/RedisSortedSetCommands.java @@ -200,9 +200,31 @@ public interface RedisSortedSetCommands { */ Long zinterstore(K destination, ZStoreArgs storeArgs, K... keys); + /** + * Count the number of members in a sorted set between a given lexicographical range. + * + * @param key the key + * @param min min score + * @param max max score + * @return Long integer-reply the number of elements in the specified score range. + * @deprecated Use {@link #zlexcount(java.lang.Object, Range)} + */ + @Deprecated + Long zlexcount(K key, String min, String max); + + /** + * Count the number of members in a sorted set between a given lexicographical range. + * + * @param key the key + * @param range the range + * @return Long integer-reply the number of elements in the specified score range. + * @since 4.3 + */ + Long zlexcount(K key, Range range); + /** * Return a range of members in a sorted set, by index. - * + * * @param key the key * @param start the start * @param stop the stop @@ -210,9 +232,20 @@ public interface RedisSortedSetCommands { */ List zrange(K key, long start, long stop); + /** + * Return a range of members in a sorted set, by index. + * + * @param channel streaming channel that receives a call for every value + * @param key the key + * @param start the start + * @param stop the stop + * @return Long count of elements in the specified range. + */ + Long zrange(ValueStreamingChannel channel, K key, long start, long stop); + /** * Return a range of members with scores in a sorted set, by index. - * + * * @param key the key * @param start the start * @param stop the stop @@ -220,9 +253,67 @@ public interface RedisSortedSetCommands { */ List> zrangeWithScores(K key, long start, long stop); + /** + * Stream over a range of members with scores in a sorted set, by index. + * + * @param channel streaming channel that receives a call for every value + * @param key the key + * @param start the start + * @param stop the stop + * @return Long count of elements in the specified range. + */ + Long zrangeWithScores(ScoredValueStreamingChannel channel, K key, long start, long stop); + + /** + * Return a range of members in a sorted set, by lexicographical range. + * + * @param key the key + * @param min min score + * @param max max score + * @return List<V> array-reply list of elements in the specified range. + * @deprecated Use {@link #zrangebylex(java.lang.Object, Range)} + */ + @Deprecated + List zrangebylex(K key, String min, String max); + + /** + * Return a range of members in a sorted set, by lexicographical range. + * + * @param key the key + * @param range the range + * @return List<V> array-reply list of elements in the specified range. + * @since 4.3 + */ + List zrangebylex(K key, Range range); + + /** + * Return a range of members in a sorted set, by lexicographical range. + * + * @param key the key + * @param min min score + * @param max max score + * @param offset the offset + * @param count the count + * @return List<V> array-reply list of elements in the specified range. + * @deprecated Use {@link #zrangebylex(java.lang.Object, Range)} + */ + @Deprecated + List zrangebylex(K key, String min, String max, long offset, long count); + + /** + * Return a range of members in a sorted set, by lexicographical range. + * + * @param key the key + * @param range the range + * @param limit the limit + * @return List<V> array-reply list of elements in the specified range. + * @since 4.3 + */ + List zrangebylex(K key, Range range, Limit limit); + /** * Return a range of members in a sorted set, by score. - * + * * @param key the key * @param min min score * @param max max score @@ -234,7 +325,7 @@ public interface RedisSortedSetCommands { /** * Return a range of members in a sorted set, by score. - * + * * @param key the key * @param min min score * @param max max score @@ -256,7 +347,7 @@ public interface RedisSortedSetCommands { /** * Return a range of members in a sorted set, by score. - * + * * @param key the key * @param min min score * @param max max score @@ -270,7 +361,7 @@ public interface RedisSortedSetCommands { /** * Return a range of members in a sorted set, by score. - * + * * @param key the key * @param min min score * @param max max score @@ -294,181 +385,159 @@ public interface RedisSortedSetCommands { List zrangebyscore(K key, Range range, Limit limit); /** - * Return a range of members with score in a sorted set, by score. + * Stream over a range of members in a sorted set, by score. * + * @param channel streaming channel that receives a call for every value * @param key the key * @param min min score * @param max max score - * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. - * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range)} + * @return Long count of elements in the specified score range. + * @deprecated Use {@link #zrangebyscore(ValueStreamingChannel, java.lang.Object, Range)} */ @Deprecated - List> zrangebyscoreWithScores(K key, double min, double max); + Long zrangebyscore(ValueStreamingChannel channel, K key, double min, double max); /** - * Return a range of members with score in a sorted set, by score. + * Stream over a range of members in a sorted set, by score. * + * @param channel streaming channel that receives a call for every value * @param key the key * @param min min score * @param max max score - * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. - * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range)} + * @return Long count of elements in the specified score range. + * @deprecated Use {@link #zrangebyscore(ValueStreamingChannel, java.lang.Object, Range)} */ @Deprecated - List> zrangebyscoreWithScores(K key, String min, String max); + Long zrangebyscore(ValueStreamingChannel channel, K key, String min, String max); /** - * Return a range of members with score in a sorted set, by score. + * Stream over a range of members in a sorted set, by score. * + * @param channel streaming channel that receives a call for every value * @param key the key * @param range the range - * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @return Long count of elements in the specified score range. * @since 4.3 */ - List> zrangebyscoreWithScores(K key, Range range); + Long zrangebyscore(ValueStreamingChannel channel, K key, Range range); /** - * Return a range of members with score in a sorted set, by score. + * Stream over range of members in a sorted set, by score. * + * @param channel streaming channel that receives a call for every value * @param key the key * @param min min score * @param max max score * @param offset the offset * @param count the count - * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. - * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range, Limit limit)} + * @return Long count of elements in the specified score range. + * @deprecated Use {@link #zrangebyscore(ValueStreamingChannel, java.lang.Object, Range, Limit limit)} */ - List> zrangebyscoreWithScores(K key, double min, double max, long offset, long count); + @Deprecated + Long zrangebyscore(ValueStreamingChannel channel, K key, double min, double max, long offset, long count); /** - * Return a range of members with score in a sorted set, by score. + * Stream over a range of members in a sorted set, by score. * + * @param channel streaming channel that receives a call for every value * @param key the key * @param min min score * @param max max score * @param offset the offset * @param count the count - * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. - * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range, Limit)} + * @return Long count of elements in the specified score range. + * @deprecated Use {@link #zrangebyscore(ValueStreamingChannel, java.lang.Object, Range, Limit limit)} */ @Deprecated - List> zrangebyscoreWithScores(K key, String min, String max, long offset, long count); + Long zrangebyscore(ValueStreamingChannel channel, K key, String min, String max, long offset, long count); /** - * Return a range of members with score in a sorted set, by score. + * Stream over a range of members in a sorted set, by score. * + * @param channel streaming channel that receives a call for every value * @param key the key * @param range the range * @param limit the limit - * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @return Long count of elements in the specified score range. * @since 4.3 */ - List> zrangebyscoreWithScores(K key, Range range, Limit limit); - - /** - * Return a range of members in a sorted set, by index. - * - * @param channel streaming channel that receives a call for every value - * @param key the key - * @param start the start - * @param stop the stop - * @return Long count of elements in the specified range. - */ - Long zrange(ValueStreamingChannel channel, K key, long start, long stop); - - /** - * Stream over a range of members with scores in a sorted set, by index. - * - * @param channel streaming channel that receives a call for every value - * @param key the key - * @param start the start - * @param stop the stop - * @return Long count of elements in the specified range. - */ - Long zrangeWithScores(ScoredValueStreamingChannel channel, K key, long start, long stop); + Long zrangebyscore(ValueStreamingChannel channel, K key, Range range, Limit limit); /** - * Stream over a range of members in a sorted set, by score. - * - * @param channel streaming channel that receives a call for every value + * Return a range of members with score in a sorted set, by score. + * * @param key the key * @param min min score * @param max max score - * @return Long count of elements in the specified score range. - * @deprecated Use {@link #zrangebyscore(ValueStreamingChannel, java.lang.Object, Range)} + * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range)} */ @Deprecated - Long zrangebyscore(ValueStreamingChannel channel, K key, double min, double max); + List> zrangebyscoreWithScores(K key, double min, double max); /** - * Stream over a range of members in a sorted set, by score. - * - * @param channel streaming channel that receives a call for every value + * Return a range of members with score in a sorted set, by score. + * * @param key the key * @param min min score * @param max max score - * @return Long count of elements in the specified score range. - * @deprecated Use {@link #zrangebyscore(ValueStreamingChannel, java.lang.Object, Range)} + * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range)} */ @Deprecated - Long zrangebyscore(ValueStreamingChannel channel, K key, String min, String max); + List> zrangebyscoreWithScores(K key, String min, String max); /** - * Stream over a range of members in a sorted set, by score. + * Return a range of members with score in a sorted set, by score. * - * @param channel streaming channel that receives a call for every value * @param key the key * @param range the range - * @return Long count of elements in the specified score range. + * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. * @since 4.3 */ - Long zrangebyscore(ValueStreamingChannel channel, K key, Range range); + List> zrangebyscoreWithScores(K key, Range range); /** - * Stream over range of members in a sorted set, by score. - * - * @param channel streaming channel that receives a call for every value + * Return a range of members with score in a sorted set, by score. + * * @param key the key * @param min min score * @param max max score * @param offset the offset * @param count the count - * @return Long count of elements in the specified score range. - * @deprecated Use {@link #zrangebyscore(ValueStreamingChannel, java.lang.Object, Range, Limit limit)} + * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range, Limit limit)} */ - @Deprecated - Long zrangebyscore(ValueStreamingChannel channel, K key, double min, double max, long offset, long count); + List> zrangebyscoreWithScores(K key, double min, double max, long offset, long count); /** - * Stream over a range of members in a sorted set, by score. - * - * @param channel streaming channel that receives a call for every value + * Return a range of members with score in a sorted set, by score. + * * @param key the key * @param min min score * @param max max score * @param offset the offset * @param count the count - * @return Long count of elements in the specified score range. - * @deprecated Use {@link #zrangebyscore(ValueStreamingChannel, java.lang.Object, Range, Limit limit)} + * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range, Limit)} */ @Deprecated - Long zrangebyscore(ValueStreamingChannel channel, K key, String min, String max, long offset, long count); + List> zrangebyscoreWithScores(K key, String min, String max, long offset, long count); /** - * Stream over a range of members in a sorted set, by score. + * Return a range of members with score in a sorted set, by score. * - * @param channel streaming channel that receives a call for every value * @param key the key * @param range the range * @param limit the limit - * @return Long count of elements in the specified score range. + * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. * @since 4.3 */ - Long zrangebyscore(ValueStreamingChannel channel, K key, Range range, Limit limit); + List> zrangebyscoreWithScores(K key, Range range, Limit limit); /** * Stream over a range of members with scores in a sorted set, by score. - * + * * @param channel streaming channel that receives a call for every scored value * @param key the key * @param min min score @@ -481,7 +550,7 @@ public interface RedisSortedSetCommands { /** * Stream over a range of members with scores in a sorted set, by score. - * + * * @param channel streaming channel that receives a call for every scored value * @param key the key * @param min min score @@ -505,7 +574,7 @@ public interface RedisSortedSetCommands { /** * Stream over a range of members with scores in a sorted set, by score. - * + * * @param channel streaming channel that receives a call for every scored value * @param key the key * @param min min score @@ -521,7 +590,7 @@ Long zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, doub /** * Stream over a range of members with scores in a sorted set, by score. - * + * * @param channel streaming channel that receives a call for every scored value * @param key the key * @param min min score @@ -549,7 +618,7 @@ Long zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, Stri /** * Determine the index of a member in a sorted set. - * + * * @param key the key * @param member the member type: value * @return Long integer-reply the rank of {@code member}. If {@code member} does not exist in the sorted set or {@code key} @@ -559,28 +628,50 @@ Long zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, Stri /** * Remove one or more members from a sorted set. - * + * * @param key the key * @param members the member type: value * @return Long integer-reply specifically: - * + * * The number of members removed from the sorted set, not including non existing members. */ Long zrem(K key, V... members); /** - * Remove all members in a sorted set within the given indexes. - * + * Remove all members in a sorted set between the given lexicographical range. + * * @param key the key - * @param start the start type: long - * @param stop the stop type: long - * @return Long integer-reply the number of elements removed. + * @param min min score + * @param max max score + * @return Long integer-reply the number of elements removed. + * @deprecated Use {@link #zremrangebylex(java.lang.Object, Range)} + */ + @Deprecated + Long zremrangebylex(K key, String min, String max); + + /** + * Remove all members in a sorted set between the given lexicographical range. + * + * @param key the key + * @param range the range + * @return Long integer-reply the number of elements removed. + * @since 4.3 + */ + Long zremrangebylex(K key, Range range); + + /** + * Remove all members in a sorted set within the given indexes. + * + * @param key the key + * @param start the start type: long + * @param stop the stop type: long + * @return Long integer-reply the number of elements removed. */ Long zremrangebyrank(K key, long start, long stop); /** * Remove all members in a sorted set within the given scores. - * + * * @param key the key * @param min min score * @param max max score @@ -592,7 +683,7 @@ Long zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, Stri /** * Remove all members in a sorted set within the given scores. - * + * * @param key the key * @param min min score * @param max max score @@ -614,7 +705,7 @@ Long zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, Stri /** * Return a range of members in a sorted set, by index, with scores ordered from high to low. - * + * * @param key the key * @param start the start * @param stop the stop @@ -622,9 +713,20 @@ Long zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, Stri */ List zrevrange(K key, long start, long stop); + /** + * Stream over a range of members in a sorted set, by index, with scores ordered from high to low. + * + * @param channel streaming channel that receives a call for every scored value + * @param key the key + * @param start the start + * @param stop the stop + * @return Long count of elements in the specified range. + */ + Long zrevrange(ValueStreamingChannel channel, K key, long start, long stop); + /** * Return a range of members with scores in a sorted set, by index, with scores ordered from high to low. - * + * * @param key the key * @param start the start * @param stop the stop @@ -632,6 +734,17 @@ Long zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, Stri */ List> zrevrangeWithScores(K key, long start, long stop); + /** + * Stream over a range of members with scores in a sorted set, by index, with scores ordered from high to low. + * + * @param channel streaming channel that receives a call for every scored value + * @param key the key + * @param start the start + * @param stop the stop + * @return Long count of elements in the specified range. + */ + Long zrevrangeWithScores(ScoredValueStreamingChannel channel, K key, long start, long stop); + /** * Return a range of members in a sorted set, by lexicographical range ordered from high to low. * @@ -655,7 +768,7 @@ Long zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, Stri /** * Return a range of members in a sorted set, by score, with scores ordered from high to low. - * + * * @param key the key * @param min min score * @param max max score @@ -667,7 +780,7 @@ Long zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, Stri /** * Return a range of members in a sorted set, by score, with scores ordered from high to low. - * + * * @param key the key * @param min min score * @param max max score @@ -689,7 +802,7 @@ Long zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, Stri /** * Return a range of members in a sorted set, by score, with scores ordered from high to low. - * + * * @param key the key * @param max max score * @param min min score @@ -703,7 +816,7 @@ Long zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, Stri /** * Return a range of members in a sorted set, by score, with scores ordered from high to low. - * + * * @param key the key * @param max max score * @param min min score @@ -727,182 +840,160 @@ Long zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, Stri List zrevrangebyscore(K key, Range range, Limit limit); /** - * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. - * + * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. + * + * @param channel streaming channel that receives a call for every value * @param key the key * @param max max score * @param min min score - * @return List<V> array-reply list of elements in the specified score range. - * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range)} + * @return Long count of elements in the specified range. + * @deprecated Use {@link #zrevrangebyscore(java.lang.Object, Range)} */ @Deprecated - List> zrevrangebyscoreWithScores(K key, double max, double min); + Long zrevrangebyscore(ValueStreamingChannel channel, K key, double max, double min); /** - * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. - * + * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. + * + * @param channel streaming channel that receives a call for every value * @param key the key - * @param max max score * @param min min score - * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. - * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range)} + * @param max max score + * @return Long count of elements in the specified range. + * @deprecated Use {@link #zrevrangebyscore(java.lang.Object, Range)} */ @Deprecated - List> zrevrangebyscoreWithScores(K key, String max, String min); + Long zrevrangebyscore(ValueStreamingChannel channel, K key, String max, String min); /** - * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. + * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. * + * @param channel streaming channel that receives a call for every value * @param key the key * @param range the range - * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @return Long count of elements in the specified range. * @since 4.3 */ - List> zrevrangebyscoreWithScores(K key, Range range); + Long zrevrangebyscore(ValueStreamingChannel channel, K key, Range range); /** - * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. - * + * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. + * + * @param channel streaming channel that receives a call for every value * @param key the key - * @param max max score * @param min min score + * @param max max score * @param offset the offset * @param count the count - * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @return Long count of elements in the specified range. * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range, Limit)} */ @Deprecated - List> zrevrangebyscoreWithScores(K key, double max, double min, long offset, long count); + Long zrevrangebyscore(ValueStreamingChannel channel, K key, double max, double min, long offset, long count); /** - * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. - * + * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. + * + * @param channel streaming channel that receives a call for every value * @param key the key - * @param max max score * @param min min score + * @param max max score * @param offset the offset * @param count the count - * @return List<V> array-reply list of elements in the specified score range. + * @return Long count of elements in the specified range. * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range, Limit)} */ @Deprecated - List> zrevrangebyscoreWithScores(K key, String max, String min, long offset, long count); + Long zrevrangebyscore(ValueStreamingChannel channel, K key, String max, String min, long offset, long count); /** - * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. + * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. * + * @param channel streaming channel that receives a call for every value * @param key the key * @param range the range - * @param limit limit - * @return List<V> array-reply list of elements in the specified score range. - * @since 4.3 - */ - List> zrevrangebyscoreWithScores(K key, Range range, Limit limit); - - /** - * Stream over a range of members in a sorted set, by index, with scores ordered from high to low. - * - * @param channel streaming channel that receives a call for every scored value - * @param key the key - * @param start the start - * @param stop the stop - * @return Long count of elements in the specified range. - */ - Long zrevrange(ValueStreamingChannel channel, K key, long start, long stop); - - /** - * Stream over a range of members with scores in a sorted set, by index, with scores ordered from high to low. - * - * @param channel streaming channel that receives a call for every scored value - * @param key the key - * @param start the start - * @param stop the stop + * @param limit the limit * @return Long count of elements in the specified range. + * @since 4.3 */ - Long zrevrangeWithScores(ScoredValueStreamingChannel channel, K key, long start, long stop); + Long zrevrangebyscore(ValueStreamingChannel channel, K key, Range range, Limit limit); /** - * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. - * - * @param channel streaming channel that receives a call for every value + * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. + * * @param key the key * @param max max score * @param min min score - * @return Long count of elements in the specified range. - * @deprecated Use {@link #zrevrangebyscore(java.lang.Object, Range)} + * @return List<V> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range)} */ @Deprecated - Long zrevrangebyscore(ValueStreamingChannel channel, K key, double max, double min); + List> zrevrangebyscoreWithScores(K key, double max, double min); /** - * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. - * - * @param channel streaming channel that receives a call for every value + * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. + * * @param key the key - * @param min min score * @param max max score - * @return Long count of elements in the specified range. - * @deprecated Use {@link #zrevrangebyscore(java.lang.Object, Range)} + * @param min min score + * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. + * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range)} */ @Deprecated - Long zrevrangebyscore(ValueStreamingChannel channel, K key, String max, String min); + List> zrevrangebyscoreWithScores(K key, String max, String min); /** - * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. + * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. * - * @param channel streaming channel that receives a call for every value * @param key the key * @param range the range - * @return Long count of elements in the specified range. + * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. * @since 4.3 */ - Long zrevrangebyscore(ValueStreamingChannel channel, K key, Range range); + List> zrevrangebyscoreWithScores(K key, Range range); /** - * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. - * - * @param channel streaming channel that receives a call for every value + * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. + * * @param key the key - * @param min min score * @param max max score + * @param min min score * @param offset the offset * @param count the count - * @return Long count of elements in the specified range. + * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range, Limit)} */ @Deprecated - Long zrevrangebyscore(ValueStreamingChannel channel, K key, double max, double min, long offset, long count); + List> zrevrangebyscoreWithScores(K key, double max, double min, long offset, long count); /** - * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. - * - * @param channel streaming channel that receives a call for every value + * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. + * * @param key the key - * @param min min score * @param max max score + * @param min min score * @param offset the offset * @param count the count - * @return Long count of elements in the specified range. + * @return List<V> array-reply list of elements in the specified score range. * @deprecated Use {@link #zrevrangebyscoreWithScores(java.lang.Object, Range, Limit)} */ @Deprecated - Long zrevrangebyscore(ValueStreamingChannel channel, K key, String max, String min, long offset, long count); + List> zrevrangebyscoreWithScores(K key, String max, String min, long offset, long count); /** - * Stream over a range of members in a sorted set, by score, with scores ordered from high to low. + * Return a range of members with scores in a sorted set, by score, with scores ordered from high to low. * - * @param channel streaming channel that receives a call for every value * @param key the key * @param range the range - * @param limit the limit - * @return Long count of elements in the specified range. + * @param limit limit + * @return List<V> array-reply list of elements in the specified score range. * @since 4.3 */ - Long zrevrangebyscore(ValueStreamingChannel channel, K key, Range range, Limit limit); + List> zrevrangebyscoreWithScores(K key, Range range, Limit limit); /** * Stream over a range of members with scores in a sorted set, by score, with scores ordered from high to low. - * + * * @param channel streaming channel that receives a call for every scored value * @param key the key * @param min min score @@ -915,7 +1006,7 @@ Long zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, Stri /** * Stream over a range of members with scores in a sorted set, by score, with scores ordered from high to low. - * + * * @param channel streaming channel that receives a call for every scored value * @param key the key * @param min min score @@ -938,7 +1029,7 @@ Long zrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, Stri /** * Stream over a range of members with scores in a sorted set, by score, with scores ordered from high to low. - * + * * @param channel streaming channel that receives a call for every scored value * @param key the key * @param min min score @@ -954,7 +1045,7 @@ Long zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, d /** * Stream over a range of members with scores in a sorted set, by score, with scores ordered from high to low. - * + * * @param channel streaming channel that receives a call for every scored value * @param key the key * @param min min score @@ -982,7 +1073,7 @@ Long zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, S /** * Determine the index of a member in a sorted set, with scores ordered from high to low. - * + * * @param key the key * @param member the member type: value * @return Long integer-reply the rank of {@code member}. If {@code member} does not exist in the sorted set or {@code key} @@ -990,35 +1081,6 @@ Long zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, S */ Long zrevrank(K key, V member); - /** - * Get the score associated with the given member in a sorted set. - * - * @param key the key - * @param member the member type: value - * @return Double bulk-string-reply the score of {@code member} (a double precision floating point number), represented as - * string. - */ - Double zscore(K key, V member); - - /** - * Add multiple sorted sets and store the resulting sorted set in a new key. - * - * @param destination destination key - * @param keys source keys - * @return Long integer-reply the number of elements in the resulting sorted set at {@code destination}. - */ - Long zunionstore(K destination, K... keys); - - /** - * Add multiple sorted sets and store the resulting sorted set in a new key. - * - * @param destination the destination - * @param storeArgs the storeArgs - * @param keys the keys - * @return Long integer-reply the number of elements in the resulting sorted set at {@code destination}. - */ - Long zunionstore(K destination, ZStoreArgs storeArgs, K... keys); - /** * Incrementally iterate sorted sets elements and associated scores. * @@ -1076,7 +1138,7 @@ Long zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, S /** * Incrementally iterate sorted sets elements and associated scores. - * + * * @param channel streaming channel that receives a call for every scored value * @param key the key * @param scanCursor cursor to resume from a previous scan, must not be {@literal null} @@ -1096,93 +1158,31 @@ Long zrevrangebyscoreWithScores(ScoredValueStreamingChannel channel, K key, S StreamScanCursor zscan(ScoredValueStreamingChannel channel, K key, ScanCursor scanCursor); /** - * Count the number of members in a sorted set between a given lexicographical range. - * - * @param key the key - * @param min min score - * @param max max score - * @return Long integer-reply the number of elements in the specified score range. - * @deprecated Use {@link #zlexcount(java.lang.Object, Range)} - */ - @Deprecated - Long zlexcount(K key, String min, String max); - - /** - * Count the number of members in a sorted set between a given lexicographical range. - * - * @param key the key - * @param range the range - * @return Long integer-reply the number of elements in the specified score range. - * @since 4.3 - */ - Long zlexcount(K key, Range range); - - /** - * Remove all members in a sorted set between the given lexicographical range. - * - * @param key the key - * @param min min score - * @param max max score - * @return Long integer-reply the number of elements removed. - * @deprecated Use {@link #zremrangebylex(java.lang.Object, Range)} - */ - @Deprecated - Long zremrangebylex(K key, String min, String max); - - /** - * Remove all members in a sorted set between the given lexicographical range. + * Get the score associated with the given member in a sorted set. * * @param key the key - * @param range the range - * @return Long integer-reply the number of elements removed. - * @since 4.3 - */ - Long zremrangebylex(K key, Range range); - - /** - * Return a range of members in a sorted set, by lexicographical range. - * - * @param key the key - * @param min min score - * @param max max score - * @return List<V> array-reply list of elements in the specified range. - * @deprecated Use {@link #zrangebylex(java.lang.Object, Range)} + * @param member the member type: value + * @return Double bulk-string-reply the score of {@code member} (a double precision floating point number), represented as + * string. */ - @Deprecated - List zrangebylex(K key, String min, String max); + Double zscore(K key, V member); /** - * Return a range of members in a sorted set, by lexicographical range. + * Add multiple sorted sets and store the resulting sorted set in a new key. * - * @param key the key - * @param range the range - * @return List<V> array-reply list of elements in the specified range. - * @since 4.3 - */ - List zrangebylex(K key, Range range); - - /** - * Return a range of members in a sorted set, by lexicographical range. - * - * @param key the key - * @param min min score - * @param max max score - * @param offset the offset - * @param count the count - * @return List<V> array-reply list of elements in the specified range. - * @deprecated Use {@link #zrangebylex(java.lang.Object, Range)} + * @param destination destination key + * @param keys source keys + * @return Long integer-reply the number of elements in the resulting sorted set at {@code destination}. */ - @Deprecated - List zrangebylex(K key, String min, String max, long offset, long count); + Long zunionstore(K destination, K... keys); /** - * Return a range of members in a sorted set, by lexicographical range. + * Add multiple sorted sets and store the resulting sorted set in a new key. * - * @param key the key - * @param range the range - * @param limit the limit - * @return List<V> array-reply list of elements in the specified range. - * @since 4.3 + * @param destination the destination + * @param storeArgs the storeArgs + * @param keys the keys + * @return Long integer-reply the number of elements in the resulting sorted set at {@code destination}. */ - List zrangebylex(K key, Range range, Limit limit); + Long zunionstore(K destination, ZStoreArgs storeArgs, K... keys); } diff --git a/src/test/java/com/lambdaworks/apigenerator/Constants.java b/src/test/java/com/lambdaworks/apigenerator/Constants.java index 8d61b69e43..3f60c1dceb 100644 --- a/src/test/java/com/lambdaworks/apigenerator/Constants.java +++ b/src/test/java/com/lambdaworks/apigenerator/Constants.java @@ -7,7 +7,8 @@ */ class Constants { - public final static String[] TEMPLATE_NAMES = { "RedisSortedSetCommands", + public final static String[] TEMPLATE_NAMES = { "RedisHashCommands", "RedisHLLCommands", "RedisKeyCommands", + "RedisListCommands", "RedisScriptingCommands", "RedisServerCommands", "RedisSetCommands", "RedisSortedSetCommands", "RedisStringCommands", "RedisTransactionalCommands", "RedisSentinelCommands", "BaseRedisCommands", "RedisGeoCommands" }; diff --git a/src/test/java/com/lambdaworks/apigenerator/CreateAsyncApi.java b/src/test/java/com/lambdaworks/apigenerator/CreateAsyncApi.java index 914aac2530..d102af1d56 100644 --- a/src/test/java/com/lambdaworks/apigenerator/CreateAsyncApi.java +++ b/src/test/java/com/lambdaworks/apigenerator/CreateAsyncApi.java @@ -97,7 +97,7 @@ protected Function methodTypeMutator() { } /** - * Supply addititional imports. + * Supply additional imports. * * @return */ diff --git a/src/test/java/com/lambdaworks/apigenerator/CreateAsyncNodeSelectionClusterApi.java b/src/test/java/com/lambdaworks/apigenerator/CreateAsyncNodeSelectionClusterApi.java index 7ae6d2cfca..af4796334e 100644 --- a/src/test/java/com/lambdaworks/apigenerator/CreateAsyncNodeSelectionClusterApi.java +++ b/src/test/java/com/lambdaworks/apigenerator/CreateAsyncNodeSelectionClusterApi.java @@ -107,7 +107,7 @@ protected Function methodTypeMutator() { } /** - * Supply addititional imports. + * Supply additional imports. * * @return */ diff --git a/src/test/java/com/lambdaworks/apigenerator/CreateSyncApi.java b/src/test/java/com/lambdaworks/apigenerator/CreateSyncApi.java index 9ac6075046..59edd075c9 100644 --- a/src/test/java/com/lambdaworks/apigenerator/CreateSyncApi.java +++ b/src/test/java/com/lambdaworks/apigenerator/CreateSyncApi.java @@ -98,7 +98,7 @@ protected Function methodTypeMutator() { } /** - * Supply addititional imports. + * Supply additional imports. * * @return */ diff --git a/src/test/java/com/lambdaworks/apigenerator/CreateSyncNodeSelectionClusterApi.java b/src/test/java/com/lambdaworks/apigenerator/CreateSyncNodeSelectionClusterApi.java index 27e813df11..40e913ed75 100644 --- a/src/test/java/com/lambdaworks/apigenerator/CreateSyncNodeSelectionClusterApi.java +++ b/src/test/java/com/lambdaworks/apigenerator/CreateSyncNodeSelectionClusterApi.java @@ -111,7 +111,7 @@ protected Function methodTypeMutator() { } /** - * Supply addititional imports. + * Supply additional imports. * * @return */ diff --git a/src/test/java/com/lambdaworks/apigenerator/CreateSyncAsyncRxApis.java b/src/test/java/com/lambdaworks/apigenerator/GenerateCommandInterfaces.java similarity index 72% rename from src/test/java/com/lambdaworks/apigenerator/CreateSyncAsyncRxApis.java rename to src/test/java/com/lambdaworks/apigenerator/GenerateCommandInterfaces.java index 35ecb176fb..8e40107cfd 100644 --- a/src/test/java/com/lambdaworks/apigenerator/CreateSyncAsyncRxApis.java +++ b/src/test/java/com/lambdaworks/apigenerator/GenerateCommandInterfaces.java @@ -4,11 +4,13 @@ import org.junit.runners.Suite; /** + * Entrypoint to generate all Redis command interfaces from {@code src/main/templates}. + * * @author Mark Paluch */ @RunWith(Suite.class) @Suite.SuiteClasses({ CreateAsyncApi.class, CreateSyncApi.class, CreateReactiveApi.class, CreateAsyncNodeSelectionClusterApi.class, CreateSyncNodeSelectionClusterApi.class }) -public class CreateSyncAsyncRxApis { +public class GenerateCommandInterfaces { } From 4b3f980879087c3b401e3a77b3cb22e2f464bdeb Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Sat, 15 Oct 2016 15:09:04 +0200 Subject: [PATCH 039/808] Adopt changed error message in SELECT command --- src/test/java/com/lambdaworks/redis/ConnectionCommandTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/lambdaworks/redis/ConnectionCommandTest.java b/src/test/java/com/lambdaworks/redis/ConnectionCommandTest.java index a2fa7eab76..5efbefc87e 100644 --- a/src/test/java/com/lambdaworks/redis/ConnectionCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/ConnectionCommandTest.java @@ -122,7 +122,7 @@ public void selectInvalid() throws Exception { async.select(1024); fail("Selected invalid db index"); } catch (RedisException e) { - assertThat(e.getMessage()).isEqualTo("ERR invalid DB index"); + assertThat(e.getMessage()).startsWith("ERR"); StatefulRedisConnection statefulRedisCommands = async.getStatefulConnection(); assertThat(ReflectionTestUtils.getField(statefulRedisCommands, "db")).isEqualTo(0); } finally { From be21fb51c682f52bacb93e0a05c8e482ec87c107 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Tue, 18 Oct 2016 10:40:41 +0200 Subject: [PATCH 040/808] Fix RedisAdvancedClusterAsyncCommandsImpl.msetnx return value #376 MSETNX on RedisAdvancedClusterAsyncCommandsImpl returns now only true if all distributed MSETNX operations returned true. MSETNX has still a caveat when run on multiple cluster nodes: MSETNX executed on a single node with a mixed set of existing and non-existing keys will not set the non-existing keys if a key of the operation already exists. That's different with the MSETNX cluster operation. It can't guarantee atomicity so some keys might get set on one node while another node does not set any keys at all. --- ...RedisAdvancedClusterAsyncCommandsImpl.java | 7 ++--- ...isAdvancedClusterReactiveCommandsImpl.java | 2 +- .../cluster/AdvancedClusterClientTest.java | 26 ++++++++++--------- .../cluster/AdvancedClusterReactiveTest.java | 26 ++++++++++++++----- .../commands/StringClusterCommandTest.java | 3 ++- .../StringClusterReactiveCommandTest.java | 3 ++- 6 files changed, 42 insertions(+), 25 deletions(-) diff --git a/src/main/java/com/lambdaworks/redis/cluster/RedisAdvancedClusterAsyncCommandsImpl.java b/src/main/java/com/lambdaworks/redis/cluster/RedisAdvancedClusterAsyncCommandsImpl.java index 39882bf075..8df797e054 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/RedisAdvancedClusterAsyncCommandsImpl.java +++ b/src/main/java/com/lambdaworks/redis/cluster/RedisAdvancedClusterAsyncCommandsImpl.java @@ -225,14 +225,15 @@ public RedisFuture msetnx(Map map) { } return new PipelinedRedisFuture<>(executions, objectPipelinedRedisFuture -> { + for (RedisFuture listRedisFuture : executions.values()) { Boolean b = MultiNodeExecution.execute(() -> listRedisFuture.get()); - if (b != null && b) { - return true; + if (b == null || !b) { + return false; } } - return false; + return !executions.isEmpty(); }); } diff --git a/src/main/java/com/lambdaworks/redis/cluster/RedisAdvancedClusterReactiveCommandsImpl.java b/src/main/java/com/lambdaworks/redis/cluster/RedisAdvancedClusterReactiveCommandsImpl.java index 985812a43a..be4b0f2068 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/RedisAdvancedClusterReactiveCommandsImpl.java +++ b/src/main/java/com/lambdaworks/redis/cluster/RedisAdvancedClusterReactiveCommandsImpl.java @@ -197,7 +197,7 @@ public Mono mget(KeyValueStreamingChannel channel, Iterable keys) public Mono msetnx(Map map) { return pipeliningWithMap(map, kvMap -> RedisAdvancedClusterReactiveCommandsImpl.super.msetnx(kvMap).flux(), - booleanFlux -> booleanFlux).reduce((accu, next) -> accu || next); + booleanFlux -> booleanFlux).reduce((accu, next) -> accu && next); } @Override diff --git a/src/test/java/com/lambdaworks/redis/cluster/AdvancedClusterClientTest.java b/src/test/java/com/lambdaworks/redis/cluster/AdvancedClusterClientTest.java index 341be73b36..fac9504b05 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/AdvancedClusterClientTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/AdvancedClusterClientTest.java @@ -149,23 +149,16 @@ public void msetCrossSlot() throws Exception { } } - protected Map prepareMset() { - Map mset = new HashMap<>(); - for (char c = 'a'; c < 'z'; c++) { - String key = new String(new char[] { c, c, c }); - mset.put(key, "value-" + key); - } - return mset; - } - @Test public void msetnxCrossSlot() throws Exception { Map mset = prepareMset(); - RedisFuture result = commands.msetnx(mset); - - assertThat(result.get()).isTrue(); + String key = mset.keySet().iterator().next(); + Map submap = Collections.singletonMap(key, mset.get(key)); + + assertThat(commands.msetnx(submap).get()).isTrue(); + assertThat(commands.msetnx(mset).get()).isFalse(); for (String mykey : mset.keySet()) { String s1 = commands.get(mykey).get(); @@ -585,5 +578,14 @@ private void writeKeysToTwoNodes() { syncCommands.set(KEY_ON_NODE_1, value); syncCommands.set(KEY_ON_NODE_2, value); } + + protected Map prepareMset() { + Map mset = new HashMap<>(); + for (char c = 'a'; c < 'z'; c++) { + String key = new String(new char[] { c, c, c }); + mset.put(key, "value-" + key); + } + return mset; + } } diff --git a/src/test/java/com/lambdaworks/redis/cluster/AdvancedClusterReactiveTest.java b/src/test/java/com/lambdaworks/redis/cluster/AdvancedClusterReactiveTest.java index 34b248f439..57115d04d2 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/AdvancedClusterReactiveTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/AdvancedClusterReactiveTest.java @@ -3,10 +3,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.fail; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; import java.util.concurrent.atomic.AtomicBoolean; import java.util.stream.Collectors; @@ -77,11 +74,17 @@ public void msetCrossSlot() throws Exception { @Test public void msetnxCrossSlot() throws Exception { - assertThat(block(commands.msetnx(RandomKeys.MAP))).isTrue(); + Map mset = prepareMset(); - for (String mykey : RandomKeys.KEYS) { + String key = mset.keySet().iterator().next(); + Map submap = Collections.singletonMap(key, mset.get(key)); + + assertThat(block(commands.msetnx(submap))).isTrue(); + assertThat(block(commands.msetnx(mset))).isFalse(); + + for (String mykey : mset.keySet()) { String s1 = syncCommands.get(mykey); - assertThat(s1).isEqualTo(RandomKeys.MAP.get(mykey)); + assertThat(s1).isEqualTo(mset.get(mykey)); } } @@ -365,4 +368,13 @@ private void writeKeysToTwoNodes() { syncCommands.set(KEY_ON_NODE_1, value); syncCommands.set(KEY_ON_NODE_2, value); } + + protected Map prepareMset() { + Map mset = new HashMap<>(); + for (char c = 'a'; c < 'z'; c++) { + String key = new String(new char[] { c, c, c }); + mset.put(key, "value-" + key); + } + return mset; + } } diff --git a/src/test/java/com/lambdaworks/redis/cluster/commands/StringClusterCommandTest.java b/src/test/java/com/lambdaworks/redis/cluster/commands/StringClusterCommandTest.java index 3739ed8a87..1c89ef9cc7 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/commands/StringClusterCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/commands/StringClusterCommandTest.java @@ -56,8 +56,9 @@ public void msetnx() throws Exception { Map map = new LinkedHashMap<>(); map.put("one", "1"); map.put("two", "2"); - assertThat(redis.msetnx(map)).isTrue(); + assertThat(redis.msetnx(map)).isFalse(); redis.del("one"); + redis.del("two"); // probably set on a different node assertThat(redis.msetnx(map)).isTrue(); assertThat(redis.get("two")).isEqualTo("2"); } diff --git a/src/test/java/com/lambdaworks/redis/cluster/commands/reactive/StringClusterReactiveCommandTest.java b/src/test/java/com/lambdaworks/redis/cluster/commands/reactive/StringClusterReactiveCommandTest.java index e44abe0626..9624658558 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/commands/reactive/StringClusterReactiveCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/commands/reactive/StringClusterReactiveCommandTest.java @@ -59,8 +59,9 @@ public void msetnx() throws Exception { Map map = new LinkedHashMap<>(); map.put("one", "1"); map.put("two", "2"); - assertThat(redis.msetnx(map)).isTrue(); + assertThat(redis.msetnx(map)).isFalse(); redis.del("one"); + redis.del("two"); // probably set on a different node assertThat(redis.msetnx(map)).isTrue(); assertThat(redis.get("two")).isEqualTo("2"); } From d8bac18ce8e1ef50ff85e15665936bcb4f75f982 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Fri, 21 Oct 2016 11:58:20 +0200 Subject: [PATCH 041/808] Propagate array sizes in MultiOutput #380 MultiOutput now propagates the array size of the nested responses. The very first count indicates the overall response size and is filtered from child outputs. This also fixes a subsequent NPE caused by the missing array beggining indication. --- .../lambdaworks/redis/output/MultiOutput.java | 12 +- .../transactional/BitTxCommandTest.java | 16 +++ .../transactional/GeoTxCommandTest.java | 57 ++++++++++ .../transactional/HLLTxCommandTest.java | 15 +++ .../transactional/HashTxCommandTest.java | 15 +++ .../transactional/KeyTxCommandTest.java | 22 ++++ .../transactional/ListTxCommandTest.java | 15 +++ .../transactional/SetTxCommandTest.java | 16 +++ .../transactional/SortTxCommandTest.java | 15 +++ .../transactional/SortedSetTxCommandTest.java | 15 +++ .../transactional/StringTxCommandTest.java | 15 +++ .../TxSyncInvocationHandler.java | 104 ++++++++++++++++++ 12 files changed, 309 insertions(+), 8 deletions(-) create mode 100644 src/test/java/com/lambdaworks/redis/commands/transactional/BitTxCommandTest.java create mode 100644 src/test/java/com/lambdaworks/redis/commands/transactional/GeoTxCommandTest.java create mode 100644 src/test/java/com/lambdaworks/redis/commands/transactional/HLLTxCommandTest.java create mode 100644 src/test/java/com/lambdaworks/redis/commands/transactional/HashTxCommandTest.java create mode 100644 src/test/java/com/lambdaworks/redis/commands/transactional/KeyTxCommandTest.java create mode 100644 src/test/java/com/lambdaworks/redis/commands/transactional/ListTxCommandTest.java create mode 100644 src/test/java/com/lambdaworks/redis/commands/transactional/SetTxCommandTest.java create mode 100644 src/test/java/com/lambdaworks/redis/commands/transactional/SortTxCommandTest.java create mode 100644 src/test/java/com/lambdaworks/redis/commands/transactional/SortedSetTxCommandTest.java create mode 100644 src/test/java/com/lambdaworks/redis/commands/transactional/StringTxCommandTest.java create mode 100644 src/test/java/com/lambdaworks/redis/commands/transactional/TxSyncInvocationHandler.java diff --git a/src/main/java/com/lambdaworks/redis/output/MultiOutput.java b/src/main/java/com/lambdaworks/redis/output/MultiOutput.java index 77aec87804..728005da56 100644 --- a/src/main/java/com/lambdaworks/redis/output/MultiOutput.java +++ b/src/main/java/com/lambdaworks/redis/output/MultiOutput.java @@ -62,16 +62,12 @@ public void set(ByteBuffer bytes) { public void multi(int count) { if (rolledBack == null) { - if (count == -1) { - rolledBack = true; - } else { - rolledBack = false; + rolledBack = count == -1; + } else { + if (!queue.isEmpty()) { + queue.peek().getOutput().multi(count); } } - - if (count == -1 && !queue.isEmpty()) { - queue.peek().getOutput().multi(count); - } } @Override diff --git a/src/test/java/com/lambdaworks/redis/commands/transactional/BitTxCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/transactional/BitTxCommandTest.java new file mode 100644 index 0000000000..23a9df92f5 --- /dev/null +++ b/src/test/java/com/lambdaworks/redis/commands/transactional/BitTxCommandTest.java @@ -0,0 +1,16 @@ +package com.lambdaworks.redis.commands.transactional; + +import com.lambdaworks.redis.api.sync.RedisCommands; +import com.lambdaworks.redis.commands.BitCommandTest; + +/** + * @author Mark Paluch + */ +public class BitTxCommandTest extends BitCommandTest { + + @Override + protected RedisCommands connect() { + bitstring = TxSyncInvocationHandler.sync(client.connect(new BitStringCodec())); + return TxSyncInvocationHandler.sync(client.connect()); + } +} diff --git a/src/test/java/com/lambdaworks/redis/commands/transactional/GeoTxCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/transactional/GeoTxCommandTest.java new file mode 100644 index 0000000000..26462c321d --- /dev/null +++ b/src/test/java/com/lambdaworks/redis/commands/transactional/GeoTxCommandTest.java @@ -0,0 +1,57 @@ +package com.lambdaworks.redis.commands.transactional; + +import org.junit.Ignore; + +import com.lambdaworks.redis.api.sync.RedisCommands; +import com.lambdaworks.redis.commands.GeoCommandTest; + +/** + * @author Mark Paluch + */ +public class GeoTxCommandTest extends GeoCommandTest { + + @Override + protected RedisCommands connect() { + return TxSyncInvocationHandler.sync(client.connect()); + } + + @Ignore + @Override + public void georadiusbymemberWithArgsAndTransaction() throws Exception { + } + + @Ignore + @Override + public void geoaddWithTransaction() throws Exception { + } + + @Ignore + @Override + public void geoaddMultiWithTransaction() throws Exception { + } + + @Ignore + @Override + public void geoposWithTransaction() throws Exception { + } + + @Ignore + @Override + public void georadiusWithArgsAndTransaction() throws Exception { + } + + @Ignore + @Override + public void georadiusWithTransaction() throws Exception { + } + + @Ignore + @Override + public void geodistWithTransaction() throws Exception { + } + + @Ignore + @Override + public void geohashWithTransaction() throws Exception { + } +} diff --git a/src/test/java/com/lambdaworks/redis/commands/transactional/HLLTxCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/transactional/HLLTxCommandTest.java new file mode 100644 index 0000000000..2ea20437c9 --- /dev/null +++ b/src/test/java/com/lambdaworks/redis/commands/transactional/HLLTxCommandTest.java @@ -0,0 +1,15 @@ +package com.lambdaworks.redis.commands.transactional; + +import com.lambdaworks.redis.api.sync.RedisCommands; +import com.lambdaworks.redis.commands.HLLCommandTest; + +/** + * @author Mark Paluch + */ +public class HLLTxCommandTest extends HLLCommandTest { + + @Override + protected RedisCommands connect() { + return TxSyncInvocationHandler.sync(client.connect()); + } +} diff --git a/src/test/java/com/lambdaworks/redis/commands/transactional/HashTxCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/transactional/HashTxCommandTest.java new file mode 100644 index 0000000000..b7759cd74b --- /dev/null +++ b/src/test/java/com/lambdaworks/redis/commands/transactional/HashTxCommandTest.java @@ -0,0 +1,15 @@ +package com.lambdaworks.redis.commands.transactional; + +import com.lambdaworks.redis.api.sync.RedisCommands; +import com.lambdaworks.redis.commands.HashCommandTest; + +/** + * @author Mark Paluch + */ +public class HashTxCommandTest extends HashCommandTest { + + @Override + protected RedisCommands connect() { + return TxSyncInvocationHandler.sync(client.connect()); + } +} diff --git a/src/test/java/com/lambdaworks/redis/commands/transactional/KeyTxCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/transactional/KeyTxCommandTest.java new file mode 100644 index 0000000000..0ce7887367 --- /dev/null +++ b/src/test/java/com/lambdaworks/redis/commands/transactional/KeyTxCommandTest.java @@ -0,0 +1,22 @@ +package com.lambdaworks.redis.commands.transactional; + +import org.junit.Ignore; + +import com.lambdaworks.redis.api.sync.RedisCommands; +import com.lambdaworks.redis.commands.KeyCommandTest; + +/** + * @author Mark Paluch + */ +public class KeyTxCommandTest extends KeyCommandTest { + + @Override + protected RedisCommands connect() { + return TxSyncInvocationHandler.sync(client.connect()); + } + + @Ignore + @Override + public void move() throws Exception { + } +} diff --git a/src/test/java/com/lambdaworks/redis/commands/transactional/ListTxCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/transactional/ListTxCommandTest.java new file mode 100644 index 0000000000..1019e34e9f --- /dev/null +++ b/src/test/java/com/lambdaworks/redis/commands/transactional/ListTxCommandTest.java @@ -0,0 +1,15 @@ +package com.lambdaworks.redis.commands.transactional; + +import com.lambdaworks.redis.api.sync.RedisCommands; +import com.lambdaworks.redis.commands.ListCommandTest; + +/** + * @author Mark Paluch + */ +public class ListTxCommandTest extends ListCommandTest { + + @Override + protected RedisCommands connect() { + return TxSyncInvocationHandler.sync(client.connect()); + } +} diff --git a/src/test/java/com/lambdaworks/redis/commands/transactional/SetTxCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/transactional/SetTxCommandTest.java new file mode 100644 index 0000000000..96c01706dc --- /dev/null +++ b/src/test/java/com/lambdaworks/redis/commands/transactional/SetTxCommandTest.java @@ -0,0 +1,16 @@ +package com.lambdaworks.redis.commands.transactional; + +import com.lambdaworks.redis.api.sync.RedisCommands; +import com.lambdaworks.redis.commands.SetCommandTest; + +/** + * @author Mark Paluch + */ +public class SetTxCommandTest extends SetCommandTest { + + @Override + protected RedisCommands connect() { + return TxSyncInvocationHandler.sync(client.connect()); + } + +} diff --git a/src/test/java/com/lambdaworks/redis/commands/transactional/SortTxCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/transactional/SortTxCommandTest.java new file mode 100644 index 0000000000..eaf5bafa07 --- /dev/null +++ b/src/test/java/com/lambdaworks/redis/commands/transactional/SortTxCommandTest.java @@ -0,0 +1,15 @@ +package com.lambdaworks.redis.commands.transactional; + +import com.lambdaworks.redis.api.sync.RedisCommands; +import com.lambdaworks.redis.commands.SortCommandTest; + +/** + * @author Mark Paluch + */ +public class SortTxCommandTest extends SortCommandTest { + + @Override + protected RedisCommands connect() { + return TxSyncInvocationHandler.sync(client.connect()); + } +} diff --git a/src/test/java/com/lambdaworks/redis/commands/transactional/SortedSetTxCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/transactional/SortedSetTxCommandTest.java new file mode 100644 index 0000000000..5d6f39970d --- /dev/null +++ b/src/test/java/com/lambdaworks/redis/commands/transactional/SortedSetTxCommandTest.java @@ -0,0 +1,15 @@ +package com.lambdaworks.redis.commands.transactional; + +import com.lambdaworks.redis.api.sync.RedisCommands; +import com.lambdaworks.redis.commands.SortedSetCommandTest; + +/** + * @author Mark Paluch + */ +public class SortedSetTxCommandTest extends SortedSetCommandTest { + + @Override + protected RedisCommands connect() { + return TxSyncInvocationHandler.sync(client.connect()); + } +} diff --git a/src/test/java/com/lambdaworks/redis/commands/transactional/StringTxCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/transactional/StringTxCommandTest.java new file mode 100644 index 0000000000..41d4ff15bb --- /dev/null +++ b/src/test/java/com/lambdaworks/redis/commands/transactional/StringTxCommandTest.java @@ -0,0 +1,15 @@ +package com.lambdaworks.redis.commands.transactional; + +import com.lambdaworks.redis.api.sync.RedisCommands; +import com.lambdaworks.redis.commands.StringCommandTest; + +/** + * @author Mark Paluch + */ +public class StringTxCommandTest extends StringCommandTest { + + @Override + protected RedisCommands connect() { + return TxSyncInvocationHandler.sync(client.connect()); + } +} diff --git a/src/test/java/com/lambdaworks/redis/commands/transactional/TxSyncInvocationHandler.java b/src/test/java/com/lambdaworks/redis/commands/transactional/TxSyncInvocationHandler.java new file mode 100644 index 0000000000..90f3a3ee24 --- /dev/null +++ b/src/test/java/com/lambdaworks/redis/commands/transactional/TxSyncInvocationHandler.java @@ -0,0 +1,104 @@ +package com.lambdaworks.redis.commands.transactional; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.List; + +import com.lambdaworks.redis.TransactionResult; +import com.lambdaworks.redis.api.StatefulRedisConnection; +import com.lambdaworks.redis.api.sync.RedisCommands; +import com.lambdaworks.redis.internal.AbstractInvocationHandler; + +/** + * Invocation handler for testing purposes that wraps each call into a transaction. + * + * @param + * @param + */ +public class TxSyncInvocationHandler extends AbstractInvocationHandler { + + private final Object api; + private final Method multi; + private final Method discard; + private final Method exec; + private final Method ping; + + public TxSyncInvocationHandler(Object api) throws Exception { + + this.api = api; + this.multi = api.getClass().getMethod("multi"); + this.exec = api.getClass().getMethod("exec"); + this.discard = api.getClass().getMethod("discard"); + this.ping = api.getClass().getMethod("ping"); + } + + @Override + @SuppressWarnings("unchecked") + protected Object handleInvocation(Object proxy, Method method, Object[] args) throws Throwable { + + try { + + if (method.getName().equals("exec") || method.getName().equals("multi")) { + throw new IllegalStateException("Cannot execute transaction commands over this transactional wrapper"); + } + + Method targetMethod = api.getClass().getMethod(method.getName(), method.getParameterTypes()); + + if (!method.getName().equals("close") && !method.getName().equals("getStatefulConnection")) { + + multi.invoke(api); + ping.invoke(api); + + targetMethod.invoke(api, args); + + Object result = exec.invoke(api); + + if (result == null || !(result instanceof TransactionResult)) { + return result; + } + + TransactionResult txResult = (TransactionResult) result; + + if (txResult.size() > 1) { + + result = txResult.get(1); + if (result instanceof Exception) { + throw (Exception) result; + } + + return result; + } + + return null; + } + + return targetMethod.invoke(api, args); + + } catch (InvocationTargetException e) { + try { + discard.invoke(api); + } catch (Exception e1) { + } + throw e.getTargetException(); + } + } + + /** + * Create a transactional wrapper proxy for {@link RedisCommands}. + * + * @param connection the connection + * @return the wrapper proxy. + */ + @SuppressWarnings("unchecked") + public static RedisCommands sync(StatefulRedisConnection connection) { + + try { + TxSyncInvocationHandler handler = new TxSyncInvocationHandler<>(connection.sync()); + return (RedisCommands) Proxy.newProxyInstance(handler.getClass().getClassLoader(), + new Class[] { RedisCommands.class }, handler); + } catch (Exception e) { + throw new IllegalStateException(e); + } + } +} \ No newline at end of file From b8eacfd5b190064c64eb68141cbb052de940195f Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Fri, 21 Oct 2016 12:13:20 +0200 Subject: [PATCH 042/808] Polishing Improve JavaDoc and formatting. --- src/main/java/com/lambdaworks/redis/Range.java | 16 +++++++++++----- .../redis/resource/DefaultClientResources.java | 4 ++-- .../reactive/BitReactiveCommandTest.java | 2 +- .../reactive/CustomReactiveCommandTest.java | 3 +-- .../reactive/GeoReactiveCommandTest.java | 3 +++ .../reactive/HLLReactiveCommandTest.java | 3 +++ .../reactive/HashReactiveCommandTest.java | 4 +++- .../reactive/KeyReactiveCommandTest.java | 4 ++++ .../reactive/ListReactiveCommandTest.java | 4 ++++ .../reactive/NumericReactiveCommandTest.java | 4 ++++ .../reactive/ScriptingReactiveCommandTest.java | 4 +++- .../reactive/ServerReactiveCommandTest.java | 5 ++++- .../reactive/SetReactiveCommandTest.java | 4 +++- .../reactive/SortReactiveCommandTest.java | 4 ++++ .../reactive/SortedSetReactiveCommandTest.java | 4 ++++ .../reactive/StringReactiveCommandTest.java | 9 +++++++-- .../reactive/TransactionReactiveCommandTest.java | 5 ++++- 17 files changed, 65 insertions(+), 17 deletions(-) diff --git a/src/main/java/com/lambdaworks/redis/Range.java b/src/main/java/com/lambdaworks/redis/Range.java index 98a416f0a5..05173a0a42 100644 --- a/src/main/java/com/lambdaworks/redis/Range.java +++ b/src/main/java/com/lambdaworks/redis/Range.java @@ -25,7 +25,10 @@ private Range(Boundary lower, Boundary upper) { /** * Create a new range from {@code lower} and {@code upper} boundary values. Both values are included (greater than or equals * and less than or equals). - * + * + * @param lower lower boundary, must not be {@literal null}. + * @param upper upper boundary, must not be {@literal null}. + * @param value type * @return new {@link Range} */ public static Range create(T lower, T upper) { @@ -37,6 +40,7 @@ public static Range create(T lower, T upper) { * * @param lower lower boundary, must not be {@literal null}. * @param upper upper boundary, must not be {@literal null}. + * @param value type. * @return new {@link Range} */ public static Range from(Boundary lower, Boundary upper) { @@ -44,6 +48,7 @@ public static Range from(Boundary lower, Boundary upper) { } /** + * @param value type. * @return new {@link Range} with {@code lower} and {@code upper} set to {@link Boundary#unbounded()}. */ public static Range unbounded() { @@ -56,7 +61,7 @@ public static Range unbounded() { * @param lower the lower boundary value. * @return {@code this} {@link Range} with {@code lower} applied. */ - public Range gte(T lower) { + public Range gte(T lower) { this.lower = Boundary.including(lower); return this; @@ -68,7 +73,7 @@ public Range gte(T lower) { * @param lower the lower boundary value. * @return {@code this} {@link Range} with {@code lower} applied. */ - public Range gt(T lower) { + public Range gt(T lower) { this.lower = Boundary.excluding(lower); return this; @@ -139,6 +144,7 @@ private Boundary(T value, boolean including) { * Creates an unbounded (infinite) boundary that marks the beginning/end of the range. * * @return the unbounded boundary. + * @param inferred type. */ @SuppressWarnings("unchecked") public static Boundary unbounded() { @@ -150,7 +156,7 @@ public static Boundary unbounded() { * equals, less or equals. but not Greater or equal, less or equal to {@code value}. * * @param value must not be {@literal null}. - * @param value type + * @param value type. * @return the {@link Boundary}. */ public static Boundary including(T value) { @@ -165,7 +171,7 @@ public static Boundary including(T value) { * to {@code value} but not greater or equal, less or equal. * * @param value must not be {@literal null}. - * @param value type + * @param value type. * @return the {@link Boundary}. */ public static Boundary excluding(T value) { diff --git a/src/main/java/com/lambdaworks/redis/resource/DefaultClientResources.java b/src/main/java/com/lambdaworks/redis/resource/DefaultClientResources.java index 544f4aa41a..4a63e18955 100644 --- a/src/main/java/com/lambdaworks/redis/resource/DefaultClientResources.java +++ b/src/main/java/com/lambdaworks/redis/resource/DefaultClientResources.java @@ -330,8 +330,8 @@ public Builder reconnectDelay(Delay reconnectDelay) { } /** - * Sets the stateful reconnect {@link Supplier} to delay reconnect attempts. Defaults to binary exponential delay capped at - * {@literal 30 SECONDS}. + * Sets the stateful reconnect {@link Supplier} to delay reconnect attempts. Defaults to binary exponential delay capped + * at {@literal 30 SECONDS}. * * @param reconnectDelay the reconnect delay, must not be {@literal null}. * @return this diff --git a/src/test/java/com/lambdaworks/redis/commands/reactive/BitReactiveCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/reactive/BitReactiveCommandTest.java index 8a17a22feb..9bf704072d 100644 --- a/src/test/java/com/lambdaworks/redis/commands/reactive/BitReactiveCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/reactive/BitReactiveCommandTest.java @@ -8,10 +8,10 @@ * @author Mark Paluch */ public class BitReactiveCommandTest extends BitCommandTest { + @Override protected RedisCommands connect() { bitstring = ReactiveSyncInvocationHandler.sync(client.connect(new BitStringCodec())); return ReactiveSyncInvocationHandler.sync(client.connect()); } - } diff --git a/src/test/java/com/lambdaworks/redis/commands/reactive/CustomReactiveCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/reactive/CustomReactiveCommandTest.java index 6ec73e14b2..43ca857766 100644 --- a/src/test/java/com/lambdaworks/redis/commands/reactive/CustomReactiveCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/reactive/CustomReactiveCommandTest.java @@ -1,6 +1,5 @@ package com.lambdaworks.redis.commands.reactive; -import com.lambdaworks.redis.reactive.TestSubscriber; import org.junit.Test; import com.lambdaworks.redis.api.reactive.RedisReactiveCommands; @@ -10,6 +9,7 @@ import com.lambdaworks.redis.output.ValueOutput; import com.lambdaworks.redis.protocol.CommandArgs; import com.lambdaworks.redis.protocol.CommandType; +import com.lambdaworks.redis.reactive.TestSubscriber; import com.lambdaworks.util.ReactiveSyncInvocationHandler; import reactor.core.publisher.Flux; @@ -49,5 +49,4 @@ public void dispatchList() throws Exception { TestSubscriber testSubscriber = TestSubscriber.subscribe(flux); testSubscriber.awaitAndAssertNextValues("a", "b", "c").assertComplete().assertNoError(); } - } diff --git a/src/test/java/com/lambdaworks/redis/commands/reactive/GeoReactiveCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/reactive/GeoReactiveCommandTest.java index c6f351ea4a..16ac5a0f90 100644 --- a/src/test/java/com/lambdaworks/redis/commands/reactive/GeoReactiveCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/reactive/GeoReactiveCommandTest.java @@ -15,6 +15,9 @@ import com.lambdaworks.redis.commands.GeoCommandTest; import com.lambdaworks.util.ReactiveSyncInvocationHandler; +/** + * @author Mark Paluch + */ public class GeoReactiveCommandTest extends GeoCommandTest { @Override diff --git a/src/test/java/com/lambdaworks/redis/commands/reactive/HLLReactiveCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/reactive/HLLReactiveCommandTest.java index cb54b23aee..47ce5648c4 100644 --- a/src/test/java/com/lambdaworks/redis/commands/reactive/HLLReactiveCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/reactive/HLLReactiveCommandTest.java @@ -4,6 +4,9 @@ import com.lambdaworks.redis.commands.HLLCommandTest; import com.lambdaworks.util.ReactiveSyncInvocationHandler; +/** + * @author Mark Paluch + */ public class HLLReactiveCommandTest extends HLLCommandTest { @Override diff --git a/src/test/java/com/lambdaworks/redis/commands/reactive/HashReactiveCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/reactive/HashReactiveCommandTest.java index 492f7cf1b8..6273435d9f 100644 --- a/src/test/java/com/lambdaworks/redis/commands/reactive/HashReactiveCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/reactive/HashReactiveCommandTest.java @@ -4,11 +4,13 @@ import com.lambdaworks.redis.commands.HashCommandTest; import com.lambdaworks.util.ReactiveSyncInvocationHandler; +/** + * @author Mark Paluch + */ public class HashReactiveCommandTest extends HashCommandTest { @Override protected RedisCommands connect() { return ReactiveSyncInvocationHandler.sync(client.connect()); } - } diff --git a/src/test/java/com/lambdaworks/redis/commands/reactive/KeyReactiveCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/reactive/KeyReactiveCommandTest.java index 5258ccc205..4e6e825b4c 100644 --- a/src/test/java/com/lambdaworks/redis/commands/reactive/KeyReactiveCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/reactive/KeyReactiveCommandTest.java @@ -4,7 +4,11 @@ import com.lambdaworks.redis.commands.KeyCommandTest; import com.lambdaworks.util.ReactiveSyncInvocationHandler; +/** + * @author Mark Paluch + */ public class KeyReactiveCommandTest extends KeyCommandTest { + @Override protected RedisCommands connect() { return ReactiveSyncInvocationHandler.sync(client.connect()); diff --git a/src/test/java/com/lambdaworks/redis/commands/reactive/ListReactiveCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/reactive/ListReactiveCommandTest.java index 08aace213c..89a3b8fc28 100644 --- a/src/test/java/com/lambdaworks/redis/commands/reactive/ListReactiveCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/reactive/ListReactiveCommandTest.java @@ -4,7 +4,11 @@ import com.lambdaworks.redis.commands.ListCommandTest; import com.lambdaworks.util.ReactiveSyncInvocationHandler; +/** + * @author Mark Paluch + */ public class ListReactiveCommandTest extends ListCommandTest { + @Override protected RedisCommands connect() { return ReactiveSyncInvocationHandler.sync(client.connect()); diff --git a/src/test/java/com/lambdaworks/redis/commands/reactive/NumericReactiveCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/reactive/NumericReactiveCommandTest.java index 93b4f43c7f..3da291297d 100644 --- a/src/test/java/com/lambdaworks/redis/commands/reactive/NumericReactiveCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/reactive/NumericReactiveCommandTest.java @@ -4,7 +4,11 @@ import com.lambdaworks.redis.commands.NumericCommandTest; import com.lambdaworks.util.ReactiveSyncInvocationHandler; +/** + * @author Mark Paluch + */ public class NumericReactiveCommandTest extends NumericCommandTest { + @Override protected RedisCommands connect() { return ReactiveSyncInvocationHandler.sync(client.connect()); diff --git a/src/test/java/com/lambdaworks/redis/commands/reactive/ScriptingReactiveCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/reactive/ScriptingReactiveCommandTest.java index 92546430af..fe4f8a6d95 100644 --- a/src/test/java/com/lambdaworks/redis/commands/reactive/ScriptingReactiveCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/reactive/ScriptingReactiveCommandTest.java @@ -4,9 +4,11 @@ import com.lambdaworks.redis.commands.ScriptingCommandTest; import com.lambdaworks.util.ReactiveSyncInvocationHandler; +/** + * @author Mark Paluch + */ public class ScriptingReactiveCommandTest extends ScriptingCommandTest { - @Override protected RedisCommands connect() { return ReactiveSyncInvocationHandler.sync(client.connect()); diff --git a/src/test/java/com/lambdaworks/redis/commands/reactive/ServerReactiveCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/reactive/ServerReactiveCommandTest.java index 150d40a2b6..b8432a2dec 100644 --- a/src/test/java/com/lambdaworks/redis/commands/reactive/ServerReactiveCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/reactive/ServerReactiveCommandTest.java @@ -2,14 +2,17 @@ import static org.assertj.core.api.Assertions.assertThat; -import com.lambdaworks.util.ReactiveSyncInvocationHandler; import org.junit.Before; import org.junit.Test; import com.lambdaworks.redis.api.reactive.RedisReactiveCommands; import com.lambdaworks.redis.api.sync.RedisCommands; import com.lambdaworks.redis.commands.ServerCommandTest; +import com.lambdaworks.util.ReactiveSyncInvocationHandler; +/** + * @author Mark Paluch + */ public class ServerReactiveCommandTest extends ServerCommandTest { private RedisReactiveCommands reactive; diff --git a/src/test/java/com/lambdaworks/redis/commands/reactive/SetReactiveCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/reactive/SetReactiveCommandTest.java index 5b588e81f7..9c163bdbf4 100644 --- a/src/test/java/com/lambdaworks/redis/commands/reactive/SetReactiveCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/reactive/SetReactiveCommandTest.java @@ -4,11 +4,13 @@ import com.lambdaworks.redis.commands.SetCommandTest; import com.lambdaworks.util.ReactiveSyncInvocationHandler; +/** + * @author Mark Paluch + */ public class SetReactiveCommandTest extends SetCommandTest { @Override protected RedisCommands connect() { return ReactiveSyncInvocationHandler.sync(client.connect()); } - } diff --git a/src/test/java/com/lambdaworks/redis/commands/reactive/SortReactiveCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/reactive/SortReactiveCommandTest.java index 87127a1f49..41ccaaa8e8 100644 --- a/src/test/java/com/lambdaworks/redis/commands/reactive/SortReactiveCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/reactive/SortReactiveCommandTest.java @@ -4,7 +4,11 @@ import com.lambdaworks.redis.commands.SortCommandTest; import com.lambdaworks.util.ReactiveSyncInvocationHandler; +/** + * @author Mark Paluch + */ public class SortReactiveCommandTest extends SortCommandTest { + @Override protected RedisCommands connect() { return ReactiveSyncInvocationHandler.sync(client.connect()); diff --git a/src/test/java/com/lambdaworks/redis/commands/reactive/SortedSetReactiveCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/reactive/SortedSetReactiveCommandTest.java index 68b190e01a..7f2d9468c6 100644 --- a/src/test/java/com/lambdaworks/redis/commands/reactive/SortedSetReactiveCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/reactive/SortedSetReactiveCommandTest.java @@ -4,7 +4,11 @@ import com.lambdaworks.redis.commands.SortedSetCommandTest; import com.lambdaworks.util.ReactiveSyncInvocationHandler; +/** + * @author Mark Paluch + */ public class SortedSetReactiveCommandTest extends SortedSetCommandTest { + @Override protected RedisCommands connect() { return ReactiveSyncInvocationHandler.sync(client.connect()); diff --git a/src/test/java/com/lambdaworks/redis/commands/reactive/StringReactiveCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/reactive/StringReactiveCommandTest.java index e3c69eed09..a0ebaa15f8 100644 --- a/src/test/java/com/lambdaworks/redis/commands/reactive/StringReactiveCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/reactive/StringReactiveCommandTest.java @@ -2,16 +2,21 @@ import static org.assertj.core.api.Assertions.assertThat; -import com.lambdaworks.redis.KeyValue; -import com.lambdaworks.util.ReactiveSyncInvocationHandler; import org.junit.Test; +import com.lambdaworks.redis.KeyValue; import com.lambdaworks.redis.api.StatefulRedisConnection; import com.lambdaworks.redis.api.sync.RedisCommands; import com.lambdaworks.redis.commands.StringCommandTest; +import com.lambdaworks.util.ReactiveSyncInvocationHandler; + import reactor.core.publisher.Flux; +/** + * @author Mark Paluch + */ public class StringReactiveCommandTest extends StringCommandTest { + @Override protected RedisCommands connect() { return ReactiveSyncInvocationHandler.sync(client.connect()); diff --git a/src/test/java/com/lambdaworks/redis/commands/reactive/TransactionReactiveCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/reactive/TransactionReactiveCommandTest.java index 7760a6e294..605b3c6b41 100644 --- a/src/test/java/com/lambdaworks/redis/commands/reactive/TransactionReactiveCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/reactive/TransactionReactiveCommandTest.java @@ -4,7 +4,6 @@ import java.util.List; -import com.lambdaworks.redis.reactive.TestSubscriber; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -17,11 +16,15 @@ import com.lambdaworks.redis.api.reactive.RedisReactiveCommands; import com.lambdaworks.redis.api.sync.RedisCommands; import com.lambdaworks.redis.commands.TransactionCommandTest; +import com.lambdaworks.redis.reactive.TestSubscriber; import com.lambdaworks.util.ReactiveSyncInvocationHandler; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; +/** + * @author Mark Paluch + */ public class TransactionReactiveCommandTest extends TransactionCommandTest { private RedisReactiveCommands commands; From 0a0d23c75d702bc024914105b05bcafa423201a0 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Sat, 22 Oct 2016 09:10:39 +0200 Subject: [PATCH 043/808] Support integer width multiplied offsets in BITFIELD #379 BitFieldArgs exposes now BitFieldArgs.offset and BitFieldArgs.typeWidthBasedOffset factory methods to create Offset instances that can be used together with BITFIELD subcommands. --- .../com/lambdaworks/redis/BitFieldArgs.java | 233 ++++++++++++++++-- .../redis/commands/BitCommandTest.java | 46 +++- 2 files changed, 254 insertions(+), 25 deletions(-) diff --git a/src/main/java/com/lambdaworks/redis/BitFieldArgs.java b/src/main/java/com/lambdaworks/redis/BitFieldArgs.java index 7e562e7acc..a24a9b2315 100644 --- a/src/main/java/com/lambdaworks/redis/BitFieldArgs.java +++ b/src/main/java/com/lambdaworks/redis/BitFieldArgs.java @@ -42,7 +42,7 @@ private Builder() { } /** - * Adds a new {@link Get} subcommand. + * Create a new {@link Get} subcommand. * * @param bitFieldType the bit field type, must not be {@literal null}. * @param offset bitfield offset @@ -53,7 +53,19 @@ public static BitFieldArgs get(BitFieldType bitFieldType, int offset) { } /** - * Adds a new {@link Set} subcommand. + * Create a new {@link Get} subcommand. + * + * @param bitFieldType the bit field type, must not be {@literal null}. + * @param offset bitfield offset, must not be {@literal null}. + * @return a new {@link Get} subcommand for the given {@code bitFieldType} and {@code offset}. + * @since 4.3 + */ + public static BitFieldArgs get(BitFieldType bitFieldType, Offset offset) { + return new BitFieldArgs().get(bitFieldType, offset); + } + + /** + * Create a new {@link Set} subcommand. * * @param bitFieldType the bit field type, must not be {@literal null}. * @param offset bitfield offset @@ -65,7 +77,20 @@ public static BitFieldArgs set(BitFieldType bitFieldType, int offset, long value } /** - * Adds a new {@link IncrBy} subcommand. + * Create a new {@link Set} subcommand. + * + * @param bitFieldType the bit field type, must not be {@literal null}. + * @param offset bitfield offset, must not be {@literal null}. + * @param value the value + * @return a new {@link Set} subcommand for the given {@code bitFieldType}, {@code offset} and {@code value}. + * @since 4.3 + */ + public static BitFieldArgs set(BitFieldType bitFieldType, Offset offset, long value) { + return new BitFieldArgs().set(bitFieldType, offset, value); + } + + /** + * Create a new {@link IncrBy} subcommand. * * @param bitFieldType the bit field type, must not be {@literal null}. * @param offset bitfield offset @@ -76,6 +101,19 @@ public static BitFieldArgs incrBy(BitFieldType bitFieldType, int offset, long va return new BitFieldArgs().incrBy(bitFieldType, offset, value); } + /** + * Create a new {@link IncrBy} subcommand. + * + * @param bitFieldType the bit field type, must not be {@literal null}. + * @param offset bitfield offset, must not be {@literal null}. + * @param value the value + * @return a new {@link IncrBy} subcommand for the given {@code bitFieldType}, {@code offset} and {@code value}. + * @since 4.3 + */ + public static BitFieldArgs incrBy(BitFieldType bitFieldType, Offset offset, long value) { + return new BitFieldArgs().incrBy(bitFieldType, offset, value); + } + /** * Adds a new {@link Overflow} subcommand. * @@ -92,8 +130,8 @@ public static BitFieldArgs overflow(OverflowType overflowType) { * * Redis allows up to {@code 64} bits for unsigned integers. * - * @param bits - * @return + * @param bits number of bits to define the integer type width. + * @return the {@link BitFieldType}. */ public static BitFieldType signed(int bits) { return new BitFieldType(true, bits); @@ -103,19 +141,43 @@ public static BitFieldType signed(int bits) { * Creates a new unsigned {@link BitFieldType} for the given number of {@code bits}. Redis allows up to {@code 63} bits for * unsigned integers. * - * @param bits - * @return + * @param bits number of bits to define the integer type width. + * @return the {@link BitFieldType}. */ public static BitFieldType unsigned(int bits) { return new BitFieldType(false, bits); } + /** + * Creates a new {@link Offset} for the given {@code offset}. + * + * @param offset zero-based offset. + * @return the {@link Offset}. + * @since 4.3 + */ + public static Offset offset(int offset) { + return new Offset(false, offset); + } + + /** + * Creates a new {@link Offset} for the given {@code offset} that is multiplied by the integer type width used in the sub + * command. + * + * @param offset offset to be multiplied by the integer type width. + * @return the {@link Offset}. + * @since 4.3 + */ + public static Offset typeWidthBasedOffset(int offset) { + return new Offset(true, offset); + } + /** * Adds a new {@link SubCommand} to the {@code BITFIELD} execution. * - * @param subCommand + * @param subCommand must not be {@literal null}. */ private BitFieldArgs addSubCommand(SubCommand subCommand) { + LettuceAssert.notNull(subCommand, "SubCommand must not be null"); commands.add(subCommand); return this; @@ -149,7 +211,22 @@ public BitFieldArgs get(BitFieldType bitFieldType) { * @return a new {@link Get} subcommand for the given {@code bitFieldType} and {@code offset}. */ public BitFieldArgs get(BitFieldType bitFieldType, int offset) { - return addSubCommand(new Get(bitFieldType, offset)); + return addSubCommand(new Get(bitFieldType, false, offset)); + } + + /** + * Adds a new {@link Get} subcommand. + * + * @param bitFieldType the bit field type, must not be {@literal null}. + * @param offset bitfield offset + * @return a new {@link Get} subcommand for the given {@code bitFieldType} and {@code offset}. + * @since 4.3 + */ + public BitFieldArgs get(BitFieldType bitFieldType, Offset offset) { + + LettuceAssert.notNull(offset, "BitFieldOffset must not be null"); + + return addSubCommand(new Get(bitFieldType, offset.isMultiplyByTypeWidth(), offset.getOffset())); } /** @@ -206,7 +283,23 @@ public BitFieldArgs set(int offset, long value) { * @return a new {@link Set} subcommand for the given {@code bitFieldType}, {@code offset} and {@code value}. */ public BitFieldArgs set(BitFieldType bitFieldType, int offset, long value) { - return addSubCommand(new Set(bitFieldType, offset, value)); + return addSubCommand(new Set(bitFieldType, false, offset, value)); + } + + /** + * Adds a new {@link Set} subcommand. + * + * @param bitFieldType the bit field type, must not be {@literal null}. + * @param offset bitfield offset, must not be {@literal null}. + * @param value the value + * @return a new {@link Set} subcommand for the given {@code bitFieldType}, {@code offset} and {@code value}. + * @since 4.3 + */ + public BitFieldArgs set(BitFieldType bitFieldType, Offset offset, long value) { + + LettuceAssert.notNull(offset, "BitFieldOffset must not be null"); + + return addSubCommand(new Set(bitFieldType, offset.isMultiplyByTypeWidth(), offset.getOffset(), value)); } /** @@ -252,7 +345,23 @@ public BitFieldArgs incrBy(int offset, long value) { * @return a new {@link IncrBy} subcommand for the given {@code bitFieldType}, {@code offset} and {@code value}. */ public BitFieldArgs incrBy(BitFieldType bitFieldType, int offset, long value) { - return addSubCommand(new IncrBy(bitFieldType, offset, value)); + return addSubCommand(new IncrBy(bitFieldType, false, offset, value)); + } + + /** + * Adds a new {@link IncrBy} subcommand. + * + * @param bitFieldType the bit field type, must not be {@literal null}. + * @param offset bitfield offset, must not be {@literal null}. + * @param value the value + * @return a new {@link IncrBy} subcommand for the given {@code bitFieldType}, {@code offset} and {@code value}. + * @since 4.3 + */ + public BitFieldArgs incrBy(BitFieldType bitFieldType, Offset offset, long value) { + + LettuceAssert.notNull(offset, "BitFieldOffset must not be null"); + + return addSubCommand(new IncrBy(bitFieldType, offset.isMultiplyByTypeWidth(), offset.getOffset(), value)); } /** @@ -294,22 +403,33 @@ private BitFieldType previousFieldType() { private static class Set extends SubCommand { private final BitFieldType bitFieldType; + private final boolean bitOffset; private final long offset; private final long value; - private Set(BitFieldType bitFieldType, int offset, long value) { + private Set(BitFieldType bitFieldType, boolean bitOffset, int offset, long value) { LettuceAssert.notNull(bitFieldType, "BitFieldType must not be null"); LettuceAssert.isTrue(offset > -1, "Offset must be greater or equal to 0"); - this.offset = offset; this.bitFieldType = bitFieldType; + this.bitOffset = bitOffset; + this.offset = offset; this.value = value; } @Override void build(CommandArgs args) { - args.add(CommandType.SET).add(bitFieldType.asString()).add(offset).add(value); + + args.add(CommandType.SET).add(bitFieldType.asString()); + + if (bitOffset) { + args.add(String.format("#%d", offset)); + } else { + args.add(offset); + } + + args.add(value); } } @@ -319,20 +439,29 @@ void build(CommandArgs args) { private static class Get extends SubCommand { private final BitFieldType bitFieldType; - private final long offset; + private final boolean bitOffset; + private final int offset; - private Get(BitFieldType bitFieldType, int offset) { + private Get(BitFieldType bitFieldType, boolean bitOffset, int offset) { LettuceAssert.notNull(bitFieldType, "BitFieldType must not be null"); LettuceAssert.isTrue(offset > -1, "Offset must be greater or equal to 0"); - this.offset = offset; this.bitFieldType = bitFieldType; + this.bitOffset = bitOffset; + this.offset = offset; } @Override void build(CommandArgs args) { - args.add(CommandType.GET).add(bitFieldType.asString()).add(offset); + + args.add(CommandType.GET).add(bitFieldType.asString()); + + if (bitOffset) { + args.add(String.format("#%d", offset)); + } else { + args.add(offset); + } } } @@ -342,22 +471,34 @@ void build(CommandArgs args) { private static class IncrBy extends SubCommand { private final BitFieldType bitFieldType; + private final boolean bitOffset; private final long offset; private final long value; - private IncrBy(BitFieldType bitFieldType, int offset, long value) { + private IncrBy(BitFieldType bitFieldType, boolean offsetWidthMultiplier, int offset, long value) { LettuceAssert.notNull(bitFieldType, "BitFieldType must not be null"); LettuceAssert.isTrue(offset > -1, "Offset must be greater or equal to 0"); - this.offset = offset; this.bitFieldType = bitFieldType; + this.bitOffset = offsetWidthMultiplier; + this.offset = offset; this.value = value; } @Override void build(CommandArgs args) { - args.add(CommandType.INCRBY).add(bitFieldType.asString()).add(offset).add(value); + + args.add(CommandType.INCRBY).add(bitFieldType.asString()); + + if (bitOffset) { + args.add(String.format("#%d", offset)); + } else { + args.add(offset); + } + + args.add(value); + } } @@ -403,7 +544,7 @@ public enum OverflowType implements ProtocolKeyword { public final byte[] bytes; - private OverflowType() { + OverflowType() { bytes = name().getBytes(LettuceCharsets.ASCII); } @@ -451,8 +592,52 @@ public int getBits() { return bits; } - private String asString() { - return (signed ? "i" : "u") + bits; + private String asString() { + return String.format("%s%d", (signed ? "i" : "u"), bits); + } + + @Override + public String toString() { + return asString(); + } + } + + /** + * Represents a bit field offset. See also Bits and + * positional offsets + * + * @since 4.3 + */ + public static class Offset { + + private final boolean multiplyByTypeWidth; + private final int offset; + + private Offset(boolean multiplyByTypeWidth, int offset) { + + this.multiplyByTypeWidth = multiplyByTypeWidth; + this.offset = offset; + } + + /** + * @return {@literal true} if the offset should be multiplied by integer width that is represented with a leading hash + * ({@code #}) when constructing the command + */ + public boolean isMultiplyByTypeWidth() { + return multiplyByTypeWidth; + } + + /** + * + * @return the offset. + */ + public int getOffset() { + return offset; + } + + @Override + public String toString() { + return String.format("%s%d", (multiplyByTypeWidth ? "#" : ""), offset); } } } diff --git a/src/test/java/com/lambdaworks/redis/commands/BitCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/BitCommandTest.java index 6369343a6e..bb4272792e 100644 --- a/src/test/java/com/lambdaworks/redis/commands/BitCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/BitCommandTest.java @@ -2,7 +2,9 @@ package com.lambdaworks.redis.commands; +import static com.lambdaworks.redis.BitFieldArgs.offset; import static com.lambdaworks.redis.BitFieldArgs.signed; +import static com.lambdaworks.redis.BitFieldArgs.typeWidthBasedOffset; import static com.lambdaworks.redis.BitFieldArgs.unsigned; import static com.lambdaworks.redis.BitFieldArgs.OverflowType.WRAP; import static org.assertj.core.api.Assertions.assertThat; @@ -10,7 +12,6 @@ import java.nio.ByteBuffer; import java.util.List; -import org.assertj.core.api.Assertions; import org.junit.Test; import com.lambdaworks.redis.AbstractRedisClientTest; @@ -73,6 +74,16 @@ public void bitfieldBuilderEmptyPreviousType() throws Exception { new BitFieldArgs().overflow(WRAP).get(); } + @Test + public void bitfieldArgsTest() throws Exception { + + assertThat(signed(5).toString()).isEqualTo("i5"); + assertThat(unsigned(5).toString()).isEqualTo("u5"); + + assertThat(offset(5).toString()).isEqualTo("5"); + assertThat(typeWidthBasedOffset(5).toString()).isEqualTo("#5"); + } + @Test public void bitfield() throws Exception { @@ -84,6 +95,17 @@ public void bitfield() throws Exception { assertThat(bitstring.get(key)).isEqualTo("0000000000010011"); } + @Test + public void bitfieldGetWithOffset() throws Exception { + + BitFieldArgs bitFieldArgs = BitFieldArgs.Builder.set(signed(8), 0, 1).get(signed(2), typeWidthBasedOffset(1)); + + List values = redis.bitfield(key, bitFieldArgs); + + assertThat(values).containsExactly(0L, 0L); + assertThat(bitstring.get(key)).isEqualTo("10000000"); + } + @Test public void bitfieldSet() throws Exception { @@ -95,6 +117,17 @@ public void bitfieldSet() throws Exception { assertThat(bitstring.get(key)).isEqualTo("10100000"); } + @Test + public void bitfieldWithOffsetSet() throws Exception { + + redis.bitfield(key, BitFieldArgs.Builder.set(signed(8), typeWidthBasedOffset(2), 5)); + assertThat(bitstring.get(key)).isEqualTo("000000000000000010100000"); + + redis.del(key); + redis.bitfield(key, BitFieldArgs.Builder.set(signed(8), offset(2), 5)); + assertThat(bitstring.get(key)).isEqualTo("1000000000000010"); + } + @Test public void bitfieldIncrBy() throws Exception { @@ -106,6 +139,17 @@ public void bitfieldIncrBy() throws Exception { assertThat(bitstring.get(key)).isEqualTo("01100000"); } + @Test + public void bitfieldWithOffsetIncrBy() throws Exception { + + redis.bitfield(key, BitFieldArgs.Builder.incrBy(signed(8), typeWidthBasedOffset(2), 1)); + assertThat(bitstring.get(key)).isEqualTo("000000000000000010000000"); + + redis.del(key); + redis.bitfield(key, BitFieldArgs.Builder.incrBy(signed(8), offset(2), 1)); + assertThat(bitstring.get(key)).isEqualTo("0000000000000010"); + } + @Test public void bitfieldOverflow() throws Exception { From f58389c4f0e8c6d80866492fee51d08e63f180e6 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Mon, 24 Oct 2016 13:49:22 +0200 Subject: [PATCH 044/808] Allow empty values in BITFIELD using the reactive API #378 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit RedisStringReactiveCommands.bitfield(…) now returns a Flux of Value of Long instead a Flux of Long to allow empty (nil) values caused by OVERFLOW FAIL. --- .../redis/AbstractRedisReactiveCommands.java | 4 +- .../reactive/RedisStringReactiveCommands.java | 5 +- .../apigenerator/CreateReactiveApi.java | 11 ++- .../reactive/BitReactiveCommandTest.java | 87 ++++++++++++++++++- 4 files changed, 99 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/lambdaworks/redis/AbstractRedisReactiveCommands.java b/src/main/java/com/lambdaworks/redis/AbstractRedisReactiveCommands.java index 704bf74645..13a510139a 100644 --- a/src/main/java/com/lambdaworks/redis/AbstractRedisReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/AbstractRedisReactiveCommands.java @@ -81,8 +81,8 @@ public Mono bitcount(K key, long start, long end) { } @Override - public Flux bitfield(K key, BitFieldArgs args) { - return createDissolvingFlux(() -> commandBuilder.bitfield(key, args)); + public Flux> bitfield(K key, BitFieldArgs args) { + return createDissolvingFlux(() -> commandBuilder.bitfieldValue(key, args)); } @Override diff --git a/src/main/java/com/lambdaworks/redis/api/reactive/RedisStringReactiveCommands.java b/src/main/java/com/lambdaworks/redis/api/reactive/RedisStringReactiveCommands.java index b6934b126f..fda40cf542 100644 --- a/src/main/java/com/lambdaworks/redis/api/reactive/RedisStringReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/reactive/RedisStringReactiveCommands.java @@ -1,9 +1,7 @@ package com.lambdaworks.redis.api.reactive; -import java.util.List; import java.util.Map; import com.lambdaworks.redis.output.KeyValueStreamingChannel; -import com.lambdaworks.redis.output.ValueStreamingChannel; import com.lambdaworks.redis.BitFieldArgs; import com.lambdaworks.redis.KeyValue; import com.lambdaworks.redis.SetArgs; @@ -59,7 +57,7 @@ public interface RedisStringReactiveCommands { * * @return Long bulk-reply the results from the bitfield commands. */ - Flux bitfield(K key, BitFieldArgs bitFieldArgs); + Flux> bitfield(K key, BitFieldArgs bitFieldArgs); /** * Find first bit set or clear in a string. @@ -111,7 +109,6 @@ public interface RedisStringReactiveCommands { Mono bitpos(K key, boolean state, long start, long end); /** - * Perform bitwise AND between strings. * * @param destination result key of the operation * @param keys operation input key names diff --git a/src/test/java/com/lambdaworks/apigenerator/CreateReactiveApi.java b/src/test/java/com/lambdaworks/apigenerator/CreateReactiveApi.java index d1508dde47..e1fffc81af 100644 --- a/src/test/java/com/lambdaworks/apigenerator/CreateReactiveApi.java +++ b/src/test/java/com/lambdaworks/apigenerator/CreateReactiveApi.java @@ -30,7 +30,16 @@ public class CreateReactiveApi { "BaseRedisCommands.reset", "getStatefulConnection", "setAutoFlushCommands", "flushCommands"); private static Set FORCE_FLUX_RESULT = LettuceSets.unmodifiableSet("eval", "evalsha", "dispatch"); - private static Map RESULT_SPEC = Collections.singletonMap("geopos", "Flux>"); + private static final Map RESULT_SPEC; + + static { + + Map resultSpec = new HashMap<>(); + resultSpec.put("geopos", "Flux>"); + resultSpec.put("bitfield", "Flux>"); + + RESULT_SPEC = resultSpec; + } private CompilationUnitFactory factory; diff --git a/src/test/java/com/lambdaworks/redis/commands/reactive/BitReactiveCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/reactive/BitReactiveCommandTest.java index 9bf704072d..c5408baf79 100644 --- a/src/test/java/com/lambdaworks/redis/commands/reactive/BitReactiveCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/reactive/BitReactiveCommandTest.java @@ -1,5 +1,19 @@ package com.lambdaworks.redis.commands.reactive; +import static com.lambdaworks.redis.BitFieldArgs.offset; +import static com.lambdaworks.redis.BitFieldArgs.signed; +import static com.lambdaworks.redis.BitFieldArgs.typeWidthBasedOffset; +import static com.lambdaworks.redis.BitFieldArgs.OverflowType.FAIL; +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.List; + +import org.junit.Test; + +import com.lambdaworks.redis.BitFieldArgs; +import com.lambdaworks.redis.Value; +import com.lambdaworks.redis.api.StatefulRedisConnection; +import com.lambdaworks.redis.api.reactive.RedisStringReactiveCommands; import com.lambdaworks.redis.api.sync.RedisCommands; import com.lambdaworks.redis.commands.BitCommandTest; import com.lambdaworks.util.ReactiveSyncInvocationHandler; @@ -9,9 +23,80 @@ */ public class BitReactiveCommandTest extends BitCommandTest { + private RedisStringReactiveCommands reactive; + @Override protected RedisCommands connect() { bitstring = ReactiveSyncInvocationHandler.sync(client.connect(new BitStringCodec())); - return ReactiveSyncInvocationHandler.sync(client.connect()); + + StatefulRedisConnection connection = client.connect(); + reactive = connection.reactive(); + return ReactiveSyncInvocationHandler.sync(connection); + } + + @Test + public void bitfield() throws Exception { + + BitFieldArgs bitFieldArgs = BitFieldArgs.Builder.set(signed(8), 0, 1).set(5, 1).incrBy(2, 3).get().get(2); + + List> values = reactive.bitfield(key, bitFieldArgs).collectList().block(); + + assertThat(values).containsExactly(Value.just(0L), Value.just(32L), Value.just(3L), Value.just(0L), Value.just(3L)); + assertThat(bitstring.get(key)).isEqualTo("0000000000010011"); + } + + @Test + public void bitfieldGetWithOffset() throws Exception { + + BitFieldArgs bitFieldArgs = BitFieldArgs.Builder.set(signed(8), 0, 1).get(signed(2), typeWidthBasedOffset(1)); + + List> values = reactive.bitfield(key, bitFieldArgs).collectList().block(); + + assertThat(values).containsExactly(Value.just(0L), Value.just(0L)); + assertThat(bitstring.get(key)).isEqualTo("10000000"); + } + + @Test + public void bitfieldSet() throws Exception { + + BitFieldArgs bitFieldArgs = BitFieldArgs.Builder.set(signed(8), 0, 5).set(5); + + List> values = reactive.bitfield(key, bitFieldArgs).collectList().block(); + + assertThat(values).containsExactly(Value.just(0L), Value.just(5L)); + assertThat(bitstring.get(key)).isEqualTo("10100000"); + } + + @Test + public void bitfieldWithOffsetSet() throws Exception { + + reactive.bitfield(key, BitFieldArgs.Builder.set(signed(8), typeWidthBasedOffset(2), 5)).last().block(); + assertThat(bitstring.get(key)).isEqualTo("000000000000000010100000"); + + redis.del(key); + reactive.bitfield(key, BitFieldArgs.Builder.set(signed(8), offset(2), 5)).last().block(); + assertThat(bitstring.get(key)).isEqualTo("1000000000000010"); + } + + @Test + public void bitfieldIncrBy() throws Exception { + + BitFieldArgs bitFieldArgs = BitFieldArgs.Builder.set(signed(8), 0, 5).incrBy(1); + + List> values = reactive.bitfield(key, bitFieldArgs).collectList().block(); + + assertThat(values).containsExactly(Value.just(0L), Value.just(6L)); + assertThat(bitstring.get(key)).isEqualTo("01100000"); + } + + @Test + public void bitfieldOverflow() throws Exception { + + BitFieldArgs bitFieldArgs = BitFieldArgs.Builder.overflow(FAIL).set(signed(8), 9, 5).incrBy(signed(8), + Integer.MAX_VALUE); + + List> values = reactive.bitfield(key, bitFieldArgs).collectList().block(); + + assertThat(values).containsExactly(Value.just(0L), Value.empty()); } } From f93d38646ef540fa26ef223c35495143695c33e3 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Mon, 24 Oct 2016 17:10:02 +0200 Subject: [PATCH 045/808] Allow hostnames in MasterSlaveTopologyProvider when parsing in master_host #377 Add dash to allow hostnames in when parsing master_host details received from Redis. Previously, parsing of hostnames with a dash failed due to a restrictive regex. --- .../MasterSlaveTopologyProvider.java | 2 +- .../MasterSlaveTopologyProviderTest.java | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/lambdaworks/redis/masterslave/MasterSlaveTopologyProvider.java b/src/main/java/com/lambdaworks/redis/masterslave/MasterSlaveTopologyProvider.java index 624e177216..2ed40412cd 100644 --- a/src/main/java/com/lambdaworks/redis/masterslave/MasterSlaveTopologyProvider.java +++ b/src/main/java/com/lambdaworks/redis/masterslave/MasterSlaveTopologyProvider.java @@ -26,7 +26,7 @@ public class MasterSlaveTopologyProvider implements TopologyProvider { public static final Pattern ROLE_PATTERN = Pattern.compile("^role\\:([a-z]+)$", Pattern.MULTILINE); public static final Pattern SLAVE_PATTERN = Pattern.compile("^slave(\\d+)\\:([a-zA-Z\\,\\=\\d\\.\\:]+)$", Pattern.MULTILINE); - public static final Pattern MASTER_HOST_PATTERN = Pattern.compile("^master_host\\:([a-zA-Z\\,\\=\\d\\.\\:]+)$", + public static final Pattern MASTER_HOST_PATTERN = Pattern.compile("^master_host\\:([a-zA-Z\\,\\=\\d\\.\\:\\-]+)$", Pattern.MULTILINE); public static final Pattern MASTER_PORT_PATTERN = Pattern.compile("^master_port\\:(\\d+)$", Pattern.MULTILINE); public static final Pattern IP_PATTERN = Pattern.compile("ip\\=([a-zA-Z\\d\\.\\:]+)"); diff --git a/src/test/java/com/lambdaworks/redis/masterslave/MasterSlaveTopologyProviderTest.java b/src/test/java/com/lambdaworks/redis/masterslave/MasterSlaveTopologyProviderTest.java index 53fdc8e3b3..0b0879299e 100644 --- a/src/test/java/com/lambdaworks/redis/masterslave/MasterSlaveTopologyProviderTest.java +++ b/src/test/java/com/lambdaworks/redis/masterslave/MasterSlaveTopologyProviderTest.java @@ -56,6 +56,23 @@ public void shouldParseMasterAndSlave() throws Exception { assertThat(master.getUri().getHost()).isEqualTo("127.0.0.1"); } + @Test + public void shouldParseMasterHostname() throws Exception { + + String info = "# Replication\r\n" + "role:slave\r\n" + "connected_slaves:1\r\n" + "master_host:my.Host-name.COM\r\n" + + "master_port:1234\r\n" + "master_repl_offset:56276\r\n" + "repl_backlog_active:1\r\n"; + + List result = sut.getNodesFromInfo(info); + assertThat(result).hasSize(2); + + RedisNodeDescription slave = result.get(0); + assertThat(slave.getRole()).isEqualTo(RedisInstance.Role.SLAVE); + + RedisNodeDescription master = result.get(1); + assertThat(master.getRole()).isEqualTo(RedisInstance.Role.MASTER); + assertThat(master.getUri().getHost()).isEqualTo("my.Host-name.COM"); + } + @Test public void shouldParseIPv6MasterAddress() throws Exception { From efaf6e3348b4c2a466298c00d848205f2d4ad5a4 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Mon, 24 Oct 2016 17:27:16 +0200 Subject: [PATCH 046/808] Use lenient check for BITFIELD INCRBY/OVERFLOW test Redis does not isolate previously issued BITFIELD/OVERFLOW commands properly so responses happen to be non-deterministic in serveral cases. --- .../redis/commands/reactive/BitReactiveCommandTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/lambdaworks/redis/commands/reactive/BitReactiveCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/reactive/BitReactiveCommandTest.java index c5408baf79..76d3032ee1 100644 --- a/src/test/java/com/lambdaworks/redis/commands/reactive/BitReactiveCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/reactive/BitReactiveCommandTest.java @@ -97,6 +97,6 @@ public void bitfieldOverflow() throws Exception { List> values = reactive.bitfield(key, bitFieldArgs).collectList().block(); - assertThat(values).containsExactly(Value.just(0L), Value.empty()); + assertThat(values).contains(Value.empty()); } } From 7373760d5feed1b3c09cdbd1717485a359d439cd Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Tue, 25 Oct 2016 21:44:46 +0200 Subject: [PATCH 047/808] Add support for SWAPDB #375 --- .../redis/AbstractRedisAsyncCommands.java | 4 ++++ .../redis/AbstractRedisReactiveCommands.java | 4 ++++ .../lambdaworks/redis/RedisCommandBuilder.java | 5 +++++ .../redis/api/async/RedisAsyncCommands.java | 11 +++++++++++ .../api/reactive/RedisReactiveCommands.java | 10 ++++++++++ .../redis/api/sync/RedisCommands.java | 10 ++++++++++ .../redis/protocol/CommandType.java | 2 +- .../redis/commands/ServerCommandTest.java | 18 ++++++++++++++++++ 8 files changed, 63 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/lambdaworks/redis/AbstractRedisAsyncCommands.java b/src/main/java/com/lambdaworks/redis/AbstractRedisAsyncCommands.java index 7fed0dabf7..81bdb80876 100644 --- a/src/main/java/com/lambdaworks/redis/AbstractRedisAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/AbstractRedisAsyncCommands.java @@ -815,6 +815,10 @@ protected AsyncCommand selectAsync(int db) { return dispatch(commandBuilder.select(db)); } + public RedisFuture swapdb(int db1, int db2) { + return dispatch(commandBuilder.swapdb(db1, db2)); + } + @Override public RedisFuture set(K key, V value) { return dispatch(commandBuilder.set(key, value)); diff --git a/src/main/java/com/lambdaworks/redis/AbstractRedisReactiveCommands.java b/src/main/java/com/lambdaworks/redis/AbstractRedisReactiveCommands.java index 13a510139a..99dd0fff10 100644 --- a/src/main/java/com/lambdaworks/redis/AbstractRedisReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/AbstractRedisReactiveCommands.java @@ -811,6 +811,10 @@ public Mono select(int db) { return createMono(() -> commandBuilder.select(db)); } + public Mono swapdb(int db1, int db2) { + return createMono(() -> commandBuilder.swapdb(db1, db2)); + } + @Override public Mono set(K key, V value) { return createMono(() -> commandBuilder.set(key, value)); diff --git a/src/main/java/com/lambdaworks/redis/RedisCommandBuilder.java b/src/main/java/com/lambdaworks/redis/RedisCommandBuilder.java index af599bd073..e6b43901ab 100644 --- a/src/main/java/com/lambdaworks/redis/RedisCommandBuilder.java +++ b/src/main/java/com/lambdaworks/redis/RedisCommandBuilder.java @@ -1134,6 +1134,11 @@ public Command select(int db) { return createCommand(SELECT, new StatusOutput(codec), args); } + public Command swapdb(int db1, int db2) { + CommandArgs args = new CommandArgs(codec).add(db1).add(db2); + return createCommand(SWAPDB, new StatusOutput(codec), args); + } + public Command set(K key, V value) { notNullKey(key); diff --git a/src/main/java/com/lambdaworks/redis/api/async/RedisAsyncCommands.java b/src/main/java/com/lambdaworks/redis/api/async/RedisAsyncCommands.java index 31adaa7a6f..890f2ebc7a 100644 --- a/src/main/java/com/lambdaworks/redis/api/async/RedisAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/async/RedisAsyncCommands.java @@ -2,6 +2,7 @@ import java.util.concurrent.TimeUnit; +import com.lambdaworks.redis.RedisFuture; import com.lambdaworks.redis.api.StatefulRedisConnection; import com.lambdaworks.redis.cluster.api.async.RedisClusterAsyncCommands; @@ -43,6 +44,16 @@ public interface RedisAsyncCommands extends RedisHashAsyncCommands, */ String select(int db); + /** + * Swap two Redis databases, so that immediately all the clients connected to a given DB will see the data of the other DB, + * and the other way around + * + * @param db1 the first database number + * @param db2 the second database number + * @return String simple-string-reply + */ + RedisFuture swapdb(int db1, int db2); + /** * @return the underlying connection. */ diff --git a/src/main/java/com/lambdaworks/redis/api/reactive/RedisReactiveCommands.java b/src/main/java/com/lambdaworks/redis/api/reactive/RedisReactiveCommands.java index cc8a08962c..dbe5053db4 100644 --- a/src/main/java/com/lambdaworks/redis/api/reactive/RedisReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/reactive/RedisReactiveCommands.java @@ -45,6 +45,16 @@ public interface RedisReactiveCommands extends RedisHashReactiveCommands select(int db); + /** + * Swap two Redis databases, so that immediately all the clients connected to a given DB will see the data of the other DB, + * and the other way around + * + * @param db1 the first database number + * @param db2 the second database number + * @return String simple-string-reply + */ + Mono swapdb(int db1, int db2); + /** * @return the underlying connection. */ diff --git a/src/main/java/com/lambdaworks/redis/api/sync/RedisCommands.java b/src/main/java/com/lambdaworks/redis/api/sync/RedisCommands.java index 3a84e48bf8..896bbcc23b 100644 --- a/src/main/java/com/lambdaworks/redis/api/sync/RedisCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/sync/RedisCommands.java @@ -43,6 +43,16 @@ public interface RedisCommands extends RedisHashCommands, RedisKeyCo */ String select(int db); + /** + * Swap two Redis databases, so that immediately all the clients connected to a given DB will see the data of the other DB, + * and the other way around + * + * @param db1 the first database number + * @param db2 the second database number + * @return String simple-string-reply + */ + String swapdb(int db1, int db2); + /** * @return the underlying connection. */ diff --git a/src/main/java/com/lambdaworks/redis/protocol/CommandType.java b/src/main/java/com/lambdaworks/redis/protocol/CommandType.java index 77e76f8c94..e21d1366c7 100644 --- a/src/main/java/com/lambdaworks/redis/protocol/CommandType.java +++ b/src/main/java/com/lambdaworks/redis/protocol/CommandType.java @@ -10,7 +10,7 @@ public enum CommandType implements ProtocolKeyword { // Connection - AUTH, ECHO, PING, QUIT, READONLY, READWRITE, SELECT, + AUTH, ECHO, PING, QUIT, READONLY, READWRITE, SELECT, SWAPDB, // Server diff --git a/src/test/java/com/lambdaworks/redis/commands/ServerCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/ServerCommandTest.java index 07a95815d9..a6e78641a6 100644 --- a/src/test/java/com/lambdaworks/redis/commands/ServerCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/ServerCommandTest.java @@ -328,4 +328,22 @@ public void slowlog() throws Exception { redis.configSet("slowlog-log-slower-than", "10000"); } + + @Test + public void swapdb() { + + redis.select(1); + redis.set(key, "value1"); + + redis.select(2); + redis.set(key, "value2"); + assertThat(redis.get(key)).isEqualTo("value2"); + + redis.swapdb(1, 2); + redis.select(1); + assertThat(redis.get(key)).isEqualTo("value2"); + + redis.select(2); + assertThat(redis.get(key)).isEqualTo("value1"); + } } From c8feada636c3ad3a5d27b492e0d0e752cf05e6ff Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Fri, 30 Sep 2016 14:42:51 +0200 Subject: [PATCH 048/808] Reattempt initially failed Sentinel connections in Master/Slave API #306 Lettuce now retries to connect to Redis Sentinel nodes that were unavailable initially. The Master/Slave connection tracks established and missing connections. It retries only missing connections and does not obtain Sentinel endpoint details from pub/sub messages. Connection retries are signalled by Sentinel events. --- .../masterslave/SentinelTopologyRefresh.java | 262 +++++++++++++----- .../SentinelTopologyRefreshTest.java | 143 ++++++++-- 2 files changed, 320 insertions(+), 85 deletions(-) diff --git a/src/main/java/com/lambdaworks/redis/masterslave/SentinelTopologyRefresh.java b/src/main/java/com/lambdaworks/redis/masterslave/SentinelTopologyRefresh.java index fa4e605e3a..9772c5d44c 100644 --- a/src/main/java/com/lambdaworks/redis/masterslave/SentinelTopologyRefresh.java +++ b/src/main/java/com/lambdaworks/redis/masterslave/SentinelTopologyRefresh.java @@ -1,16 +1,21 @@ package com.lambdaworks.redis.masterslave; import java.io.Closeable; -import java.io.IOException; import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; +import java.util.function.BiPredicate; +import java.util.function.Consumer; +import java.util.function.Supplier; import com.lambdaworks.redis.RedisClient; import com.lambdaworks.redis.RedisConnectionException; import com.lambdaworks.redis.RedisURI; -import com.lambdaworks.redis.api.StatefulConnection; -import com.lambdaworks.redis.codec.Utf8StringCodec; +import com.lambdaworks.redis.codec.StringCodec; +import com.lambdaworks.redis.internal.LettuceLists; +import com.lambdaworks.redis.protocol.LettuceCharsets; import com.lambdaworks.redis.pubsub.RedisPubSubAdapter; import com.lambdaworks.redis.pubsub.StatefulRedisPubSubConnection; @@ -19,7 +24,8 @@ import io.netty.util.internal.logging.InternalLoggerFactory; /** - * Sentinel Pub/Sub listener-enabled topology refresh. + * Sentinel Pub/Sub listener-enabled topology refresh. This refresh triggers topology updates if Redis topology changes + * (monitored master/slaves) or the Sentinel availability changes. * * @author Mark Paluch * @since 4.2 @@ -27,43 +33,82 @@ class SentinelTopologyRefresh implements Closeable { private static final InternalLogger LOG = InternalLoggerFactory.getInstance(SentinelTopologyRefresh.class); + private static final StringCodec CODEC = new StringCodec(LettuceCharsets.ASCII); + private static final Set PROCESSING_CHANNELS = new HashSet<>( + Arrays.asList("failover-end", "failover-end-for-timeout")); - private final List> pubSubConnections = new ArrayList<>(); + private final Map> pubSubConnections = new ConcurrentHashMap<>(); private final RedisClient redisClient; - private final String masterId; private final List sentinels; - private final AtomicReference timeoutRef = new AtomicReference(); - private final Set PROCESSING_CHANNELS = new HashSet<>(Arrays.asList("failover-end", "failover-end-for-timeout")); + private final List refreshRunnables = new CopyOnWriteArrayList<>(); + private final RedisPubSubAdapter adapter = new RedisPubSubAdapter() { - private int timeout = 5; - private TimeUnit timeUnit = TimeUnit.SECONDS; + @Override + public void message(String pattern, String channel, String message) { + SentinelTopologyRefresh.this.processMessage(pattern, channel, message); + } + }; + + private final PubSubMessageActionScheduler topologyRefresh; + private final PubSubMessageActionScheduler sentinelReconnect; - private RedisPubSubAdapter adapter; + private volatile boolean closed = false; SentinelTopologyRefresh(RedisClient redisClient, String masterId, List sentinels) { this.redisClient = redisClient; - this.masterId = masterId; - this.sentinels = sentinels; + this.sentinels = LettuceLists.newList(sentinels); + this.topologyRefresh = new PubSubMessageActionScheduler(redisClient.getResources().eventExecutorGroup(), + new TopologyRefreshMessagePredicate(masterId)); + this.sentinelReconnect = new PubSubMessageActionScheduler(redisClient.getResources().eventExecutorGroup(), + new SentinelReconnectMessagePredicate()); + } @Override - public void close() throws IOException { + public void close() { - pubSubConnections.forEach(c -> c.removeListener(adapter)); - pubSubConnections.forEach(StatefulConnection::close); + closed = true; + + HashMap> connections = new HashMap<>(pubSubConnections); + connections.forEach((k, c) -> { + c.removeListener(adapter); + c.close(); + pubSubConnections.remove(k); + }); } void bind(Runnable runnable) { - Utf8StringCodec codec = new Utf8StringCodec(); + refreshRunnables.add(runnable); + + initializeSentinels(); + } + + private void initializeSentinels() { + + if (closed) { + return; + } + AtomicReference ref = new AtomicReference<>(); sentinels.forEach(redisURI -> { + if (closed) { + return; + } + + StatefulRedisPubSubConnection pubSubConnection = null; try { - StatefulRedisPubSubConnection pubSubConnection = redisClient.connectPubSub(codec, redisURI); - pubSubConnections.add(pubSubConnection); + if (!pubSubConnections.containsKey(redisURI)) { + + pubSubConnection = redisClient.connectPubSub(CODEC, redisURI); + pubSubConnections.put(redisURI, pubSubConnection); + + pubSubConnection.addListener(adapter); + pubSubConnection.async().psubscribe("*"); + } } catch (RedisConnectionException e) { if (ref.get() == null) { ref.set(e); @@ -77,84 +122,169 @@ void bind(Runnable runnable) { throw ref.get(); } - adapter = new RedisPubSubAdapter() { - - @Override - public void message(String pattern, String channel, String message) { + if (closed) { + close(); + } + } - if (processingAllowed(channel, message)) { + private void processMessage(String pattern, String channel, String message) { - LOG.debug("Received topology changed signal from Redis Sentinel, scheduling topology update"); + topologyRefresh.processMessage(channel, message, () -> { + LOG.debug("Received topology changed signal from Redis Sentinel, scheduling topology update"); + return () -> refreshRunnables.forEach(Runnable::run); + }); - Timeout timeout = timeoutRef.get(); - if (timeout == null) { - getEventExecutor().submit(runnable); - } else { - getEventExecutor().schedule(runnable, timeout.remaining(), TimeUnit.MILLISECONDS); - } - } - } - }; + sentinelReconnect.processMessage(channel, message, () -> { - pubSubConnections.forEach(c -> { + LOG.debug("Received sentinel state changed signal from Redis Sentinel, scheduling sentinel reconnect attempts"); - c.addListener(adapter); - c.async().psubscribe("*"); + return this::initializeSentinels; }); - } - private boolean processingAllowed(String channel, String message) { + private static class PubSubMessageActionScheduler { - if (getEventExecutor().isShuttingDown()) { - return false; + private final TimedSemaphore timedSemaphore = new TimedSemaphore(); + private final EventExecutorGroup eventExecutors; + private final MessagePredicate filter; + + PubSubMessageActionScheduler(EventExecutorGroup eventExecutors, MessagePredicate filter) { + this.eventExecutors = eventExecutors; + this.filter = filter; } - if (!messageMatches(channel, message)) { - return false; + void processMessage(String channel, String message, Supplier runnableSupplier) { + + if (!processingAllowed(channel, message)) { + return; + } + + timedSemaphore.onEvent(timeout -> { + + Runnable runnable = runnableSupplier.get(); + + if (timeout == null) { + eventExecutors.submit(runnable); + } else { + eventExecutors.schedule(runnable, timeout.remaining(), TimeUnit.MILLISECONDS); + } + + }); } - Timeout existingTimeout = timeoutRef.get(); + private boolean processingAllowed(String channel, String message) { + + if (eventExecutors.isShuttingDown()) { + return false; + } - if (existingTimeout != null) { - if (!existingTimeout.isExpired()) { + if (!filter.test(channel, message)) { return false; } + + return true; } + } + + /** + * Lock-free semaphore that limits calls by using a {@link Timeout}. This class is thread-safe and + * {@link #onEvent(Consumer)} may be called by multiple threads concurrently. It's guaranteed the first caller for an + * expired {@link Timeout} will be called. + */ + private static class TimedSemaphore { + + private final AtomicReference timeoutRef = new AtomicReference<>(); - Timeout timeout = new Timeout(this.timeout, this.timeUnit); - return timeoutRef.compareAndSet(existingTimeout, timeout); + private final int timeout = 5; + private final TimeUnit timeUnit = TimeUnit.SECONDS; + + /** + * Rate-limited method that notifies the given {@link Consumer} once the current {@link Timeout} is expired. + * + * @param timeoutConsumer callback. + */ + protected void onEvent(Consumer timeoutConsumer) { + + Timeout existingTimeout = timeoutRef.get(); + + if (existingTimeout != null) { + if (!existingTimeout.isExpired()) { + return; + } + } + + Timeout timeout = new Timeout(this.timeout, this.timeUnit); + boolean state = timeoutRef.compareAndSet(existingTimeout, timeout); + + if (state) { + timeoutConsumer.accept(timeout); + } + } } - protected EventExecutorGroup getEventExecutor() { - return redisClient.getResources().eventExecutorGroup(); + static interface MessagePredicate extends BiPredicate { + + @Override + boolean test(String message, String channel); } - private boolean messageMatches(String channel, String message) { + /** + * {@link MessagePredicate} to check whether the channel and message contain topology changes related to the monitored + * master. + */ + private static class TopologyRefreshMessagePredicate implements MessagePredicate { - // trailing spaces after the master name are not bugs - if (channel.equals("+elected-leader")) { - if (message.startsWith(String.format("master %s ", masterId))) { - return true; - } + private final String masterId; + + TopologyRefreshMessagePredicate(String masterId) { + this.masterId = masterId; } - if (channel.equals("+switch-master")) { - if (message.startsWith(String.format("%s ", masterId))) { - return true; + @Override + public boolean test(String channel, String message) { + + // trailing spaces after the master name are not bugs + if (channel.equals("+elected-leader")) { + if (message.startsWith(String.format("master %s ", masterId))) { + return true; + } + } + + if (channel.equals("+switch-master")) { + if (message.startsWith(String.format("%s ", masterId))) { + return true; + } } + + if (channel.equals("fix-slave-config")) { + if (message.contains(String.format("@ %s ", masterId))) { + return true; + } + } + + return PROCESSING_CHANNELS.contains(channel); } + } + + /** + * {@link MessagePredicate} to check whether the channel and message contain Sentinel availability changes or a Sentinel was + * added. + */ + private static class SentinelReconnectMessagePredicate implements MessagePredicate { - if (channel.equals("fix-slave-config")) { - if (message.contains(String.format("@ %s ", masterId))) { + @Override + public boolean test(String message, String channel) { + if (channel.equals("+sentinel")) { return true; } - } - if (PROCESSING_CHANNELS.contains(channel)) { - return true; - } + if (channel.equals("-odown") || channel.equals("-sdown")) { + if (message.startsWith("sentinel ")) { + return true; + } + } - return false; + return false; + } } } diff --git a/src/test/java/com/lambdaworks/redis/masterslave/SentinelTopologyRefreshTest.java b/src/test/java/com/lambdaworks/redis/masterslave/SentinelTopologyRefreshTest.java index 7ac7ec3a53..47109c6ae5 100644 --- a/src/test/java/com/lambdaworks/redis/masterslave/SentinelTopologyRefreshTest.java +++ b/src/test/java/com/lambdaworks/redis/masterslave/SentinelTopologyRefreshTest.java @@ -1,25 +1,28 @@ package com.lambdaworks.redis.masterslave; +import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyLong; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.Mockito.when; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.*; import java.util.Arrays; +import java.util.Collections; +import java.util.Map; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; import org.springframework.test.util.ReflectionTestUtils; import com.lambdaworks.redis.RedisClient; +import com.lambdaworks.redis.RedisConnectionException; import com.lambdaworks.redis.RedisURI; -import com.lambdaworks.redis.codec.Utf8StringCodec; +import com.lambdaworks.redis.codec.StringCodec; import com.lambdaworks.redis.pubsub.RedisPubSubAdapter; import com.lambdaworks.redis.pubsub.StatefulRedisPubSubConnection; import com.lambdaworks.redis.pubsub.api.async.RedisPubSubAsyncCommands; @@ -30,9 +33,13 @@ /** * @author Mark Paluch */ +@SuppressWarnings("unchecked") @RunWith(MockitoJUnitRunner.class) public class SentinelTopologyRefreshTest { + private static final RedisURI host1 = RedisURI.create("localhost", 1234); + private static final RedisURI host2 = RedisURI.create("localhost", 3456); + @Mock private RedisClient redisClient; @@ -51,17 +58,20 @@ public class SentinelTopologyRefreshTest { @Mock private Runnable refreshRunnable; + @Captor + private ArgumentCaptor captor; + private SentinelTopologyRefresh sut; @Before public void before() throws Exception { - sut = new SentinelTopologyRefresh(redisClient, "mymaster", Arrays.asList(RedisURI.create("localhost", 1234))); - - when(redisClient.connectPubSub(any(Utf8StringCodec.class), any())).thenReturn(connection); + when(redisClient.connectPubSub(any(StringCodec.class), eq(host1))).thenReturn(connection); when(clientResources.eventExecutorGroup()).thenReturn(eventExecutors); when(redisClient.getResources()).thenReturn(clientResources); when(connection.async()).thenReturn(pubSubAsyncCommands); + + sut = new SentinelTopologyRefresh(redisClient, "mymaster", Collections.singletonList(host1)); } @Test @@ -73,6 +83,78 @@ public void bind() throws Exception { verify(pubSubAsyncCommands).psubscribe("*"); } + @Test + public void bindWithSecondSentinelFails() throws Exception { + + sut = new SentinelTopologyRefresh(redisClient, "mymaster", Arrays.asList(host1, host2)); + + when(redisClient.connectPubSub(any(StringCodec.class), eq(host2))).thenThrow(new RedisConnectionException("err")); + + sut.bind(refreshRunnable); + + Map> connections = (Map) ReflectionTestUtils.getField(sut, + "pubSubConnections"); + + assertThat(connections).containsKey(host1).hasSize(1); + } + + @Test + public void bindWithSentinelRecovery() throws Exception { + + StatefulRedisPubSubConnection connection2 = mock(StatefulRedisPubSubConnection.class); + RedisPubSubAsyncCommands async2 = mock(RedisPubSubAsyncCommands.class); + when(connection2.async()).thenReturn(async2); + + sut = new SentinelTopologyRefresh(redisClient, "mymaster", Arrays.asList(host1, host2)); + + when(redisClient.connectPubSub(any(StringCodec.class), eq(host2))).thenThrow(new RedisConnectionException("err")) + .thenReturn(connection2); + + sut.bind(refreshRunnable); + + verify(redisClient).connectPubSub(any(), eq(host1)); + verify(redisClient).connectPubSub(any(), eq(host2)); + + Map> connections = (Map) ReflectionTestUtils.getField(sut, + "pubSubConnections"); + + RedisPubSubAdapter adapter = getAdapter(); + + adapter.message("*", "+sentinel", + "sentinel c14cc895bb0479c91312cee0e0440b7d99ad367b 127.0.0.1 26380 @ mymaster 127.0.0.1 6483"); + + verify(redisClient, times(2)).connectPubSub(any(), eq(host2)); + assertThat(connections).containsKey(host1).containsKey(host2).hasSize(2); + verify(refreshRunnable, never()).run(); + } + + @Test + public void bindDuringClose() throws Exception { + + sut = new SentinelTopologyRefresh(redisClient, "mymaster", Arrays.asList(host1, host2)); + + StatefulRedisPubSubConnection connection2 = mock(StatefulRedisPubSubConnection.class); + RedisPubSubAsyncCommands async2 = mock(RedisPubSubAsyncCommands.class); + when(connection2.async()).thenReturn(async2); + + when(redisClient.connectPubSub(any(StringCodec.class), eq(host2))).thenAnswer(invocation -> { + + sut.close(); + return connection2; + }); + + sut.bind(refreshRunnable); + + verify(redisClient).connectPubSub(any(), eq(host2)); + verify(connection).close(); + verify(connection2).close(); + + Map> connections = (Map) ReflectionTestUtils.getField(sut, + "pubSubConnections"); + + assertThat(connections).isEmpty(); + } + @Test public void close() throws Exception { @@ -83,6 +165,16 @@ public void close() throws Exception { verify(connection).close(); } + @Test + public void bindAfterClose() throws Exception { + + sut.close(); + sut.bind(refreshRunnable); + + verify(redisClient, times(2)).getResources(); + verifyNoMoreInteractions(redisClient); + } + @Test public void shouldNotProcessOtherEvents() throws Exception { @@ -90,8 +182,9 @@ public void shouldNotProcessOtherEvents() throws Exception { adapter.message("*", "*", "irreleval"); - verify(eventExecutors).isShuttingDown(); - verifyNoMoreInteractions(eventExecutors); + verify(redisClient, times(2)).getResources(); + verify(redisClient).connectPubSub(any(), any()); + verifyNoMoreInteractions(redisClient); } @Test @@ -101,7 +194,9 @@ public void shouldProcessElectedLeader() throws Exception { adapter.message("*", "+elected-leader", "master mymaster 127.0.0.1"); - verify(eventExecutors).schedule(any(Runnable.class), anyLong(), any()); + verify(eventExecutors, times(1)).schedule(captor.capture(), anyLong(), any()); + captor.getValue().run(); + verify(refreshRunnable, times(1)).run(); } @Test @@ -111,7 +206,9 @@ public void shouldProcessSwitchMaster() throws Exception { adapter.message("*", "+switch-master", "mymaster 127.0.0.1"); - verify(eventExecutors).schedule(any(Runnable.class), anyLong(), any()); + verify(eventExecutors, times(1)).schedule(captor.capture(), anyLong(), any()); + captor.getValue().run(); + verify(refreshRunnable, times(1)).run(); } @Test @@ -121,7 +218,9 @@ public void shouldProcessFixSlaveConfig() throws Exception { adapter.message("*", "fix-slave-config", "@ mymaster 127.0.0.1"); - verify(eventExecutors).schedule(any(Runnable.class), anyLong(), any()); + verify(eventExecutors, times(1)).schedule(captor.capture(), anyLong(), any()); + captor.getValue().run(); + verify(refreshRunnable, times(1)).run(); } @Test @@ -131,7 +230,9 @@ public void shouldProcessFailoverEnd() throws Exception { adapter.message("*", "failover-end", ""); - verify(eventExecutors).schedule(any(Runnable.class), anyLong(), any()); + verify(eventExecutors, times(1)).schedule(captor.capture(), anyLong(), any()); + captor.getValue().run(); + verify(refreshRunnable, times(1)).run(); } @Test @@ -141,7 +242,9 @@ public void shouldProcessFailoverTimeout() throws Exception { adapter.message("*", "failover-end-for-timeout", ""); - verify(eventExecutors).schedule(any(Runnable.class), anyLong(), any()); + verify(eventExecutors, times(1)).schedule(captor.capture(), anyLong(), any()); + captor.getValue().run(); + verify(refreshRunnable, times(1)).run(); } @Test @@ -152,7 +255,9 @@ public void shouldExecuteOnceWithinATimeout() throws Exception { adapter.message("*", "failover-end-for-timeout", ""); adapter.message("*", "failover-end-for-timeout", ""); - verify(eventExecutors, times(1)).schedule(any(Runnable.class), anyLong(), any()); + verify(eventExecutors, times(1)).schedule(captor.capture(), anyLong(), any()); + captor.getValue().run(); + verify(refreshRunnable, times(1)).run(); } @Test @@ -163,13 +268,13 @@ public void shouldNotProcessIfExecutorIsShuttingDown() throws Exception { adapter.message("*", "failover-end-for-timeout", ""); + verify(redisClient).connectPubSub(any(), any()); verify(eventExecutors, never()).schedule(any(Runnable.class), anyLong(), any()); } private RedisPubSubAdapter getAdapter() { sut.bind(refreshRunnable); - return (RedisPubSubAdapter) ReflectionTestUtils.getField(sut, - "adapter"); + return (RedisPubSubAdapter) ReflectionTestUtils.getField(sut, "adapter"); } } \ No newline at end of file From dd24abc171a971c7e220f3a7451165b8307e7c47 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Wed, 26 Oct 2016 16:48:00 +0200 Subject: [PATCH 049/808] Consider role changes as trigger for update using MasterSlave connections #370 Lettuce now considers +convert-to-slave and +role-change messages as topology refresh triggers. --- .../masterslave/SentinelTopologyRefresh.java | 6 +++++ .../SentinelTopologyRefreshTest.java | 26 ++++++++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/lambdaworks/redis/masterslave/SentinelTopologyRefresh.java b/src/main/java/com/lambdaworks/redis/masterslave/SentinelTopologyRefresh.java index 9772c5d44c..6070aba35c 100644 --- a/src/main/java/com/lambdaworks/redis/masterslave/SentinelTopologyRefresh.java +++ b/src/main/java/com/lambdaworks/redis/masterslave/SentinelTopologyRefresh.java @@ -262,6 +262,12 @@ public boolean test(String channel, String message) { } } + if (channel.equals("+convert-to-slave") || channel.equals("+role-change")) { + if (message.contains(String.format("@ %s ", masterId))) { + return true; + } + } + return PROCESSING_CHANNELS.contains(channel); } } diff --git a/src/test/java/com/lambdaworks/redis/masterslave/SentinelTopologyRefreshTest.java b/src/test/java/com/lambdaworks/redis/masterslave/SentinelTopologyRefreshTest.java index 47109c6ae5..ac589fa70c 100644 --- a/src/test/java/com/lambdaworks/redis/masterslave/SentinelTopologyRefreshTest.java +++ b/src/test/java/com/lambdaworks/redis/masterslave/SentinelTopologyRefreshTest.java @@ -223,6 +223,30 @@ public void shouldProcessFixSlaveConfig() throws Exception { verify(refreshRunnable, times(1)).run(); } + @Test + public void shouldProcessConvertToSlave() throws Exception { + + RedisPubSubAdapter adapter = getAdapter(); + + adapter.message("*", "+convert-to-slave", "@ mymaster 127.0.0.1"); + + verify(eventExecutors, times(1)).schedule(captor.capture(), anyLong(), any()); + captor.getValue().run(); + verify(refreshRunnable, times(1)).run(); + } + + @Test + public void shouldProcessRoleChange() throws Exception { + + RedisPubSubAdapter adapter = getAdapter(); + + adapter.message("*", "+role-change", "@ mymaster 127.0.0.1"); + + verify(eventExecutors, times(1)).schedule(captor.capture(), anyLong(), any()); + captor.getValue().run(); + verify(refreshRunnable, times(1)).run(); + } + @Test public void shouldProcessFailoverEnd() throws Exception { @@ -277,4 +301,4 @@ private RedisPubSubAdapter getAdapter() { sut.bind(refreshRunnable); return (RedisPubSubAdapter) ReflectionTestUtils.getField(sut, "adapter"); } -} \ No newline at end of file +} From 882cece69b1adc0a51e6fc30f11811bf4d91882d Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Wed, 26 Oct 2016 16:52:12 +0200 Subject: [PATCH 050/808] Increase cluster-node-timeout to 150ms. --- Makefile | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 3ddbc22034..a554424939 100644 --- a/Makefile +++ b/Makefile @@ -148,7 +148,7 @@ work/cluster-node-7385.conf: @echo appendonly no >> $@ @echo unixsocket $(ROOT_DIR)/work/socket-7385 >> $@ @echo cluster-enabled yes >> $@ - @echo cluster-node-timeout 50 >> $@ + @echo cluster-node-timeout 150 >> $@ @echo cluster-config-file $(shell pwd)/work/cluster-node-config-7385.conf >> $@ @echo requirepass foobared >> $@ @@ -163,7 +163,7 @@ work/cluster-node-7479.conf: @echo save \"\" >> $@ @echo appendonly no >> $@ @echo cluster-enabled yes >> $@ - @echo cluster-node-timeout 50 >> $@ + @echo cluster-node-timeout 150 >> $@ @echo cluster-config-file $(shell pwd)/work/cluster-node-config-7479.conf >> $@ @echo cluster-announce-port 7443 >> $@ @echo requirepass foobared >> $@ @@ -179,7 +179,7 @@ work/cluster-node-7480.conf: @echo save \"\" >> $@ @echo appendonly no >> $@ @echo cluster-enabled yes >> $@ - @echo cluster-node-timeout 50 >> $@ + @echo cluster-node-timeout 150 >> $@ @echo cluster-config-file $(shell pwd)/work/cluster-node-config-7480.conf >> $@ @echo cluster-announce-port 7444 >> $@ @echo requirepass foobared >> $@ @@ -195,7 +195,7 @@ work/cluster-node-7481.conf: @echo save \"\" >> $@ @echo appendonly no >> $@ @echo cluster-enabled yes >> $@ - @echo cluster-node-timeout 50 >> $@ + @echo cluster-node-timeout 150 >> $@ @echo cluster-config-file $(shell pwd)/work/cluster-node-config-7481.conf >> $@ @echo cluster-announce-port 7445 >> $@ @echo requirepass foobared >> $@ @@ -213,7 +213,7 @@ work/cluster-node-%.conf: @echo client-output-buffer-limit pubsub 256k 128k 5 >> $@ @echo unixsocket $(ROOT_DIR)/work/socket-$* >> $@ @echo cluster-enabled yes >> $@ - @echo cluster-node-timeout 50 >> $@ + @echo cluster-node-timeout 150 >> $@ @echo cluster-config-file $(shell pwd)/work/cluster-node-config-$*.conf >> $@ work/cluster-node-%.pid: work/cluster-node-%.conf work/redis-git/src/redis-server From b248997e06eff5113cf792bfc984238261526709 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Wed, 26 Oct 2016 17:06:57 +0200 Subject: [PATCH 051/808] Provide Timer as part of ClientResources #354 A `io.netty.util.Timer` can now be provided using `ClientResources` to reduce the amount of threads created when creating Redis Client/Cluster Client instances. --- .../redis/AbstractRedisClient.java | 12 ++-- .../redis/resource/ClientResources.java | 10 ++++ .../resource/DefaultClientResources.java | 55 ++++++++++++++++--- 3 files changed, 62 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/lambdaworks/redis/AbstractRedisClient.java b/src/main/java/com/lambdaworks/redis/AbstractRedisClient.java index cd651e8151..99596458c0 100644 --- a/src/main/java/com/lambdaworks/redis/AbstractRedisClient.java +++ b/src/main/java/com/lambdaworks/redis/AbstractRedisClient.java @@ -21,7 +21,6 @@ import io.netty.buffer.PooledByteBufAllocator; import io.netty.channel.*; import io.netty.channel.group.ChannelGroup; -import io.netty.channel.group.ChannelGroupFuture; import io.netty.channel.group.DefaultChannelGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioSocketChannel; @@ -86,7 +85,7 @@ protected AbstractRedisClient(ClientResources clientResources) { unit = TimeUnit.SECONDS; genericWorkerPool = this.clientResources.eventExecutorGroup(); channels = new DefaultChannelGroup(genericWorkerPool.next()); - timer = new HashedWheelTimer(); + timer = (HashedWheelTimer) this.clientResources.timer(); } /** @@ -245,8 +244,6 @@ public void shutdown(long quietPeriod, long timeout, TimeUnit timeUnit) { if (shutdown.compareAndSet(false, true)) { - timer.stop(); - while (!closeableResources.isEmpty()) { Closeable closeableResource = closeableResources.iterator().next(); try { @@ -268,8 +265,11 @@ public void shutdown(long quietPeriod, long timeout, TimeUnit timeUnit) { } } - ChannelGroupFuture closeFuture = channels.close(); - closeFutures.add(closeFuture); + try { + closeFutures.add(channels.close()); + } catch (Exception e) { + logger.debug("Cannot close channels", e); + } if (!sharedResources) { clientResources.shutdown(quietPeriod, timeout, timeUnit); diff --git a/src/main/java/com/lambdaworks/redis/resource/ClientResources.java b/src/main/java/com/lambdaworks/redis/resource/ClientResources.java index 1ee05ac66f..10e258caf7 100644 --- a/src/main/java/com/lambdaworks/redis/resource/ClientResources.java +++ b/src/main/java/com/lambdaworks/redis/resource/ClientResources.java @@ -6,6 +6,7 @@ import com.lambdaworks.redis.event.EventPublisherOptions; import com.lambdaworks.redis.metrics.CommandLatencyCollector; +import io.netty.util.Timer; import io.netty.util.concurrent.EventExecutorGroup; import io.netty.util.concurrent.Future; @@ -86,6 +87,15 @@ public interface ClientResources { */ int computationThreadPoolSize(); + /** + * Returns the {@link Timer} to schedule events. A timer object may run single- or multi-threaded but must be used for + * scheduling of short-running jobs only. Long-running jobs should be scheduled and executed using + * {@link #eventExecutorGroup()}. + * + * @return the timer. + */ + Timer timer(); + /** * Returns the event bus used to publish events. * diff --git a/src/main/java/com/lambdaworks/redis/resource/DefaultClientResources.java b/src/main/java/com/lambdaworks/redis/resource/DefaultClientResources.java index 4a63e18955..1ef7721093 100644 --- a/src/main/java/com/lambdaworks/redis/resource/DefaultClientResources.java +++ b/src/main/java/com/lambdaworks/redis/resource/DefaultClientResources.java @@ -19,6 +19,8 @@ import com.lambdaworks.redis.metrics.DefaultCommandLatencyCollectorOptions; import com.lambdaworks.redis.resource.Delay.StatefulDelay; +import io.netty.util.HashedWheelTimer; +import io.netty.util.Timer; import io.netty.util.concurrent.*; import io.netty.util.internal.SystemPropertyUtil; import io.netty.util.internal.logging.InternalLogger; @@ -42,6 +44,7 @@ *
  • a {@code commandLatencyCollector} which is a provided instance of * {@link com.lambdaworks.redis.metrics.CommandLatencyCollector}.
  • *
  • a {@code dnsResolver} which is a provided instance of {@link DnsResolver}.
  • + *
  • a {@code timer} that is a provided instance of {@link io.netty.util.HashedWheelTimer}.
  • * * * @author Mark Paluch @@ -74,6 +77,8 @@ public class DefaultClientResources implements ClientResources { private final EventLoopGroupProvider eventLoopGroupProvider; private final boolean sharedEventExecutor; private final EventExecutorGroup eventExecutorGroup; + private final Timer timer; + private final boolean sharedTimer; private final EventBus eventBus; private final CommandLatencyCollector commandLatencyCollector; private final boolean sharedCommandLatencyCollector; @@ -120,6 +125,14 @@ protected DefaultClientResources(Builder builder) { eventExecutorGroup = builder.eventExecutorGroup; } + if (builder.timer == null) { + timer = new HashedWheelTimer(new DefaultThreadFactory("lettuce-timer")); + sharedTimer = false; + } else { + timer = builder.timer; + sharedTimer = true; + } + if (builder.eventBus == null) { eventBus = new DefaultEventBus(Schedulers.fromExecutor(eventExecutorGroup)); } else { @@ -191,6 +204,7 @@ public static class Builder { private int computationThreadPoolSize = DEFAULT_COMPUTATION_THREADS; private EventExecutorGroup eventExecutorGroup; private EventLoopGroupProvider eventLoopGroupProvider; + private Timer timer; private EventBus eventBus; private CommandLatencyCollectorOptions commandLatencyCollectorOptions = DefaultCommandLatencyCollectorOptions.create(); private CommandLatencyCollector commandLatencyCollector; @@ -215,9 +229,9 @@ public Builder ioThreadPoolSize(int ioThreadPoolSize) { /** * Sets a shared {@link EventLoopGroupProvider event executor provider} that can be used across different instances of - * the RedisClient. The provided {@link EventLoopGroupProvider} instance will not be shut down when shutting down the - * client resources. You have to take care of that. This is an advanced configuration that should only be used if you - * know what you are doing. + * {@link com.lambdaworks.redis.RedisClient} and {@link com.lambdaworks.redis.cluster.RedisClusterClient}. The provided + * {@link EventLoopGroupProvider} instance will not be shut down when shutting down the client resources. You have to + * take care of that. This is an advanced configuration that should only be used if you know what you are doing. * * @param eventLoopGroupProvider the shared eventLoopGroupProvider * @return this @@ -240,10 +254,10 @@ public Builder computationThreadPoolSize(int computationThreadPoolSize) { } /** - * Sets a shared {@link EventExecutorGroup event executor group} that can be used across different instances of the - * RedisClient. The provided {@link EventExecutorGroup} instance will not be shut down when shutting down the client - * resources. You have to take care of that. This is an advanced configuration that should only be used if you know what - * you are doing. + * Sets a shared {@link EventExecutorGroup event executor group} that can be used across different instances of + * {@link com.lambdaworks.redis.RedisClient} and {@link com.lambdaworks.redis.cluster.RedisClusterClient}. The provided + * {@link EventExecutorGroup} instance will not be shut down when shutting down the client resources. You have to take + * care of that. This is an advanced configuration that should only be used if you know what you are doing. * * @param eventExecutorGroup the shared eventExecutorGroup * @return this @@ -253,6 +267,20 @@ public Builder eventExecutorGroup(EventExecutorGroup eventExecutorGroup) { return this; } + /** + * Sets a shared {@link Timer} that can be used across different instances of {@link com.lambdaworks.redis.RedisClient} + * and {@link com.lambdaworks.redis.cluster.RedisClusterClient} The provided {@link Timer} instance will not be shut + * down when shutting down the client resources. You have to take care of that. This is an advanced configuration that + * should only be used if you know what you are doing. + * + * @param timer the shared {@link Timer}. + * @return this + */ + public Builder timer(Timer timer) { + this.timer = timer; + return this; + } + /** * Sets the {@link EventBus} that can that can be used across different instances of the RedisClient. * @@ -315,8 +343,8 @@ public Builder dnsResolver(DnsResolver dnsResolver) { } /** - * Sets the stateless reconnect {@link Delay} to delay reconnect attempts. Defaults to binary exponential delay capped at - * {@literal 30 SECONDS}. {@code reconnectDelay} must be a stateless {@link Delay}. + * Sets the stateless reconnect {@link Delay} to delay reconnect attempts. Defaults to binary exponential delay capped + * at {@literal 30 SECONDS}. {@code reconnectDelay} must be a stateless {@link Delay}. * * @param reconnectDelay the reconnect delay, must not be {@literal null}. * @return this @@ -406,6 +434,10 @@ public Future shutdown(long quietPeriod, long timeout, TimeUnit timeUni metricEventPublisher.shutdown(); } + if (!sharedTimer) { + timer.stop(); + } + if (!sharedEventLoopGroupProvider) { Future shutdown = eventLoopGroupProvider.shutdown(quietPeriod, timeout, timeUnit); if (shutdown instanceof Promise) { @@ -455,6 +487,11 @@ public EventBus eventBus() { return eventBus; } + @Override + public Timer timer() { + return timer; + } + @Override public CommandLatencyCollector commandLatencyCollector() { return commandLatencyCollector; From 4ab6ceaa7686849b4290a0b76e0b4ad9129f9b15 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Wed, 26 Oct 2016 17:16:35 +0200 Subject: [PATCH 052/808] Polishing Improve JavaDoc. Add not-null assertions to ClientResourcesBuilder. --- .../resource/DefaultClientResources.java | 59 +++++++++++++++---- .../resource/DefaultClientResourcesTest.java | 7 ++- 2 files changed, 54 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/lambdaworks/redis/resource/DefaultClientResources.java b/src/main/java/com/lambdaworks/redis/resource/DefaultClientResources.java index 1ef7721093..91a5b06d26 100644 --- a/src/main/java/com/lambdaworks/redis/resource/DefaultClientResources.java +++ b/src/main/java/com/lambdaworks/redis/resource/DefaultClientResources.java @@ -54,13 +54,23 @@ public class DefaultClientResources implements ClientResources { protected static final InternalLogger logger = InternalLoggerFactory.getInstance(DefaultClientResources.class); + /** + * Minimum number of I/O threads. + */ public static final int MIN_IO_THREADS = 3; + + /** + * Minimum number of computation threads. + */ public static final int MIN_COMPUTATION_THREADS = 3; public static final int DEFAULT_IO_THREADS; public static final int DEFAULT_COMPUTATION_THREADS; - public static final Supplier DEFAULT_RECONNECT_DELAY = () -> Delay.exponential(); + /** + * Default delay {@link Supplier} for {@link Delay#exponential()} delay. + */ + public static final Supplier DEFAULT_RECONNECT_DELAY = Delay::exponential; static { int threads = Math.max(1, SystemPropertyUtil.getInt("io.netty.eventLoopThreads", @@ -219,10 +229,13 @@ private Builder() { * Sets the thread pool size (number of threads to use) for I/O operations (default value is the number of CPUs). The * thread pool size is only effective if no {@code eventLoopGroupProvider} is provided. * - * @param ioThreadPoolSize the thread pool size + * @param ioThreadPoolSize the thread pool size, must be greater {@code 0}. * @return this */ public Builder ioThreadPoolSize(int ioThreadPoolSize) { + + LettuceAssert.isTrue(ioThreadPoolSize > 0, "I/O thread pool size must be greater zero"); + this.ioThreadPoolSize = ioThreadPoolSize; return this; } @@ -233,10 +246,13 @@ public Builder ioThreadPoolSize(int ioThreadPoolSize) { * {@link EventLoopGroupProvider} instance will not be shut down when shutting down the client resources. You have to * take care of that. This is an advanced configuration that should only be used if you know what you are doing. * - * @param eventLoopGroupProvider the shared eventLoopGroupProvider + * @param eventLoopGroupProvider the shared eventLoopGroupProvider, must not be {@literal null}. * @return this */ public Builder eventLoopGroupProvider(EventLoopGroupProvider eventLoopGroupProvider) { + + LettuceAssert.notNull(eventLoopGroupProvider, "EventLoopGroupProvider must not be null"); + this.eventLoopGroupProvider = eventLoopGroupProvider; return this; } @@ -245,10 +261,13 @@ public Builder eventLoopGroupProvider(EventLoopGroupProvider eventLoopGroupProvi * Sets the thread pool size (number of threads to use) for computation operations (default value is the number of * CPUs). The thread pool size is only effective if no {@code eventExecutorGroup} is provided. * - * @param computationThreadPoolSize the thread pool size + * @param computationThreadPoolSize the thread pool size, must be greater {@code 0}. * @return this */ public Builder computationThreadPoolSize(int computationThreadPoolSize) { + + LettuceAssert.isTrue(computationThreadPoolSize > 0, "Computation thread pool size must be greater zero"); + this.computationThreadPoolSize = computationThreadPoolSize; return this; } @@ -259,10 +278,13 @@ public Builder computationThreadPoolSize(int computationThreadPoolSize) { * {@link EventExecutorGroup} instance will not be shut down when shutting down the client resources. You have to take * care of that. This is an advanced configuration that should only be used if you know what you are doing. * - * @param eventExecutorGroup the shared eventExecutorGroup + * @param eventExecutorGroup the shared eventExecutorGroup, must not be {@literal null}. * @return this */ public Builder eventExecutorGroup(EventExecutorGroup eventExecutorGroup) { + + LettuceAssert.notNull(eventExecutorGroup, "EventExecutorGroup must not be null"); + this.eventExecutorGroup = eventExecutorGroup; return this; } @@ -273,10 +295,13 @@ public Builder eventExecutorGroup(EventExecutorGroup eventExecutorGroup) { * down when shutting down the client resources. You have to take care of that. This is an advanced configuration that * should only be used if you know what you are doing. * - * @param timer the shared {@link Timer}. + * @param timer the shared {@link Timer}, must not be {@literal null}. * @return this */ public Builder timer(Timer timer) { + + LettuceAssert.notNull(timer, "Timer must not be null"); + this.timer = timer; return this; } @@ -284,10 +309,13 @@ public Builder timer(Timer timer) { /** * Sets the {@link EventBus} that can that can be used across different instances of the RedisClient. * - * @param eventBus the event bus + * @param eventBus the event bus, must not be {@literal null}. * @return this */ public Builder eventBus(EventBus eventBus) { + + LettuceAssert.notNull(eventBus, "EventBus must not be null"); + this.eventBus = eventBus; return this; } @@ -296,10 +324,13 @@ public Builder eventBus(EventBus eventBus) { * Sets the {@link EventPublisherOptions} to publish command latency metrics using the {@link EventBus}. * * @param commandLatencyPublisherOptions the {@link EventPublisherOptions} to publish command latency metrics using the - * {@link EventBus}. + * {@link EventBus}, must not be {@literal null}. * @return this */ public Builder commandLatencyPublisherOptions(EventPublisherOptions commandLatencyPublisherOptions) { + + LettuceAssert.notNull(commandLatencyPublisherOptions, "EventPublisherOptions must not be null"); + this.commandLatencyPublisherOptions = commandLatencyPublisherOptions; return this; } @@ -308,10 +339,13 @@ public Builder commandLatencyPublisherOptions(EventPublisherOptions commandLaten * Sets the {@link CommandLatencyCollectorOptions} that can that can be used across different instances of the * RedisClient. The options are only effective if no {@code commandLatencyCollector} is provided. * - * @param commandLatencyCollectorOptions the command latency collector options + * @param commandLatencyCollectorOptions the command latency collector options, must not be {@link null}. * @return this */ public Builder commandLatencyCollectorOptions(CommandLatencyCollectorOptions commandLatencyCollectorOptions) { + + LettuceAssert.notNull(commandLatencyCollectorOptions, "CommandLatencyCollectorOptions must not be null"); + this.commandLatencyCollectorOptions = commandLatencyCollectorOptions; return this; } @@ -319,10 +353,13 @@ public Builder commandLatencyCollectorOptions(CommandLatencyCollectorOptions com /** * Sets the {@link CommandLatencyCollector} that can that can be used across different instances of the RedisClient. * - * @param commandLatencyCollector the command latency collector + * @param commandLatencyCollector the command latency collector, must not be {@literal null}. * @return this */ public Builder commandLatencyCollector(CommandLatencyCollector commandLatencyCollector) { + + LettuceAssert.notNull(commandLatencyCollector, "CommandLatencyCollector must not be null"); + this.commandLatencyCollector = commandLatencyCollector; return this; } @@ -336,7 +373,7 @@ public Builder commandLatencyCollector(CommandLatencyCollector commandLatencyCol */ public Builder dnsResolver(DnsResolver dnsResolver) { - LettuceAssert.notNull(dnsResolver, "DNSResolver must not be null"); + LettuceAssert.notNull(dnsResolver, "DnsResolver must not be null"); this.dnsResolver = dnsResolver; return this; diff --git a/src/test/java/com/lambdaworks/redis/resource/DefaultClientResourcesTest.java b/src/test/java/com/lambdaworks/redis/resource/DefaultClientResourcesTest.java index 4148f8c57f..258a15f380 100644 --- a/src/test/java/com/lambdaworks/redis/resource/DefaultClientResourcesTest.java +++ b/src/test/java/com/lambdaworks/redis/resource/DefaultClientResourcesTest.java @@ -8,6 +8,7 @@ import java.util.concurrent.TimeUnit; +import io.netty.util.Timer; import org.junit.Test; import com.lambdaworks.redis.FastShutdown; @@ -84,21 +85,25 @@ public void testProvidedResources() throws Exception { EventExecutorGroup executorMock = mock(EventExecutorGroup.class); EventLoopGroupProvider groupProviderMock = mock(EventLoopGroupProvider.class); + Timer timerMock = mock(Timer.class); EventBus eventBusMock = mock(EventBus.class); CommandLatencyCollector latencyCollectorMock = mock(CommandLatencyCollector.class); DefaultClientResources sut = DefaultClientResources.builder().eventExecutorGroup(executorMock) - .eventLoopGroupProvider(groupProviderMock).eventBus(eventBusMock).commandLatencyCollector(latencyCollectorMock) + .eventLoopGroupProvider(groupProviderMock).timer(timerMock).eventBus(eventBusMock) + .commandLatencyCollector(latencyCollectorMock) .build(); assertThat(sut.eventExecutorGroup()).isSameAs(executorMock); assertThat(sut.eventLoopGroupProvider()).isSameAs(groupProviderMock); + assertThat(sut.timer()).isSameAs(timerMock); assertThat(sut.eventBus()).isSameAs(eventBusMock); assertThat(sut.shutdown().get()).isTrue(); verifyZeroInteractions(executorMock); verifyZeroInteractions(groupProviderMock); + verifyZeroInteractions(timerMock); verify(latencyCollectorMock).isEnabled(); verifyNoMoreInteractions(latencyCollectorMock); } From cc64a19cc54eb8b94ac747f4a8662cab449dad19 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Wed, 26 Oct 2016 17:23:53 +0200 Subject: [PATCH 053/808] Use predefined keys and values in KeysAndValues for tests --- .../{RandomKeys.java => KeysAndValues.java} | 27 ++++------ .../redis/ReactiveStreamingOutputTest.java | 14 ++--- .../cluster/AdvancedClusterClientTest.java | 19 +++---- .../cluster/AdvancedClusterReactiveTest.java | 51 ++++++++++--------- 4 files changed, 53 insertions(+), 58 deletions(-) rename src/test/java/com/lambdaworks/{RandomKeys.java => KeysAndValues.java} (52%) diff --git a/src/test/java/com/lambdaworks/RandomKeys.java b/src/test/java/com/lambdaworks/KeysAndValues.java similarity index 52% rename from src/test/java/com/lambdaworks/RandomKeys.java rename to src/test/java/com/lambdaworks/KeysAndValues.java index 95ee0cf500..9c0019cba4 100644 --- a/src/test/java/com/lambdaworks/RandomKeys.java +++ b/src/test/java/com/lambdaworks/KeysAndValues.java @@ -2,22 +2,20 @@ import java.util.*; -import org.apache.commons.lang3.RandomStringUtils; - /** - * Random keys for testing slot-hashes. + * Keys for testing slot-hashes. * * @author Mark Paluch */ -public class RandomKeys { +public class KeysAndValues { /** - * Ordered list of random keys. The order corresponds with the list of {@code VALUES}. + * Ordered list of keys. The order corresponds with the list of {@code VALUES}. */ public static final List KEYS; /** - * Ordered list of random values. The order corresponds with the list of {@code KEYS}. + * Ordered list of values. The order corresponds with the list of {@code KEYS}. */ public static final List VALUES; @@ -36,24 +34,19 @@ public class RandomKeys { List keys = new ArrayList<>(); List values = new ArrayList<>(); Map map = new HashMap<>(); - Set uniqueKeys = new HashSet<>(); - - while (map.size() < COUNT) { - String key = RandomStringUtils.random(10, true, true); - String value = RandomStringUtils.random(10, true, true); + for (int i = 0; i < COUNT; i++) { - if (uniqueKeys.add(key)) { + String key = "key-" + i; + String value = "value-" + i; - keys.add(key); - values.add(value); - map.put(key, value); - } + keys.add(key); + values.add(value); + map.put(key, value); } KEYS = Collections.unmodifiableList(keys); VALUES = Collections.unmodifiableList(values); MAP = Collections.unmodifiableMap(map); } - } diff --git a/src/test/java/com/lambdaworks/redis/ReactiveStreamingOutputTest.java b/src/test/java/com/lambdaworks/redis/ReactiveStreamingOutputTest.java index 4d39b19e38..1e19c554f3 100644 --- a/src/test/java/com/lambdaworks/redis/ReactiveStreamingOutputTest.java +++ b/src/test/java/com/lambdaworks/redis/ReactiveStreamingOutputTest.java @@ -11,7 +11,7 @@ import org.junit.Test; import org.junit.rules.ExpectedException; -import com.lambdaworks.RandomKeys; +import com.lambdaworks.KeysAndValues; import com.lambdaworks.redis.GeoArgs.Unit; import com.lambdaworks.redis.api.StatefulRedisConnection; import com.lambdaworks.redis.api.reactive.RedisReactiveCommands; @@ -42,12 +42,12 @@ public void closeReactiveConnection() throws Exception { @Test public void keyListCommandShouldReturnAllElements() throws Exception { - redis.mset(RandomKeys.MAP); + redis.mset(KeysAndValues.MAP); reactive.keys("*").subscribe(subscriber); subscriber.await(); - assertThat(getValues()).containsAll(RandomKeys.KEYS); + assertThat(getValues()).containsAll(KeysAndValues.KEYS); } public List getValues() { @@ -61,17 +61,17 @@ public List getValues(TestSubscriber subscriber) { @Test public void valueListCommandShouldReturnAllElements() throws Exception { - redis.mset(RandomKeys.MAP); + redis.mset(KeysAndValues.MAP); TestSubscriber> subscriber = TestSubscriber.create(); - reactive.mget(RandomKeys.KEYS.toArray(new String[RandomKeys.COUNT])).subscribe(subscriber); + reactive.mget(KeysAndValues.KEYS.toArray(new String[KeysAndValues.COUNT])).subscribe(subscriber); subscriber.await(); assertThat(getValues(subscriber).stream().map(KeyValue::getValue).collect(Collectors.toList())) - .containsAll(RandomKeys.VALUES); + .containsAll(KeysAndValues.VALUES); assertThat(getValues(subscriber).stream().map(KeyValue::getKey).collect(Collectors.toList())) - .containsAll(RandomKeys.KEYS); + .containsAll(KeysAndValues.KEYS); } @Test diff --git a/src/test/java/com/lambdaworks/redis/cluster/AdvancedClusterClientTest.java b/src/test/java/com/lambdaworks/redis/cluster/AdvancedClusterClientTest.java index fac9504b05..0e93178897 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/AdvancedClusterClientTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/AdvancedClusterClientTest.java @@ -11,7 +11,7 @@ import org.junit.Ignore; import org.junit.Test; -import com.lambdaworks.RandomKeys; +import com.lambdaworks.KeysAndValues; import com.lambdaworks.redis.*; import com.lambdaworks.redis.api.StatefulRedisConnection; import com.lambdaworks.redis.cluster.api.StatefulRedisClusterConnection; @@ -470,7 +470,7 @@ public void pipelining() throws Exception { public void clusterScan() throws Exception { RedisAdvancedClusterCommands sync = commands.getStatefulConnection().sync(); - sync.mset(RandomKeys.MAP); + sync.mset(KeysAndValues.MAP); Set allKeys = new HashSet<>(); @@ -485,7 +485,7 @@ public void clusterScan() throws Exception { allKeys.addAll(scanCursor.getKeys()); } while (!scanCursor.isFinished()); - assertThat(allKeys).containsAll(RandomKeys.KEYS); + assertThat(allKeys).containsAll(KeysAndValues.KEYS); } @@ -493,7 +493,7 @@ public void clusterScan() throws Exception { public void clusterScanWithArgs() throws Exception { RedisAdvancedClusterCommands sync = commands.getStatefulConnection().sync(); - sync.mset(RandomKeys.MAP); + sync.mset(KeysAndValues.MAP); Set allKeys = new HashSet<>(); @@ -508,7 +508,8 @@ public void clusterScanWithArgs() throws Exception { allKeys.addAll(scanCursor.getKeys()); } while (!scanCursor.isFinished()); - assertThat(allKeys).containsAll(RandomKeys.KEYS.stream().filter(k -> k.startsWith("a")).collect(Collectors.toList())); + assertThat(allKeys) + .containsAll(KeysAndValues.KEYS.stream().filter(k -> k.startsWith("a")).collect(Collectors.toList())); } @@ -516,7 +517,7 @@ public void clusterScanWithArgs() throws Exception { public void clusterScanStreaming() throws Exception { RedisAdvancedClusterCommands sync = commands.getStatefulConnection().sync(); - sync.mset(RandomKeys.MAP); + sync.mset(KeysAndValues.MAP); ListStreamingAdapter adapter = new ListStreamingAdapter<>(); @@ -530,7 +531,7 @@ public void clusterScanStreaming() throws Exception { } } while (!scanCursor.isFinished()); - assertThat(adapter.getList()).containsAll(RandomKeys.KEYS); + assertThat(adapter.getList()).containsAll(KeysAndValues.KEYS); } @@ -538,7 +539,7 @@ public void clusterScanStreaming() throws Exception { public void clusterScanStreamingWithArgs() throws Exception { RedisAdvancedClusterCommands sync = commands.getStatefulConnection().sync(); - sync.mset(RandomKeys.MAP); + sync.mset(KeysAndValues.MAP); ListStreamingAdapter adapter = new ListStreamingAdapter<>(); @@ -552,7 +553,7 @@ public void clusterScanStreamingWithArgs() throws Exception { } while (!scanCursor.isFinished()); assertThat(adapter.getList()) - .containsAll(RandomKeys.KEYS.stream().filter(k -> k.startsWith("a")).collect(Collectors.toList())); + .containsAll(KeysAndValues.KEYS.stream().filter(k -> k.startsWith("a")).collect(Collectors.toList())); } diff --git a/src/test/java/com/lambdaworks/redis/cluster/AdvancedClusterReactiveTest.java b/src/test/java/com/lambdaworks/redis/cluster/AdvancedClusterReactiveTest.java index 57115d04d2..81d4db86e1 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/AdvancedClusterReactiveTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/AdvancedClusterReactiveTest.java @@ -12,7 +12,7 @@ import org.junit.Ignore; import org.junit.Test; -import com.lambdaworks.RandomKeys; +import com.lambdaworks.KeysAndValues; import com.lambdaworks.redis.*; import com.lambdaworks.redis.api.sync.RedisCommands; import com.lambdaworks.redis.cluster.api.reactive.RedisAdvancedClusterReactiveCommands; @@ -62,12 +62,12 @@ public void invalidHost() throws Exception { @Test public void msetCrossSlot() throws Exception { - Mono mset = commands.mset(RandomKeys.MAP); + Mono mset = commands.mset(KeysAndValues.MAP); assertThat(block(mset)).isEqualTo("OK"); - for (String mykey : RandomKeys.KEYS) { + for (String mykey : KeysAndValues.KEYS) { String s1 = syncCommands.get(mykey); - assertThat(s1).isEqualTo(RandomKeys.MAP.get(mykey)); + assertThat(s1).isEqualTo(KeysAndValues.MAP.get(mykey)); } } @@ -93,14 +93,14 @@ public void mgetCrossSlot() throws Exception { msetCrossSlot(); - Map> partitioned = SlotHash.partition(new Utf8StringCodec(), RandomKeys.KEYS); + Map> partitioned = SlotHash.partition(new Utf8StringCodec(), KeysAndValues.KEYS); assertThat(partitioned.size()).isGreaterThan(100); - Flux> flux = commands.mget(RandomKeys.KEYS.toArray(new String[RandomKeys.COUNT])); + Flux> flux = commands.mget(KeysAndValues.KEYS.toArray(new String[KeysAndValues.COUNT])); List> result = flux.collectList().block(); - assertThat(result).hasSize(RandomKeys.COUNT); - assertThat(result.stream().map(Value::getValue).collect(Collectors.toList())).isEqualTo(RandomKeys.VALUES); + assertThat(result).hasSize(KeysAndValues.COUNT); + assertThat(result.stream().map(Value::getValue).collect(Collectors.toList())).isEqualTo(KeysAndValues.VALUES); } @Test @@ -110,11 +110,11 @@ public void mgetCrossSlotStreaming() throws Exception { KeyValueStreamingAdapter result = new KeyValueStreamingAdapter<>(); - Mono mono = commands.mget(result, RandomKeys.KEYS.toArray(new String[RandomKeys.COUNT])); + Mono mono = commands.mget(result, KeysAndValues.KEYS.toArray(new String[KeysAndValues.COUNT])); Long count = block(mono); - assertThat(result.getMap()).hasSize(RandomKeys.COUNT); - assertThat(count).isEqualTo(RandomKeys.COUNT); + assertThat(result.getMap()).hasSize(KeysAndValues.COUNT); + assertThat(count).isEqualTo(KeysAndValues.COUNT); } @Test @@ -122,12 +122,12 @@ public void delCrossSlot() throws Exception { msetCrossSlot(); - Mono mono = commands.del(RandomKeys.KEYS.toArray(new String[RandomKeys.COUNT])); + Mono mono = commands.del(KeysAndValues.KEYS.toArray(new String[KeysAndValues.COUNT])); Long result = block(mono); - assertThat(result).isEqualTo(RandomKeys.COUNT); + assertThat(result).isEqualTo(KeysAndValues.COUNT); - for (String mykey : RandomKeys.KEYS) { + for (String mykey : KeysAndValues.KEYS) { String s1 = syncCommands.get(mykey); assertThat(s1).isNull(); } @@ -138,12 +138,12 @@ public void unlinkCrossSlot() throws Exception { msetCrossSlot(); - Mono mono = commands.unlink(RandomKeys.KEYS.toArray(new String[RandomKeys.COUNT])); + Mono mono = commands.unlink(KeysAndValues.KEYS.toArray(new String[KeysAndValues.COUNT])); Long result = block(mono); - assertThat(result).isEqualTo(RandomKeys.COUNT); + assertThat(result).isEqualTo(KeysAndValues.COUNT); - for (String mykey : RandomKeys.KEYS) { + for (String mykey : KeysAndValues.KEYS) { String s1 = syncCommands.get(mykey); assertThat(s1).isNull(); } @@ -272,7 +272,7 @@ public void readFromSlaves() throws Exception { public void clusterScan() throws Exception { RedisAdvancedClusterCommands sync = commands.getStatefulConnection().sync(); - sync.mset(RandomKeys.MAP); + sync.mset(KeysAndValues.MAP); Set allKeys = new HashSet<>(); @@ -287,7 +287,7 @@ public void clusterScan() throws Exception { allKeys.addAll(scanCursor.getKeys()); } while (!scanCursor.isFinished()); - assertThat(allKeys).containsAll(RandomKeys.KEYS); + assertThat(allKeys).containsAll(KeysAndValues.KEYS); } @@ -295,7 +295,7 @@ public void clusterScan() throws Exception { public void clusterScanWithArgs() throws Exception { RedisAdvancedClusterCommands sync = commands.getStatefulConnection().sync(); - sync.mset(RandomKeys.MAP); + sync.mset(KeysAndValues.MAP); Set allKeys = new HashSet<>(); @@ -310,7 +310,8 @@ public void clusterScanWithArgs() throws Exception { allKeys.addAll(scanCursor.getKeys()); } while (!scanCursor.isFinished()); - assertThat(allKeys).containsAll(RandomKeys.KEYS.stream().filter(k -> k.startsWith("a")).collect(Collectors.toList())); + assertThat(allKeys) + .containsAll(KeysAndValues.KEYS.stream().filter(k -> k.startsWith("a")).collect(Collectors.toList())); } @@ -318,7 +319,7 @@ public void clusterScanWithArgs() throws Exception { public void clusterScanStreaming() throws Exception { RedisAdvancedClusterCommands sync = commands.getStatefulConnection().sync(); - sync.mset(RandomKeys.MAP); + sync.mset(KeysAndValues.MAP); ListStreamingAdapter adapter = new ListStreamingAdapter<>(); @@ -332,7 +333,7 @@ public void clusterScanStreaming() throws Exception { } } while (!scanCursor.isFinished()); - assertThat(adapter.getList()).containsAll(RandomKeys.KEYS); + assertThat(adapter.getList()).containsAll(KeysAndValues.KEYS); } @@ -340,7 +341,7 @@ public void clusterScanStreaming() throws Exception { public void clusterScanStreamingWithArgs() throws Exception { RedisAdvancedClusterCommands sync = commands.getStatefulConnection().sync(); - sync.mset(RandomKeys.MAP); + sync.mset(KeysAndValues.MAP); ListStreamingAdapter adapter = new ListStreamingAdapter<>(); @@ -355,7 +356,7 @@ public void clusterScanStreamingWithArgs() throws Exception { } while (!scanCursor.isFinished()); assertThat(adapter.getList()).containsAll( - RandomKeys.KEYS.stream().filter(k -> k.startsWith("a")).collect(Collectors.toList())); + KeysAndValues.KEYS.stream().filter(k -> k.startsWith("a")).collect(Collectors.toList())); } From 5d4c541517c2967a3e9313605f0b84a2eb4bacff Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Wed, 26 Oct 2016 17:34:00 +0200 Subject: [PATCH 054/808] Expose Value.map methods #386 --- src/main/java/com/lambdaworks/redis/KeyValue.java | 2 +- src/main/java/com/lambdaworks/redis/ScoredValue.java | 4 ++-- src/main/java/com/lambdaworks/redis/Value.java | 3 ++- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/lambdaworks/redis/KeyValue.java b/src/main/java/com/lambdaworks/redis/KeyValue.java index 2120f3d01b..9e79063076 100644 --- a/src/main/java/com/lambdaworks/redis/KeyValue.java +++ b/src/main/java/com/lambdaworks/redis/KeyValue.java @@ -149,7 +149,7 @@ public K getKey() { * @return the new {@link KeyValue} */ @SuppressWarnings("unchecked") - KeyValue map(Function mapper) { + public KeyValue map(Function mapper) { LettuceAssert.notNull(mapper, "Mapper function must not be null"); diff --git a/src/main/java/com/lambdaworks/redis/ScoredValue.java b/src/main/java/com/lambdaworks/redis/ScoredValue.java index f3530ea243..c288da7ba3 100644 --- a/src/main/java/com/lambdaworks/redis/ScoredValue.java +++ b/src/main/java/com/lambdaworks/redis/ScoredValue.java @@ -139,7 +139,7 @@ public String toString() { * @return the new {@link ScoredValue} */ @SuppressWarnings("unchecked") - ScoredValue map(Function mapper) { + public ScoredValue map(Function mapper) { LettuceAssert.notNull(mapper, "Mapper function must not be null"); @@ -158,7 +158,7 @@ ScoredValue map(Function mapper) { * @return the new {@link ScoredValue} */ @SuppressWarnings("unchecked") - ScoredValue mapScore(Function mapper) { + public ScoredValue mapScore(Function mapper) { LettuceAssert.notNull(mapper, "Mapper function must not be null"); diff --git a/src/main/java/com/lambdaworks/redis/Value.java b/src/main/java/com/lambdaworks/redis/Value.java index 7c28f6e1a9..50ab1f00cb 100644 --- a/src/main/java/com/lambdaworks/redis/Value.java +++ b/src/main/java/com/lambdaworks/redis/Value.java @@ -212,7 +212,8 @@ public V getValueOrElseThrow(Supplier excepti * @return the new {@link Value} */ @SuppressWarnings("unchecked") - Value map(Function mapper) { + public Value map(Function mapper) { + LettuceAssert.notNull(mapper, "Mapper function must not be null"); if (hasValue()) { From a5d7af9b96c1b8f7d238772c912a9e92ea21a31e Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Wed, 26 Oct 2016 17:40:59 +0200 Subject: [PATCH 055/808] Provide Value.ifEmpty() and Value.ifHasValue() callbacks #386 Provide monad callbacks if Value has a value/is empty to facilitate functional programming. --- .../java/com/lambdaworks/redis/Value.java | 29 +++++++++++++ .../java/com/lambdaworks/redis/ValueTest.java | 43 ++++++++++++++++++- 2 files changed, 71 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/lambdaworks/redis/Value.java b/src/main/java/com/lambdaworks/redis/Value.java index 50ab1f00cb..61c871bdd5 100644 --- a/src/main/java/com/lambdaworks/redis/Value.java +++ b/src/main/java/com/lambdaworks/redis/Value.java @@ -3,6 +3,7 @@ import java.io.Serializable; import java.util.NoSuchElementException; import java.util.Optional; +import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Supplier; import java.util.stream.Stream; @@ -223,6 +224,34 @@ public Value map(Function mapper) { return (Value) this; } + /** + * If a value is present, invoke the specified {@link java.util.function.Consumer} with the value, otherwise do nothing. + * + * @param consumer block to be executed if a value is present, must not be {@literal null}. + */ + public void ifHasValue(Consumer consumer) { + + LettuceAssert.notNull(consumer, "Consumer must not be null"); + + if (hasValue()) { + consumer.accept(getValue()); + } + } + + /** + * If no value is present, invoke the specified {@link Runnable}, otherwise do nothing. + * + * @param runnable block to be executed if no value value is present, must not be {@literal null}. + */ + public void ifEmpty(Runnable runnable) { + + LettuceAssert.notNull(runnable, "Runnable must not be null"); + + if (!hasValue()) { + runnable.run(); + } + } + /** * Returns an {@link Optional} wrapper for the value. * diff --git a/src/test/java/com/lambdaworks/redis/ValueTest.java b/src/test/java/com/lambdaworks/redis/ValueTest.java index 40563b35ba..5bfa8361d4 100644 --- a/src/test/java/com/lambdaworks/redis/ValueTest.java +++ b/src/test/java/com/lambdaworks/redis/ValueTest.java @@ -4,6 +4,7 @@ import java.util.NoSuchElementException; import java.util.Optional; +import java.util.concurrent.atomic.AtomicBoolean; import org.junit.Test; @@ -148,6 +149,46 @@ public void mapShouldMapValue() { assertThat(value.map(s -> s + "-world").getValue()).isEqualTo("hello-world"); } + @Test + public void ifHasValueShouldExecuteCallback() { + + Value value = Value.just("hello"); + AtomicBoolean atomicBoolean = new AtomicBoolean(); + value.ifHasValue(s -> atomicBoolean.set(true)); + + assertThat(atomicBoolean.get()).isTrue(); + } + + @Test + public void emptyValueShouldNotExecuteIfHasValueCallback() { + + Value value = Value.empty(); + AtomicBoolean atomicBoolean = new AtomicBoolean(); + value.ifHasValue(s -> atomicBoolean.set(true)); + + assertThat(atomicBoolean.get()).isFalse(); + } + + @Test + public void ifEmptyShouldExecuteCallback() { + + Value value = Value.empty(); + AtomicBoolean atomicBoolean = new AtomicBoolean(); + value.ifEmpty(() -> atomicBoolean.set(true)); + + assertThat(atomicBoolean.get()).isTrue(); + } + + @Test + public void valueShouldNotExecuteIfEmptyCallback() { + + Value value = Value.just("hello"); + AtomicBoolean atomicBoolean = new AtomicBoolean(); + value.ifEmpty(() -> atomicBoolean.set(true)); + + assertThat(atomicBoolean.get()).isFalse(); + } + @Test public void emptyValueMapShouldNotMapEmptyValue() { @@ -200,4 +241,4 @@ public void streamShouldCreateAStream() { assertThat(empty.stream().count()).isEqualTo(1); } -} \ No newline at end of file +} From 73c7d77de6342758fb31e954c2b296b1ba2abd7c Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Mon, 17 Oct 2016 14:46:05 +0200 Subject: [PATCH 056/808] Provide a dynamic Redis Command API #371 Redis exposes a huge amount of API methods that all available in different command interfaces. Those interfaces carry a lot of different methods with overloads so using the API always requires searching for the right method. Users can declare their own command interfaces and argument sequences where the command name is derived from the method name or provided with `@Command`. Introduction of new commands does not require users to wait for a new lettuce release but they can invoke commands through own declaration. That interface could be also supporting different key and value types, depending on the use-case. Commands are executed applying synchronization, asynchronous and in a reactive fashion, depending on the method declaration. Example: public interface MyRedisCommands { String get(String key); // Synchronous Execution of GET @Command("GET") byte[] getAsBytes(String key); // Synchronous Execution of GET returning data as byte array @Command("SET") // synchronous execution applying a Timeout String setSync(String key, String value, Timeout timeout); Future set(String key, String value); // asynchronous SET execution @Command("SET") Mono setReactive(String key, String value); // reactive SET execution using SetArgs @CommandNaming(split = DOT) // support for Redis Module command notation -> NR.RUN double nrRun(String key, int... indexes); } RedisCommandFactory factory = new RedisCommandFactory(connection); MyRedisCommands commands = factory.getCommands(MyRedisCommands.class); String value = commands.get("key"); --- .../com/lambdaworks/redis/BitFieldArgs.java | 4 +- .../lambdaworks/redis/CompositeArgument.java | 33 + .../java/com/lambdaworks/redis/GeoArgs.java | 2 +- .../lambdaworks/redis/GeoRadiusStoreArgs.java | 2 +- .../java/com/lambdaworks/redis/KillArgs.java | 4 +- .../com/lambdaworks/redis/LettuceStrings.java | 55 + .../com/lambdaworks/redis/MigrateArgs.java | 2 +- .../java/com/lambdaworks/redis/ScanArgs.java | 8 +- .../java/com/lambdaworks/redis/SetArgs.java | 2 +- .../java/com/lambdaworks/redis/SortArgs.java | 11 +- .../java/com/lambdaworks/redis/ZAddArgs.java | 2 +- .../com/lambdaworks/redis/ZStoreArgs.java | 4 +- .../CodecAwareMethodParametersAccessor.java | 93 ++ .../dynamic/CommandCreationException.java | 20 + .../redis/dynamic/CommandFactory.java | 23 + .../redis/dynamic/CommandMethod.java | 173 +++ .../dynamic/CommandMethodSyntaxException.java | 11 + .../redis/dynamic/CommandMethodVerifier.java | 191 +++ .../dynamic/CommandSegmentCommandFactory.java | 81 + .../DefaultMethodParametersAccessor.java | 114 ++ .../dynamic/DefaultRedisCommandsMetadata.java | 130 ++ .../redis/dynamic/ParameterBinder.java | 120 ++ .../ReactiveCommandSegmentCommandFactory.java | 53 + .../redis/dynamic/ReactiveWrappers.java | 69 + .../redis/dynamic/RedisCommandFactory.java | 408 +++++ .../redis/dynamic/RedisCommandsMetadata.java | 22 + .../redis/dynamic/annotation/Command.java | 44 + .../dynamic/annotation/CommandNaming.java | 69 + .../redis/dynamic/annotation/Key.java | 16 + .../redis/dynamic/annotation/Param.java | 23 + .../redis/dynamic/annotation/Value.java | 16 + .../dynamic/annotation/package-info.java | 4 + .../codec/AnnotationRedisCodecResolver.java | 197 +++ .../dynamic/codec/RedisCodecResolver.java | 21 + .../redis/dynamic/domain/FlushMode.java | 8 + .../redis/dynamic/domain/Timeout.java | 55 + .../redis/dynamic/domain/package-info.java | 4 + .../intercept/DefaultMethodInvocation.java | 30 + .../intercept/InvocationProxyFactory.java | 113 ++ .../dynamic/intercept/MethodInterceptor.java | 24 + .../dynamic/intercept/MethodInvocation.java | 36 + .../redis/dynamic/intercept/package-info.java | 4 + .../CodecAwareOutputFactoryResolver.java | 90 ++ .../dynamic/output/CommandOutputFactory.java | 24 + .../output/CommandOutputFactoryResolver.java | 33 + .../output/CommandOutputResolverSupport.java | 73 + .../redis/dynamic/output/OutputRegistry.java | 197 +++ ...tRegistryCommandOutputFactoryResolver.java | 89 ++ .../redis/dynamic/output/OutputSelector.java | 99 ++ .../redis/dynamic/output/OutputType.java | 90 ++ .../redis/dynamic/output/VoidOutput.java | 34 + .../redis/dynamic/output/package-info.java | 4 + .../redis/dynamic/package-info.java | 4 + .../ExecutionSpecificParameters.java | 86 ++ .../parameter/MethodParametersAccessor.java | 60 + .../redis/dynamic/parameter/Parameter.java | 122 ++ .../redis/dynamic/parameter/Parameters.java | 92 ++ .../redis/dynamic/parameter/package-info.java | 4 + .../AnnotationCommandSegmentFactory.java | 214 +++ .../redis/dynamic/segment/CommandSegment.java | 146 ++ .../segment/CommandSegmentFactory.java | 20 + .../dynamic/segment/CommandSegments.java | 80 + .../redis/dynamic/segment/package-info.java | 4 + .../AnnotationParameterNameDiscoverer.java | 62 + .../dynamic/support/ClassTypeInformation.java | 165 ++ .../CompositeParameterNameDiscoverer.java | 50 + .../support/GenericArrayTypeInformation.java | 48 + .../dynamic/support/GenericTypeResolver.java | 70 + .../dynamic/support/MethodParameter.java | 511 +++++++ .../support/ParameterNameDiscoverer.java | 31 + .../support/ParametrizedTypeInformation.java | 182 +++ .../ParentTypeAwareTypeInformation.java | 79 + .../dynamic/support/ReflectionUtils.java | 351 +++++ .../redis/dynamic/support/ResolvableType.java | 1350 +++++++++++++++++ ...dardReflectionParameterNameDiscoverer.java | 43 + .../redis/dynamic/support/TypeDiscoverer.java | 365 +++++ .../dynamic/support/TypeInformation.java | 115 ++ .../support/TypeVariableTypeInformation.java | 95 ++ .../redis/dynamic/support/TypeWrapper.java | 349 +++++ .../redis/dynamic/support/package-info.java | 4 + .../redis/internal/LettuceClassUtils.java | 77 + .../redis/protocol/CommandArgs.java | 34 +- .../resource/DefaultClientResources.java | 4 +- .../redis/dynamic/CommandMethodTest.java | 56 + .../dynamic/CommandMethodVerifierTest.java | 114 ++ .../CommandSegmentCommandFactoryTest.java | 163 ++ ...ctiveCommandSegmentCommandFactoryTest.java | 73 + .../redis/dynamic/RedisCommandsTest.java | 106 ++ .../AnnotationRedisCodecResolverTest.java | 100 ++ .../intercept/InvocationProxyFactoryTest.java | 47 + .../output/CodecAwareOutputResolverTest.java | 136 ++ ...istryCommandOutputFactoryResolverTest.java | 129 ++ .../dynamic/output/OutputRegistryTest.java | 64 + .../AnnotationCommandSegmentFactoryTest.java | 110 ++ 94 files changed, 8929 insertions(+), 20 deletions(-) create mode 100644 src/main/java/com/lambdaworks/redis/CompositeArgument.java create mode 100644 src/main/java/com/lambdaworks/redis/dynamic/CodecAwareMethodParametersAccessor.java create mode 100644 src/main/java/com/lambdaworks/redis/dynamic/CommandCreationException.java create mode 100644 src/main/java/com/lambdaworks/redis/dynamic/CommandFactory.java create mode 100644 src/main/java/com/lambdaworks/redis/dynamic/CommandMethod.java create mode 100644 src/main/java/com/lambdaworks/redis/dynamic/CommandMethodSyntaxException.java create mode 100644 src/main/java/com/lambdaworks/redis/dynamic/CommandMethodVerifier.java create mode 100644 src/main/java/com/lambdaworks/redis/dynamic/CommandSegmentCommandFactory.java create mode 100644 src/main/java/com/lambdaworks/redis/dynamic/DefaultMethodParametersAccessor.java create mode 100644 src/main/java/com/lambdaworks/redis/dynamic/DefaultRedisCommandsMetadata.java create mode 100644 src/main/java/com/lambdaworks/redis/dynamic/ParameterBinder.java create mode 100644 src/main/java/com/lambdaworks/redis/dynamic/ReactiveCommandSegmentCommandFactory.java create mode 100644 src/main/java/com/lambdaworks/redis/dynamic/ReactiveWrappers.java create mode 100644 src/main/java/com/lambdaworks/redis/dynamic/RedisCommandFactory.java create mode 100644 src/main/java/com/lambdaworks/redis/dynamic/RedisCommandsMetadata.java create mode 100644 src/main/java/com/lambdaworks/redis/dynamic/annotation/Command.java create mode 100644 src/main/java/com/lambdaworks/redis/dynamic/annotation/CommandNaming.java create mode 100644 src/main/java/com/lambdaworks/redis/dynamic/annotation/Key.java create mode 100644 src/main/java/com/lambdaworks/redis/dynamic/annotation/Param.java create mode 100644 src/main/java/com/lambdaworks/redis/dynamic/annotation/Value.java create mode 100644 src/main/java/com/lambdaworks/redis/dynamic/annotation/package-info.java create mode 100644 src/main/java/com/lambdaworks/redis/dynamic/codec/AnnotationRedisCodecResolver.java create mode 100644 src/main/java/com/lambdaworks/redis/dynamic/codec/RedisCodecResolver.java create mode 100644 src/main/java/com/lambdaworks/redis/dynamic/domain/FlushMode.java create mode 100644 src/main/java/com/lambdaworks/redis/dynamic/domain/Timeout.java create mode 100644 src/main/java/com/lambdaworks/redis/dynamic/domain/package-info.java create mode 100644 src/main/java/com/lambdaworks/redis/dynamic/intercept/DefaultMethodInvocation.java create mode 100644 src/main/java/com/lambdaworks/redis/dynamic/intercept/InvocationProxyFactory.java create mode 100644 src/main/java/com/lambdaworks/redis/dynamic/intercept/MethodInterceptor.java create mode 100644 src/main/java/com/lambdaworks/redis/dynamic/intercept/MethodInvocation.java create mode 100644 src/main/java/com/lambdaworks/redis/dynamic/intercept/package-info.java create mode 100644 src/main/java/com/lambdaworks/redis/dynamic/output/CodecAwareOutputFactoryResolver.java create mode 100644 src/main/java/com/lambdaworks/redis/dynamic/output/CommandOutputFactory.java create mode 100644 src/main/java/com/lambdaworks/redis/dynamic/output/CommandOutputFactoryResolver.java create mode 100644 src/main/java/com/lambdaworks/redis/dynamic/output/CommandOutputResolverSupport.java create mode 100644 src/main/java/com/lambdaworks/redis/dynamic/output/OutputRegistry.java create mode 100644 src/main/java/com/lambdaworks/redis/dynamic/output/OutputRegistryCommandOutputFactoryResolver.java create mode 100644 src/main/java/com/lambdaworks/redis/dynamic/output/OutputSelector.java create mode 100644 src/main/java/com/lambdaworks/redis/dynamic/output/OutputType.java create mode 100644 src/main/java/com/lambdaworks/redis/dynamic/output/VoidOutput.java create mode 100644 src/main/java/com/lambdaworks/redis/dynamic/output/package-info.java create mode 100644 src/main/java/com/lambdaworks/redis/dynamic/package-info.java create mode 100644 src/main/java/com/lambdaworks/redis/dynamic/parameter/ExecutionSpecificParameters.java create mode 100644 src/main/java/com/lambdaworks/redis/dynamic/parameter/MethodParametersAccessor.java create mode 100644 src/main/java/com/lambdaworks/redis/dynamic/parameter/Parameter.java create mode 100644 src/main/java/com/lambdaworks/redis/dynamic/parameter/Parameters.java create mode 100644 src/main/java/com/lambdaworks/redis/dynamic/parameter/package-info.java create mode 100644 src/main/java/com/lambdaworks/redis/dynamic/segment/AnnotationCommandSegmentFactory.java create mode 100644 src/main/java/com/lambdaworks/redis/dynamic/segment/CommandSegment.java create mode 100644 src/main/java/com/lambdaworks/redis/dynamic/segment/CommandSegmentFactory.java create mode 100644 src/main/java/com/lambdaworks/redis/dynamic/segment/CommandSegments.java create mode 100644 src/main/java/com/lambdaworks/redis/dynamic/segment/package-info.java create mode 100644 src/main/java/com/lambdaworks/redis/dynamic/support/AnnotationParameterNameDiscoverer.java create mode 100644 src/main/java/com/lambdaworks/redis/dynamic/support/ClassTypeInformation.java create mode 100644 src/main/java/com/lambdaworks/redis/dynamic/support/CompositeParameterNameDiscoverer.java create mode 100644 src/main/java/com/lambdaworks/redis/dynamic/support/GenericArrayTypeInformation.java create mode 100644 src/main/java/com/lambdaworks/redis/dynamic/support/GenericTypeResolver.java create mode 100644 src/main/java/com/lambdaworks/redis/dynamic/support/MethodParameter.java create mode 100644 src/main/java/com/lambdaworks/redis/dynamic/support/ParameterNameDiscoverer.java create mode 100644 src/main/java/com/lambdaworks/redis/dynamic/support/ParametrizedTypeInformation.java create mode 100644 src/main/java/com/lambdaworks/redis/dynamic/support/ParentTypeAwareTypeInformation.java create mode 100644 src/main/java/com/lambdaworks/redis/dynamic/support/ReflectionUtils.java create mode 100644 src/main/java/com/lambdaworks/redis/dynamic/support/ResolvableType.java create mode 100644 src/main/java/com/lambdaworks/redis/dynamic/support/StandardReflectionParameterNameDiscoverer.java create mode 100644 src/main/java/com/lambdaworks/redis/dynamic/support/TypeDiscoverer.java create mode 100644 src/main/java/com/lambdaworks/redis/dynamic/support/TypeInformation.java create mode 100644 src/main/java/com/lambdaworks/redis/dynamic/support/TypeVariableTypeInformation.java create mode 100644 src/main/java/com/lambdaworks/redis/dynamic/support/TypeWrapper.java create mode 100644 src/main/java/com/lambdaworks/redis/dynamic/support/package-info.java create mode 100644 src/test/java/com/lambdaworks/redis/dynamic/CommandMethodTest.java create mode 100644 src/test/java/com/lambdaworks/redis/dynamic/CommandMethodVerifierTest.java create mode 100644 src/test/java/com/lambdaworks/redis/dynamic/CommandSegmentCommandFactoryTest.java create mode 100644 src/test/java/com/lambdaworks/redis/dynamic/ReactiveCommandSegmentCommandFactoryTest.java create mode 100644 src/test/java/com/lambdaworks/redis/dynamic/RedisCommandsTest.java create mode 100644 src/test/java/com/lambdaworks/redis/dynamic/codec/AnnotationRedisCodecResolverTest.java create mode 100644 src/test/java/com/lambdaworks/redis/dynamic/intercept/InvocationProxyFactoryTest.java create mode 100644 src/test/java/com/lambdaworks/redis/dynamic/output/CodecAwareOutputResolverTest.java create mode 100644 src/test/java/com/lambdaworks/redis/dynamic/output/OutputRegistryCommandOutputFactoryResolverTest.java create mode 100644 src/test/java/com/lambdaworks/redis/dynamic/output/OutputRegistryTest.java create mode 100644 src/test/java/com/lambdaworks/redis/dynamic/segment/AnnotationCommandSegmentFactoryTest.java diff --git a/src/main/java/com/lambdaworks/redis/BitFieldArgs.java b/src/main/java/com/lambdaworks/redis/BitFieldArgs.java index a24a9b2315..82ec346ccd 100644 --- a/src/main/java/com/lambdaworks/redis/BitFieldArgs.java +++ b/src/main/java/com/lambdaworks/redis/BitFieldArgs.java @@ -16,7 +16,7 @@ * @author Mark Paluch * @since 4.2 */ -public class BitFieldArgs { +public class BitFieldArgs implements CompositeArgument { private List commands; @@ -528,7 +528,7 @@ private abstract static class SubCommand { abstract void build(CommandArgs args); } - void build(CommandArgs args) { + public void build(CommandArgs args) { for (SubCommand command : commands) { command.build(args); diff --git a/src/main/java/com/lambdaworks/redis/CompositeArgument.java b/src/main/java/com/lambdaworks/redis/CompositeArgument.java new file mode 100644 index 0000000000..8864b65164 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/CompositeArgument.java @@ -0,0 +1,33 @@ +package com.lambdaworks.redis; + +import com.lambdaworks.redis.protocol.CommandArgs; + +/** + * Interface for composite command argument objects. Implementing classes of {@link CompositeArgument} consolidate multiple + * arguments for a particular Redis command in to one type and reduce the amount of individual arguments passed in a method + * signature. + *

    + * Command builder call {@link #build(CommandArgs)} during command construction to contribute command arguments for command + * invocation. A composite argument is usually stateless as it can be reused multiple times by different commands. + * + * @author Mark Paluch + * @since 5.0 + * @see CommandArgs + * @see SetArgs + * @see ZStoreArgs + * @see GeoArgs + */ +public interface CompositeArgument { + + /** + * Build command arguments and contribute arguments to {@link CommandArgs}. + *

    + * Implementing classes are required to implement this method. Depending on the command nature and configured arguments, + * this method may contribute arguments but is not required to add arguments if none are specified. + * + * @param args the command arguments, must not be {@literal null}. + * @param Key type. + * @param Value type. + */ + void build(CommandArgs args); +} diff --git a/src/main/java/com/lambdaworks/redis/GeoArgs.java b/src/main/java/com/lambdaworks/redis/GeoArgs.java index e443e92c5f..2780ea6a64 100644 --- a/src/main/java/com/lambdaworks/redis/GeoArgs.java +++ b/src/main/java/com/lambdaworks/redis/GeoArgs.java @@ -9,7 +9,7 @@ * * @author Mark Paluch */ -public class GeoArgs { +public class GeoArgs implements CompositeArgument { private boolean withdistance; private boolean withcoordinates; diff --git a/src/main/java/com/lambdaworks/redis/GeoRadiusStoreArgs.java b/src/main/java/com/lambdaworks/redis/GeoRadiusStoreArgs.java index 66981f78db..65ba799269 100644 --- a/src/main/java/com/lambdaworks/redis/GeoRadiusStoreArgs.java +++ b/src/main/java/com/lambdaworks/redis/GeoRadiusStoreArgs.java @@ -10,7 +10,7 @@ * * @author Mark Paluch */ -public class GeoRadiusStoreArgs { +public class GeoRadiusStoreArgs implements CompositeArgument { private K storeKey; private K storeDistKey; diff --git a/src/main/java/com/lambdaworks/redis/KillArgs.java b/src/main/java/com/lambdaworks/redis/KillArgs.java index ad90193999..1ecd269e74 100644 --- a/src/main/java/com/lambdaworks/redis/KillArgs.java +++ b/src/main/java/com/lambdaworks/redis/KillArgs.java @@ -13,7 +13,7 @@ * @author Mark Paluch * @since 3.0 */ -public class KillArgs { +public class KillArgs implements CompositeArgument { private static enum Type { NORMAL, SLAVE, PUBSUB @@ -86,7 +86,7 @@ public KillArgs type(Type type) { return this; } - void build(CommandArgs args) { + public void build(CommandArgs args) { if (skipme != null) { args.add(SKIPME).add(skipme.booleanValue() ? "yes" : "no"); diff --git a/src/main/java/com/lambdaworks/redis/LettuceStrings.java b/src/main/java/com/lambdaworks/redis/LettuceStrings.java index c591fffea9..283cf9811e 100644 --- a/src/main/java/com/lambdaworks/redis/LettuceStrings.java +++ b/src/main/java/com/lambdaworks/redis/LettuceStrings.java @@ -3,6 +3,8 @@ import java.nio.ByteBuffer; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; +import java.util.Collection; +import java.util.Iterator; import com.lambdaworks.codec.Base16; @@ -80,4 +82,57 @@ public static String digest(ByteBuffer script) { throw new RedisException("JVM does not support SHA1"); } } + + /** + * Convert a {@code String} array into a delimited {@code String} (e.g. CSV). + *

    + * Useful for {@code toString()} implementations. + * + * @param arr the array to display + * @param delim the delimiter to use (typically a ",") + * @return the delimited {@code String} + */ + public static String arrayToDelimitedString(Object[] arr, String delim) { + if ((arr == null || arr.length == 0)) { + return ""; + } + if (arr.length == 1) { + return "" + arr[0]; + } + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < arr.length; i++) { + if (i > 0) { + sb.append(delim); + } + sb.append(arr[i]); + } + return sb.toString(); + } + + /** + * Convert a {@link Collection} to a delimited {@code String} (e.g. CSV). + *

    + * Useful for {@code toString()} implementations. + * + * @param coll the {@code Collection} to convert + * @param delim the delimiter to use (typically a ",") + * @param prefix the {@code String} to start each element with + * @param suffix the {@code String} to end each element with + * @return the delimited {@code String} + */ + public static String collectionToDelimitedString(Collection coll, String delim, String prefix, String suffix) { + + if (coll == null || coll.isEmpty()) { + return ""; + } + StringBuilder sb = new StringBuilder(); + Iterator it = coll.iterator(); + while (it.hasNext()) { + sb.append(prefix).append(it.next()).append(suffix); + if (it.hasNext()) { + sb.append(delim); + } + } + return sb.toString(); + } } diff --git a/src/main/java/com/lambdaworks/redis/MigrateArgs.java b/src/main/java/com/lambdaworks/redis/MigrateArgs.java index 539780c64c..f9d9b914c9 100644 --- a/src/main/java/com/lambdaworks/redis/MigrateArgs.java +++ b/src/main/java/com/lambdaworks/redis/MigrateArgs.java @@ -15,7 +15,7 @@ * * @author Mark Paluch */ -public class MigrateArgs { +public class MigrateArgs implements CompositeArgument { private boolean copy = false; private boolean replace = false; diff --git a/src/main/java/com/lambdaworks/redis/ScanArgs.java b/src/main/java/com/lambdaworks/redis/ScanArgs.java index 8a8a413591..375684bca4 100644 --- a/src/main/java/com/lambdaworks/redis/ScanArgs.java +++ b/src/main/java/com/lambdaworks/redis/ScanArgs.java @@ -1,6 +1,7 @@ package com.lambdaworks.redis; -import static com.lambdaworks.redis.protocol.CommandKeyword.*; +import static com.lambdaworks.redis.protocol.CommandKeyword.COUNT; +import static com.lambdaworks.redis.protocol.CommandKeyword.MATCH; import com.lambdaworks.redis.internal.LettuceAssert; import com.lambdaworks.redis.protocol.CommandArgs; @@ -12,7 +13,7 @@ * @author Mark Paluch * @since 3.0 */ -public class ScanArgs { +public class ScanArgs implements CompositeArgument { private Long count; private String match; @@ -73,7 +74,7 @@ public ScanArgs limit(long count) { return this; } - void build(CommandArgs args) { + public void build(CommandArgs args) { if (match != null) { args.add(MATCH).add(match); @@ -84,5 +85,4 @@ void build(CommandArgs args) { } } - } diff --git a/src/main/java/com/lambdaworks/redis/SetArgs.java b/src/main/java/com/lambdaworks/redis/SetArgs.java index 53b03b566b..2c3f37c92e 100644 --- a/src/main/java/com/lambdaworks/redis/SetArgs.java +++ b/src/main/java/com/lambdaworks/redis/SetArgs.java @@ -11,7 +11,7 @@ * * @author Vincent Rischmann */ -public class SetArgs { +public class SetArgs implements CompositeArgument { private Long ex; private Long px; diff --git a/src/main/java/com/lambdaworks/redis/SortArgs.java b/src/main/java/com/lambdaworks/redis/SortArgs.java index 1545c51268..87c4b53aef 100644 --- a/src/main/java/com/lambdaworks/redis/SortArgs.java +++ b/src/main/java/com/lambdaworks/redis/SortArgs.java @@ -18,7 +18,7 @@ * * @author Will Glozer */ -public class SortArgs { +public class SortArgs implements CompositeArgument { private String by; private Limit limit = Limit.unlimited(); @@ -102,7 +102,8 @@ public SortArgs alpha() { return this; } - void build(CommandArgs args, K store) { + @Override + public void build(CommandArgs args) { if (by != null) { args.add(BY); @@ -130,6 +131,12 @@ void build(CommandArgs args, K store) { args.add(ALPHA); } + } + + void build(CommandArgs args, K store) { + + build(args); + if (store != null) { args.add(STORE); args.addKey(store); diff --git a/src/main/java/com/lambdaworks/redis/ZAddArgs.java b/src/main/java/com/lambdaworks/redis/ZAddArgs.java index 8864e1026f..f9ca95b348 100644 --- a/src/main/java/com/lambdaworks/redis/ZAddArgs.java +++ b/src/main/java/com/lambdaworks/redis/ZAddArgs.java @@ -8,7 +8,7 @@ * * @author Mark Paluch */ -public class ZAddArgs { +public class ZAddArgs implements CompositeArgument { private boolean nx = false; private boolean xx = false; diff --git a/src/main/java/com/lambdaworks/redis/ZStoreArgs.java b/src/main/java/com/lambdaworks/redis/ZStoreArgs.java index 5a7d85c9e8..6be16621da 100644 --- a/src/main/java/com/lambdaworks/redis/ZStoreArgs.java +++ b/src/main/java/com/lambdaworks/redis/ZStoreArgs.java @@ -16,7 +16,7 @@ * * @author Will Glozer */ -public class ZStoreArgs { +public class ZStoreArgs implements CompositeArgument { private static enum Aggregate { SUM, MIN, MAX @@ -96,7 +96,7 @@ private static double[] toDoubleArray(long[] weights) { return result; } - void build(CommandArgs args) { + public void build(CommandArgs args) { if (weights != null) { diff --git a/src/main/java/com/lambdaworks/redis/dynamic/CodecAwareMethodParametersAccessor.java b/src/main/java/com/lambdaworks/redis/dynamic/CodecAwareMethodParametersAccessor.java new file mode 100644 index 0000000000..0dfc7183aa --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/dynamic/CodecAwareMethodParametersAccessor.java @@ -0,0 +1,93 @@ +package com.lambdaworks.redis.dynamic; + +import java.util.Iterator; + +import com.lambdaworks.redis.codec.RedisCodec; +import com.lambdaworks.redis.dynamic.parameter.MethodParametersAccessor; +import com.lambdaworks.redis.dynamic.support.ClassTypeInformation; +import com.lambdaworks.redis.dynamic.support.TypeInformation; +import com.lambdaworks.redis.internal.LettuceAssert; + +/** + * @author Mark Paluch + */ +public class CodecAwareMethodParametersAccessor implements MethodParametersAccessor { + + private final MethodParametersAccessor delegate; + private final TypeInformation keyType; + private final TypeInformation valueType; + + public CodecAwareMethodParametersAccessor(MethodParametersAccessor delegate, RedisCodec redisCodec) { + + LettuceAssert.notNull(delegate, "MethodParametersAccessor must not be null"); + LettuceAssert.notNull(redisCodec, "RedisCodec must not be null"); + + this.delegate = delegate; + + ClassTypeInformation typeInformation = ClassTypeInformation.from(redisCodec.getClass()); + + this.keyType = typeInformation.getTypeArgument(RedisCodec.class, 0); + this.valueType = typeInformation.getTypeArgument(RedisCodec.class, 1); + + } + + @Override + public int getParameterCount() { + return delegate.getParameterCount(); + } + + @Override + public Object getBindableValue(int index) { + return delegate.getBindableValue(index); + } + + @Override + public boolean isKey(int index) { + + if (delegate.isValue(index)) { + return false; + } + + if (delegate.isKey(index)) { + return true; + } + + Object bindableValue = getBindableValue(index); + + if (bindableValue != null && keyType.getType().isAssignableFrom(bindableValue.getClass())) { + return true; + } + + return false; + } + + @Override + public boolean isValue(int index) { + + if (delegate.isKey(index)) { + return false; + } + + if (delegate.isValue(index)) { + return true; + } + + Object bindableValue = getBindableValue(index); + + if (bindableValue != null && valueType.getType().isAssignableFrom(bindableValue.getClass())) { + return true; + } + + return false; + } + + @Override + public Iterator iterator() { + return delegate.iterator(); + } + + @Override + public int resolveParameterIndex(String name) { + return delegate.resolveParameterIndex(name); + } +} diff --git a/src/main/java/com/lambdaworks/redis/dynamic/CommandCreationException.java b/src/main/java/com/lambdaworks/redis/dynamic/CommandCreationException.java new file mode 100644 index 0000000000..fb4dcdb736 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/dynamic/CommandCreationException.java @@ -0,0 +1,20 @@ +package com.lambdaworks.redis.dynamic; + +import com.lambdaworks.redis.RedisException; + +/** + * @author Mark Paluch + */ +public class CommandCreationException extends RedisException { + + private final CommandMethod commandMethod; + + public CommandCreationException(CommandMethod commandMethod, String msg) { + super(String.format("%s Offending method: %s", msg, commandMethod)); + this.commandMethod = commandMethod; + } + + public CommandMethod getCommandMethod() { + return commandMethod; + } +} diff --git a/src/main/java/com/lambdaworks/redis/dynamic/CommandFactory.java b/src/main/java/com/lambdaworks/redis/dynamic/CommandFactory.java new file mode 100644 index 0000000000..fc9a03adc1 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/dynamic/CommandFactory.java @@ -0,0 +1,23 @@ +package com.lambdaworks.redis.dynamic; + +import com.lambdaworks.redis.protocol.RedisCommand; + +/** + * Strategy interface to create {@link RedisCommand}s. + * + *

    + * Implementing classes are required to construct {@link RedisCommand}s given an array of parameters for command execution. + * + * @author Mark Paluch + * @since 5.0 + */ +interface CommandFactory { + + /** + * Create a new {@link RedisCommand} given {@code parameters}. + * + * @param parameters must not be {@literal null}. + * @return the {@link RedisCommand}. + */ + RedisCommand createCommand(Object[] parameters); +} diff --git a/src/main/java/com/lambdaworks/redis/dynamic/CommandMethod.java b/src/main/java/com/lambdaworks/redis/dynamic/CommandMethod.java new file mode 100644 index 0000000000..c4bb1a854e --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/dynamic/CommandMethod.java @@ -0,0 +1,173 @@ +package com.lambdaworks.redis.dynamic; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.Future; + +import org.reactivestreams.Publisher; + +import com.lambdaworks.redis.dynamic.parameter.ExecutionSpecificParameters; +import com.lambdaworks.redis.dynamic.parameter.Parameter; +import com.lambdaworks.redis.dynamic.parameter.Parameters; +import com.lambdaworks.redis.dynamic.support.ClassTypeInformation; +import com.lambdaworks.redis.dynamic.support.TypeInformation; +import com.lambdaworks.redis.internal.LettuceAssert; + +/** + * Abstraction of a method that is designated to execute a Redis command method. Enriches the standard {@link Method} interface + * with specific information that is necessary to construct {@link com.lambdaworks.redis.protocol.RedisCommand} for the method. + * + * @author Mark Paluch + * @since 5.0 + */ +public class CommandMethod { + + private final Method method; + private final TypeInformation returnType; + private final List> arguments = new ArrayList<>(); + private final Parameters parameters; + private final TypeInformation actualReturnType; + + /** + * Create a new {@link CommandMethod} given a {@link Method}. + * + * @param method must not be null. + */ + public CommandMethod(Method method) { + this(method, new ExecutionSpecificParameters(method)); + } + + /** + * Create a new {@link CommandMethod} given a {@link Method} and {@link Parameters}. + * + * @param method must not be null. + * @param parameters must not be null. + */ + public CommandMethod(Method method, Parameters parameters) { + + LettuceAssert.notNull(method, "Method must not be null"); + LettuceAssert.notNull(parameters, "Parameters must not be null"); + + this.method = method; + this.returnType = ClassTypeInformation.fromReturnTypeOf(method); + this.parameters = parameters; + Collections.addAll(arguments, method.getParameterTypes()); + + TypeInformation actualReturnType = this.returnType; + + while (Future.class.isAssignableFrom(actualReturnType.getType()) + || Publisher.class.isAssignableFrom(actualReturnType.getType())) { + actualReturnType = actualReturnType.getComponentType(); + } + + this.actualReturnType = actualReturnType; + } + + /** + * + * @return the method {@link Parameters}. + */ + public Parameters getParameters() { + return parameters; + } + + /** + * + * @return the {@link Method}. + */ + public Method getMethod() { + return method; + } + + /** + * + * @return declared {@link Method} return {@link TypeInformation}. + */ + public TypeInformation getReturnType() { + return returnType; + } + + /** + * + * @return the actual {@link Method} return {@link TypeInformation} after unwrapping. + */ + public TypeInformation getActualReturnType() { + return actualReturnType; + } + + /** + * Lookup a method annotation. + * + * @param annotationClass the annotation class. + * @return the annotation object or {@literal null} if not found. + */ + public A getAnnotation(Class annotationClass) { + return method.getAnnotation(annotationClass); + } + + /** + * + * @param annotationClass the annotation class. + * @return {@literal true} if the method is annotated with {@code annotationClass}. + */ + public boolean hasAnnotation(Class annotationClass) { + return method.getAnnotation(annotationClass) != null; + } + + /** + * + * @return the method name. + */ + public String getName() { + return method.getName(); + } + + /** + * + * @return {@literal true} if the method uses asynchronous execution declaring {@link Future} as result type. + */ + public boolean isFutureExecution() { + return Future.class.isAssignableFrom(getReturnType().getType()); + } + + /** + * + * @return {@literal true} if the method uses reactive execution declaring {@link Publisher} as result type. + */ + public boolean isReactiveExecution() { + return ReactiveWrappers.supports(getReturnType().getType()); + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (!(o instanceof CommandMethod)) + return false; + + CommandMethod that = (CommandMethod) o; + + if (method != null ? !method.equals(that.method) : that.method != null) + return false; + if (returnType != null ? !returnType.equals(that.returnType) : that.returnType != null) + return false; + return arguments != null ? arguments.equals(that.arguments) : that.arguments == null; + + } + + @Override + public int hashCode() { + int result = method != null ? method.hashCode() : 0; + result = 31 * result + (returnType != null ? returnType.hashCode() : 0); + result = 31 * result + (arguments != null ? arguments.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return method.toGenericString(); + } +} diff --git a/src/main/java/com/lambdaworks/redis/dynamic/CommandMethodSyntaxException.java b/src/main/java/com/lambdaworks/redis/dynamic/CommandMethodSyntaxException.java new file mode 100644 index 0000000000..43b13024b6 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/dynamic/CommandMethodSyntaxException.java @@ -0,0 +1,11 @@ +package com.lambdaworks.redis.dynamic; + +/** + * @author Mark Paluch + */ +public class CommandMethodSyntaxException extends CommandCreationException { + + public CommandMethodSyntaxException(CommandMethod commandMethod, String msg) { + super(commandMethod, msg); + } +} diff --git a/src/main/java/com/lambdaworks/redis/dynamic/CommandMethodVerifier.java b/src/main/java/com/lambdaworks/redis/dynamic/CommandMethodVerifier.java new file mode 100644 index 0000000000..9ee5ee7784 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/dynamic/CommandMethodVerifier.java @@ -0,0 +1,191 @@ +package com.lambdaworks.redis.dynamic; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +import com.lambdaworks.redis.LettuceStrings; +import com.lambdaworks.redis.dynamic.parameter.Parameter; +import com.lambdaworks.redis.dynamic.segment.CommandSegments; +import com.lambdaworks.redis.internal.LettuceAssert; +import com.lambdaworks.redis.internal.LettuceLists; +import com.lambdaworks.redis.models.command.CommandDetail; + +/** + * Verifies {@link CommandMethod} declarations by checking available Redis commands. + * + * @author Mark Paluch + */ +class CommandMethodVerifier { + + /** + * Default maximum property distance: 2 + */ + public static final int DEFAULT_MAX_DISTANCE = 2; + + private List commandDetails; + + /** + * Create a new {@link CommandMethodVerifier} given a {@link List} of {@link CommandDetail} + * + * @param commandDetails must not be {@literal null}. + */ + public CommandMethodVerifier(List commandDetails) { + + LettuceAssert.notNull(commandDetails, "Command details must not be null"); + + this.commandDetails = LettuceLists.newList(commandDetails); + } + + /** + * + * Verify a {@link CommandMethod} with its {@link CommandSegments}. This method verifies that the command exists and that + * the required number of arguments is declared. + * + * @param commandSegments + * @param commandMethod + */ + public void validate(CommandSegments commandSegments, CommandMethod commandMethod) throws CommandMethodSyntaxException { + + LettuceAssert.notEmpty(commandSegments.getCommandType().name(), "Command name must not be empty"); + + CommandDetail commandDetail = findCommandDetail(commandSegments.getCommandType().name()) + .orElseThrow(() -> syntaxException(commandSegments.getCommandType().name(), commandMethod)); + + validateParameters(commandDetail, commandSegments, commandMethod); + } + + private void validateParameters(CommandDetail commandDetail, CommandSegments commandSegments, CommandMethod commandMethod) { + + List bindableParameters = commandMethod.getParameters().getBindableParameters(); + + int availableParameterCount = bindableParameters.size() + commandSegments.size(); + + // exact parameter count + if (commandDetail.getArity() - 1 == availableParameterCount) { + return; + } + + // more or same parameter cound for dynamic arg count commands + if (0 > commandDetail.getArity() && availableParameterCount >= -(commandDetail.getArity() + 1)) { + return; + } + + for (Parameter bindableParameter : bindableParameters) { + + // Can't verify collection-like arguments as they may contain multiple elements. + if (bindableParameter.getTypeInformation().isCollectionLike()) { + return; + } + } + + String message; + if (commandDetail.getArity() == 1) { + message = String.format("Command %s accepts no parameters.", commandDetail.getName().toUpperCase()); + } else if (commandDetail.getArity() < -1) { + message = String.format("Command %s requires at least %d parameters but method declares %d parameter(s).", + commandDetail.getName().toUpperCase(), Math.abs(commandDetail.getArity()) - 1, availableParameterCount); + } else { + message = String.format("Command %s accepts %d parameters but method declares %d parameter(s).", + commandDetail.getName().toUpperCase(), commandDetail.getArity() - 1, availableParameterCount); + } + + throw new CommandMethodSyntaxException(commandMethod, message); + } + + private CommandMethodSyntaxException syntaxException(String commandName, CommandMethod commandMethod) { + + CommandMatches commandMatches = CommandMatches.forCommand(commandName, commandDetails); + + if (commandMatches.hasMatches()) { + return new CommandMethodSyntaxException(commandMethod, + String.format("Command %s does not exist. Did you mean: %s?", commandName, commandMatches)); + } + + return new CommandMethodSyntaxException(commandMethod, String.format("Command %s does not exist", commandName)); + + } + + private Optional findCommandDetail(String commandName) { + return commandDetails.stream().filter(commandDetail -> commandDetail.getName().equalsIgnoreCase(commandName)) + .findFirst(); + } + + static class CommandMatches { + + private final List matches = new ArrayList<>(); + + private CommandMatches(List matches) { + this.matches.addAll(matches); + } + + public static CommandMatches forCommand(String command, List commandDetails) { + return new CommandMatches(calculateMatches(command, commandDetails)); + } + + private static List calculateMatches(String command, List commandDetails) { + + return commandDetails.stream() // + .filter(commandDetail -> calculateStringDistance(commandDetail.getName().toLowerCase(), + command.toLowerCase()) <= DEFAULT_MAX_DISTANCE) + .map(CommandDetail::getName) // + .map(String::toUpperCase) // + .sorted((o1, o2) -> calculateStringDistance(o1, o2)).collect(Collectors.toList()); + } + + public boolean hasMatches() { + return !matches.isEmpty(); + } + + @Override + public String toString() { + return LettuceStrings.collectionToDelimitedString(matches, ", ", "", ""); + } + + /** + * Calculate the distance between the given two Strings according to the Levenshtein algorithm. + * + * @param s1 the first String + * @param s2 the second String + * @return the distance value + */ + private static int calculateStringDistance(String s1, String s2) { + + if (s1.length() == 0) { + return s2.length(); + } + + if (s2.length() == 0) { + return s1.length(); + } + + int d[][] = new int[s1.length() + 1][s2.length() + 1]; + + for (int i = 0; i <= s1.length(); i++) { + d[i][0] = i; + } + + for (int j = 0; j <= s2.length(); j++) { + d[0][j] = j; + } + + for (int i = 1; i <= s1.length(); i++) { + char s_i = s1.charAt(i - 1); + for (int j = 1; j <= s2.length(); j++) { + int cost; + char t_j = s2.charAt(j - 1); + if (s_i == t_j) { + cost = 0; + } else { + cost = 1; + } + d[i][j] = Math.min(Math.min(d[i - 1][j] + 1, d[i][j - 1] + 1), d[i - 1][j - 1] + cost); + } + } + + return d[s1.length()][s2.length()]; + } + } + +} diff --git a/src/main/java/com/lambdaworks/redis/dynamic/CommandSegmentCommandFactory.java b/src/main/java/com/lambdaworks/redis/dynamic/CommandSegmentCommandFactory.java new file mode 100644 index 0000000000..1ef12a7eab --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/dynamic/CommandSegmentCommandFactory.java @@ -0,0 +1,81 @@ +package com.lambdaworks.redis.dynamic; + +import com.lambdaworks.redis.codec.RedisCodec; +import com.lambdaworks.redis.dynamic.output.CommandOutputFactory; +import com.lambdaworks.redis.dynamic.output.CommandOutputFactoryResolver; +import com.lambdaworks.redis.dynamic.output.OutputSelector; +import com.lambdaworks.redis.dynamic.parameter.ExecutionSpecificParameters; +import com.lambdaworks.redis.dynamic.parameter.MethodParametersAccessor; +import com.lambdaworks.redis.dynamic.segment.CommandSegments; +import com.lambdaworks.redis.output.CommandOutput; +import com.lambdaworks.redis.protocol.CommandArgs; +import com.lambdaworks.redis.protocol.RedisCommand; + +/** + * {@link CommandFactory} based on {@link CommandSegments}. + * + * @author Mark Paluch + */ +class CommandSegmentCommandFactory implements CommandFactory { + + private final CommandMethod commandMethod; + private final CommandSegments segments; + private final CommandOutputFactoryResolver outputResolver; + private final RedisCodec redisCodec; + private final ParameterBinder parameterBinder = new ParameterBinder(); + private final CommandOutputFactory outputFactory; + + public CommandSegmentCommandFactory(CommandSegments commandSegments, CommandMethod commandMethod, + RedisCodec redisCodec, CommandOutputFactoryResolver outputResolver) { + + this.segments = commandSegments; + this.commandMethod = commandMethod; + this.redisCodec = redisCodec; + this.outputResolver = outputResolver; + + OutputSelector outputSelector = new OutputSelector(commandMethod.getActualReturnType()); + CommandOutputFactory factory = resolveCommandOutputFactory(outputSelector); + + if (factory == null) { + throw new IllegalArgumentException(String.format("Cannot resolve CommandOutput for result type %s on method %s", + commandMethod.getActualReturnType(), commandMethod.getMethod())); + } + + if (commandMethod.getParameters() instanceof ExecutionSpecificParameters) { + + ExecutionSpecificParameters executionAwareParameters = (ExecutionSpecificParameters) commandMethod.getParameters(); + + if (commandMethod.isFutureExecution() && executionAwareParameters.hasTimeoutIndex()) { + throw new CommandCreationException(commandMethod, + "Asynchronous command methods do not support Timeout parameters"); + } + } + + this.outputFactory = factory; + } + + protected CommandOutputFactoryResolver getOutputResolver() { + return outputResolver; + } + + protected CommandOutputFactory resolveCommandOutputFactory(OutputSelector outputSelector) { + return outputResolver.resolveCommandOutput(outputSelector); + } + + @Override + public RedisCommand createCommand(Object[] parameters) { + + MethodParametersAccessor parametersAccessor = new CodecAwareMethodParametersAccessor( + new DefaultMethodParametersAccessor(commandMethod.getParameters(), parameters), redisCodec); + + CommandArgs args = new CommandArgs<>(redisCodec); + + CommandOutput output = outputFactory.create(redisCodec); + com.lambdaworks.redis.protocol.Command command = new com.lambdaworks.redis.protocol.Command<>( + this.segments.getCommandType(), output, args); + + parameterBinder.bind(args, segments, parametersAccessor); + + return command; + } +} diff --git a/src/main/java/com/lambdaworks/redis/dynamic/DefaultMethodParametersAccessor.java b/src/main/java/com/lambdaworks/redis/dynamic/DefaultMethodParametersAccessor.java new file mode 100644 index 0000000000..d6c07070e7 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/dynamic/DefaultMethodParametersAccessor.java @@ -0,0 +1,114 @@ +package com.lambdaworks.redis.dynamic; + +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; + +import com.lambdaworks.redis.dynamic.annotation.Key; +import com.lambdaworks.redis.dynamic.annotation.Value; +import com.lambdaworks.redis.dynamic.parameter.MethodParametersAccessor; +import com.lambdaworks.redis.dynamic.parameter.Parameter; +import com.lambdaworks.redis.dynamic.parameter.Parameters; +import com.lambdaworks.redis.internal.LettuceAssert; + +/** + * Default {@link MethodParametersAccessor} implementation. + * + * @author Mark Paluch + * @since 5.0 + */ +class DefaultMethodParametersAccessor implements MethodParametersAccessor { + + private final Parameters parameters; + private final List values; + + public DefaultMethodParametersAccessor(Parameters parameters, Object[] values) { + + this.parameters = parameters; + this.values = Arrays.asList(values); + + } + + public int getParameterCount() { + return parameters.getBindableParameters().size(); + } + + @Override + public Object getBindableValue(int index) { + return values.get(parameters.getBindableParameter(index).getParameterIndex()); + } + + @Override + public boolean isKey(int index) { + return parameters.getBindableParameter(index).findAnnotation(Key.class) != null; + } + + @Override + public boolean isValue(int index) { + return parameters.getBindableParameter(index).findAnnotation(Value.class) != null; + } + + @Override + public Iterator iterator() { + return new BindableParameterIterator(this); + } + + @Override + public int resolveParameterIndex(String name) { + + List bindableParameters = parameters.getBindableParameters(); + for (int i = 0; i < bindableParameters.size(); i++) { + + if (name.equals(bindableParameters.get(i).getName())) { + return i; + } + } + + throw new IllegalArgumentException(String.format("Cannot resolve named parameter %s", name)); + } + + public Parameters getParameters() { + return parameters; + } + + /** + * Iterator class to allow traversing all bindable parameters inside the accessor. + */ + private static class BindableParameterIterator implements Iterator { + + private final int bindableParameterCount; + private final DefaultMethodParametersAccessor accessor; + + private int currentIndex = 0; + + /** + * Creates a new {@link BindableParameterIterator}. + * + * @param accessor must not be {@literal null}. + */ + public BindableParameterIterator(DefaultMethodParametersAccessor accessor) { + + LettuceAssert.notNull(accessor, "ParametersParameterAccessor must not be null!"); + + this.accessor = accessor; + this.bindableParameterCount = accessor.getParameters().getBindableParameters().size(); + } + + /** + * Return the next bindable parameter. + * + * @return + */ + public Object next() { + return accessor.getBindableValue(currentIndex++); + } + + public boolean hasNext() { + return bindableParameterCount > currentIndex; + } + + public void remove() { + throw new UnsupportedOperationException(); + } + } +} diff --git a/src/main/java/com/lambdaworks/redis/dynamic/DefaultRedisCommandsMetadata.java b/src/main/java/com/lambdaworks/redis/dynamic/DefaultRedisCommandsMetadata.java new file mode 100644 index 0000000000..749a245727 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/dynamic/DefaultRedisCommandsMetadata.java @@ -0,0 +1,130 @@ +package com.lambdaworks.redis.dynamic; + +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +import com.lambdaworks.redis.internal.LettuceAssert; + +/** + * Default implementation of {@link RedisCommandsMetadata}. + * + * @author Mark Paluch + * @since 5.0 + */ +class DefaultRedisCommandsMetadata implements RedisCommandsMetadata { + + /** The package separator character: '.' */ + private static final char PACKAGE_SEPARATOR = '.'; + + private final Class apiInterface; + + /** + * Create {@link DefaultRedisCommandsMetadata} given a {@link Class command interface}. + * + * @param apiInterface must not be {@literal null}. + */ + DefaultRedisCommandsMetadata(Class apiInterface) { + this.apiInterface = apiInterface; + } + + @Override + public Class getCommandsInterface() { + return apiInterface; + } + + @Override + public Collection getMethods() { + + Set result = new HashSet(); + + for (Method method : getCommandsInterface().getMethods()) { + method = getMostSpecificMethod(method, getCommandsInterface()); + if (isQueryMethodCandidate(method)) { + result.add(method); + } + } + + return Collections.unmodifiableSet(result); + } + + /** + * Checks whether the given method is a query method candidate. + * + * @param method + * @return + */ + private boolean isQueryMethodCandidate(Method method) { + return !method.isBridge() && !method.isDefault(); + } + + /** + * Given a method, which may come from an interface, and a target class used in the current reflective invocation, find the + * corresponding target method if there is one. E.g. the method may be {@code IFoo.bar()} and the target class may be + * {@code DefaultFoo}. In this case, the method may be {@code DefaultFoo.bar()}. This enables attributes on that method to + * be found. + * + * @param method the method to be invoked, which may come from an interface + * @param targetClass the target class for the current invocation. May be {@code null} or may not even implement the method. + * @return the specific target method, or the original method if the {@code targetClass} doesn't implement it or is + * {@code null} + */ + public static Method getMostSpecificMethod(Method method, Class targetClass) { + if (method != null && isOverridable(method, targetClass) && targetClass != null + && targetClass != method.getDeclaringClass()) { + try { + try { + return targetClass.getMethod(method.getName(), method.getParameterTypes()); + } catch (NoSuchMethodException ex) { + return method; + } + } catch (SecurityException ex) { + } + } + return method; + } + + /** + * Determine whether the given method is overridable in the given target class. + * + * @param method the method to check + * @param targetClass the target class to check against + */ + private static boolean isOverridable(Method method, Class targetClass) { + if (Modifier.isPrivate(method.getModifiers())) { + return false; + } + if (Modifier.isPublic(method.getModifiers()) || Modifier.isProtected(method.getModifiers())) { + return true; + } + return getPackageName(method.getDeclaringClass()).equals(getPackageName(targetClass)); + } + + /** + * Determine the name of the package of the given class, e.g. "java.lang" for the {@code java.lang.String} class. + * + * @param clazz the class + * @return the package name, or the empty String if the class is defined in the default package + */ + private static String getPackageName(Class clazz) { + LettuceAssert.notNull(clazz, "Class must not be null"); + return getPackageName(clazz.getName()); + } + + /** + * Determine the name of the package of the given fully-qualified class name, e.g. "java.lang" for the + * {@code java.lang.String} class name. + * + * @param fqClassName the fully-qualified class name + * @return the package name, or the empty String if the class is defined in the default package + */ + private static String getPackageName(String fqClassName) { + LettuceAssert.notNull(fqClassName, "Class name must not be null"); + int lastDotIndex = fqClassName.lastIndexOf(PACKAGE_SEPARATOR); + return (lastDotIndex != -1 ? fqClassName.substring(0, lastDotIndex) : ""); + } + +} diff --git a/src/main/java/com/lambdaworks/redis/dynamic/ParameterBinder.java b/src/main/java/com/lambdaworks/redis/dynamic/ParameterBinder.java new file mode 100644 index 0000000000..ef9cc7980b --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/dynamic/ParameterBinder.java @@ -0,0 +1,120 @@ +package com.lambdaworks.redis.dynamic; + +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import com.lambdaworks.redis.CompositeArgument; +import com.lambdaworks.redis.dynamic.parameter.MethodParametersAccessor; +import com.lambdaworks.redis.dynamic.segment.CommandSegment; +import com.lambdaworks.redis.dynamic.segment.CommandSegment.ArgumentContribution; +import com.lambdaworks.redis.dynamic.segment.CommandSegments; +import com.lambdaworks.redis.protocol.CommandArgs; +import com.lambdaworks.redis.protocol.ProtocolKeyword; + +/** + * Parameter binder for {@link CommandSegments}-based Redis Commands. + * + * @author Mark Paluch + * @since 5.0 + */ +class ParameterBinder { + + /** + * Bind {@link CommandSegments} and method parameters to {@link CommandArgs}. + * + * @param args + * @param commandSegments + * @param accessor + * @param + * @param + * @return + */ + CommandArgs bind(CommandArgs args, CommandSegments commandSegments, MethodParametersAccessor accessor) { + + int parameterCount = accessor.getParameterCount(); + + Set eatenParameters = new HashSet<>(); + + for (CommandSegment commandSegment : commandSegments) { + + ArgumentContribution argumentContribution = commandSegment.contribute(accessor); + bind(args, argumentContribution.getValue(), argumentContribution.getParameterIndex(), accessor); + + eatenParameters.add(argumentContribution.getParameterIndex()); + } + + for (int i = 0; i < parameterCount; i++) { + + if (eatenParameters.contains(i)) { + continue; + } + + Object bindableValue = accessor.getBindableValue(i); + bind(args, bindableValue, i, accessor); + + eatenParameters.add(i); + } + + return args; + } + + @SuppressWarnings("unchecked") + private void bind(CommandArgs args, Object argument, int index, MethodParametersAccessor accessor) { + + if (argument == null) { + args.add(new byte[0]); + return; + } + + if (index != -1) { + if (accessor.isKey(index)) { + + if (argument instanceof Iterable) { + args.addKeys((Iterable) argument); + } else { + args.addKey((K) argument); + } + return; + } + + if (accessor.isValue(index)) { + + if (argument instanceof Iterable) { + args.addValues((Iterable) argument); + } else { + args.addValue((V) argument); + } + return; + } + } + + if (argument instanceof String) { + args.add((String) argument); + } + + if (argument instanceof byte[]) { + args.add((byte[]) argument); + } + + if (argument instanceof Double) { + args.add(((Double) argument)); + } else if (argument instanceof Number) { + args.add(((Number) argument).longValue()); + } + + if (argument instanceof ProtocolKeyword) { + args.add((ProtocolKeyword) argument); + return; + } + + if (argument instanceof Map) { + args.add((Map) argument); + return; + } + + if (argument instanceof CompositeArgument) { + ((CompositeArgument) argument).build(args); + } + } +} diff --git a/src/main/java/com/lambdaworks/redis/dynamic/ReactiveCommandSegmentCommandFactory.java b/src/main/java/com/lambdaworks/redis/dynamic/ReactiveCommandSegmentCommandFactory.java new file mode 100644 index 0000000000..7935a4783b --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/dynamic/ReactiveCommandSegmentCommandFactory.java @@ -0,0 +1,53 @@ +package com.lambdaworks.redis.dynamic; + +import com.lambdaworks.redis.codec.RedisCodec; +import com.lambdaworks.redis.dynamic.output.CommandOutputFactory; +import com.lambdaworks.redis.dynamic.output.CommandOutputFactoryResolver; +import com.lambdaworks.redis.dynamic.output.OutputSelector; +import com.lambdaworks.redis.dynamic.parameter.ExecutionSpecificParameters; +import com.lambdaworks.redis.dynamic.segment.CommandSegments; + +/** + * {@link CommandSegmentCommandFactory} for Reactive Command execution. + * + * @author Mark Paluch + */ +class ReactiveCommandSegmentCommandFactory extends CommandSegmentCommandFactory { + + private boolean streamingExecution; + + public ReactiveCommandSegmentCommandFactory(CommandSegments commandSegments, CommandMethod commandMethod, + RedisCodec redisCodec, CommandOutputFactoryResolver outputResolver) { + + super(commandSegments, commandMethod, redisCodec, outputResolver); + + if (commandMethod.getParameters() instanceof ExecutionSpecificParameters) { + + ExecutionSpecificParameters executionAwareParameters = (ExecutionSpecificParameters) commandMethod.getParameters(); + + if (executionAwareParameters.hasTimeoutIndex()) { + throw new CommandCreationException(commandMethod, "Reactive command methods do not support Timeout parameters"); + } + } + } + + @Override + protected CommandOutputFactory resolveCommandOutputFactory(OutputSelector outputSelector) { + + CommandOutputFactory factory = getOutputResolver().resolveStreamingCommandOutput(outputSelector); + + if (factory != null) { + streamingExecution = true; + return factory; + } + + return super.resolveCommandOutputFactory(outputSelector); + } + + /** + * @return {@literal true} if the resolved {@link com.lambdaworks.redis.output.CommandOutput} should use streaming. + */ + public boolean isStreamingExecution() { + return streamingExecution; + } +} diff --git a/src/main/java/com/lambdaworks/redis/dynamic/ReactiveWrappers.java b/src/main/java/com/lambdaworks/redis/dynamic/ReactiveWrappers.java new file mode 100644 index 0000000000..c8fb206aa7 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/dynamic/ReactiveWrappers.java @@ -0,0 +1,69 @@ +package com.lambdaworks.redis.dynamic; + +import java.util.HashSet; +import java.util.Set; + +import com.lambdaworks.redis.internal.LettuceAssert; +import com.lambdaworks.redis.internal.LettuceClassUtils; + +/** + * Converters to potentially convert the execution of a command method into a variety of wrapper types potentially being + * available on the classpath. Currently supported: + *
      + *
    • {@link reactor.core.publisher.Mono}
    • + *
    • {@link reactor.core.publisher.Flux}
    • + *
    • {@link org.reactivestreams.Publisher}
    • + *
    + * + * @author Mark Paluch + * @since 5.0 + */ +abstract class ReactiveWrappers { + + private static final Class MONO = LettuceClassUtils.findClass("reactor.core.publisher.Mono"); + private static final Class FLUX = LettuceClassUtils.findClass("reactor.core.publisher.Flux"); + private static final Class PUBLISHER = LettuceClassUtils.findClass("org.reactivestreams.Publisher"); + + private static final Set> REACTIVE_WRAPPERS = new HashSet<>(); + private static final Set> SINGLE_WRAPPERS = new HashSet<>(); + private static final Set> MULTI_WRAPPERS = new HashSet<>(); + + static { + + if (MONO != null) { + REACTIVE_WRAPPERS.add(MONO); + SINGLE_WRAPPERS.add(MONO); + } + + if (FLUX != null) { + REACTIVE_WRAPPERS.add(FLUX); + MULTI_WRAPPERS.add(FLUX); + } + + if (PUBLISHER != null) { + REACTIVE_WRAPPERS.add(PUBLISHER); + MULTI_WRAPPERS.add(PUBLISHER); + } + } + + public static boolean supports(Class wrapperType) { + + LettuceAssert.notNull(wrapperType, "Wrapper type must not be null"); + + return REACTIVE_WRAPPERS.contains(wrapperType); + } + + public static boolean isSingle(Class wrapperType) { + + LettuceAssert.notNull(wrapperType, "Wrapper type must not be null"); + + return SINGLE_WRAPPERS.contains(wrapperType) && !isMulti(wrapperType); + } + + public static boolean isMulti(Class wrapperType) { + + LettuceAssert.notNull(wrapperType, "Wrapper type must not be null"); + + return MULTI_WRAPPERS.contains(wrapperType); + } +} diff --git a/src/main/java/com/lambdaworks/redis/dynamic/RedisCommandFactory.java b/src/main/java/com/lambdaworks/redis/dynamic/RedisCommandFactory.java new file mode 100644 index 0000000000..74a1a3a8b8 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/dynamic/RedisCommandFactory.java @@ -0,0 +1,408 @@ +package com.lambdaworks.redis.dynamic; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; + +import com.lambdaworks.redis.AbstractRedisReactiveCommands; +import com.lambdaworks.redis.LettuceFutures; +import com.lambdaworks.redis.RedisFuture; +import com.lambdaworks.redis.api.StatefulConnection; +import com.lambdaworks.redis.api.StatefulRedisConnection; +import com.lambdaworks.redis.api.async.BaseRedisAsyncCommands; +import com.lambdaworks.redis.api.reactive.BaseRedisReactiveCommands; +import com.lambdaworks.redis.cluster.api.StatefulRedisClusterConnection; +import com.lambdaworks.redis.codec.ByteArrayCodec; +import com.lambdaworks.redis.codec.RedisCodec; +import com.lambdaworks.redis.codec.StringCodec; +import com.lambdaworks.redis.dynamic.codec.AnnotationRedisCodecResolver; +import com.lambdaworks.redis.dynamic.domain.Timeout; +import com.lambdaworks.redis.dynamic.intercept.InvocationProxyFactory; +import com.lambdaworks.redis.dynamic.intercept.MethodInterceptor; +import com.lambdaworks.redis.dynamic.intercept.MethodInvocation; +import com.lambdaworks.redis.dynamic.output.CodecAwareOutputFactoryResolver; +import com.lambdaworks.redis.dynamic.output.CommandOutputFactoryResolver; +import com.lambdaworks.redis.dynamic.output.OutputRegistry; +import com.lambdaworks.redis.dynamic.output.OutputRegistryCommandOutputFactoryResolver; +import com.lambdaworks.redis.dynamic.parameter.ExecutionSpecificParameters; +import com.lambdaworks.redis.dynamic.segment.AnnotationCommandSegmentFactory; +import com.lambdaworks.redis.dynamic.segment.CommandSegments; +import com.lambdaworks.redis.internal.LettuceAssert; +import com.lambdaworks.redis.internal.LettuceLists; +import com.lambdaworks.redis.models.command.CommandDetail; +import com.lambdaworks.redis.models.command.CommandDetailParser; +import com.lambdaworks.redis.output.CommandOutput; +import com.lambdaworks.redis.protocol.CommandArgs; +import com.lambdaworks.redis.protocol.LettuceCharsets; +import com.lambdaworks.redis.protocol.RedisCommand; + +/** + * Factory to create Redis Command interface instances. + *

    + * This class is the entry point to implement command interfaces and obtain a reference to the implementation. Redis Command + * interfaces provide a dynamic API that are declared in userland code. {@link RedisCommandFactory} and its supportive classes + * analyze method declarations and derive from those factories to create and execute {@link RedisCommand}s. + * + *

    Example

    +public interface MyRedisCommands {
    +
    +    String get(String key); // Synchronous Execution of GET
    +
    +    @Command("GET")
    +    byte[] getAsBytes(String key); // Synchronous Execution of GET returning data as byte array
    +
    +    @Command("SET") // synchronous execution applying a Timeout
    +    String setSync(String key, String value, Timeout timeout);
    +
    +    Future set(String key, String value); // asynchronous SET execution
    +
    +    @Command("SET")
    +    Mono setReactive(String key, String value, SetArgs setArgs); // reactive SET execution using SetArgs
    +
    +    @CommandNaming(split = DOT) // support for Redis Module command notation -> NR.RUN
    +    double nrRun(String key, int... indexes);
    +}
    +
    + RedisCommandFactory factory = new RedisCommandFactory(connection);
    +
    + MyRedisCommands commands = factory.getCommands(MyRedisCommands.class);
    +
    + String value = commands.get("key");
    +
    + * 
    + * + * @author Mark Paluch + * @since 5.0 + * @see com.lambdaworks.redis.dynamic.annotation.Command + * @see CommandMethod + */ +public class RedisCommandFactory { + + private final StatefulConnection connection; + private final CommandMethodVerifier commandMethodVerifier; + private final List> redisCodecs = new ArrayList<>(); + + private CommandOutputFactoryResolver commandOutputFactoryResolver = new OutputRegistryCommandOutputFactoryResolver( + new OutputRegistry()); + + private boolean verifyCommandMethods = true; + + /** + * Create a new {@link CommandFactory} given {@link StatefulConnection}. + * + * @param connection must not be {@literal null}. + */ + public RedisCommandFactory(StatefulConnection connection) { + this(connection, LettuceLists.newList(new ByteArrayCodec(), new StringCodec(LettuceCharsets.UTF8))); + } + + /** + * Create a new {@link CommandFactory} given {@link StatefulConnection} and a {@link List} of {@link RedisCodec}s to use + * + * @param connection must not be {@literal null}. + * @param redisCodecs must not be {@literal null}. + */ + public RedisCommandFactory(StatefulConnection connection, Iterable> redisCodecs) { + + LettuceAssert.notNull(connection, "Redis Connection must not be null"); + LettuceAssert.notNull(redisCodecs, "Iterable of RedisCodec must not be null"); + + this.connection = connection; + this.redisCodecs.addAll(LettuceLists.newList(redisCodecs)); + + commandMethodVerifier = new CommandMethodVerifier(getCommands(connection)); + } + + @SuppressWarnings("unchecked") + private List getCommands(StatefulConnection connection) { + + List commands = Collections.emptyList(); + if (connection instanceof StatefulRedisConnection) { + commands = ((StatefulRedisConnection) connection).sync().command(); + } + + if (connection instanceof StatefulRedisClusterConnection) { + commands = ((StatefulRedisClusterConnection) connection).sync().command(); + } + + if (commands.isEmpty()) { + verifyCommandMethods = false; + } + + return CommandDetailParser.parse(commands); + } + + /** + * Set a {@link CommandOutputFactoryResolver}. + * + * @param commandOutputFactoryResolver must not be {@literal null}. + */ + public void setCommandOutputFactoryResolver(CommandOutputFactoryResolver commandOutputFactoryResolver) { + + LettuceAssert.notNull(commandOutputFactoryResolver, "CommandOutputFactoryResolver must not be null"); + + this.commandOutputFactoryResolver = commandOutputFactoryResolver; + } + + /** + * Enables/disables command verification which checks the command name against Redis {@code COMMAND} and the argument count. + * + * @param verifyCommandMethods {@literal true} to enable command verification (default) or {@literal false} to disable + * command verification. + */ + public void setVerifyCommandMethods(boolean verifyCommandMethods) { + this.verifyCommandMethods = verifyCommandMethods; + } + + /** + * Returns a Redis Command instance for the given interface. + * + * @param commandInterface must not be {@literal null}. + * @return the implemented Redis Commands interface. + */ + public T getCommands(Class commandInterface) { + + LettuceAssert.notNull(commandInterface, "Redis Command Interface must not be null"); + + RedisCommandsMetadata redisCommandsMetadata = new DefaultRedisCommandsMetadata(commandInterface); + + InvocationProxyFactory factory = new InvocationProxyFactory(); + factory.addInterface(commandInterface); + + if (connection instanceof StatefulRedisConnection) { + + StatefulRedisConnection redisConnection = (StatefulRedisConnection) connection; + + factory.addInterceptor( + new ReactiveCommandFactoryExecutorMethodInterceptor(redisCommandsMetadata, redisConnection.reactive())); + + factory.addInterceptor(new CommandFactoryExecutorMethodInterceptor(redisCommandsMetadata, redisConnection.async())); + } + + return factory.createProxy(commandInterface.getClassLoader()); + } + + /** + * {@link CommandFactory}-based {@link MethodInterceptor} to create and invoke Redis Commands using asynchronous and + * synchronous execution models. + * + * @author Mark Paluch + */ + class CommandFactoryExecutorMethodInterceptor implements MethodInterceptor { + + private final Map commandFactories = new ConcurrentHashMap<>(); + private final BaseRedisAsyncCommands redisAsyncCommands; + + public CommandFactoryExecutorMethodInterceptor(RedisCommandsMetadata redisCommandsMetadata, + BaseRedisAsyncCommands redisAsyncCommands) { + + RedisCommandFactoryResolver lookupStrategy = new DefaultRedisCommandFactoryResolver(redisCodecs); + + for (Method method : redisCommandsMetadata.getMethods()) { + + if (ReactiveWrappers.supports(method.getReturnType())) { + continue; + } + + CommandFactory commandFactory = lookupStrategy.resolveRedisCommandFactory(method, redisCommandsMetadata); + commandFactories.put(method, commandFactory); + } + + this.redisAsyncCommands = redisAsyncCommands; + } + + @SuppressWarnings("unchecked") + @Override + public Object invoke(MethodInvocation invocation) throws Throwable { + + Method method = invocation.getMethod(); + Object[] arguments = invocation.getArguments(); + + if (hasFactoryFor(method)) { + + CommandMethod commandMethod = new CommandMethod(method); + CommandFactory commandFactory = commandFactories.get(method); + RedisCommand command = commandFactory.createCommand(arguments); + + if (commandMethod.isFutureExecution()) { + return redisAsyncCommands.dispatch(command.getType(), (CommandOutput) command.getOutput(), + (CommandArgs) command.getArgs()); + } + + RedisFuture dispatch = redisAsyncCommands.dispatch(command.getType(), (CommandOutput) command.getOutput(), + (CommandArgs) command.getArgs()); + + long timeout = connection.getTimeout(); + TimeUnit unit = connection.getTimeoutUnit(); + + if (commandMethod.getParameters() instanceof ExecutionSpecificParameters) { + ExecutionSpecificParameters executionSpecificParameters = (ExecutionSpecificParameters) commandMethod + .getParameters(); + + if (executionSpecificParameters.hasTimeoutIndex()) { + Timeout timeoutArg = (Timeout) arguments[executionSpecificParameters.getTimeoutIndex()]; + if (timeoutArg != null) { + timeout = timeoutArg.getTimeout(); + unit = timeoutArg.getTimeUnit(); + } + } + } + + LettuceFutures.awaitAll(timeout, unit, dispatch); + + return dispatch.get(); + } + + return invocation.proceed(); + } + + private boolean hasFactoryFor(Method method) { + return commandFactories.containsKey(method); + } + } + + /** + * {@link CommandFactory}-based {@link MethodInterceptor} to create and invoke Redis Commands using reactive execution. + * + * @author Mark Paluch + */ + class ReactiveCommandFactoryExecutorMethodInterceptor implements MethodInterceptor { + + private final Map commandFactories = new ConcurrentHashMap<>(); + private final AbstractRedisReactiveCommands redisReactiveCommands; + + public ReactiveCommandFactoryExecutorMethodInterceptor(RedisCommandsMetadata redisCommandsMetadata, + BaseRedisReactiveCommands redisReactiveCommands) { + + ReactiveRedisCommandFactoryResolver lookupStrategy = new ReactiveRedisCommandFactoryResolver(redisCodecs); + + for (Method method : redisCommandsMetadata.getMethods()) { + + if (ReactiveWrappers.supports(method.getReturnType())) { + + ReactiveCommandSegmentCommandFactory commandFactory = lookupStrategy.resolveRedisCommandFactory(method, + redisCommandsMetadata); + commandFactories.put(method, commandFactory); + } + } + + this.redisReactiveCommands = (AbstractRedisReactiveCommands) redisReactiveCommands; + } + + @Override + public Object invoke(MethodInvocation invocation) throws Throwable { + + Method method = invocation.getMethod(); + Object[] arguments = invocation.getArguments(); + + if (hasFactoryFor(method)) { + + ReactiveCommandSegmentCommandFactory commandFactory = commandFactories.get(method); + + if (ReactiveWrappers.isSingle(method.getReturnType())) { + return redisReactiveCommands.createMono(() -> commandFactory.createCommand(arguments)); + } + + if (commandFactory.isStreamingExecution()) { + + return redisReactiveCommands.createDissolvingFlux(() -> commandFactory.createCommand(arguments)); + } + + return redisReactiveCommands.createFlux(() -> commandFactory.createCommand(arguments)); + } + + return invocation.proceed(); + } + + private boolean hasFactoryFor(Method method) { + return commandFactories.containsKey(method); + } + } + + @SuppressWarnings("unchecked") + class DefaultRedisCommandFactoryResolver implements RedisCommandFactoryResolver { + + final AnnotationCommandSegmentFactory commandSegmentFactory = new AnnotationCommandSegmentFactory(); + final AnnotationRedisCodecResolver codecResolver; + + DefaultRedisCommandFactoryResolver(List> redisCodecs) { + codecResolver = new AnnotationRedisCodecResolver(redisCodecs); + } + + @Override + public CommandFactory resolveRedisCommandFactory(Method method, RedisCommandsMetadata redisCommandsMetadata) { + + CommandMethod commandMethod = new CommandMethod(method); + + RedisCodec codec = codecResolver.resolve(commandMethod); + + if (codec == null) { + throw new CommandCreationException(commandMethod, "Cannot resolve codec."); + } + + CodecAwareOutputFactoryResolver outputFactoryResolver = new CodecAwareOutputFactoryResolver( + commandOutputFactoryResolver, codec); + CommandSegments commandSegments = commandSegmentFactory.createCommandSegments(commandMethod); + + if (verifyCommandMethods) { + commandMethodVerifier.validate(commandSegments, commandMethod); + } + + if (commandMethod.isReactiveExecution()) { + + return new ReactiveCommandSegmentCommandFactory(commandSegments, commandMethod, (RedisCodec) codec, + outputFactoryResolver); + } + + return new CommandSegmentCommandFactory<>(commandSegments, commandMethod, (RedisCodec) codec, + outputFactoryResolver); + } + } + + class ReactiveRedisCommandFactoryResolver implements RedisCommandFactoryResolver { + + final AnnotationCommandSegmentFactory commandSegmentFactory = new AnnotationCommandSegmentFactory(); + final AnnotationRedisCodecResolver codecResolver; + + ReactiveRedisCommandFactoryResolver(List> redisCodecs) { + codecResolver = new AnnotationRedisCodecResolver(redisCodecs); + } + + @Override + public ReactiveCommandSegmentCommandFactory resolveRedisCommandFactory(Method method, + RedisCommandsMetadata redisCommandsMetadata) { + + CommandMethod commandMethod = new CommandMethod(method); + + RedisCodec codec = codecResolver.resolve(commandMethod); + + if (codec == null) { + throw new CommandCreationException(commandMethod, "Cannot resolve codec."); + } + + CommandSegments commandSegments = commandSegmentFactory.createCommandSegments(commandMethod); + + if (verifyCommandMethods) { + commandMethodVerifier.validate(commandSegments, commandMethod); + } + + CodecAwareOutputFactoryResolver outputFactoryResolver = new CodecAwareOutputFactoryResolver( + commandOutputFactoryResolver, codec); + + return new ReactiveCommandSegmentCommandFactory(commandSegments, commandMethod, (RedisCodec) codec, + outputFactoryResolver); + } + } + + /** + * Strategy interface to resolve a {@link CommandFactory}. + */ + interface RedisCommandFactoryResolver { + + CommandFactory resolveRedisCommandFactory(Method method, RedisCommandsMetadata redisCommandsMetadata); + } +} diff --git a/src/main/java/com/lambdaworks/redis/dynamic/RedisCommandsMetadata.java b/src/main/java/com/lambdaworks/redis/dynamic/RedisCommandsMetadata.java new file mode 100644 index 0000000000..abc6ebcb88 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/dynamic/RedisCommandsMetadata.java @@ -0,0 +1,22 @@ +package com.lambdaworks.redis.dynamic; + +import java.lang.reflect.Method; +import java.util.Collection; + +/** + * Interface exposing Redis command interface metadata. + * + * @author Mark Paluch + * @since 5.0 + */ +public interface RedisCommandsMetadata { + + Collection getMethods(); + + /** + * Returns the Redis Commands interface. + * + * @return + */ + Class getCommandsInterface(); +} diff --git a/src/main/java/com/lambdaworks/redis/dynamic/annotation/Command.java b/src/main/java/com/lambdaworks/redis/dynamic/annotation/Command.java new file mode 100644 index 0000000000..13a4aba102 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/dynamic/annotation/Command.java @@ -0,0 +1,44 @@ +package com.lambdaworks.redis.dynamic.annotation; + +import com.lambdaworks.redis.dynamic.domain.Timeout; + +import java.lang.annotation.*; + +/** + * Redis command method annotation specifying a command string. A command string can contain the command name, a sequence of + * command string bytes and parameter references. + *

    + * Parameters: Parameters can be referenced by their name {@code :myArg} or index {@code ?0}. Additional, not referenced + * parameters are appended to the command in the order of their appearance. Declared parameters are matched against + * {@link com.lambdaworks.redis.codec.RedisCodec} for codec resolution. Additional parameter types such as {@link Timeout} + * control execution behavior and are not added to command arguments. + *

    + * Usage

    +    @Command("SET ?0 ?1")
    +    public String setKey(String key, String value)
    +
    +    @Command("SET :key :value")
    +    public String setKeyNamed(@Param("key") String key, @Param("value") String value)
    +    
    + *

    + * Implementation notes: A {@link Command#value()} is split into command segments of which each segment is represented as ASCII + * string or parameter reference. + * + * @author Mark Paluch + * @since 5.0 + * @see CommandNaming + * @see Param + * @see Key + * @see Value + * @see com.lambdaworks.redis.dynamic.codec.RedisCodecResolver + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +@Documented +public @interface Command { + + /** + * Command string. + */ + String value(); +} diff --git a/src/main/java/com/lambdaworks/redis/dynamic/annotation/CommandNaming.java b/src/main/java/com/lambdaworks/redis/dynamic/annotation/CommandNaming.java new file mode 100644 index 0000000000..deaba6de23 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/dynamic/annotation/CommandNaming.java @@ -0,0 +1,69 @@ +package com.lambdaworks.redis.dynamic.annotation; + +import java.lang.annotation.*; + +/** + * Command naming strategy for Redis command methods. Redis command methods name can be provided either by annotating method + * with {@link Command} or derived from its name. Annotate a command interface or method with {@link CommandNaming} to set a + * command naming {@link Strategy}. + * + * @author Mark Paluch + * @since 5.0 + * @see Command + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ ElementType.TYPE, ElementType.METHOD }) +@Documented +public @interface CommandNaming { + + /** + * Apply a naming {@link Strategy} to transform the method name into a Redis command name. + */ + Strategy strategy() default Strategy.DEFAULT; + + /** + * Adjust letter case, defaults to {@link LetterCase#UPPERCASE}. + */ + LetterCase letterCase() default LetterCase.DEFAULT; + + public enum Strategy { + + /** + * Replace camel humps with spaces and split the method name into multiple command segments. A method named + * {@code clientSetname} would issue a command {@code CLIENT SETNAME}. + */ + SPLIT, + + /** + * Replace camel humps with spaces. A method named {@code nrRun} would issue a command named {@code NR.RUN}. + */ + DOT, + + /** + * Passthru the command as-is. A method named {@code clientSetname} would issue a command named {@code CLIENTSETNAME}. + */ + METHOD_NAME, + + /** + * Not defined here which defaults to {@link #SPLIT} if nothing else found. + */ + DEFAULT; + } + + public enum LetterCase { + /** + * Keep command name as specified. + */ + AS_IS, + + /** + * Convert command to uppercase. + */ + UPPERCASE, + + /** + * Not defined here which defaults to {@link #UPPERCASE} if nothing else found. + */ + DEFAULT; + } +} diff --git a/src/main/java/com/lambdaworks/redis/dynamic/annotation/Key.java b/src/main/java/com/lambdaworks/redis/dynamic/annotation/Key.java new file mode 100644 index 0000000000..3f2d1bbc47 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/dynamic/annotation/Key.java @@ -0,0 +1,16 @@ +package com.lambdaworks.redis.dynamic.annotation; + +import java.lang.annotation.*; + +/** + * Marker annotation to declare a method parameter as key. + * + * @author Mark Paluch + * @see Value + * @since 5.0 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.PARAMETER) +@Documented +public @interface Key { +} diff --git a/src/main/java/com/lambdaworks/redis/dynamic/annotation/Param.java b/src/main/java/com/lambdaworks/redis/dynamic/annotation/Param.java new file mode 100644 index 0000000000..1f939dbdef --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/dynamic/annotation/Param.java @@ -0,0 +1,23 @@ +package com.lambdaworks.redis.dynamic.annotation; + +import java.lang.annotation.*; + +/** + * Annotation to bind method parameters using their name. + * + * @author Mark Paluch + * @see Key + * @since 5.0 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.PARAMETER) +@Documented +public @interface Param { + + /** + * Name of the parameter. + * + * @return + */ + String value(); +} diff --git a/src/main/java/com/lambdaworks/redis/dynamic/annotation/Value.java b/src/main/java/com/lambdaworks/redis/dynamic/annotation/Value.java new file mode 100644 index 0000000000..9eef7135e6 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/dynamic/annotation/Value.java @@ -0,0 +1,16 @@ +package com.lambdaworks.redis.dynamic.annotation; + +import java.lang.annotation.*; + +/** + * Marker annotation to declare a method parameter as value. + * + * @author Mark Paluch + * @see Key + * @since 5.0 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.PARAMETER) +@Documented +public @interface Value { +} diff --git a/src/main/java/com/lambdaworks/redis/dynamic/annotation/package-info.java b/src/main/java/com/lambdaworks/redis/dynamic/annotation/package-info.java new file mode 100644 index 0000000000..492b5ff59c --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/dynamic/annotation/package-info.java @@ -0,0 +1,4 @@ +/** + * Central domain abstractions to be used in combination with Redis Command interfaces. + */ +package com.lambdaworks.redis.dynamic.annotation; \ No newline at end of file diff --git a/src/main/java/com/lambdaworks/redis/dynamic/codec/AnnotationRedisCodecResolver.java b/src/main/java/com/lambdaworks/redis/dynamic/codec/AnnotationRedisCodecResolver.java new file mode 100644 index 0000000000..a8a52f78bc --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/dynamic/codec/AnnotationRedisCodecResolver.java @@ -0,0 +1,197 @@ +package com.lambdaworks.redis.dynamic.codec; + +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +import com.lambdaworks.redis.dynamic.annotation.Key; +import com.lambdaworks.redis.dynamic.annotation.Value; +import com.lambdaworks.redis.codec.RedisCodec; +import com.lambdaworks.redis.dynamic.CommandMethod; +import com.lambdaworks.redis.dynamic.parameter.Parameter; +import com.lambdaworks.redis.dynamic.support.ClassTypeInformation; +import com.lambdaworks.redis.dynamic.support.TypeInformation; +import com.lambdaworks.redis.internal.LettuceAssert; +import com.lambdaworks.redis.internal.LettuceLists; + +/** + * Annotation-based {@link RedisCodecResolver}. Considers {@code @Key} and {@code @Value} annotations of method parameters to + * determine a {@link RedisCodec} that is able to handle all involved types. + * + * @author Mark Paluch + * @since 5.0 + * @see Key + * @see Value + */ +public class AnnotationRedisCodecResolver implements RedisCodecResolver { + + private final List> codecs; + + /** + * Creates a new {@link AnnotationRedisCodecResolver} given a {@link List} of {@link RedisCodec}s. + * + * @param codecs must not be {@literal null}. + */ + public AnnotationRedisCodecResolver(List> codecs) { + + LettuceAssert.notNull(codecs, "List of RedisCodecs must not be null"); + + this.codecs = LettuceLists.unmodifiableList(codecs); + } + + @Override + public RedisCodec resolve(CommandMethod commandMethod) { + + LettuceAssert.notNull(commandMethod, "CommandMethod must not be null"); + + Set> keyTypes = findTypes(commandMethod, Key.class); + Set> valueTypes = findTypes(commandMethod, Value.class); + + if (keyTypes.isEmpty() && valueTypes.isEmpty()) { + + Voted> voted = voteForTypeMajority(commandMethod); + if (voted != null) { + return voted.subject; + } + + return codecs.get(0); + } + + if ((keyTypes.size() == 1 && (valueTypes.isEmpty() || valueTypes.size() == 1)) + || (valueTypes.size() == 1 && (keyTypes.isEmpty() || keyTypes.size() == 1))) { + + RedisCodec codec = resolveCodec(keyTypes, valueTypes); + if (codec != null) { + return codec; + } + } + + throw new IllegalStateException(String.format("Cannot resolve Codec for method %s", commandMethod.getMethod())); + } + + private Voted> voteForTypeMajority(CommandMethod commandMethod) { + + List>> votes = codecs.stream().map(redisCodec -> new Voted>(redisCodec, 0)) + .collect(Collectors.toList()); + + commandMethod.getParameters().getBindableParameters().forEach(parameter -> { + + for (Voted> vote : votes) { + ClassTypeInformation typeInformation = ClassTypeInformation.from(vote.subject.getClass()); + + TypeInformation superTypeInformation = typeInformation.getSuperTypeInformation(RedisCodec.class); + + List> typeArguments = superTypeInformation.getTypeArguments(); + + if (typeArguments.size() != 2) { + continue; + } + + TypeInformation keyType = typeArguments.get(0); + TypeInformation valueType = typeArguments.get(1); + + if (keyType.isAssignableFrom(parameter.getTypeInformation())) { + vote.votes++; + } + + if (valueType.isAssignableFrom(parameter.getTypeInformation())) { + vote.votes++; + } + } + }); + + Collections.sort(votes); + if (votes.isEmpty()) { + return null; + } + + Voted> voted = votes.get(votes.size() - 1); + + if (voted.votes == 0) { + return null; + } + + return voted; + } + + private RedisCodec resolveCodec(Set> keyTypes, Set> valueTypes) { + + Class keyType = keyTypes.isEmpty() ? null : keyTypes.iterator().next(); + Class valueType = valueTypes.isEmpty() ? null : valueTypes.iterator().next(); + + for (RedisCodec codec : codecs) { + + ClassTypeInformation typeInformation = ClassTypeInformation.from(codec.getClass()); + TypeInformation keyTypeArgument = typeInformation.getTypeArgument(RedisCodec.class, 0); + TypeInformation valueTypeArgument = typeInformation.getTypeArgument(RedisCodec.class, 1); + + if (keyTypeArgument == null || valueTypeArgument == null) { + continue; + } + + boolean keyMatch = false; + boolean valueMatch = false; + + if (keyType != null) { + keyMatch = keyTypeArgument.isAssignableFrom(ClassTypeInformation.from(keyType)); + } + + if (valueType != null) { + valueMatch = valueTypeArgument.isAssignableFrom(ClassTypeInformation.from(valueType)); + } + + if (keyType != null && valueType != null && keyMatch && valueMatch) { + return codec; + } + + if (keyType != null && valueType == null && keyMatch) { + return codec; + } + + if (keyType == null && valueType != null && valueMatch) { + return codec; + } + } + + return null; + } + + private Set> findTypes(CommandMethod commandMethod, Class annotation) { + + Set> types = new HashSet<>(); + + for (Parameter parameter : commandMethod.getParameters().getBindableParameters()) { + + types.addAll(parameter.getAnnotations().stream() + .filter(parameterAnnotation -> annotation.isAssignableFrom(parameterAnnotation.getClass())) + .map(parameterAnnotation -> { + if (parameter.getTypeInformation().isCollectionLike() + && !parameter.getTypeInformation().getType().isArray()) { + return parameter.getTypeInformation().getComponentType().getType(); + } + return parameter.getTypeInformation().getType(); + + }).collect(Collectors.toList())); + } + + return types; + } + + private static class Voted implements Comparable> { + + private T subject; + private int votes; + + public Voted(T subject, int votes) { + this.subject = subject; + this.votes = votes; + } + + @Override + public int compareTo(Voted o) { + return votes - o.votes; + } + } +} diff --git a/src/main/java/com/lambdaworks/redis/dynamic/codec/RedisCodecResolver.java b/src/main/java/com/lambdaworks/redis/dynamic/codec/RedisCodecResolver.java new file mode 100644 index 0000000000..7b463c71e7 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/dynamic/codec/RedisCodecResolver.java @@ -0,0 +1,21 @@ +package com.lambdaworks.redis.dynamic.codec; + +import com.lambdaworks.redis.codec.RedisCodec; +import com.lambdaworks.redis.dynamic.CommandMethod; + +/** + * Strategy interface to resolve a {@link RedisCodec} for a {@link CommandMethod}. + * + * @author Mark Paluch + * @since 5.0 + */ +public interface RedisCodecResolver { + + /** + * Resolve a {@link RedisCodec} for the given {@link CommandMethod}. + * + * @param commandMethod must not be {@literal null}. + * @return the resolved {@link RedisCodec} or {@literal null} if not resolvable. + */ + RedisCodec resolve(CommandMethod commandMethod); +} diff --git a/src/main/java/com/lambdaworks/redis/dynamic/domain/FlushMode.java b/src/main/java/com/lambdaworks/redis/dynamic/domain/FlushMode.java new file mode 100644 index 0000000000..d55881ee75 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/dynamic/domain/FlushMode.java @@ -0,0 +1,8 @@ +package com.lambdaworks.redis.dynamic.domain; + +/** + * @author Mark Paluch + */ +public enum FlushMode { + DEFAULT, ENQUEUE, FLUSH; +} diff --git a/src/main/java/com/lambdaworks/redis/dynamic/domain/Timeout.java b/src/main/java/com/lambdaworks/redis/dynamic/domain/Timeout.java new file mode 100644 index 0000000000..0c8e6b0b7e --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/dynamic/domain/Timeout.java @@ -0,0 +1,55 @@ +package com.lambdaworks.redis.dynamic.domain; + +import java.util.concurrent.TimeUnit; + +import com.lambdaworks.redis.dynamic.annotation.Command; +import com.lambdaworks.redis.internal.LettuceAssert; + +/** + * Timeout value object to represent a timeout value with its {@link TimeUnit}. + * + * @author Mark Paluch + * @since 5.0 + * @see Command + */ +public class Timeout { + + private final long timeout; + private final TimeUnit timeUnit; + + private Timeout(long timeout, TimeUnit timeUnit) { + + LettuceAssert.isTrue(timeout >= 0, "Timeout must be greater or equal to zero"); + LettuceAssert.notNull(timeUnit, "TimeUnit must not be null"); + + this.timeout = timeout; + this.timeUnit = timeUnit; + } + + /** + * Create a {@link Timeout}. + * + * @param timeout the timeout value, must be non-negative. + * @param timeUnit the associated {@link TimeUnit}, must not be {@literal null}. + * @return the {@link Timeout}. + */ + public static Timeout create(long timeout, TimeUnit timeUnit) { + return new Timeout(timeout, timeUnit); + } + + /** + * + * @return the timeout value. + */ + public long getTimeout() { + return timeout; + } + + /** + * + * @return the {@link TimeUnit}. + */ + public TimeUnit getTimeUnit() { + return timeUnit; + } +} diff --git a/src/main/java/com/lambdaworks/redis/dynamic/domain/package-info.java b/src/main/java/com/lambdaworks/redis/dynamic/domain/package-info.java new file mode 100644 index 0000000000..86723bb0a4 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/dynamic/domain/package-info.java @@ -0,0 +1,4 @@ +/** + * Core annotations to be used with Redis Command interfaces. + */ +package com.lambdaworks.redis.dynamic.domain; \ No newline at end of file diff --git a/src/main/java/com/lambdaworks/redis/dynamic/intercept/DefaultMethodInvocation.java b/src/main/java/com/lambdaworks/redis/dynamic/intercept/DefaultMethodInvocation.java new file mode 100644 index 0000000000..7e474e337b --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/dynamic/intercept/DefaultMethodInvocation.java @@ -0,0 +1,30 @@ +package com.lambdaworks.redis.dynamic.intercept; + +import java.lang.reflect.Method; + +/** + * Default implementation of {@link MethodInvocation} + * + * @author Mark Paluch + */ +abstract class DefaultMethodInvocation implements MethodInvocation { + + private final Method method; + private final Object[] arguments; + + DefaultMethodInvocation(Method method, Object[] arguments) { + + this.method = method; + this.arguments = arguments; + } + + @Override + public Method getMethod() { + return method; + } + + @Override + public Object[] getArguments() { + return arguments; + } +} diff --git a/src/main/java/com/lambdaworks/redis/dynamic/intercept/InvocationProxyFactory.java b/src/main/java/com/lambdaworks/redis/dynamic/intercept/InvocationProxyFactory.java new file mode 100644 index 0000000000..38a81d48bc --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/dynamic/intercept/InvocationProxyFactory.java @@ -0,0 +1,113 @@ +package com.lambdaworks.redis.dynamic.intercept; + +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import com.lambdaworks.redis.internal.AbstractInvocationHandler; +import com.lambdaworks.redis.internal.LettuceAssert; +import com.lambdaworks.redis.internal.LettuceLists; + +/** + * Factory to create invocation proxies. + *

    + * Method calls to invocation proxies can be intercepted and modified by a chain of {@link MethodInterceptor}s. Each + * {@link MethodInterceptor} can continue the call chain, terminate prematurely or modify all aspects of a {@link Method} + * invocation. + *

    + * {@link InvocationProxyFactory} produces invocation proxies which can implement multiple interface type. Any non-interface + * types are rejected. + * + * @author Mark Paluch + * @since 5.0 + * @see MethodInterceptor + * @see MethodInvocation + */ +public class InvocationProxyFactory { + + private final List interceptors = new ArrayList<>(); + private final List> interfaces = new ArrayList<>(); + + /** + * Create a proxy instance give a {@link ClassLoader}. + * + * @param classLoader must not be {@literal null}. + * @param inferred result type. + * @return the invocation proxy instance. + */ + @SuppressWarnings("unchecked") + public T createProxy(ClassLoader classLoader) { + + LettuceAssert.notNull(classLoader, "ClassLoader must not be null"); + + Class[] interfaces = this.interfaces.toArray(new Class[this.interfaces.size()]); + + return (T) Proxy.newProxyInstance(classLoader, interfaces, new InterceptorChainInvocationHandler(interceptors)); + } + + /** + * Add a interface type that should be implemented by the resulting invocation proxy. + * + * @param ifc must not be {@literal null} and must be an interface type. + */ + public void addInterface(Class ifc) { + + LettuceAssert.notNull(ifc, "Interface type must not be null"); + LettuceAssert.isTrue(ifc.isInterface(), "Type must be an interface"); + + this.interfaces.add(ifc); + } + + /** + * Add a {@link MethodInterceptor} to the interceptor chain. + * + * @param interceptor notNull + */ + public void addInterceptor(MethodInterceptor interceptor) { + + LettuceAssert.notNull(interceptor, "MethodInterceptor must not be null"); + + this.interceptors.add(interceptor); + } + + /** + * {@link MethodInterceptor}-based {@link InterceptorChainInvocationHandler}. + */ + private static class InterceptorChainInvocationHandler extends AbstractInvocationHandler { + + private final List interceptors; + + InterceptorChainInvocationHandler(List interceptors) { + this.interceptors = LettuceLists.newList(interceptors); + } + + @Override + protected Object handleInvocation(Object proxy, Method method, Object[] args) throws Throwable { + + Iterator iterator = interceptors.iterator(); + + if (iterator.hasNext()) { + return iterator.next().invoke(getInvocation(method, args, iterator)); + } + + return null; + } + + private DefaultMethodInvocation getInvocation(final Method method, final Object[] args, + final Iterator iterator) { + return new DefaultMethodInvocation(method, args) { + + @Override + public Object proceed() throws Throwable { + + if (iterator.hasNext()) { + return iterator.next().invoke(getInvocation(method, args, iterator)); + } + return null; + } + }; + } + } +} diff --git a/src/main/java/com/lambdaworks/redis/dynamic/intercept/MethodInterceptor.java b/src/main/java/com/lambdaworks/redis/dynamic/intercept/MethodInterceptor.java new file mode 100644 index 0000000000..79d2aa0e28 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/dynamic/intercept/MethodInterceptor.java @@ -0,0 +1,24 @@ +package com.lambdaworks.redis.dynamic.intercept; + +/** + * Intercepts calls on an interface on its way to the target. These are nested "on top" of the target. + * + *

    + * Implementing classes are required to implement the {@link #invoke(MethodInvocation)} method to modify the original behavior. + * + * @author Mark Paluch + * @since 5.0 + */ +public interface MethodInterceptor { + + /** + * Implement this method to perform extra treatments before and after the invocation. Polite implementations would certainly + * like to invoke {@link MethodInvocation#proceed()}. + * + * @param invocation the method invocation + * @return the result of the call to {@link MethodInvocation#proceed()}, might be intercepted by the interceptor. + * @throws Throwable if the interceptors or the target-object throws an exception. + */ + Object invoke(MethodInvocation invocation) throws Throwable; + +} \ No newline at end of file diff --git a/src/main/java/com/lambdaworks/redis/dynamic/intercept/MethodInvocation.java b/src/main/java/com/lambdaworks/redis/dynamic/intercept/MethodInvocation.java new file mode 100644 index 0000000000..62c31e921b --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/dynamic/intercept/MethodInvocation.java @@ -0,0 +1,36 @@ +package com.lambdaworks.redis.dynamic.intercept; + +import java.lang.reflect.Method; + +/** + * Description of an invocation to a method, given to an interceptor upon method-call. + * + *

    + * A method invocation is a joinpoint and can be intercepted by a method interceptor. + * + * @see MethodInterceptor + * @author Mark Paluch + * @since 5.0 + */ +public interface MethodInvocation { + + /** + * Proceed to the next interceptor in the chain. + *

    + * The implementation and the semantics of this method depends on the actual joinpoint type (see the children interfaces). + * + * @return see the children interfaces' proceed definition + * @throws Throwable if the invocation throws an exception + */ + Object proceed() throws Throwable; + + /** + * @return the originally called {@link Method}. + */ + Method getMethod(); + + /** + * @return method call arguments. + */ + Object[] getArguments(); +} diff --git a/src/main/java/com/lambdaworks/redis/dynamic/intercept/package-info.java b/src/main/java/com/lambdaworks/redis/dynamic/intercept/package-info.java new file mode 100644 index 0000000000..e3c1fb4dc6 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/dynamic/intercept/package-info.java @@ -0,0 +1,4 @@ +/** + * Invocation proxy support. + */ +package com.lambdaworks.redis.dynamic.intercept; \ No newline at end of file diff --git a/src/main/java/com/lambdaworks/redis/dynamic/output/CodecAwareOutputFactoryResolver.java b/src/main/java/com/lambdaworks/redis/dynamic/output/CodecAwareOutputFactoryResolver.java new file mode 100644 index 0000000000..a4cb773f54 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/dynamic/output/CodecAwareOutputFactoryResolver.java @@ -0,0 +1,90 @@ +package com.lambdaworks.redis.dynamic.output; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.lambdaworks.redis.codec.RedisCodec; +import com.lambdaworks.redis.dynamic.support.ClassTypeInformation; +import com.lambdaworks.redis.dynamic.support.TypeInformation; +import com.lambdaworks.redis.internal.LettuceAssert; + +/** + * {@link RedisCodec}-aware implementation of {@link CommandOutputFactoryResolver}. This implementation inspects + * {@link RedisCodec} regarding its type and enhances {@link OutputSelector} for {@link CommandOutputFactory} resolution. + * + * @author Mark Paluch + * @since 5.0 + */ +public class CodecAwareOutputFactoryResolver implements CommandOutputFactoryResolver { + + private final CommandOutputFactoryResolver delegate; + private final TypeInformation keyType; + private final TypeInformation valueType; + private final Map> typeVariables = new HashMap<>(); + + /** + * Create a new {@link CodecAwareOutputFactoryResolver} given {@link CommandOutputFactoryResolver} and {@link RedisCodec}. + * + * @param delegate must not be {@literal null}. + * @param redisCodec must not be {@literal null}. + */ + public CodecAwareOutputFactoryResolver(CommandOutputFactoryResolver delegate, RedisCodec redisCodec) { + + LettuceAssert.notNull(delegate, "CommandOutputFactoryResolver delegate must not be null"); + LettuceAssert.notNull(redisCodec, "RedisCodec must not be null"); + + this.delegate = delegate; + + ClassTypeInformation typeInformation = ClassTypeInformation.from(redisCodec.getClass()); + TypeInformation superTypeInformation = typeInformation.getSuperTypeInformation(RedisCodec.class); + List> typeArguments = superTypeInformation.getTypeArguments(); + + this.keyType = typeArguments.get(0); + this.valueType = typeArguments.get(1); + + this.typeVariables.put("K", keyType); + this.typeVariables.put("V", valueType); + } + + @Override + public CommandOutputFactory resolveCommandOutput(OutputSelector outputSelector) { + + Map> typeVariables = new HashMap<>(outputSelector.getTypeVariables()); + typeVariables.putAll(this.typeVariables); + + return delegate.resolveCommandOutput( + new OutputSelector(outputSelector.getTypeInformation(), isKeyType(outputSelector.getTypeInformation()), + isValueType(outputSelector.getTypeInformation()), typeVariables)); + } + + @Override + public CommandOutputFactory resolveStreamingCommandOutput(OutputSelector outputSelector) { + + Map> typeVariables = new HashMap<>(outputSelector.getTypeVariables()); + typeVariables.putAll(this.typeVariables); + + return delegate.resolveStreamingCommandOutput( + new OutputSelector(outputSelector.getTypeInformation(), isKeyType(outputSelector.getTypeInformation()), + isValueType(outputSelector.getTypeInformation()), typeVariables)); + } + + protected boolean isKeyType(TypeInformation typeInformation) { + return walkComponentTypeAssignability(typeInformation, keyType); + } + + protected boolean isValueType(TypeInformation typeInformation) { + return walkComponentTypeAssignability(typeInformation, valueType); + } + + private boolean walkComponentTypeAssignability(TypeInformation typeInformation, TypeInformation sourceType) { + + do { + if (typeInformation.isAssignableFrom(sourceType)) { + return true; + } + typeInformation = typeInformation.getComponentType(); + } while (typeInformation != null); + return false; + } +} diff --git a/src/main/java/com/lambdaworks/redis/dynamic/output/CommandOutputFactory.java b/src/main/java/com/lambdaworks/redis/dynamic/output/CommandOutputFactory.java new file mode 100644 index 0000000000..8c5e015e58 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/dynamic/output/CommandOutputFactory.java @@ -0,0 +1,24 @@ +package com.lambdaworks.redis.dynamic.output; + +import com.lambdaworks.redis.codec.RedisCodec; +import com.lambdaworks.redis.output.CommandOutput; + +/** + * Strategy interface to create {@link CommandOutput} given {@link RedisCodec}. + * + *

    + * Implementing classes usually produce the same {@link CommandOutput} type. + * + * @author Mark Paluch + * @since 5.0 + */ +public interface CommandOutputFactory { + + /** + * Create and initialize a new {@link CommandOutput} given {@link RedisCodec}. + * + * @param codec must not be {@literal null}. + * @return the new {@link CommandOutput}. + */ + CommandOutput create(RedisCodec codec); +} diff --git a/src/main/java/com/lambdaworks/redis/dynamic/output/CommandOutputFactoryResolver.java b/src/main/java/com/lambdaworks/redis/dynamic/output/CommandOutputFactoryResolver.java new file mode 100644 index 0000000000..b850071cf9 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/dynamic/output/CommandOutputFactoryResolver.java @@ -0,0 +1,33 @@ +package com.lambdaworks.redis.dynamic.output; + +/** + * Strategy interface to resolve a {@link CommandOutputFactory} based on a {@link OutputSelector}. Resolution of + * {@link CommandOutputFactory} is based on {@link com.lambdaworks.redis.dynamic.CommandMethod} result types and can be + * influenced whether the result type is a key or value result type. Additional type variables (based on the used + * {@link com.lambdaworks.redis.codec.RedisCodec} are hints to improve output resolution. + * + * @author Mark Paluch + * @since 5.0 + * @see OutputSelector + */ +public interface CommandOutputFactoryResolver { + + /** + * Resolve a regular {@link CommandOutputFactory} that produces the {@link com.lambdaworks.redis.output.CommandOutput} + * result component type. + * + * @param outputSelector must not be {@literal null}. + * @return the {@link CommandOutputFactory} if resolved, {@literal null} otherwise. + */ + CommandOutputFactory resolveCommandOutput(OutputSelector outputSelector); + + /** + * Resolve a streaming {@link CommandOutputFactory} that produces the {@link com.lambdaworks.redis.output.StreamingOutput} + * result component type. + * + * @param outputSelector must not be {@literal null}. + * @return the {@link CommandOutputFactory} that implements {@link com.lambdaworks.redis.output.StreamingOutput} if + * resolved, {@literal null} otherwise. + */ + CommandOutputFactory resolveStreamingCommandOutput(OutputSelector outputSelector); +} diff --git a/src/main/java/com/lambdaworks/redis/dynamic/output/CommandOutputResolverSupport.java b/src/main/java/com/lambdaworks/redis/dynamic/output/CommandOutputResolverSupport.java new file mode 100644 index 0000000000..e6728b00bb --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/dynamic/output/CommandOutputResolverSupport.java @@ -0,0 +1,73 @@ +package com.lambdaworks.redis.dynamic.output; + +import com.lambdaworks.redis.dynamic.support.TypeInformation; +import com.lambdaworks.redis.dynamic.support.TypeVariableTypeInformation; +import com.lambdaworks.redis.internal.LettuceClassUtils; + +/** + * Base class for {@link CommandOutputFactory} resolution such as {@link OutputRegistryCommandOutputFactoryResolver}. + *

    + * This class provides methods to check provider/selector type assignability. Subclasses are responsible for calling methods in + * this class in the correct order. + * + * @author Mark Paluch + */ +public abstract class CommandOutputResolverSupport { + + /** + * Overridable hook to check whether {@code selector} can be assigned from the provider type {@code provider}. + *

    + * This method descends the component type hierarchy and considers primitive/wrapper type conversion. + * + * @param selector must not be {@literal null}. + * @param provider must not be {@literal null}. + * @return {@literal true} if selector can be assigned from its provider type. + */ + protected boolean isAssignableFrom(OutputSelector selector, OutputType provider) { + + TypeInformation outputTypeInformation = provider.getTypeInformation(); + TypeInformation selectorTypeInformation = selector.getTypeInformation(); + + do { + + if (outputTypeInformation instanceof TypeVariableTypeInformation) { + if (selector.containsTypeVariable(outputTypeInformation.toString())) { + outputTypeInformation = selector.getTypeVariable(outputTypeInformation.toString()); + } + } + + if (outputTypeInformation.getType() == Object.class && selectorTypeInformation.getComponentType() != null) { + + if (provider.getPrimaryType() == OutputRegistry.KeySurrogate.class) { + return selector.isKey(); + } + + if (provider.getPrimaryType() == OutputRegistry.ValueSurrogate.class) { + return selector.isValue(); + } + } + + if (!isAssignableFrom(selectorTypeInformation, outputTypeInformation)) { + return false; + } + + outputTypeInformation = outputTypeInformation.getComponentType(); + selectorTypeInformation = selectorTypeInformation.getComponentType(); + + } while (outputTypeInformation != null && outputTypeInformation.getComponentType() != outputTypeInformation + && selectorTypeInformation != null && selectorTypeInformation.getComponentType() != selectorTypeInformation); + return true; + } + + /** + * Overridable hook to check whether {@code selector} can be assigned from the provider type {@code provider}. + * + * @param selector must not be {@literal null}. + * @param provider must not be {@literal null}. + * @return {@literal true} if selector can be assigned from its provider type. + */ + protected boolean isAssignableFrom(TypeInformation selector, TypeInformation provider) { + + return selector.isAssignableFrom(provider) || LettuceClassUtils.isAssignable(selector.getType(), provider.getType()); + } +} diff --git a/src/main/java/com/lambdaworks/redis/dynamic/output/OutputRegistry.java b/src/main/java/com/lambdaworks/redis/dynamic/output/OutputRegistry.java new file mode 100644 index 0000000000..faefd91fa6 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/dynamic/output/OutputRegistry.java @@ -0,0 +1,197 @@ +package com.lambdaworks.redis.dynamic.output; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +import com.lambdaworks.redis.dynamic.support.ClassTypeInformation; +import com.lambdaworks.redis.dynamic.support.TypeInformation; +import com.lambdaworks.redis.dynamic.support.TypeVariableTypeInformation; +import com.lambdaworks.redis.internal.LettuceAssert; +import com.lambdaworks.redis.output.*; + +/** + * Registry for {@link CommandOutput} types and their {@link CommandOutputFactory factories}. + * + * @author Mark Paluch + * @since 5.0 + * @see CommandOutput + */ +public class OutputRegistry { + + private final static Map BUILTIN = new LinkedHashMap<>(); + private final Map registry = new LinkedHashMap<>(); + + static { + + Map registry = new LinkedHashMap<>(); + + register(registry, ListOfMapsOutput.class, ListOfMapsOutput::new); + register(registry, ArrayOutput.class, ArrayOutput::new); + register(registry, DoubleOutput.class, DoubleOutput::new); + register(registry, ByteArrayOutput.class, ByteArrayOutput::new); + register(registry, IntegerOutput.class, IntegerOutput::new); + + register(registry, KeyOutput.class, KeyOutput::new); + register(registry, ValueOutput.class, ValueOutput::new); + register(registry, KeyListOutput.class, KeyListOutput::new); + register(registry, ValueListOutput.class, ValueListOutput::new); + register(registry, MapOutput.class, MapOutput::new); + + register(registry, ValueSetOutput.class, ValueSetOutput::new); + + register(registry, BooleanOutput.class, BooleanOutput::new); + register(registry, BooleanListOutput.class, BooleanListOutput::new); + register(registry, GeoCoordinatesListOutput.class, GeoCoordinatesListOutput::new); + register(registry, GeoCoordinatesValueListOutput.class, GeoCoordinatesValueListOutput::new); + register(registry, ScoredValueListOutput.class, ScoredValueListOutput::new); + register(registry, StringValueListOutput.class, StringValueListOutput::new); + register(registry, ValueValueListOutput.class, ValueValueListOutput::new); + + register(registry, StringListOutput.class, StringListOutput::new); + register(registry, VoidOutput.class, VoidOutput::new); + + BUILTIN.putAll(registry); + } + + /** + * Create a new {@link OutputRegistry} registering builtin {@link CommandOutput} types. + */ + public OutputRegistry() { + this(true); + } + + /** + * Create a new {@link OutputRegistry}. + * + * @param registerBuiltin {@literal true} to register builtin {@link CommandOutput} types. + */ + public OutputRegistry(boolean registerBuiltin) { + + if (registerBuiltin) { + registry.putAll(BUILTIN); + } + } + + /** + * Register a {@link CommandOutput} type with its {@link CommandOutputFactory}. + * + * @param commandOutputClass must not be {@literal null}. + * @param commandOutputFactory must not be {@literal null}. + */ + public > void register(Class commandOutputClass, + CommandOutputFactory commandOutputFactory) { + + LettuceAssert.notNull(commandOutputClass, "CommandOutput class must not be null"); + LettuceAssert.notNull(commandOutputFactory, "CommandOutputFactory must not be null"); + + register(registry, commandOutputClass, commandOutputFactory); + } + + /** + * Return the registry map. + * + * @return map of {@link OutputType} to {@link CommandOutputFactory}. + */ + Map getRegistry() { + return registry; + } + + private static void register(Map registry, + Class commandOutputClass, CommandOutputFactory commandOutputFactory) { + + List outputTypes = getOutputTypes(commandOutputClass); + + for (OutputType outputType : outputTypes) { + registry.put(outputType, commandOutputFactory); + } + } + + private static List getOutputTypes(Class commandOutputClass) { + + OutputType streamingType = getStreamingType(commandOutputClass); + OutputType componentOutputType = getOutputComponentType(commandOutputClass); + + List types = new ArrayList<>(2); + if (streamingType != null) { + types.add(streamingType); + } + + if (componentOutputType != null) { + types.add(componentOutputType); + } + + return types; + } + + /** + * Retrieve {@link OutputType} for a {@link StreamingOutput} type. + * + * @param commandOutputClass + * @return + */ + static OutputType getStreamingType(Class commandOutputClass) { + + ClassTypeInformation classTypeInformation = ClassTypeInformation.from(commandOutputClass); + + TypeInformation superTypeInformation = classTypeInformation.getSuperTypeInformation(StreamingOutput.class); + + if (superTypeInformation == null) { + return null; + } + + List> typeArguments = superTypeInformation.getTypeArguments(); + Class primaryType = getPrimaryType(typeArguments.get(0)); + + return new OutputType(primaryType, commandOutputClass, typeArguments.get(0), true); + } + + /** + * Retrieve {@link OutputType} for a {@link CommandOutput} type. + * + * @param commandOutputClass + * @return + */ + static OutputType getOutputComponentType(Class commandOutputClass) { + + ClassTypeInformation classTypeInformation = ClassTypeInformation.from(commandOutputClass); + + TypeInformation superTypeInformation = classTypeInformation.getSuperTypeInformation(CommandOutput.class); + + if (superTypeInformation == null) { + return null; + } + + List> typeArguments = superTypeInformation.getTypeArguments(); + Class primaryType = getPrimaryType(typeArguments.get(2)); + + return new OutputType(primaryType, commandOutputClass, typeArguments.get(2), false); + } + + private static Class getPrimaryType(TypeInformation typeInformation) { + + Class primaryType = typeInformation.getType(); + while (typeInformation.isCollectionLike() && typeInformation != typeInformation.getComponentType()) { + typeInformation = typeInformation.getComponentType(); + } + + if (typeInformation instanceof TypeVariableTypeInformation) { + + // TODO: Requires maybe a more sophisticated resolution. + if (typeInformation.toString().equals("K")) { + primaryType = KeySurrogate.class; + } + + if (typeInformation.toString().equals("V")) { + primaryType = ValueSurrogate.class; + } + } + return primaryType; + } + + static class KeySurrogate { + } + + static class ValueSurrogate { + } + +} diff --git a/src/main/java/com/lambdaworks/redis/dynamic/output/OutputRegistryCommandOutputFactoryResolver.java b/src/main/java/com/lambdaworks/redis/dynamic/output/OutputRegistryCommandOutputFactoryResolver.java new file mode 100644 index 0000000000..a2ebdf79be --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/dynamic/output/OutputRegistryCommandOutputFactoryResolver.java @@ -0,0 +1,89 @@ +package com.lambdaworks.redis.dynamic.output; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import com.lambdaworks.redis.dynamic.support.ClassTypeInformation; +import com.lambdaworks.redis.internal.LettuceAssert; +import com.lambdaworks.redis.output.CommandOutput; + +/** + * {@link CommandOutputFactoryResolver} using {@link OutputRegistry} to resolve a {@link CommandOutputFactory}. + *

    + * Types registered in {@link OutputRegistry} are inspected for the types they produce and matched with the declared repository + * method. If resolution yields multiple {@link CommandOutput}s, the first matched output is used. + * + * @author Mark Paluch + * @since 5.0 + * @see OutputRegistry + */ +public class OutputRegistryCommandOutputFactoryResolver extends CommandOutputResolverSupport + implements CommandOutputFactoryResolver { + + private static final ClassTypeInformation COMMAND_OUTPUT = ClassTypeInformation.from(CommandOutput.class); + + private final OutputRegistry outputRegistry; + + /** + * Create a new {@link OutputRegistryCommandOutputFactoryResolver} given {@link OutputRegistry}. + * + * @param outputRegistry must not be {@literal null}. + */ + public OutputRegistryCommandOutputFactoryResolver(OutputRegistry outputRegistry) { + + LettuceAssert.notNull(outputRegistry, "OutputRegistry must not be null"); + + this.outputRegistry = outputRegistry; + } + + @Override + public CommandOutputFactory resolveCommandOutput(OutputSelector outputSelector) { + + Map registry = outputRegistry.getRegistry(); + + Set outputTypes = registry.keySet().stream().filter((outputType) -> !outputType.isStreaming()) + .collect(Collectors.toSet()); + + List candidates = getCandidates(outputTypes, outputSelector); + + if (candidates.isEmpty()) { + return null; + } + + return registry.get(candidates.get(0)); + } + + @Override + public CommandOutputFactory resolveStreamingCommandOutput(OutputSelector outputSelector) { + + Map registry = outputRegistry.getRegistry(); + + Set outputTypes = registry.keySet().stream().filter(OutputType::isStreaming).collect(Collectors.toSet()); + + List candidates = getCandidates(outputTypes, outputSelector); + + if (candidates.isEmpty()) { + return null; + } + + return registry.get(candidates.get(0)); + } + + private List getCandidates(Collection outputTypes, OutputSelector outputSelector) { + + return outputTypes.stream().filter(outputType -> { + + if (COMMAND_OUTPUT.getType().isAssignableFrom(outputSelector.getTypeInformation().getType())) { + + if (outputSelector.getTypeInformation().getType().isAssignableFrom(outputType.getCommandOutputClass())) { + return true; + } + } + + return isAssignableFrom(outputSelector, outputType); + }).collect(Collectors.toList()); + } +} diff --git a/src/main/java/com/lambdaworks/redis/dynamic/output/OutputSelector.java b/src/main/java/com/lambdaworks/redis/dynamic/output/OutputSelector.java new file mode 100644 index 0000000000..f8847004b1 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/dynamic/output/OutputSelector.java @@ -0,0 +1,99 @@ +package com.lambdaworks.redis.dynamic.output; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import com.lambdaworks.redis.dynamic.support.TypeInformation; +import com.lambdaworks.redis.internal.LettuceAssert; + +/** + * Selector {@link CommandOutputFactory} resolution. + *

    + * A {@link OutputSelector} is based on the result {@link TypeInformation} and can supply additionaly whether the type is a key + * or value type. An optional {@link Map} with type variables (usually {@link com.lambdaworks.redis.codec.RedisCodec} type + * variables) can be supplied to resolve type variables inside of {@link com.lambdaworks.redis.output.CommandOutput}. + * + * @author Mark Paluch + * @since 5.0 + */ +public class OutputSelector { + + private final TypeInformation typeInformation; + private final boolean key; + private final boolean value; + private final Map> typeVariables; + + /** + * Create a new {@link OutputSelector} given {@link TypeInformation}. + * + * @param typeInformation must not be {@literal null}. + */ + public OutputSelector(TypeInformation typeInformation) { + this(typeInformation, false, false, Collections.emptyMap()); + } + + /** + * Create a new {@link OutputSelector} given {@link TypeInformation}, key/value flags and {@link Map} of type variables. + * + * @param typeInformation must not be {@literal null}. + * @param key + * @param value + * @param typeVariables must not be {@literal null}. + */ + public OutputSelector(TypeInformation typeInformation, boolean key, boolean value, + Map> typeVariables) { + + LettuceAssert.notNull(typeInformation, "Result TypeInformation must not be null"); + LettuceAssert.notNull(typeVariables, "Map of type variables must not be null"); + + this.typeInformation = typeInformation; + this.key = key; + this.value = value; + this.typeVariables = Collections.unmodifiableMap(new HashMap<>(typeVariables)); + } + + /** + * @param typeVariableName + * @return {@literal true} if the {@code typeVariableName} is provided. + */ + public boolean containsTypeVariable(String typeVariableName) { + return typeVariables.containsKey(typeVariableName); + } + + /** + * @param typeInformation + * @return the {@link TypeInformation} for a type variable. + */ + public TypeInformation getTypeVariable(String typeInformation) { + return typeVariables.get(typeInformation); + } + + /** + * @return the resulting {@link TypeInformation}. + */ + public TypeInformation getTypeInformation() { + return typeInformation; + } + + /** + * @return {@link Map} of type variables. + */ + public Map> getTypeVariables() { + return Collections.unmodifiableMap(typeVariables); + } + + /** + * @return {@literal true} if the {@link #getTypeInformation()} is a key-type. + */ + public boolean isKey() { + return key; + } + + /** + * @return {@literal true} if the {@link #getTypeInformation()} is a value-type. + */ + public boolean isValue() { + return value; + } +} diff --git a/src/main/java/com/lambdaworks/redis/dynamic/output/OutputType.java b/src/main/java/com/lambdaworks/redis/dynamic/output/OutputType.java new file mode 100644 index 0000000000..c4fc40c650 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/dynamic/output/OutputType.java @@ -0,0 +1,90 @@ +package com.lambdaworks.redis.dynamic.output; + +import com.lambdaworks.redis.dynamic.support.TypeInformation; +import com.lambdaworks.redis.internal.LettuceAssert; +import com.lambdaworks.redis.output.CommandOutput; + +/** + * Type descriptor for a {@link com.lambdaworks.redis.output.CommandOutput}. + *

    + * This value object describes the primary output type and the produced {@link TypeInformation} by the {@link CommandOutput} + * type. + *

    + * {@link OutputType} makes a distinction whether a {@link CommandOutput} is a + * {@link com.lambdaworks.redis.output.StreamingOutput} by providing {@code streaming}. Streaming outputs produce usually a + * component type hence they require an own {@link OutputType} descriptor. + * + * @author Mark Paluch + * @since 5.0 + */ +public class OutputType { + + private final Class primaryType; + private final Class commandOutputClass; + private final TypeInformation typeInformation; + private final boolean streaming; + + /** + * Create a new {@link OutputType} given {@code primaryType}, the {@code commandOutputClass}, {@link TypeInformation} and + * whether the {@link OutputType} is for a {@link com.lambdaworks.redis.output.StreamingOutput}. + * + * @param primaryType must not be {@literal null}. + * @param commandOutputClass must not be {@literal null}. + * @param typeInformation must not be {@literal null}. + * @param streaming {@literal true} if the type descriptor concerns the {@link com.lambdaworks.redis.output.StreamingOutput} + * result type. + */ + public OutputType(Class primaryType, Class commandOutputClass, + TypeInformation typeInformation, boolean streaming) { + + LettuceAssert.notNull(primaryType, "Primary type must not be null"); + LettuceAssert.notNull(commandOutputClass, "CommandOutput class must not be null"); + LettuceAssert.notNull(typeInformation, "TypeInformation must not be null"); + + this.primaryType = primaryType; + this.commandOutputClass = commandOutputClass; + this.typeInformation = typeInformation; + this.streaming = streaming; + } + + /** + * @return + */ + public Class getPrimaryType() { + return primaryType; + } + + /** + * @return + */ + public TypeInformation getTypeInformation() { + return typeInformation; + } + + /** + * @return + */ + public boolean isStreaming() { + return streaming; + } + + /** + * @return + */ + public Class getCommandOutputClass() { + return commandOutputClass; + } + + @Override + public String toString() { + + StringBuilder sb = new StringBuilder(); + sb.append(getClass().getSimpleName()); + sb.append(" [primaryType=").append(primaryType); + sb.append(", commandOutputClass=").append(commandOutputClass); + sb.append(", typeInformation=").append(typeInformation); + sb.append(", streaming=").append(streaming); + sb.append(']'); + return sb.toString(); + } +} diff --git a/src/main/java/com/lambdaworks/redis/dynamic/output/VoidOutput.java b/src/main/java/com/lambdaworks/redis/dynamic/output/VoidOutput.java new file mode 100644 index 0000000000..e40365cf0f --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/dynamic/output/VoidOutput.java @@ -0,0 +1,34 @@ +package com.lambdaworks.redis.dynamic.output; + +import java.nio.ByteBuffer; + +import com.lambdaworks.redis.codec.RedisCodec; +import com.lambdaworks.redis.output.CommandOutput; + +/** + * {@link Void} command output to consume data silently without actually processing it. + * + * @author Mark Paluch + * @since 5.0 + */ +class VoidOutput extends CommandOutput { + + /** + * Initialize a new instance that encodes and decodes keys and values using the supplied codec. + * + * @param codec Codec used to encode/decode keys and values, must not be {@literal null}. + */ + public VoidOutput(RedisCodec codec) { + super(codec, null); + } + + @Override + public void set(ByteBuffer bytes) { + // no-op + } + + @Override + public void set(long integer) { + // no-op + } +} diff --git a/src/main/java/com/lambdaworks/redis/dynamic/output/package-info.java b/src/main/java/com/lambdaworks/redis/dynamic/output/package-info.java new file mode 100644 index 0000000000..a8cd29d577 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/dynamic/output/package-info.java @@ -0,0 +1,4 @@ +/** + * {@link com.lambdaworks.redis.output.CommandOutput} resolution support. + */ +package com.lambdaworks.redis.dynamic.output; \ No newline at end of file diff --git a/src/main/java/com/lambdaworks/redis/dynamic/package-info.java b/src/main/java/com/lambdaworks/redis/dynamic/package-info.java new file mode 100644 index 0000000000..7ffe3d5810 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/dynamic/package-info.java @@ -0,0 +1,4 @@ +/** + * Core package for Redis Command Interface support through {@link com.lambdaworks.redis.dynamic.RedisCommandFactory}. + */ +package com.lambdaworks.redis.dynamic; \ No newline at end of file diff --git a/src/main/java/com/lambdaworks/redis/dynamic/parameter/ExecutionSpecificParameters.java b/src/main/java/com/lambdaworks/redis/dynamic/parameter/ExecutionSpecificParameters.java new file mode 100644 index 0000000000..c5ff8b6ab1 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/dynamic/parameter/ExecutionSpecificParameters.java @@ -0,0 +1,86 @@ +package com.lambdaworks.redis.dynamic.parameter; + +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.List; + +import com.lambdaworks.redis.dynamic.domain.FlushMode; +import com.lambdaworks.redis.dynamic.domain.Timeout; + +/** + * {@link Parameters}-implementation specific to execution. This implementation considers {@link Timeout} for a command method + * applying the appropriate synchronization. + * + * @author Mark Paluch + * @since 5.0 + * @see Timeout + */ +public class ExecutionSpecificParameters extends Parameters { + + private static final List> TYPES = Arrays.asList(FlushMode.class, Timeout.class); + + private final int flushModeIndex; + private final int timeoutIndex; + + /** + * Create new {@link ExecutionSpecificParameters} given a {@link Method}. + * + * @param method must not be {@literal null}. + */ + public ExecutionSpecificParameters(Method method) { + + super(method); + + int flushModeIndex = -1; + int timeoutIndex = -1; + + List parameters = getParameters(); + + for (int i = 0; i < method.getParameterCount(); i++) { + + Parameter methodParameter = parameters.get(i); + + if (methodParameter.isSpecialParameter()) { + if (methodParameter.isAssignableTo(Timeout.class)) { + timeoutIndex = i; + } + + if (methodParameter.isAssignableTo(FlushMode.class)) { + flushModeIndex = i; + } + } + } + + this.flushModeIndex = flushModeIndex; + this.timeoutIndex = timeoutIndex; + } + + public int getFlushModeIndex() { + return flushModeIndex; + } + + public int getTimeoutIndex() { + return timeoutIndex; + } + + @Override + protected ExecutionAwareParameter createParameter(Method method, int parameterIndex) { + return new ExecutionAwareParameter(method, parameterIndex); + } + + public boolean hasTimeoutIndex() { + return getTimeoutIndex() != -1; + } + + public static class ExecutionAwareParameter extends Parameter { + + public ExecutionAwareParameter(Method method, int parameterIndex) { + super(method, parameterIndex); + } + + @Override + public boolean isSpecialParameter() { + return super.isSpecialParameter() || TYPES.contains(getParameterType()); + } + } +} diff --git a/src/main/java/com/lambdaworks/redis/dynamic/parameter/MethodParametersAccessor.java b/src/main/java/com/lambdaworks/redis/dynamic/parameter/MethodParametersAccessor.java new file mode 100644 index 0000000000..303763b187 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/dynamic/parameter/MethodParametersAccessor.java @@ -0,0 +1,60 @@ +package com.lambdaworks.redis.dynamic.parameter; + +import com.lambdaworks.redis.dynamic.domain.FlushMode; +import com.lambdaworks.redis.dynamic.domain.Timeout; + +import java.util.Iterator; + +/** + * Accessor interface to method parameters during the actual invocation. + * + * @author Mark Paluch + * @since 5.0 + */ +public interface MethodParametersAccessor { + + /** + * @return number of parameters. + */ + int getParameterCount(); + + /** + * Returns the bindable value with the given index. Bindable means, that {@link FlushMode} and {@link Timeout} values are + * skipped without noticed in the index. For a method signature taking {@link String}, {@link Timeout} , {@link String}, + * {@code #getBindableParameter(1)} would return the second {@link String} value. + * + * @param index + * @return the bindable value. + */ + Object getBindableValue(int index); + + /** + * + * @param index + * @return {@literal true} if the parameter at {@code index} is a key. + */ + boolean isKey(int index); + + /** + * + * @param index + * @return {@literal true} if the parameter at {@code index} is a value. + */ + boolean isValue(int index); + + /** + * Returns an iterator over all bindable parameters. This means parameters implementing {@link Timeout} or + * {@link FlushMode} will not be included in this {@link Iterator}. + * + * @return + */ + Iterator iterator(); + + /** + * Resolve a parameter name to its index. + * + * @param name the name. + * @return + */ + int resolveParameterIndex(String name); +} diff --git a/src/main/java/com/lambdaworks/redis/dynamic/parameter/Parameter.java b/src/main/java/com/lambdaworks/redis/dynamic/parameter/Parameter.java new file mode 100644 index 0000000000..194b2b5079 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/dynamic/parameter/Parameter.java @@ -0,0 +1,122 @@ +package com.lambdaworks.redis.dynamic.parameter; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import com.lambdaworks.redis.dynamic.support.*; +import com.lambdaworks.redis.internal.LettuceAssert; +import com.lambdaworks.redis.internal.LettuceClassUtils; + +/** + * Abstracts a method parameter and exposes access to type and parameter information. + * + * @author Mark Paluch + * @since 5.0 + */ +public class Parameter { + + private final ParameterNameDiscoverer discoverer = new CompositeParameterNameDiscoverer( + new StandardReflectionParameterNameDiscoverer(), new AnnotationParameterNameDiscoverer()); + + private final Method method; + private final String name; + private final int parameterIndex; + private final TypeInformation typeInformation; + private final MethodParameter methodParameter; + + public Parameter(Method method, int parameterIndex) { + + this.method = method; + this.parameterIndex = parameterIndex; + this.methodParameter = new MethodParameter(method, parameterIndex); + this.methodParameter.initParameterNameDiscovery(discoverer); + this.name = methodParameter.getParameterName(); + this.typeInformation = ClassTypeInformation.fromMethodParameter(method, parameterIndex); + } + + /** + * Return the parameter annotation of the given type, if available. + * + * @param annotationType the annotation type to look for + * @return the annotation object, or {@code null} if not found + */ + public A findAnnotation(Class annotationType) { + return methodParameter.getParameterAnnotation(annotationType); + } + + /** + * Return all parameter annotations. + * + * @return the {@link List} of annotation objects. + */ + public List getAnnotations() { + + Annotation[] annotations = method.getParameterAnnotations()[parameterIndex]; + List result = new ArrayList<>(annotations.length); + Collections.addAll(result, annotations); + + return result; + } + + /** + * + * @return the parameter index. + */ + public int getParameterIndex() { + return parameterIndex; + } + + /** + * + * @return the parameter type. + */ + public Class getParameterType() { + return method.getParameterTypes()[parameterIndex]; + } + + /** + * + * @return the parameter {@link TypeInformation}. + */ + public TypeInformation getTypeInformation() { + return typeInformation; + } + + /** + * Check whether the parameter is assignable to {@code target}. + * + * @param target must not be {@literal null}. + * @return + */ + public boolean isAssignableTo(Class target) { + + LettuceAssert.notNull(target, "Target type must not be null"); + + return LettuceClassUtils.isAssignable(target, getParameterType()); + } + + /** + * + * @return {@literal true} if the parameter is a special parameter. + */ + public boolean isSpecialParameter() { + return false; + } + + /** + * @return {@literal true} if the {@link Parameter} can be bound to a command. + */ + boolean isBindable() { + return !isSpecialParameter(); + } + + /** + * @return the parameter name or {@literal null} if not available. + */ + public String getName() { + return name; + } +} diff --git a/src/main/java/com/lambdaworks/redis/dynamic/parameter/Parameters.java b/src/main/java/com/lambdaworks/redis/dynamic/parameter/Parameters.java new file mode 100644 index 0000000000..1ff3a8a515 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/dynamic/parameter/Parameters.java @@ -0,0 +1,92 @@ +package com.lambdaworks.redis.dynamic.parameter; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +/** + * Base class to abstract method {@link Parameter}s. + * + * @author Mark Paluch + */ +public abstract class Parameters

    implements Iterable

    { + + private final List

    parameters; + private final List

    bindableParameters; + + /** + * Create new {@link Parameters} given a {@link Method}. + * + * @param method must not be {@literal null}. + */ + public Parameters(Method method) { + + this.parameters = new ArrayList<>(method.getParameterCount()); + + for (int i = 0; i < method.getParameterCount(); i++) { + parameters.add(createParameter(method, i)); + } + + this.bindableParameters = createBindableParameters(); + } + + /** + * Create a new {@link Parameters} for given a {@link Method} at {@code parameterIndex}. + * + * @param method must not be {@literal null}. + * @param parameterIndex the parameter index. + * @return the {@link Parameter}. + */ + protected abstract P createParameter(Method method, int parameterIndex); + + /** + * Returns {@link Parameter} instances with effectively all special parameters removed. + * + * @return + */ + private List

    createBindableParameters() { + + List

    bindables = new ArrayList<>(parameters.size()); + + for (P parameter : parameters) { + if (parameter.isBindable()) { + bindables.add(parameter); + } + } + + return bindables; + } + + /** + * @return + */ + public List

    getParameters() { + return parameters; + } + + /** + * Get the bindable parameter according it's logical position in the command. Declarative position may differ because of + * special parameters interleaved. + * + * @param index + * @return the {@link Parameter}. + */ + public Parameter getBindableParameter(int index) { + return getBindableParameters().get(index); + } + + /** + * Returns {@link Parameter} instances with effectively all special parameters removed. + * + * @return + */ + public List

    getBindableParameters() { + return bindableParameters; + } + + @Override + public Iterator

    iterator() { + return getBindableParameters().iterator(); + } +} diff --git a/src/main/java/com/lambdaworks/redis/dynamic/parameter/package-info.java b/src/main/java/com/lambdaworks/redis/dynamic/parameter/package-info.java new file mode 100644 index 0000000000..55df8656d4 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/dynamic/parameter/package-info.java @@ -0,0 +1,4 @@ +/** + * Parameter access and descriptors. + */ +package com.lambdaworks.redis.dynamic.parameter; \ No newline at end of file diff --git a/src/main/java/com/lambdaworks/redis/dynamic/segment/AnnotationCommandSegmentFactory.java b/src/main/java/com/lambdaworks/redis/dynamic/segment/AnnotationCommandSegmentFactory.java new file mode 100644 index 0000000000..fa1dffff20 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/dynamic/segment/AnnotationCommandSegmentFactory.java @@ -0,0 +1,214 @@ +package com.lambdaworks.redis.dynamic.segment; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.regex.Pattern; + +import com.lambdaworks.redis.LettuceStrings; +import com.lambdaworks.redis.dynamic.annotation.Command; +import com.lambdaworks.redis.dynamic.annotation.CommandNaming; +import com.lambdaworks.redis.dynamic.annotation.CommandNaming.LetterCase; +import com.lambdaworks.redis.dynamic.annotation.CommandNaming.Strategy; +import com.lambdaworks.redis.dynamic.CommandMethod; +import com.lambdaworks.redis.internal.LettuceAssert; + +/** + * {@link CommandSegmentFactory} implementation that creates {@link CommandSegments} considering {@link Command} and + * {@link CommandNaming} annotations. + * + * @author Mark Paluch + * @since 5.0 + */ +public class AnnotationCommandSegmentFactory implements CommandSegmentFactory { + + private static final Pattern SPACE = Pattern.compile("\\s"); + private static final String INDEX_BASED_PARAM_START = "?"; + private static final String NAME_BASED_PARAM_START = ":"; + + @Override + public CommandSegments createCommandSegments(CommandMethod commandMethod) { + + if (CommandSegmentParser.INSTANCE.hasCommandString(commandMethod)) { + return CommandSegmentParser.INSTANCE.createCommandSegments(commandMethod); + } + + LetterCase letterCase = getLetterCase(commandMethod); + Strategy strategy = getNamingStrategy(commandMethod); + + List parts = parseMethodName(commandMethod.getName(), strategy); + return createCommandSegments(parts, letterCase); + } + + private CommandSegments createCommandSegments(List parts, LetterCase letterCase) { + + List segments = new ArrayList<>(parts.size()); + + for (String part : parts) { + + if (letterCase == LetterCase.AS_IS) { + segments.add(CommandSegment.constant(part)); + } else { + segments.add(CommandSegment.constant(part.toUpperCase())); + } + } + + return new CommandSegments(segments); + } + + private List parseMethodName(String name, Strategy strategy) { + + if (strategy == Strategy.METHOD_NAME) { + return Collections.singletonList(name); + } + + List parts = new ArrayList<>(); + + char[] chars = name.toCharArray(); + + boolean previousUpperCase = false; + StringBuffer buffer = new StringBuffer(chars.length); + for (char theChar : chars) { + + if (!Character.isUpperCase(theChar)) { + buffer.append(theChar); + previousUpperCase = false; + continue; + + } + + // Camel hump + if (!previousUpperCase) { + + if (!LettuceStrings.isEmpty(buffer)) { + + if (strategy == Strategy.DOT) { + buffer.append('.'); + } + + if (strategy == Strategy.SPLIT) { + + parts.add(buffer.toString()); + buffer = new StringBuffer(chars.length); + } + } + } + + previousUpperCase = true; + buffer.append(theChar); + } + + if (LettuceStrings.isNotEmpty(buffer)) { + parts.add(buffer.toString()); + } + + return parts; + } + + private LetterCase getLetterCase(CommandMethod commandMethod) { + + if (commandMethod.hasAnnotation(CommandNaming.class)) { + LetterCase letterCase = commandMethod.getMethod().getAnnotation(CommandNaming.class).letterCase(); + if (letterCase != LetterCase.DEFAULT) { + return letterCase; + } + } + + Class declaringClass = commandMethod.getMethod().getDeclaringClass(); + CommandNaming annotation = declaringClass.getAnnotation(CommandNaming.class); + if (annotation != null && annotation.letterCase() != LetterCase.DEFAULT) { + return annotation.letterCase(); + } + + return LetterCase.UPPERCASE; + } + + private Strategy getNamingStrategy(CommandMethod commandMethod) { + + if (commandMethod.hasAnnotation(CommandNaming.class)) { + Strategy strategy = commandMethod.getMethod().getAnnotation(CommandNaming.class).strategy(); + if (strategy != Strategy.DEFAULT) { + return strategy; + } + } + + Class declaringClass = commandMethod.getMethod().getDeclaringClass(); + CommandNaming annotation = declaringClass.getAnnotation(CommandNaming.class); + if (annotation != null && annotation.strategy() != Strategy.DEFAULT) { + return annotation.strategy(); + } + + return Strategy.SPLIT; + } + + private enum CommandSegmentParser implements CommandSegmentFactory { + + INSTANCE; + + @Override + public CommandSegments createCommandSegments(CommandMethod commandMethod) { + return parse(getCommandString(commandMethod)); + } + + private CommandSegments parse(String command) { + + String[] split = SPACE.split(command); + + LettuceAssert.notEmpty(split, "Command must not be empty"); + + return getCommandSegments(split); + } + + private CommandSegments getCommandSegments(String[] split) { + + List segments = new ArrayList<>(); + + for (String segment : split) { + + if (segment.startsWith(INDEX_BASED_PARAM_START)) { + segments.add(parseIndexBasedArgument(segment)); + continue; + } + + if (segment.startsWith(NAME_BASED_PARAM_START)) { + segments.add(parseNameBasedArgument(segment)); + continue; + } + + segments.add(CommandSegment.constant(segment)); + } + + return new CommandSegments(segments); + } + + private CommandSegment parseIndexBasedArgument(String segment) { + + String index = segment.substring(INDEX_BASED_PARAM_START.length()); + return getIndexBasedArgument(index); + } + + private CommandSegment parseNameBasedArgument(String segment) { + return CommandSegment.namedParameter(segment.substring(NAME_BASED_PARAM_START.length())); + } + + private CommandSegment getIndexBasedArgument(String index) { + return CommandSegment.indexedParameter(Integer.parseInt(index)); + } + + private String getCommandString(CommandMethod commandMethod) { + + Command annotation = commandMethod.getAnnotation(Command.class); + return annotation.value(); + } + + private boolean hasCommandString(CommandMethod commandMethod) { + + if (commandMethod.hasAnnotation(Command.class)) { + Command annotation = commandMethod.getAnnotation(Command.class); + return LettuceStrings.isNotEmpty(annotation.value()); + } + + return false; + } + } +} diff --git a/src/main/java/com/lambdaworks/redis/dynamic/segment/CommandSegment.java b/src/main/java/com/lambdaworks/redis/dynamic/segment/CommandSegment.java new file mode 100644 index 0000000000..c2ad12ae70 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/dynamic/segment/CommandSegment.java @@ -0,0 +1,146 @@ +package com.lambdaworks.redis.dynamic.segment; + +import com.lambdaworks.redis.dynamic.parameter.MethodParametersAccessor; +import com.lambdaworks.redis.internal.LettuceAssert; + +/** + * Value object representing a segment within a Redis Command. + *

    + * A command segment is an ASCII string denoting a command, a named or an index-parameter reference. + * + * @author Mark Paluch + * @since 5.0 + */ +public abstract class CommandSegment { + + /** + * Create a constant {@link CommandSegment}. + * + * @param content must not be empty or {@literal null}. + * @return the {@link CommandSegment}. + */ + public static CommandSegment constant(String content) { + return new Constant(content); + } + + /** + * Create a named parameter reference {@link CommandSegment}. + * + * @param name must not be empty or {@literal null}. + * @return + */ + public static CommandSegment namedParameter(String name) { + return new NamedParameter(name); + } + + public static CommandSegment indexedParameter(int index) { + return new IndexedParameter(index); + } + + /** + * + * @return the command segment in its {@link String representation} + */ + public abstract String asString(); + + /** + * + * @param parametersAccessor + * @return + */ + public abstract ArgumentContribution contribute(MethodParametersAccessor parametersAccessor); + + @Override + public String toString() { + final StringBuffer sb = new StringBuffer(); + sb.append(getClass().getSimpleName()); + sb.append(" ").append(asString()); + return sb.toString(); + } + + private static class Constant extends CommandSegment { + + private final String content; + + public Constant(String content) { + + LettuceAssert.notEmpty(content, "Constant must not be empty"); + + this.content = content; + } + + @Override + public String asString() { + return content; + } + + @Override + public ArgumentContribution contribute(MethodParametersAccessor parametersAccessor) { + return new ArgumentContribution(-1, asString()); + } + } + + private static class NamedParameter extends CommandSegment { + + private final String name; + + public NamedParameter(String name) { + + LettuceAssert.notEmpty(name, "Parameter name must not be empty"); + + this.name = name; + } + + @Override + public String asString() { + return name; + } + + @Override + public ArgumentContribution contribute(MethodParametersAccessor parametersAccessor) { + + int index = parametersAccessor.resolveParameterIndex(name); + return new ArgumentContribution(index, parametersAccessor.getBindableValue(index)); + } + } + + private static class IndexedParameter extends CommandSegment { + + private final int index; + + public IndexedParameter(int index) { + + LettuceAssert.isTrue(index >= 0, "Parameter index must be non-negative starting at 0"); + this.index = index; + } + + @Override + public String asString() { + return Integer.toString(index); + } + + @Override + public ArgumentContribution contribute(MethodParametersAccessor parametersAccessor) { + return new ArgumentContribution(index, parametersAccessor.getBindableValue(index)); + } + } + + public static class ArgumentContribution { + + private final int parameterIndex; + private final Object value; + + ArgumentContribution(int parameterIndex, Object value) { + this.parameterIndex = parameterIndex; + this.value = value; + } + + public int getParameterIndex() { + return parameterIndex; + } + + public Object getValue() { + return value; + } + } +} diff --git a/src/main/java/com/lambdaworks/redis/dynamic/segment/CommandSegmentFactory.java b/src/main/java/com/lambdaworks/redis/dynamic/segment/CommandSegmentFactory.java new file mode 100644 index 0000000000..732f3809eb --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/dynamic/segment/CommandSegmentFactory.java @@ -0,0 +1,20 @@ +package com.lambdaworks.redis.dynamic.segment; + +import com.lambdaworks.redis.dynamic.CommandMethod; + +/** + * Strategy interface to create {@link CommandSegments} for a {@link CommandMethod}.l + * + * @author Mark Paluch + * @since 5.0 + */ +public interface CommandSegmentFactory { + + /** + * Create {@link CommandSegments} for a {@link CommandMethod}. + * + * @param commandMethod must not be {@literal null}. + * @return the {@link CommandSegments}. + */ + CommandSegments createCommandSegments(CommandMethod commandMethod); +} diff --git a/src/main/java/com/lambdaworks/redis/dynamic/segment/CommandSegments.java b/src/main/java/com/lambdaworks/redis/dynamic/segment/CommandSegments.java new file mode 100644 index 0000000000..f5bb6798e0 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/dynamic/segment/CommandSegments.java @@ -0,0 +1,80 @@ +package com.lambdaworks.redis.dynamic.segment; + +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +import com.lambdaworks.redis.internal.LettuceAssert; +import com.lambdaworks.redis.protocol.ProtocolKeyword; + +/** + * Value object abstracting multiple {@link CommandSegment}s. + * + * @author Mark Paluch + * @since 5.0 + */ +public class CommandSegments implements Iterable { + + private final StringCommandType commandType; + private final List segments; + + /** + * Create {@link CommandSegments} given a {@link List} of {@link CommandSegment}s. + * + * @param segments must not be {@literal null.} + */ + public CommandSegments(List segments) { + + LettuceAssert.isTrue(!segments.isEmpty(), "Command segments must not be empty"); + + this.segments = segments.size() > 1 ? Collections.unmodifiableList(segments.subList(1, segments.size())) + : Collections.emptyList(); + this.commandType = new StringCommandType(segments.get(0).asString()); + } + + @Override + public Iterator iterator() { + return segments.iterator(); + } + + public ProtocolKeyword getCommandType() { + return commandType; + } + + public int size() { + return segments.size(); + } + + private static class StringCommandType implements ProtocolKeyword { + + private final byte[] commandTypeBytes; + private final String commandType; + + public StringCommandType(String commandType) { + this.commandType = commandType; + this.commandTypeBytes = commandType.getBytes(); + } + + @Override + public byte[] getBytes() { + return commandTypeBytes; + } + + @Override + public String name() { + return commandType; + } + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(getCommandType().name()); + + for (CommandSegment segment : segments) { + sb.append(' ').append(segment); + } + + return sb.toString(); + } +} diff --git a/src/main/java/com/lambdaworks/redis/dynamic/segment/package-info.java b/src/main/java/com/lambdaworks/redis/dynamic/segment/package-info.java new file mode 100644 index 0000000000..10ae382b47 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/dynamic/segment/package-info.java @@ -0,0 +1,4 @@ +/** + * Support for {@link com.lambdaworks.redis.dynamic.segment.CommandSegments} and segment parsing. + */ +package com.lambdaworks.redis.dynamic.segment; \ No newline at end of file diff --git a/src/main/java/com/lambdaworks/redis/dynamic/support/AnnotationParameterNameDiscoverer.java b/src/main/java/com/lambdaworks/redis/dynamic/support/AnnotationParameterNameDiscoverer.java new file mode 100644 index 0000000000..83f02ba428 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/dynamic/support/AnnotationParameterNameDiscoverer.java @@ -0,0 +1,62 @@ +package com.lambdaworks.redis.dynamic.support; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; + +import com.lambdaworks.redis.dynamic.annotation.Param; + +/** + * {@link ParameterNameDiscoverer} based on {@link Param} annotations to resolve parameter names. + * + * @author Mark Paluch + */ +public class AnnotationParameterNameDiscoverer implements ParameterNameDiscoverer { + + @Override + public String[] getParameterNames(Method method) { + + if (method.getParameterCount() == 0) { + return new String[0]; + } + + return doGetParameterNames(method.getParameterAnnotations()); + } + + @Override + public String[] getParameterNames(Constructor ctor) { + + if (ctor.getParameterCount() == 0) { + return new String[0]; + } + + return doGetParameterNames(ctor.getParameterAnnotations()); + } + + protected String[] doGetParameterNames(Annotation[][] parameterAnnotations) { + + List names = new ArrayList<>(); + + for (int i = 0; i < parameterAnnotations.length; i++) { + + boolean foundParam = false; + for (int j = 0; j < parameterAnnotations[i].length; j++) { + + if (parameterAnnotations[i][j].annotationType().equals(Param.class)) { + foundParam = true; + Param param = (Param) parameterAnnotations[i][j]; + names.add(param.value()); + break; + } + } + + if (!foundParam) { + return null; + } + } + + return names.toArray(new String[names.size()]); + } +} diff --git a/src/main/java/com/lambdaworks/redis/dynamic/support/ClassTypeInformation.java b/src/main/java/com/lambdaworks/redis/dynamic/support/ClassTypeInformation.java new file mode 100644 index 0000000000..55a060fcbe --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/dynamic/support/ClassTypeInformation.java @@ -0,0 +1,165 @@ +package com.lambdaworks.redis.dynamic.support; + +import java.lang.ref.Reference; +import java.lang.ref.WeakReference; +import java.lang.reflect.Method; +import java.lang.reflect.Type; +import java.lang.reflect.TypeVariable; +import java.util.*; +import java.util.Map.Entry; + +import com.lambdaworks.redis.internal.LettuceAssert; +import com.lambdaworks.redis.internal.LettuceClassUtils; + +/** + * {@link TypeInformation} for a plain {@link Class}. + */ +@SuppressWarnings({ "unchecked", "rawtypes" }) +public class ClassTypeInformation extends TypeDiscoverer { + + public static final ClassTypeInformation COLLECTION = new ClassTypeInformation(Collection.class); + public static final ClassTypeInformation LIST = new ClassTypeInformation(List.class); + public static final ClassTypeInformation SET = new ClassTypeInformation(Set.class); + public static final ClassTypeInformation MAP = new ClassTypeInformation(Map.class); + public static final ClassTypeInformation OBJECT = new ClassTypeInformation(Object.class); + + private static final Map, Reference>> CACHE = Collections + .synchronizedMap(new WeakHashMap, Reference>>()); + + static { + for (ClassTypeInformation info : Arrays.asList(COLLECTION, LIST, SET, MAP, OBJECT)) { + CACHE.put(info.getType(), new WeakReference>(info)); + } + } + + private final Class type; + + /** + * Simple factory method to easily create new instances of {@link ClassTypeInformation}. + * + * @param + * @param type must not be {@literal null}. + * @return + */ + public static ClassTypeInformation from(Class type) { + + LettuceAssert.notNull(type, "Type must not be null!"); + + Reference> cachedReference = CACHE.get(type); + TypeInformation cachedTypeInfo = cachedReference == null ? null : cachedReference.get(); + + if (cachedTypeInfo != null) { + return (ClassTypeInformation) cachedTypeInfo; + } + + ClassTypeInformation result = new ClassTypeInformation(type); + CACHE.put(type, new WeakReference>(result)); + return result; + } + + /** + * Creates a {@link TypeInformation} from the given method's return type. + * + * @param method must not be {@literal null}. + * @return + */ + public static TypeInformation fromReturnTypeOf(Method method) { + + LettuceAssert.notNull(method, "Method must not be null!"); + return new ClassTypeInformation(method.getDeclaringClass()).createInfo(method.getGenericReturnType()); + } + + /** + * Creates a {@link TypeInformation} from the given method's parameter type. + * + * @param method must not be {@literal null}. + * @return + */ + public static TypeInformation fromMethodParameter(Method method, int index) { + + LettuceAssert.notNull(method, "Method must not be null!"); + return new ClassTypeInformation(method.getDeclaringClass()).createInfo(method.getGenericParameterTypes()[index]); + } + + /** + * Creates {@link ClassTypeInformation} for the given type. + * + * @param type + */ + ClassTypeInformation(Class type) { + super(getUserClass(type), getTypeVariableMap(type)); + this.type = type; + } + + /** + * Return the user-defined class for the given class: usually simply the given class, but the original class in case of a + * CGLIB-generated subclass. + * + * @param clazz the class to check + * @return the user-defined class + */ + private static Class getUserClass(Class clazz) { + if (clazz != null && clazz.getName().contains(LettuceClassUtils.CGLIB_CLASS_SEPARATOR)) { + Class superclass = clazz.getSuperclass(); + if (superclass != null && Object.class != superclass) { + return superclass; + } + } + return clazz; + } + + /** + * Little helper to allow us to create a generified map, actually just to satisfy the compiler. + * + * @param type must not be {@literal null}. + * @return + */ + private static Map, Type> getTypeVariableMap(Class type) { + return getTypeVariableMap(type, new HashSet()); + } + + @SuppressWarnings("deprecation") + private static Map, Type> getTypeVariableMap(Class type, Collection visited) { + + if (visited.contains(type)) { + return Collections.emptyMap(); + } else { + visited.add(type); + } + + Map source = GenericTypeResolver.getTypeVariableMap(type); + Map, Type> map = new HashMap<>(source.size()); + + for (Entry entry : source.entrySet()) { + + Type value = entry.getValue(); + map.put(entry.getKey(), entry.getValue()); + + if (value instanceof Class) { + map.putAll(getTypeVariableMap((Class) value, visited)); + } + } + + return map; + } + + @Override + public Class getType() { + return type; + } + + @Override + public ClassTypeInformation getRawTypeInformation() { + return this; + } + + @Override + public boolean isAssignableFrom(TypeInformation target) { + return getType().isAssignableFrom(target.getType()); + } + + @Override + public String toString() { + return type.getName(); + } +} diff --git a/src/main/java/com/lambdaworks/redis/dynamic/support/CompositeParameterNameDiscoverer.java b/src/main/java/com/lambdaworks/redis/dynamic/support/CompositeParameterNameDiscoverer.java new file mode 100644 index 0000000000..4cf525d656 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/dynamic/support/CompositeParameterNameDiscoverer.java @@ -0,0 +1,50 @@ +package com.lambdaworks.redis.dynamic.support; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.Collection; + +/** + * Composite {@link ParameterNameDiscoverer} to resolve parameter names using multiple {@link ParameterNameDiscoverer}s. + * + * @author Mark Paluch + */ +public class CompositeParameterNameDiscoverer implements ParameterNameDiscoverer { + + private Collection parameterNameDiscoverers; + + public CompositeParameterNameDiscoverer(ParameterNameDiscoverer... parameterNameDiscoverers) { + this(Arrays.asList(parameterNameDiscoverers)); + } + + public CompositeParameterNameDiscoverer(Collection parameterNameDiscoverers) { + this.parameterNameDiscoverers = parameterNameDiscoverers; + } + + @Override + public String[] getParameterNames(Method method) { + + for (ParameterNameDiscoverer parameterNameDiscoverer : parameterNameDiscoverers) { + String[] parameterNames = parameterNameDiscoverer.getParameterNames(method); + if (parameterNames != null) { + return parameterNames; + } + } + + return null; + } + + @Override + public String[] getParameterNames(Constructor ctor) { + + for (ParameterNameDiscoverer parameterNameDiscoverer : parameterNameDiscoverers) { + String[] parameterNames = parameterNameDiscoverer.getParameterNames(ctor); + if (parameterNames != null) { + return parameterNames; + } + } + + return null; + } +} diff --git a/src/main/java/com/lambdaworks/redis/dynamic/support/GenericArrayTypeInformation.java b/src/main/java/com/lambdaworks/redis/dynamic/support/GenericArrayTypeInformation.java new file mode 100644 index 0000000000..09f6550496 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/dynamic/support/GenericArrayTypeInformation.java @@ -0,0 +1,48 @@ +package com.lambdaworks.redis.dynamic.support; + +import java.lang.reflect.Array; +import java.lang.reflect.GenericArrayType; +import java.lang.reflect.Type; +import java.lang.reflect.TypeVariable; +import java.util.Map; + +/** + * Special {@link TypeDiscoverer} handling {@link GenericArrayType}s. + */ +class GenericArrayTypeInformation extends ParentTypeAwareTypeInformation { + + private final GenericArrayType type; + + /** + * Creates a new {@link GenericArrayTypeInformation} for the given {@link GenericArrayTypeInformation} and + * {@link TypeDiscoverer}. + * + * @param type must not be {@literal null}. + * @param parent must not be {@literal null}. + * @param typeVariableMap must not be {@literal null}. + */ + protected GenericArrayTypeInformation(GenericArrayType type, TypeDiscoverer parent, + Map, Type> typeVariableMap) { + + super(type, parent, typeVariableMap); + this.type = type; + } + + @Override + @SuppressWarnings("unchecked") + public Class getType() { + return (Class) Array.newInstance(resolveType(type.getGenericComponentType()), 0).getClass(); + } + + @Override + protected TypeInformation doGetComponentType() { + + Type componentType = type.getGenericComponentType(); + return createInfo(componentType); + } + + @Override + public String toString() { + return type.toString(); + } +} diff --git a/src/main/java/com/lambdaworks/redis/dynamic/support/GenericTypeResolver.java b/src/main/java/com/lambdaworks/redis/dynamic/support/GenericTypeResolver.java new file mode 100644 index 0000000000..72f755316d --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/dynamic/support/GenericTypeResolver.java @@ -0,0 +1,70 @@ +package com.lambdaworks.redis.dynamic.support; + +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.lang.reflect.TypeVariable; +import java.util.HashMap; +import java.util.Map; + +/** + * Helper class for resolving generic types against type variables. + * + *

    + * Mainly intended for usage within the framework, resolving method parameter types even when they are declared generically. + */ +public abstract class GenericTypeResolver { + + /** + * Build a mapping of {@link TypeVariable#getName TypeVariable names} to {@link Class concrete classes} for the specified + * {@link Class}. Searches all super types, enclosing types and interfaces. + */ + @SuppressWarnings("rawtypes") + public static Map getTypeVariableMap(Class clazz) { + Map typeVariableMap = new HashMap(); + buildTypeVariableMap(ResolvableType.forClass(clazz), typeVariableMap); + + return typeVariableMap; + } + + /** + * Resolve the type arguments of the given generic interface against the given target class which is assumed to implement + * the generic interface and possibly declare concrete types for its type variables. + * + * @param clazz the target class to check against + * @param genericIfc the generic interface or superclass to resolve the type argument from + * @return the resolved type of each argument, with the array size matching the number of actual type arguments, or + * {@code null} if not resolvable + */ + public static Class[] resolveTypeArguments(Class clazz, Class genericIfc) { + ResolvableType type = ResolvableType.forClass(clazz).as(genericIfc); + if (!type.hasGenerics() || type.isEntirelyUnresolvable()) { + return null; + } + return type.resolveGenerics(Object.class); + } + + @SuppressWarnings("rawtypes") + private static void buildTypeVariableMap(ResolvableType type, Map typeVariableMap) { + if (type != ResolvableType.NONE) { + if (type.getType() instanceof ParameterizedType) { + TypeVariable[] variables = type.resolve().getTypeParameters(); + for (int i = 0; i < variables.length; i++) { + ResolvableType generic = type.getGeneric(i); + while (generic.getType() instanceof TypeVariable) { + generic = generic.resolveType(); + } + if (generic != ResolvableType.NONE) { + typeVariableMap.put(variables[i], generic.getType()); + } + } + } + buildTypeVariableMap(type.getSuperType(), typeVariableMap); + for (ResolvableType interfaceType : type.getInterfaces()) { + buildTypeVariableMap(interfaceType, typeVariableMap); + } + if (type.resolve().isMemberClass()) { + buildTypeVariableMap(ResolvableType.forClass(type.resolve().getEnclosingClass()), typeVariableMap); + } + } + } +} diff --git a/src/main/java/com/lambdaworks/redis/dynamic/support/MethodParameter.java b/src/main/java/com/lambdaworks/redis/dynamic/support/MethodParameter.java new file mode 100644 index 0000000000..a930641538 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/dynamic/support/MethodParameter.java @@ -0,0 +1,511 @@ +package com.lambdaworks.redis.dynamic.support; + +import java.lang.annotation.Annotation; +import java.lang.reflect.*; +import java.util.HashMap; +import java.util.Map; + +import com.lambdaworks.redis.internal.LettuceAssert; + +/** + * Helper class that encapsulates the specification of a method parameter, i.e. a {@link Method} or {@link Constructor} plus a + * parameter index and a nested type index for a declared generic type. Useful as a specification object to pass along. + */ +public class MethodParameter { + + private final Method method; + + private final Constructor constructor; + + private final int parameterIndex; + + private int nestingLevel = 1; + + /** Map from Integer level to Integer type index */ + Map typeIndexesPerLevel; + + private volatile Class containingClass; + + private volatile Class parameterType; + + private volatile Type genericParameterType; + + private volatile Annotation[] parameterAnnotations; + + private volatile ParameterNameDiscoverer parameterNameDiscoverer; + + private volatile String parameterName; + + /** + * Create a new {@code MethodParameter} for the given method, with nesting level 1. + * + * @param method the Method to specify a parameter for + * @param parameterIndex the index of the parameter: -1 for the method return type; 0 for the first method parameter; 1 for + * the second method parameter, etc. + */ + public MethodParameter(Method method, int parameterIndex) { + this(method, parameterIndex, 1); + } + + /** + * Create a new {@code MethodParameter} for the given method. + * + * @param method the Method to specify a parameter for + * @param parameterIndex the index of the parameter: -1 for the method return type; 0 for the first method parameter; 1 for + * the second method parameter, etc. + * @param nestingLevel the nesting level of the target type (typically 1; e.g. in case of a List of Lists, 1 would indicate + * the nested List, whereas 2 would indicate the element of the nested List) + */ + public MethodParameter(Method method, int parameterIndex, int nestingLevel) { + + LettuceAssert.notNull(method, "Method must not be null"); + + this.method = method; + this.parameterIndex = parameterIndex; + this.nestingLevel = nestingLevel; + this.constructor = null; + } + + /** + * Create a new MethodParameter for the given constructor, with nesting level 1. + * + * @param constructor the Constructor to specify a parameter for + * @param parameterIndex the index of the parameter + */ + public MethodParameter(Constructor constructor, int parameterIndex) { + this(constructor, parameterIndex, 1); + } + + /** + * Create a new MethodParameter for the given constructor. + * + * @param constructor the Constructor to specify a parameter for + * @param parameterIndex the index of the parameter + * @param nestingLevel the nesting level of the target type (typically 1; e.g. in case of a List of Lists, 1 would indicate + * the nested List, whereas 2 would indicate the element of the nested List) + */ + public MethodParameter(Constructor constructor, int parameterIndex, int nestingLevel) { + LettuceAssert.notNull(constructor, "Constructor must not be null"); + this.constructor = constructor; + this.parameterIndex = parameterIndex; + this.nestingLevel = nestingLevel; + this.method = null; + } + + /** + * Copy constructor, resulting in an independent MethodParameter object based on the same metadata and cache state that the + * original object was in. + * + * @param original the original MethodParameter object to copy from + */ + public MethodParameter(MethodParameter original) { + LettuceAssert.notNull(original, "Original must not be null"); + this.method = original.method; + this.constructor = original.constructor; + this.parameterIndex = original.parameterIndex; + this.nestingLevel = original.nestingLevel; + this.typeIndexesPerLevel = original.typeIndexesPerLevel; + this.containingClass = original.containingClass; + this.parameterType = original.parameterType; + this.genericParameterType = original.genericParameterType; + this.parameterAnnotations = original.parameterAnnotations; + this.parameterNameDiscoverer = original.parameterNameDiscoverer; + this.parameterName = original.parameterName; + } + + /** + * Return the wrapped Method, if any. + *

    + * Note: Either Method or Constructor is available. + * + * @return the Method, or {@code null} if none + */ + public Method getMethod() { + return this.method; + } + + /** + * Return the wrapped Constructor, if any. + *

    + * Note: Either Method or Constructor is available. + * + * @return the Constructor, or {@code null} if none + */ + public Constructor getConstructor() { + return this.constructor; + } + + /** + * Returns the wrapped member. + * + * @return the Method or Constructor as Member + */ + public Member getMember() { + // NOTE: no ternary expression to retain JDK <8 compatibility even when using + // the JDK 8 compiler (potentially selecting java.lang.reflect.Executable + // as common type, with that new base class not available on older JDKs) + if (this.method != null) { + return this.method; + } else { + return this.constructor; + } + } + + /** + * Returns the wrapped annotated element. + * + * @return the Method or Constructor as AnnotatedElement + */ + public AnnotatedElement getAnnotatedElement() { + // NOTE: no ternary expression to retain JDK <8 compatibility even when using + // the JDK 8 compiler (potentially selecting java.lang.reflect.Executable + // as common type, with that new base class not available on older JDKs) + if (this.method != null) { + return this.method; + } else { + return this.constructor; + } + } + + /** + * Return the class that declares the underlying Method or Constructor. + */ + public Class getDeclaringClass() { + return getMember().getDeclaringClass(); + } + + /** + * Return the index of the method/constructor parameter. + * + * @return the parameter index (-1 in case of the return type) + */ + public int getParameterIndex() { + return this.parameterIndex; + } + + /** + * Increase this parameter's nesting level. + * + * @see #getNestingLevel() + */ + public void increaseNestingLevel() { + this.nestingLevel++; + } + + /** + * Decrease this parameter's nesting level. + * + * @see #getNestingLevel() + */ + public void decreaseNestingLevel() { + getTypeIndexesPerLevel().remove(this.nestingLevel); + this.nestingLevel--; + } + + /** + * Return the nesting level of the target type (typically 1; e.g. in case of a List of Lists, 1 would indicate the nested + * List, whereas 2 would indicate the element of the nested List). + */ + public int getNestingLevel() { + return this.nestingLevel; + } + + /** + * Set the type index for the current nesting level. + * + * @param typeIndex the corresponding type index (or {@code null} for the default type index) + * @see #getNestingLevel() + */ + public void setTypeIndexForCurrentLevel(int typeIndex) { + getTypeIndexesPerLevel().put(this.nestingLevel, typeIndex); + } + + /** + * Return the type index for the current nesting level. + * + * @return the corresponding type index, or {@code null} if none specified (indicating the default type index) + * @see #getNestingLevel() + */ + public Integer getTypeIndexForCurrentLevel() { + return getTypeIndexForLevel(this.nestingLevel); + } + + /** + * Return the type index for the specified nesting level. + * + * @param nestingLevel the nesting level to check + * @return the corresponding type index, or {@code null} if none specified (indicating the default type index) + */ + public Integer getTypeIndexForLevel(int nestingLevel) { + return getTypeIndexesPerLevel().get(nestingLevel); + } + + /** + * Obtain the (lazily constructed) type-indexes-per-level Map. + */ + private Map getTypeIndexesPerLevel() { + if (this.typeIndexesPerLevel == null) { + this.typeIndexesPerLevel = new HashMap(4); + } + return this.typeIndexesPerLevel; + } + + /** + * Set a containing class to resolve the parameter type against. + */ + void setContainingClass(Class containingClass) { + this.containingClass = containingClass; + } + + public Class getContainingClass() { + return (this.containingClass != null ? this.containingClass : getDeclaringClass()); + } + + /** + * Set a resolved (generic) parameter type. + */ + void setParameterType(Class parameterType) { + this.parameterType = parameterType; + } + + /** + * Return the type of the method/constructor parameter. + * + * @return the parameter type (never {@code null}) + */ + public Class getParameterType() { + if (this.parameterType == null) { + if (this.parameterIndex < 0) { + this.parameterType = (this.method != null ? this.method.getReturnType() : null); + } else { + this.parameterType = (this.method != null ? this.method.getParameterTypes()[this.parameterIndex] + : this.constructor.getParameterTypes()[this.parameterIndex]); + } + } + return this.parameterType; + } + + /** + * Return the generic type of the method/constructor parameter. + * + * @return the parameter type (never {@code null}) + */ + public Type getGenericParameterType() { + if (this.genericParameterType == null) { + if (this.parameterIndex < 0) { + this.genericParameterType = (this.method != null ? this.method.getGenericReturnType() : null); + } else { + this.genericParameterType = (this.method != null ? this.method.getGenericParameterTypes()[this.parameterIndex] + : this.constructor.getGenericParameterTypes()[this.parameterIndex]); + } + } + return this.genericParameterType; + } + + /** + * Return the nested type of the method/constructor parameter. + * + * @return the parameter type (never {@code null}) + * @see #getNestingLevel() + */ + public Class getNestedParameterType() { + if (this.nestingLevel > 1) { + Type type = getGenericParameterType(); + for (int i = 2; i <= this.nestingLevel; i++) { + if (type instanceof ParameterizedType) { + Type[] args = ((ParameterizedType) type).getActualTypeArguments(); + Integer index = getTypeIndexForLevel(i); + type = args[index != null ? index : args.length - 1]; + } + } + if (type instanceof Class) { + return (Class) type; + } else if (type instanceof ParameterizedType) { + Type arg = ((ParameterizedType) type).getRawType(); + if (arg instanceof Class) { + return (Class) arg; + } + } + return Object.class; + } else { + return getParameterType(); + } + } + + /** + * Return the nested generic type of the method/constructor parameter. + * + * @return the parameter type (never {@code null}) + * @see #getNestingLevel() + */ + public Type getNestedGenericParameterType() { + if (this.nestingLevel > 1) { + Type type = getGenericParameterType(); + for (int i = 2; i <= this.nestingLevel; i++) { + if (type instanceof ParameterizedType) { + Type[] args = ((ParameterizedType) type).getActualTypeArguments(); + Integer index = getTypeIndexForLevel(i); + type = args[index != null ? index : args.length - 1]; + } + } + return type; + } else { + return getGenericParameterType(); + } + } + + /** + * Return the annotations associated with the target method/constructor itself. + */ + public Annotation[] getMethodAnnotations() { + return adaptAnnotationArray(getAnnotatedElement().getAnnotations()); + } + + /** + * Return the method/constructor annotation of the given type, if available. + * + * @param annotationType the annotation type to look for + * @return the annotation object, or {@code null} if not found + */ + public A getMethodAnnotation(Class annotationType) { + return adaptAnnotation(getAnnotatedElement().getAnnotation(annotationType)); + } + + /** + * Return the annotations associated with the specific method/constructor parameter. + */ + public Annotation[] getParameterAnnotations() { + if (this.parameterAnnotations == null) { + Annotation[][] annotationArray = (this.method != null ? this.method.getParameterAnnotations() + : this.constructor.getParameterAnnotations()); + if (this.parameterIndex >= 0 && this.parameterIndex < annotationArray.length) { + this.parameterAnnotations = adaptAnnotationArray(annotationArray[this.parameterIndex]); + } else { + this.parameterAnnotations = new Annotation[0]; + } + } + return this.parameterAnnotations; + } + + /** + * Return the parameter annotation of the given type, if available. + * + * @param annotationType the annotation type to look for + * @return the annotation object, or {@code null} if not found + */ + @SuppressWarnings("unchecked") + public T getParameterAnnotation(Class annotationType) { + Annotation[] anns = getParameterAnnotations(); + for (Annotation ann : anns) { + if (annotationType.isInstance(ann)) { + return (T) ann; + } + } + return null; + } + + /** + * Return true if the parameter has at least one annotation, false if it has none. + */ + public boolean hasParameterAnnotations() { + return (getParameterAnnotations().length != 0); + } + + /** + * Return true if the parameter has the given annotation type, and false if it doesn't. + */ + public boolean hasParameterAnnotation(Class annotationType) { + return (getParameterAnnotation(annotationType) != null); + } + + /** + * Initialize parameter name discovery for this method parameter. + *

    + * This method does not actually try to retrieve the parameter name at this point; it just allows discovery to happen when + * the application calls {@link #getParameterName()} (if ever). + */ + public void initParameterNameDiscovery(ParameterNameDiscoverer parameterNameDiscoverer) { + this.parameterNameDiscoverer = parameterNameDiscoverer; + } + + /** + * Return the name of the method/constructor parameter. + * + * @return the parameter name (may be {@code null} if no parameter name metadata is contained in the class file or no + * {@link #initParameterNameDiscovery ParameterNameDiscoverer} has been set to begin with) + */ + public String getParameterName() { + ParameterNameDiscoverer discoverer = this.parameterNameDiscoverer; + if (discoverer != null) { + String[] parameterNames = (this.method != null ? discoverer.getParameterNames(this.method) + : discoverer.getParameterNames(this.constructor)); + if (parameterNames != null) { + this.parameterName = parameterNames[this.parameterIndex]; + } + this.parameterNameDiscoverer = null; + } + return this.parameterName; + } + + /** + * A template method to post-process a given annotation instance before returning it to the caller. + *

    + * The default implementation simply returns the given annotation as-is. + * + * @param annotation the annotation about to be returned + * @return the post-processed annotation (or simply the original one) + */ + protected A adaptAnnotation(A annotation) { + return annotation; + } + + /** + * A template method to post-process a given annotation array before returning it to the caller. + *

    + * The default implementation simply returns the given annotation array as-is. + * + * @param annotations the annotation array about to be returned + * @return the post-processed annotation array (or simply the original one) + */ + protected Annotation[] adaptAnnotationArray(Annotation[] annotations) { + return annotations; + } + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + if (!(other instanceof MethodParameter)) { + return false; + } + MethodParameter otherParam = (MethodParameter) other; + return (this.parameterIndex == otherParam.parameterIndex && getMember().equals(otherParam.getMember())); + } + + @Override + public int hashCode() { + return (getMember().hashCode() * 31 + this.parameterIndex); + } + + /** + * Create a new MethodParameter for the given method or constructor. + *

    + * This is a convenience constructor for scenarios where a Method or Constructor reference is treated in a generic fashion. + * + * @param methodOrConstructor the Method or Constructor to specify a parameter for + * @param parameterIndex the index of the parameter + * @return the corresponding MethodParameter instance + */ + public static MethodParameter forMethodOrConstructor(Object methodOrConstructor, int parameterIndex) { + if (methodOrConstructor instanceof Method) { + return new MethodParameter((Method) methodOrConstructor, parameterIndex); + } else if (methodOrConstructor instanceof Constructor) { + return new MethodParameter((Constructor) methodOrConstructor, parameterIndex); + } else { + throw new IllegalArgumentException( + "Given object [" + methodOrConstructor + "] is neither a Method nor a Constructor"); + } + } + +} diff --git a/src/main/java/com/lambdaworks/redis/dynamic/support/ParameterNameDiscoverer.java b/src/main/java/com/lambdaworks/redis/dynamic/support/ParameterNameDiscoverer.java new file mode 100644 index 0000000000..e08bd72840 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/dynamic/support/ParameterNameDiscoverer.java @@ -0,0 +1,31 @@ +package com.lambdaworks.redis.dynamic.support; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; + +/** + * Interface to discover parameter names for methods and constructors. + * + *

    + * Parameter name discovery is not always possible, but various strategies are available to try, such as looking for debug + * information that may have been emitted at compile time, and looking for argname annotation values. + */ +public interface ParameterNameDiscoverer { + + /** + * Return parameter names for this method, or {@code null} if they cannot be determined. + * + * @param method method to find parameter names for + * @return an array of parameter names if the names can be resolved, or {@code null} if they cannot + */ + String[] getParameterNames(Method method); + + /** + * Return parameter names for this constructor, or {@code null} if they cannot be determined. + * + * @param ctor constructor to find parameter names for + * @return an array of parameter names if the names can be resolved, or {@code null} if they cannot + */ + String[] getParameterNames(Constructor ctor); + +} diff --git a/src/main/java/com/lambdaworks/redis/dynamic/support/ParametrizedTypeInformation.java b/src/main/java/com/lambdaworks/redis/dynamic/support/ParametrizedTypeInformation.java new file mode 100644 index 0000000000..aa410bd455 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/dynamic/support/ParametrizedTypeInformation.java @@ -0,0 +1,182 @@ +package com.lambdaworks.redis.dynamic.support; + +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.lang.reflect.TypeVariable; +import java.util.*; + +import com.lambdaworks.redis.LettuceStrings; + +/** + * Base class for all types that include parametrization of some kind. Crucial as we have to take note of the parent class we + * will have to resolve generic parameters against. + */ +class ParametrizedTypeInformation extends ParentTypeAwareTypeInformation { + + private final ParameterizedType type; + private Boolean resolved; + + /** + * Creates a new {@link ParametrizedTypeInformation} for the given {@link Type} and parent {@link TypeDiscoverer}. + * + * @param type must not be {@literal null} + * @param parent must not be {@literal null} + */ + public ParametrizedTypeInformation(ParameterizedType type, TypeDiscoverer parent, + Map, Type> typeVariableMap) { + + super(type, parent, typeVariableMap); + this.type = type; + } + + @Override + protected TypeInformation doGetMapValueType() { + + if (Map.class.isAssignableFrom(getType())) { + + Type[] arguments = type.getActualTypeArguments(); + + if (arguments.length > 1) { + return createInfo(arguments[1]); + } + } + + Class rawType = getType(); + + Set supertypes = new HashSet(); + supertypes.add(rawType.getGenericSuperclass()); + supertypes.addAll(Arrays.asList(rawType.getGenericInterfaces())); + + for (Type supertype : supertypes) { + + Class rawSuperType = resolveType(supertype); + + if (Map.class.isAssignableFrom(rawSuperType)) { + + ParameterizedType parameterizedSupertype = (ParameterizedType) supertype; + Type[] arguments = parameterizedSupertype.getActualTypeArguments(); + return createInfo(arguments[1]); + } + } + + return super.getMapValueType(); + } + + @Override + public List> getTypeArguments() { + + List> result = new ArrayList>(); + + for (Type argument : type.getActualTypeArguments()) { + result.add(createInfo(argument)); + } + + return result; + } + + @Override + public boolean isAssignableFrom(TypeInformation target) { + + if (this.equals(target)) { + return true; + } + + Class rawType = getType(); + Class rawTargetType = target.getType(); + + if (!rawType.isAssignableFrom(rawTargetType)) { + return false; + } + + TypeInformation otherTypeInformation = rawType.equals(rawTargetType) ? target + : target.getSuperTypeInformation(rawType); + + List> myParameters = getTypeArguments(); + List> typeParameters = otherTypeInformation.getTypeArguments(); + + if (myParameters.size() != typeParameters.size()) { + return false; + } + + for (int i = 0; i < myParameters.size(); i++) { + if (!myParameters.get(i).isAssignableFrom(typeParameters.get(i))) { + return false; + } + } + + return true; + } + + @Override + protected TypeInformation doGetComponentType() { + return createInfo(type.getActualTypeArguments()[0]); + } + + @Override + public boolean equals(Object obj) { + + if (obj == this) { + return true; + } + + if (!(obj instanceof ParametrizedTypeInformation)) { + return false; + } + + ParametrizedTypeInformation that = (ParametrizedTypeInformation) obj; + + if (this.isResolvedCompletely() && that.isResolvedCompletely()) { + return this.type.equals(that.type); + } + + return super.equals(obj); + } + + @Override + public int hashCode() { + return isResolvedCompletely() ? this.type.hashCode() : super.hashCode(); + } + + @Override + public String toString() { + + return String.format("%s<%s>", getType().getName(), + LettuceStrings.collectionToDelimitedString(getTypeArguments(), ",", "", "")); + } + + private boolean isResolvedCompletely() { + + if (resolved != null) { + return resolved; + } + + Type[] typeArguments = type.getActualTypeArguments(); + + if (typeArguments.length == 0) { + return cacheAndReturn(false); + } + + for (Type typeArgument : typeArguments) { + + TypeInformation info = createInfo(typeArgument); + + if (info instanceof ParametrizedTypeInformation) { + if (!((ParametrizedTypeInformation) info).isResolvedCompletely()) { + return cacheAndReturn(false); + } + } + + if (!(info instanceof ClassTypeInformation)) { + return cacheAndReturn(false); + } + } + + return cacheAndReturn(true); + } + + private boolean cacheAndReturn(boolean resolved) { + + this.resolved = resolved; + return resolved; + } +} diff --git a/src/main/java/com/lambdaworks/redis/dynamic/support/ParentTypeAwareTypeInformation.java b/src/main/java/com/lambdaworks/redis/dynamic/support/ParentTypeAwareTypeInformation.java new file mode 100644 index 0000000000..cc275b940c --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/dynamic/support/ParentTypeAwareTypeInformation.java @@ -0,0 +1,79 @@ +package com.lambdaworks.redis.dynamic.support; + +import java.lang.reflect.Type; +import java.lang.reflect.TypeVariable; +import java.util.HashMap; +import java.util.Map; + +/** + * Base class for {@link TypeInformation} implementations that need parent type awareness. + */ +abstract class ParentTypeAwareTypeInformation extends TypeDiscoverer { + + private final TypeDiscoverer parent; + private int hashCode; + + /** + * Creates a new {@link ParentTypeAwareTypeInformation}. + * + * @param type must not be {@literal null}. + * @param parent must not be {@literal null}. + * @param map must not be {@literal null}. + */ + protected ParentTypeAwareTypeInformation(Type type, TypeDiscoverer parent, Map, Type> map) { + + super(type, mergeMaps(parent, map)); + this.parent = parent; + } + + /** + * Merges the type variable maps of the given parent with the new map. + * + * @param parent must not be {@literal null}. + * @param map must not be {@literal null}. + * @return + */ + private static Map, Type> mergeMaps(TypeDiscoverer parent, Map, Type> map) { + + Map, Type> typeVariableMap = new HashMap, Type>(); + typeVariableMap.putAll(map); + typeVariableMap.putAll(parent.getTypeVariableMap()); + + return typeVariableMap; + } + + @Override + protected TypeInformation createInfo(Type fieldType) { + + if (parent.getType().equals(fieldType)) { + return parent; + } + + return super.createInfo(fieldType); + } + + @Override + public boolean equals(Object obj) { + + if (!super.equals(obj)) { + return false; + } + + if (!this.getClass().equals(obj.getClass())) { + return false; + } + + ParentTypeAwareTypeInformation that = (ParentTypeAwareTypeInformation) obj; + return this.parent == null ? that.parent == null : this.parent.equals(that.parent); + } + + @Override + public int hashCode() { + + if (this.hashCode == 0) { + this.hashCode = super.hashCode() + 31 * parent.hashCode(); + } + + return this.hashCode; + } +} \ No newline at end of file diff --git a/src/main/java/com/lambdaworks/redis/dynamic/support/ReflectionUtils.java b/src/main/java/com/lambdaworks/redis/dynamic/support/ReflectionUtils.java new file mode 100644 index 0000000000..5498d76493 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/dynamic/support/ReflectionUtils.java @@ -0,0 +1,351 @@ +package com.lambdaworks.redis.dynamic.support; + +import java.lang.reflect.*; +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; + +import com.lambdaworks.redis.internal.LettuceAssert; + +/** + * Simple utility class for working with the reflection API and handling reflection exceptions. + * + *

    + * Only intended for internal use. + */ +public abstract class ReflectionUtils { + + /** + * Get the field represented by the supplied {@link Field field object} on the specified {@link Object target object}. In + * accordance with {@link Field#get(Object)} semantics, the returned value is automatically wrapped if the underlying field + * has a primitive type. + *

    + * Thrown exceptions are handled via a call to {@link #handleReflectionException(Exception)}. + * + * @param field the field to get + * @param target the target object from which to get the field + * @return the field's current value + */ + public static Object getField(Field field, Object target) { + try { + return field.get(target); + } catch (IllegalAccessException ex) { + handleReflectionException(ex); + throw new IllegalStateException( + "Unexpected reflection exception - " + ex.getClass().getName() + ": " + ex.getMessage()); + } + } + + /** + * Attempt to find a {@link Method} on the supplied class with the supplied name and no parameters. Searches all + * superclasses up to {@code Object}. + *

    + * Returns {@code null} if no {@link Method} can be found. + * + * @param clazz the class to introspect + * @param name the name of the method + * @return the Method object, or {@code null} if none found + */ + public static Method findMethod(Class clazz, String name) { + return findMethod(clazz, name, new Class[0]); + } + + /** + * Attempt to find a {@link Method} on the supplied class with the supplied name and parameter types. Searches all + * superclasses up to {@code Object}. + *

    + * Returns {@code null} if no {@link Method} can be found. + * + * @param clazz the class to introspect + * @param name the name of the method + * @param paramTypes the parameter types of the method (may be {@code null} to indicate any signature) + * @return the Method object, or {@code null} if none found + */ + public static Method findMethod(Class clazz, String name, Class... paramTypes) { + LettuceAssert.notNull(clazz, "Class must not be null"); + LettuceAssert.notNull(name, "Method name must not be null"); + Class searchType = clazz; + while (searchType != null) { + Method[] methods = (searchType.isInterface() ? searchType.getMethods() : getDeclaredMethods(searchType)); + for (Method method : methods) { + if (name.equals(method.getName()) + && (paramTypes == null || Arrays.equals(paramTypes, method.getParameterTypes()))) { + return method; + } + } + searchType = searchType.getSuperclass(); + } + return null; + } + + /** + * Invoke the specified {@link Method} against the supplied target object with no arguments. The target object can be + * {@code null} when invoking a static {@link Method}. + *

    + * Thrown exceptions are handled via a call to {@link #handleReflectionException}. + * + * @param method the method to invoke + * @param target the target object to invoke the method on + * @return the invocation result, if any + * @see #invokeMethod(java.lang.reflect.Method, Object, Object[]) + */ + public static Object invokeMethod(Method method, Object target) { + return invokeMethod(method, target, new Object[0]); + } + + /** + * Invoke the specified {@link Method} against the supplied target object with the supplied arguments. The target object can + * be {@code null} when invoking a static {@link Method}. + *

    + * Thrown exceptions are handled via a call to {@link #handleReflectionException}. + * + * @param method the method to invoke + * @param target the target object to invoke the method on + * @param args the invocation arguments (may be {@code null}) + * @return the invocation result, if any + */ + public static Object invokeMethod(Method method, Object target, Object... args) { + try { + return method.invoke(target, args); + } catch (Exception ex) { + handleReflectionException(ex); + } + throw new IllegalStateException("Should never get here"); + } + + /** + * Handle the given reflection exception. Should only be called if no checked exception is expected to be thrown by the + * target method. + *

    + * Throws the underlying RuntimeException or Error in case of an InvocationTargetException with such a root cause. Throws an + * IllegalStateException with an appropriate message or UndeclaredThrowableException otherwise. + * + * @param ex the reflection exception to handle + */ + public static void handleReflectionException(Exception ex) { + if (ex instanceof NoSuchMethodException) { + throw new IllegalStateException("Method not found: " + ex.getMessage()); + } + if (ex instanceof IllegalAccessException) { + throw new IllegalStateException("Could not access method: " + ex.getMessage()); + } + if (ex instanceof InvocationTargetException) { + handleInvocationTargetException((InvocationTargetException) ex); + } + if (ex instanceof RuntimeException) { + throw (RuntimeException) ex; + } + throw new UndeclaredThrowableException(ex); + } + + /** + * Handle the given invocation target exception. Should only be called if no checked exception is expected to be thrown by + * the target method. + *

    + * Throws the underlying RuntimeException or Error in case of such a root cause. Throws an UndeclaredThrowableException + * otherwise. + * + * @param ex the invocation target exception to handle + */ + public static void handleInvocationTargetException(InvocationTargetException ex) { + rethrowRuntimeException(ex.getTargetException()); + } + + /** + * Rethrow the given {@link Throwable exception}, which is presumably the target exception of an + * {@link InvocationTargetException}. Should only be called if no checked exception is expected to be thrown by the target + * method. + *

    + * Rethrows the underlying exception cast to a {@link RuntimeException} or {@link Error} if appropriate; otherwise, throws + * an {@link UndeclaredThrowableException}. + * + * @param ex the exception to rethrow + * @throws RuntimeException the rethrown exception + */ + public static void rethrowRuntimeException(Throwable ex) { + if (ex instanceof RuntimeException) { + throw (RuntimeException) ex; + } + if (ex instanceof Error) { + throw (Error) ex; + } + throw new UndeclaredThrowableException(ex); + } + + /** + * Perform the given callback operation on all matching methods of the given class and superclasses. + *

    + * The same named method occurring on subclass and superclass will appear twice, unless excluded by a {@link MethodFilter}. + * + * @param clazz the class to introspect + * @param mc the callback to invoke for each method + * @see #doWithMethods(Class, MethodCallback, MethodFilter) + */ + public static void doWithMethods(Class clazz, MethodCallback mc) { + doWithMethods(clazz, mc, null); + } + + /** + * Perform the given callback operation on all matching methods of the given class and superclasses (or given interface and + * super-interfaces). + *

    + * The same named method occurring on subclass and superclass will appear twice, unless excluded by the specified + * {@link MethodFilter}. + * + * @param clazz the class to introspect + * @param mc the callback to invoke for each method + * @param mf the filter that determines the methods to apply the callback to + */ + public static void doWithMethods(Class clazz, MethodCallback mc, MethodFilter mf) { + // Keep backing up the inheritance hierarchy. + Method[] methods = getDeclaredMethods(clazz); + for (Method method : methods) { + if (mf != null && !mf.matches(method)) { + continue; + } + try { + mc.doWith(method); + } catch (IllegalAccessException ex) { + throw new IllegalStateException("Not allowed to access method '" + method.getName() + "': " + ex); + } + } + if (clazz.getSuperclass() != null) { + doWithMethods(clazz.getSuperclass(), mc, mf); + } else if (clazz.isInterface()) { + for (Class superIfc : clazz.getInterfaces()) { + doWithMethods(superIfc, mc, mf); + } + } + } + + /** + * This variant retrieves {@link Class#getDeclaredMethods()} from a local cache in order to avoid the JVM's SecurityManager + * check and defensive array copying. In addition, it also includes Java 8 default methods from locally implemented + * interfaces, since those are effectively to be treated just like declared methods. + * + * @param clazz the class to introspect + * @return the cached array of methods + * @see Class#getDeclaredMethods() + */ + private static Method[] getDeclaredMethods(Class clazz) { + + Method[] result; + Method[] declaredMethods = clazz.getDeclaredMethods(); + List defaultMethods = findConcreteMethodsOnInterfaces(clazz); + if (defaultMethods != null) { + result = new Method[declaredMethods.length + defaultMethods.size()]; + System.arraycopy(declaredMethods, 0, result, 0, declaredMethods.length); + int index = declaredMethods.length; + for (Method defaultMethod : defaultMethods) { + result[index] = defaultMethod; + index++; + } + } else { + result = declaredMethods; + } + return result; + } + + private static List findConcreteMethodsOnInterfaces(Class clazz) { + List result = null; + for (Class ifc : clazz.getInterfaces()) { + for (Method ifcMethod : ifc.getMethods()) { + if (!Modifier.isAbstract(ifcMethod.getModifiers())) { + if (result == null) { + result = new LinkedList(); + } + result.add(ifcMethod); + } + } + } + return result; + } + + /** + * Invoke the given callback on all fields in the target class, going up the class hierarchy to get all declared fields. + * + * @param clazz the target class to analyze + * @param fc the callback to invoke for each field + */ + public static void doWithFields(Class clazz, FieldCallback fc) { + doWithFields(clazz, fc, null); + } + + /** + * Invoke the given callback on all fields in the target class, going up the class hierarchy to get all declared fields. + * + * @param clazz the target class to analyze + * @param fc the callback to invoke for each field + * @param ff the filter that determines the fields to apply the callback to + */ + public static void doWithFields(Class clazz, FieldCallback fc, FieldFilter ff) { + // Keep backing up the inheritance hierarchy. + Class targetClass = clazz; + do { + Field[] fields = targetClass.getDeclaredFields(); + for (Field field : fields) { + if (ff != null && !ff.matches(field)) { + continue; + } + try { + fc.doWith(field); + } catch (IllegalAccessException ex) { + throw new IllegalStateException("Not allowed to access field '" + field.getName() + "': " + ex); + } + } + targetClass = targetClass.getSuperclass(); + } while (targetClass != null && targetClass != Object.class); + } + + /** + * Action to take on each method. + */ + public interface MethodCallback { + + /** + * Perform an operation using the given method. + * + * @param method the method to operate on + */ + void doWith(Method method) throws IllegalArgumentException, IllegalAccessException; + } + + /** + * Callback optionally used to filter methods to be operated on by a method callback. + */ + public interface MethodFilter { + + /** + * Determine whether the given method matches. + * + * @param method the method to check + */ + boolean matches(Method method); + } + + /** + * Callback interface invoked on each field in the hierarchy. + */ + public interface FieldCallback { + + /** + * Perform an operation using the given field. + * + * @param field the field to operate on + */ + void doWith(Field field) throws IllegalArgumentException, IllegalAccessException; + } + + /** + * Callback optionally used to filter fields to be operated on by a field callback. + */ + public interface FieldFilter { + + /** + * Determine whether the given field matches. + * + * @param field the field to check + */ + boolean matches(Field field); + } +} diff --git a/src/main/java/com/lambdaworks/redis/dynamic/support/ResolvableType.java b/src/main/java/com/lambdaworks/redis/dynamic/support/ResolvableType.java new file mode 100644 index 0000000000..f07d27ae1a --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/dynamic/support/ResolvableType.java @@ -0,0 +1,1350 @@ +package com.lambdaworks.redis.dynamic.support; + +import java.io.Serializable; +import java.lang.reflect.*; +import java.util.Arrays; +import java.util.Collection; +import java.util.IdentityHashMap; +import java.util.Map; + +import com.lambdaworks.redis.LettuceStrings; +import com.lambdaworks.redis.dynamic.support.TypeWrapper.MethodParameterTypeProvider; +import com.lambdaworks.redis.dynamic.support.TypeWrapper.TypeProvider; +import com.lambdaworks.redis.internal.LettuceAssert; +import com.lambdaworks.redis.internal.LettuceClassUtils; + +/** + * Encapsulates a Java {@link java.lang.reflect.Type}, providing access to {@link #getSuperType() supertypes}, + * {@link #getInterfaces() interfaces}, and {@link #getGeneric(int...) generic parameters} along with the ability to ultimately + * {@link #resolve() resolve} to a {@link java.lang.Class}. + */ +@SuppressWarnings("serial") +class ResolvableType implements Serializable { + + /** + * {@code ResolvableType} returned when no value is available. {@code NONE} is used in preference to {@code null} so that + * multiple method calls can be safely chained. + */ + public static final ResolvableType NONE = new ResolvableType(null, null, null); + + private static final ResolvableType[] EMPTY_TYPES_ARRAY = new ResolvableType[0]; + + /** + * The underlying Java type being managed (only ever {@code null} for {@link #NONE}). + */ + private final Type type; + + /** + * Optional provider for the type. + */ + private final TypeProvider typeProvider; + + /** + * The {@code VariableResolver} to use or {@code null} if no resolver is available. + */ + private final VariableResolver variableResolver; + + /** + * The component type for an array or {@code null} if the type should be deduced. + */ + private final ResolvableType componentType; + + /** + * Copy of the resolved value. + */ + private final Class resolved; + + private ResolvableType superType; + + private ResolvableType[] interfaces; + + private ResolvableType[] generics; + + /** + * Private constructor used to create a new {@link ResolvableType} for cache key purposes, with no upfront resolution. + */ + private ResolvableType(Type type, TypeProvider typeProvider, VariableResolver variableResolver) { + this.type = type; + this.typeProvider = typeProvider; + this.variableResolver = variableResolver; + this.componentType = null; + this.resolved = resolveClass(); + } + + /** + * Private constructor used to create a new {@link ResolvableType} for uncached purposes, with upfront resolution but lazily + * calculated hash. + */ + private ResolvableType(Type type, TypeProvider typeProvider, VariableResolver variableResolver, + ResolvableType componentType) { + + this.type = type; + this.typeProvider = typeProvider; + this.variableResolver = variableResolver; + this.componentType = componentType; + this.resolved = resolveClass(); + } + + /** + * Private constructor used to create a new {@link ResolvableType} on a {@link Class} basis. Avoids all {@code instanceof} + * checks in order to create a straight {@link Class} wrapper. + */ + private ResolvableType(Class sourceClass) { + this.resolved = (sourceClass != null ? sourceClass : Object.class); + this.type = this.resolved; + this.typeProvider = null; + this.variableResolver = null; + this.componentType = null; + } + + /** + * Return the underling Java {@link Type} being managed. With the exception of the {@link #NONE} constant, this method will + * never return {@code null}. + */ + public Type getType() { + return TypeWrapper.unwrap(this.type); + } + + /** + * Return the underlying Java {@link Class} being managed, if available; otherwise {@code null}. + */ + public Class getRawClass() { + if (this.type == this.resolved) { + return this.resolved; + } + Type rawType = this.type; + if (rawType instanceof ParameterizedType) { + rawType = ((ParameterizedType) rawType).getRawType(); + } + return (rawType instanceof Class ? (Class) rawType : null); + } + + /** + * Return the underlying source of the resolvable type. Will return a {@link Field}, {@link MethodParameter} or {@link Type} + * depending on how the {@link ResolvableType} was constructed. With the exception of the {@link #NONE} constant, this + * method will never return {@code null}. This method is primarily to provide access to additional type information or + * meta-data that alternative JVM languages may provide. + */ + public Object getSource() { + Object source = (this.typeProvider != null ? this.typeProvider.getSource() : null); + return (source != null ? source : this.type); + } + + /** + * Determine whether the given object is an instance of this {@code ResolvableType}. + * + * @param obj the object to check + * @see #isAssignableFrom(Class) + */ + public boolean isInstance(Object obj) { + return (obj != null && isAssignableFrom(obj.getClass())); + } + + /** + * Determine whether this {@code ResolvableType} is assignable from the specified other type. + * + * @param other the type to be checked against (as a {@code Class}) + * @see #isAssignableFrom(ResolvableType) + */ + public boolean isAssignableFrom(Class other) { + return isAssignableFrom(forClass(other), null); + } + + /** + * Determine whether this {@code ResolvableType} is assignable from the specified other type. + *

    + * Attempts to follow the same rules as the Java compiler, considering whether both the {@link #resolve() resolved} + * {@code Class} is {@link Class#isAssignableFrom(Class) assignable from} the given type as well as whether all + * {@link #getGenerics() generics} are assignable. + * + * @param other the type to be checked against (as a {@code ResolvableType}) + * @return {@code true} if the specified other type can be assigned to this {@code ResolvableType}; {@code false} otherwise + */ + public boolean isAssignableFrom(ResolvableType other) { + return isAssignableFrom(other, null); + } + + private boolean isAssignableFrom(ResolvableType other, Map matchedBefore) { + LettuceAssert.notNull(other, "ResolvableType must not be null"); + + // If we cannot resolve types, we are not assignable + if (this == NONE || other == NONE) { + return false; + } + + // Deal with array by delegating to the component type + if (isArray()) { + return (other.isArray() && getComponentType().isAssignableFrom(other.getComponentType())); + } + + if (matchedBefore != null && matchedBefore.get(this.type) == other.type) { + return true; + } + + // Deal with wildcard bounds + WildcardBounds ourBounds = WildcardBounds.get(this); + WildcardBounds typeBounds = WildcardBounds.get(other); + + // In the from X is assignable to + if (typeBounds != null) { + return (ourBounds != null && ourBounds.isSameKind(typeBounds) + && ourBounds.isAssignableFrom(typeBounds.getBounds())); + } + + // In the form is assignable to X... + if (ourBounds != null) { + return ourBounds.isAssignableFrom(other); + } + + // Main assignability check about to follow + boolean exactMatch = (matchedBefore != null); // We're checking nested generic variables now... + boolean checkGenerics = true; + Class ourResolved = null; + if (this.type instanceof TypeVariable) { + TypeVariable variable = (TypeVariable) this.type; + // Try default variable resolution + if (this.variableResolver != null) { + ResolvableType resolved = this.variableResolver.resolveVariable(variable); + if (resolved != null) { + ourResolved = resolved.resolve(); + } + } + if (ourResolved == null) { + // Try variable resolution against target type + if (other.variableResolver != null) { + ResolvableType resolved = other.variableResolver.resolveVariable(variable); + if (resolved != null) { + ourResolved = resolved.resolve(); + checkGenerics = false; + } + } + } + if (ourResolved == null) { + // Unresolved type variable, potentially nested -> never insist on exact match + exactMatch = false; + } + } + if (ourResolved == null) { + ourResolved = resolve(Object.class); + } + Class otherResolved = other.resolve(Object.class); + + // We need an exact type match for generics + // List is not assignable from List + if (exactMatch ? !ourResolved.equals(otherResolved) : !LettuceClassUtils.isAssignable(ourResolved, otherResolved)) { + return false; + } + + if (checkGenerics) { + // Recursively check each generic + ResolvableType[] ourGenerics = getGenerics(); + ResolvableType[] typeGenerics = other.as(ourResolved).getGenerics(); + if (ourGenerics.length != typeGenerics.length) { + return false; + } + if (matchedBefore == null) { + matchedBefore = new IdentityHashMap(1); + } + matchedBefore.put(this.type, other.type); + for (int i = 0; i < ourGenerics.length; i++) { + if (!ourGenerics[i].isAssignableFrom(typeGenerics[i], matchedBefore)) { + return false; + } + } + } + + return true; + } + + /** + * Return {@code true} if this type resolves to a Class that represents an array. + * + * @see #getComponentType() + */ + public boolean isArray() { + if (this == NONE) { + return false; + } + return (((this.type instanceof Class && ((Class) this.type).isArray())) || this.type instanceof GenericArrayType + || resolveType().isArray()); + } + + /** + * Return the ResolvableType representing the component type of the array or {@link #NONE} if this type does not represent + * an array. + * + * @see #isArray() + */ + public ResolvableType getComponentType() { + if (this == NONE) { + return NONE; + } + if (this.componentType != null) { + return this.componentType; + } + if (this.type instanceof Class) { + Class componentType = ((Class) this.type).getComponentType(); + return forType(componentType, this.variableResolver); + } + if (this.type instanceof GenericArrayType) { + return forType(((GenericArrayType) this.type).getGenericComponentType(), this.variableResolver); + } + return resolveType().getComponentType(); + } + + /** + * Convenience method to return this type as a resolvable {@link Collection} type. Returns {@link #NONE} if this type does + * not implement or extend {@link Collection}. + * + * @see #as(Class) + * @see #asMap() + */ + public ResolvableType asCollection() { + return as(Collection.class); + } + + /** + * Convenience method to return this type as a resolvable {@link Map} type. Returns {@link #NONE} if this type does not + * implement or extend {@link Map}. + * + * @see #as(Class) + * @see #asCollection() + */ + public ResolvableType asMap() { + return as(Map.class); + } + + /** + * Return this type as a {@link ResolvableType} of the specified class. Searches {@link #getSuperType() supertype} and + * {@link #getInterfaces() interface} hierarchies to find a match, returning {@link #NONE} if this type does not implement + * or extend the specified class. + * + * @param type the required class type + * @return a {@link ResolvableType} representing this object as the specified type, or {@link #NONE} if not resolvable as + * that type + * @see #asCollection() + * @see #asMap() + * @see #getSuperType() + * @see #getInterfaces() + */ + public ResolvableType as(Class type) { + if (this == NONE) { + return NONE; + } + if (nullSafeEquals(resolve(), type)) { + return this; + } + for (ResolvableType interfaceType : getInterfaces()) { + ResolvableType interfaceAsType = interfaceType.as(type); + if (interfaceAsType != NONE) { + return interfaceAsType; + } + } + return getSuperType().as(type); + } + + /** + * Return a {@link ResolvableType} representing the direct supertype of this type. If no supertype is available this method + * returns {@link #NONE}. + * + * @see #getInterfaces() + */ + public ResolvableType getSuperType() { + Class resolved = resolve(); + if (resolved == null || resolved.getGenericSuperclass() == null) { + return NONE; + } + if (this.superType == null) { + this.superType = forType(TypeWrapper.forGenericSuperclass(resolved), asVariableResolver()); + } + return this.superType; + } + + /** + * Return a {@link ResolvableType} array representing the direct interfaces implemented by this type. If this type does not + * implement any interfaces an empty array is returned. + * + * @see #getSuperType() + */ + public ResolvableType[] getInterfaces() { + Class resolved = resolve(); + Object[] array = resolved.getGenericInterfaces(); + if (resolved == null || (array == null || array.length == 0)) { + return EMPTY_TYPES_ARRAY; + } + if (this.interfaces == null) { + this.interfaces = forTypes(TypeWrapper.forGenericInterfaces(resolved), asVariableResolver()); + } + return this.interfaces; + } + + /** + * Return {@code true} if this type contains generic parameters. + * + * @see #getGeneric(int...) + * @see #getGenerics() + */ + public boolean hasGenerics() { + return (getGenerics().length > 0); + } + + /** + * Return {@code true} if this type contains unresolvable generics only, that is, no substitute for any of its declared type + * variables. + */ + boolean isEntirelyUnresolvable() { + if (this == NONE) { + return false; + } + ResolvableType[] generics = getGenerics(); + for (ResolvableType generic : generics) { + if (!generic.isUnresolvableTypeVariable() && !generic.isWildcardWithoutBounds()) { + return false; + } + } + return true; + } + + /** + * Determine whether the underlying type has any unresolvable generics: either through an unresolvable type variable on the + * type itself or through implementing a generic interface in a raw fashion, i.e. without substituting that interface's type + * variables. The result will be {@code true} only in those two scenarios. + */ + public boolean hasUnresolvableGenerics() { + if (this == NONE) { + return false; + } + ResolvableType[] generics = getGenerics(); + for (ResolvableType generic : generics) { + if (generic.isUnresolvableTypeVariable() || generic.isWildcardWithoutBounds()) { + return true; + } + } + Class resolved = resolve(); + if (resolved != null) { + for (Type genericInterface : resolved.getGenericInterfaces()) { + if (genericInterface instanceof Class) { + if (forClass((Class) genericInterface).hasGenerics()) { + return true; + } + } + } + return getSuperType().hasUnresolvableGenerics(); + } + return false; + } + + /** + * Determine whether the underlying type is a type variable that cannot be resolved through the associated variable + * resolver. + */ + private boolean isUnresolvableTypeVariable() { + if (this.type instanceof TypeVariable) { + if (this.variableResolver == null) { + return true; + } + TypeVariable variable = (TypeVariable) this.type; + ResolvableType resolved = this.variableResolver.resolveVariable(variable); + if (resolved == null || resolved.isUnresolvableTypeVariable()) { + return true; + } + } + return false; + } + + /** + * Determine whether the underlying type represents a wildcard without specific bounds (i.e., equal to + * {@code ? extends Object}). + */ + private boolean isWildcardWithoutBounds() { + if (this.type instanceof WildcardType) { + WildcardType wt = (WildcardType) this.type; + if (wt.getLowerBounds().length == 0) { + Type[] upperBounds = wt.getUpperBounds(); + if (upperBounds.length == 0 || (upperBounds.length == 1 && Object.class == upperBounds[0])) { + return true; + } + } + } + return false; + } + + /** + * Return a {@link ResolvableType} for the specified nesting level. See {@link #getNested(int, Map)} for details. + * + * @param nestingLevel the nesting level + * @return the {@link ResolvableType} type, or {@code #NONE} + */ + public ResolvableType getNested(int nestingLevel) { + return getNested(nestingLevel, null); + } + + /** + * Return a {@link ResolvableType} for the specified nesting level. The nesting level refers to the specific generic + * parameter that should be returned. A nesting level of 1 indicates this type; 2 indicates the first nested generic; 3 the + * second; and so on. For example, given {@code List>} level 1 refers to the {@code List}, level 2 the + * {@code Set}, and level 3 the {@code Integer}. + *

    + * The {@code typeIndexesPerLevel} map can be used to reference a specific generic for the given level. For example, an + * index of 0 would refer to a {@code Map} key; whereas, 1 would refer to the value. If the map does not contain a value for + * a specific level the last generic will be used (e.g. a {@code Map} value). + *

    + * Nesting levels may also apply to array types; for example given {@code String[]}, a nesting level of 2 refers to + * {@code String}. + *

    + * If a type does not {@link #hasGenerics() contain} generics the {@link #getSuperType() supertype} hierarchy will be + * considered. + * + * @param nestingLevel the required nesting level, indexed from 1 for the current type, 2 for the first nested generic, 3 + * for the second and so on + * @param typeIndexesPerLevel a map containing the generic index for a given nesting level (may be {@code null}) + * @return a {@link ResolvableType} for the nested level or {@link #NONE} + */ + public ResolvableType getNested(int nestingLevel, Map typeIndexesPerLevel) { + ResolvableType result = this; + for (int i = 2; i <= nestingLevel; i++) { + if (result.isArray()) { + result = result.getComponentType(); + } else { + // Handle derived types + while (result != ResolvableType.NONE && !result.hasGenerics()) { + result = result.getSuperType(); + } + Integer index = (typeIndexesPerLevel != null ? typeIndexesPerLevel.get(i) : null); + index = (index == null ? result.getGenerics().length - 1 : index); + result = result.getGeneric(index); + } + } + return result; + } + + /** + * Return a {@link ResolvableType} representing the generic parameter for the given indexes. Indexes are zero based; for + * example given the type {@code Map>}, {@code getGeneric(0)} will access the {@code Integer}. Nested + * generics can be accessed by specifying multiple indexes; for example {@code getGeneric(1, 0)} will access the + * {@code String} from the nested {@code List}. For convenience, if no indexes are specified the first generic is returned. + *

    + * If no generic is available at the specified indexes {@link #NONE} is returned. + * + * @param indexes the indexes that refer to the generic parameter (may be omitted to return the first generic) + * @return a {@link ResolvableType} for the specified generic or {@link #NONE} + * @see #hasGenerics() + * @see #getGenerics() + * @see #resolveGeneric(int...) + * @see #resolveGenerics() + */ + public ResolvableType getGeneric(int... indexes) { + try { + if (indexes == null || indexes.length == 0) { + return getGenerics()[0]; + } + ResolvableType generic = this; + for (int index : indexes) { + generic = generic.getGenerics()[index]; + } + return generic; + } catch (IndexOutOfBoundsException ex) { + return NONE; + } + } + + /** + * Return an array of {@link ResolvableType}s representing the generic parameters of this type. If no generics are available + * an empty array is returned. If you need to access a specific generic consider using the {@link #getGeneric(int...)} + * method as it allows access to nested generics and protects against {@code IndexOutOfBoundsExceptions}. + * + * @return an array of {@link ResolvableType}s representing the generic parameters (never {@code null}) + * @see #hasGenerics() + * @see #getGeneric(int...) + * @see #resolveGeneric(int...) + * @see #resolveGenerics() + */ + public ResolvableType[] getGenerics() { + if (this == NONE) { + return EMPTY_TYPES_ARRAY; + } + if (this.generics == null) { + if (this.type instanceof Class) { + Class typeClass = (Class) this.type; + this.generics = forTypes(TypeWrapper.forTypeParameters(typeClass), this.variableResolver); + } else if (this.type instanceof ParameterizedType) { + Type[] actualTypeArguments = ((ParameterizedType) this.type).getActualTypeArguments(); + ResolvableType[] generics = new ResolvableType[actualTypeArguments.length]; + for (int i = 0; i < actualTypeArguments.length; i++) { + generics[i] = forType(actualTypeArguments[i], this.variableResolver); + } + this.generics = generics; + } else { + this.generics = resolveType().getGenerics(); + } + } + return this.generics; + } + + /** + * Convenience method that will {@link #getGenerics() get} and {@link #resolve() resolve} generic parameters. + * + * @return an array of resolved generic parameters (the resulting array will never be {@code null}, but it may contain + * {@code null} elements}) + * @see #getGenerics() + * @see #resolve() + */ + public Class[] resolveGenerics() { + return resolveGenerics(null); + } + + /** + * Convenience method that will {@link #getGenerics() get} and {@link #resolve() resolve} generic parameters, using the + * specified {@code fallback} if any type cannot be resolved. + * + * @param fallback the fallback class to use if resolution fails (may be {@code null}) + * @return an array of resolved generic parameters (the resulting array will never be {@code null}, but it may contain + * {@code null} elements}) + * @see #getGenerics() + * @see #resolve() + */ + public Class[] resolveGenerics(Class fallback) { + ResolvableType[] generics = getGenerics(); + Class[] resolvedGenerics = new Class[generics.length]; + for (int i = 0; i < generics.length; i++) { + resolvedGenerics[i] = generics[i].resolve(fallback); + } + return resolvedGenerics; + } + + /** + * Convenience method that will {@link #getGeneric(int...) get} and {@link #resolve() resolve} a specific generic + * parameters. + * + * @param indexes the indexes that refer to the generic parameter (may be omitted to return the first generic) + * @return a resolved {@link Class} or {@code null} + * @see #getGeneric(int...) + * @see #resolve() + */ + public Class resolveGeneric(int... indexes) { + return getGeneric(indexes).resolve(); + } + + /** + * Resolve this type to a {@link java.lang.Class}, returning {@code null} if the type cannot be resolved. This method will + * consider bounds of {@link TypeVariable}s and {@link WildcardType}s if direct resolution fails; however, bounds of + * {@code Object.class} will be ignored. + * + * @return the resolved {@link Class}, or {@code null} if not resolvable + * @see #resolve(Class) + * @see #resolveGeneric(int...) + * @see #resolveGenerics() + */ + public Class resolve() { + return resolve(null); + } + + /** + * Resolve this type to a {@link java.lang.Class}, returning the specified {@code fallback} if the type cannot be resolved. + * This method will consider bounds of {@link TypeVariable}s and {@link WildcardType}s if direct resolution fails; however, + * bounds of {@code Object.class} will be ignored. + * + * @param fallback the fallback class to use if resolution fails (may be {@code null}) + * @return the resolved {@link Class} or the {@code fallback} + * @see #resolve() + * @see #resolveGeneric(int...) + * @see #resolveGenerics() + */ + public Class resolve(Class fallback) { + return (this.resolved != null ? this.resolved : fallback); + } + + private Class resolveClass() { + if (this.type instanceof Class || this.type == null) { + return (Class) this.type; + } + if (this.type instanceof GenericArrayType) { + Class resolvedComponent = getComponentType().resolve(); + return (resolvedComponent != null ? Array.newInstance(resolvedComponent, 0).getClass() : null); + } + return resolveType().resolve(); + } + + /** + * Resolve this type by a single level, returning the resolved value or {@link #NONE}. + *

    + * Note: The returned {@link ResolvableType} should only be used as an intermediary as it cannot be serialized. + */ + ResolvableType resolveType() { + if (this.type instanceof ParameterizedType) { + return forType(((ParameterizedType) this.type).getRawType(), this.variableResolver); + } + if (this.type instanceof WildcardType) { + Type resolved = resolveBounds(((WildcardType) this.type).getUpperBounds()); + if (resolved == null) { + resolved = resolveBounds(((WildcardType) this.type).getLowerBounds()); + } + return forType(resolved, this.variableResolver); + } + if (this.type instanceof TypeVariable) { + TypeVariable variable = (TypeVariable) this.type; + // Try default variable resolution + if (this.variableResolver != null) { + ResolvableType resolved = this.variableResolver.resolveVariable(variable); + if (resolved != null) { + return resolved; + } + } + // Fallback to bounds + return forType(resolveBounds(variable.getBounds()), this.variableResolver); + } + return NONE; + } + + private Type resolveBounds(Type[] bounds) { + if ((bounds == null || bounds.length == 0) || Object.class == bounds[0]) { + return null; + } + return bounds[0]; + } + + private ResolvableType resolveVariable(TypeVariable variable) { + if (this.type instanceof TypeVariable) { + return resolveType().resolveVariable(variable); + } + if (this.type instanceof ParameterizedType) { + ParameterizedType parameterizedType = (ParameterizedType) this.type; + TypeVariable[] variables = resolve().getTypeParameters(); + for (int i = 0; i < variables.length; i++) { + if (nullSafeEquals(variables[i].getName(), variable.getName())) { + Type actualType = parameterizedType.getActualTypeArguments()[i]; + return forType(actualType, this.variableResolver); + } + } + if (parameterizedType.getOwnerType() != null) { + return forType(parameterizedType.getOwnerType(), this.variableResolver).resolveVariable(variable); + } + } + if (this.variableResolver != null) { + return this.variableResolver.resolveVariable(variable); + } + return null; + } + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + if (!(other instanceof ResolvableType)) { + return false; + } + + ResolvableType otherType = (ResolvableType) other; + if (!nullSafeEquals(this.type, otherType.type)) { + return false; + } + if (this.typeProvider != otherType.typeProvider && (this.typeProvider == null || otherType.typeProvider == null + || !nullSafeEquals(this.typeProvider.getSource(), otherType.typeProvider.getSource()))) { + return false; + } + if (this.variableResolver != otherType.variableResolver + && (this.variableResolver == null || otherType.variableResolver == null + || !nullSafeEquals(this.variableResolver.getSource(), otherType.variableResolver.getSource()))) { + return false; + } + if (!nullSafeEquals(this.componentType, otherType.componentType)) { + return false; + } + return true; + } + + /** + * Adapts this {@link ResolvableType} to a {@link VariableResolver}. + */ + VariableResolver asVariableResolver() { + if (this == NONE) { + return null; + } + return new DefaultVariableResolver(); + } + + /** + * Custom serialization support for {@link #NONE}. + */ + private Object readResolve() { + return (this.type == null ? NONE : this); + } + + /** + * Return a String representation of this type in its fully resolved form (including any generic parameters). + */ + @Override + public String toString() { + if (isArray()) { + return getComponentType() + "[]"; + } + if (this.resolved == null) { + return "?"; + } + if (this.type instanceof TypeVariable) { + TypeVariable variable = (TypeVariable) this.type; + if (this.variableResolver == null || this.variableResolver.resolveVariable(variable) == null) { + // Don't bother with variable boundaries for toString()... + // Can cause infinite recursions in case of self-references + return "?"; + } + } + StringBuilder result = new StringBuilder(this.resolved.getName()); + if (hasGenerics()) { + result.append('<'); + result.append(LettuceStrings.arrayToDelimitedString(getGenerics(), ", ")); + result.append('>'); + } + return result.toString(); + } + + // Factory methods + + /** + * Return a {@link ResolvableType} for the specified {@link Class}, using the full generic type information for + * assignability checks. For example: {@code ResolvableType.forClass(MyArrayList.class)}. + * + * @param sourceClass the source class ({@code null} is semantically equivalent to {@code Object.class} for typical use + * cases here} + * @return a {@link ResolvableType} for the specified class + * @see #forClass(Class, Class) + * @see #forClassWithGenerics(Class, Class...) + */ + public static ResolvableType forClass(Class sourceClass) { + return new ResolvableType(sourceClass); + } + + /** + * Return a {@link ResolvableType} for the specified {@link Class}, doing assignability checks against the raw class only + * (analogous to {@link Class#isAssignableFrom}, which this serves as a wrapper for. For example: + * {@code ResolvableType.forClass(MyArrayList.class)}. + * + * @param sourceClass the source class ({@code null} is semantically equivalent to {@code Object.class} for typical use + * cases here} + * @return a {@link ResolvableType} for the specified class + * @see #forClass(Class) + * @see #getRawClass() + */ + public static ResolvableType forRawClass(Class sourceClass) { + return new ResolvableType(sourceClass) { + @Override + public boolean isAssignableFrom(Class other) { + return LettuceClassUtils.isAssignable(getRawClass(), other); + } + }; + } + + /** + * Return a {@link ResolvableType} for the specified {@link Class} with a given implementation. For example: + * {@code ResolvableType.forClass(List.class, MyArrayList.class)}. + * + * @param sourceClass the source class (must not be {@code null} + * @param implementationClass the implementation class + * @return a {@link ResolvableType} for the specified class backed by the given implementation class + * @see #forClass(Class) + * @see #forClassWithGenerics(Class, Class...) + */ + public static ResolvableType forClass(Class sourceClass, Class implementationClass) { + LettuceAssert.notNull(sourceClass, "Source class must not be null"); + ResolvableType asType = forType(implementationClass).as(sourceClass); + return (asType == NONE ? forType(sourceClass) : asType); + } + + /** + * Return a {@link ResolvableType} for the specified {@link Class} with pre-declared generics. + * + * @param sourceClass the source class + * @param generics the generics of the class + * @return a {@link ResolvableType} for the specific class and generics + * @see #forClassWithGenerics(Class, ResolvableType...) + */ + public static ResolvableType forClassWithGenerics(Class sourceClass, Class... generics) { + LettuceAssert.notNull(sourceClass, "Source class must not be null"); + LettuceAssert.notNull(generics, "Generics must not be null"); + ResolvableType[] resolvableGenerics = new ResolvableType[generics.length]; + for (int i = 0; i < generics.length; i++) { + resolvableGenerics[i] = forClass(generics[i]); + } + return forClassWithGenerics(sourceClass, resolvableGenerics); + } + + /** + * Return a {@link ResolvableType} for the specified {@link Class} with pre-declared generics. + * + * @param sourceClass the source class + * @param generics the generics of the class + * @return a {@link ResolvableType} for the specific class and generics + * @see #forClassWithGenerics(Class, Class...) + */ + public static ResolvableType forClassWithGenerics(Class sourceClass, ResolvableType... generics) { + LettuceAssert.notNull(sourceClass, "Source class must not be null"); + LettuceAssert.notNull(generics, "Generics must not be null"); + TypeVariable[] variables = sourceClass.getTypeParameters(); + LettuceAssert.isTrue(variables.length == generics.length, "Mismatched number of generics specified"); + + Type[] arguments = new Type[generics.length]; + for (int i = 0; i < generics.length; i++) { + ResolvableType generic = generics[i]; + Type argument = (generic != null ? generic.getType() : null); + arguments[i] = (argument != null ? argument : variables[i]); + } + + ParameterizedType syntheticType = new SyntheticParameterizedType(sourceClass, arguments); + return forType(syntheticType, new TypeVariablesVariableResolver(variables, generics)); + } + + /** + * Return a {@link ResolvableType} for the specified {@link Method} return type. + * + * @param method the source for the method return type + * @return a {@link ResolvableType} for the specified method return + * @see #forMethodReturnType(Method, Class) + */ + public static ResolvableType forMethodReturnType(Method method) { + LettuceAssert.notNull(method, "Method must not be null"); + return forMethodParameter(new MethodParameter(method, -1)); + } + + /** + * Return a {@link ResolvableType} for the specified {@link Method} return type. Use this variant when the class that + * declares the method includes generic parameter variables that are satisfied by the implementation class. + * + * @param method the source for the method return type + * @param implementationClass the implementation class + * @return a {@link ResolvableType} for the specified method return + * @see #forMethodReturnType(Method) + */ + public static ResolvableType forMethodReturnType(Method method, Class implementationClass) { + LettuceAssert.notNull(method, "Method must not be null"); + MethodParameter methodParameter = new MethodParameter(method, -1); + methodParameter.setContainingClass(implementationClass); + return forMethodParameter(methodParameter); + } + + /** + * Return a {@link ResolvableType} for the specified {@link Method} parameter. + * + * @param method the source method (must not be {@code null}) + * @param parameterIndex the parameter index + * @return a {@link ResolvableType} for the specified method parameter + * @see #forMethodParameter(Method, int, Class) + * @see #forMethodParameter(MethodParameter) + */ + public static ResolvableType forMethodParameter(Method method, int parameterIndex) { + LettuceAssert.notNull(method, "Method must not be null"); + return forMethodParameter(new MethodParameter(method, parameterIndex)); + } + + /** + * Return a {@link ResolvableType} for the specified {@link Method} parameter with a given implementation. Use this variant + * when the class that declares the method includes generic parameter variables that are satisfied by the implementation + * class. + * + * @param method the source method (must not be {@code null}) + * @param parameterIndex the parameter index + * @param implementationClass the implementation class + * @return a {@link ResolvableType} for the specified method parameter + * @see #forMethodParameter(Method, int, Class) + * @see #forMethodParameter(MethodParameter) + */ + public static ResolvableType forMethodParameter(Method method, int parameterIndex, Class implementationClass) { + LettuceAssert.notNull(method, "Method must not be null"); + MethodParameter methodParameter = new MethodParameter(method, parameterIndex); + methodParameter.setContainingClass(implementationClass); + return forMethodParameter(methodParameter); + } + + /** + * Return a {@link ResolvableType} for the specified {@link MethodParameter}. + * + * @param methodParameter the source method parameter (must not be {@code null}) + * @return a {@link ResolvableType} for the specified method parameter + * @see #forMethodParameter(Method, int) + */ + public static ResolvableType forMethodParameter(MethodParameter methodParameter) { + return forMethodParameter(methodParameter, (Type) null); + } + + /** + * Return a {@link ResolvableType} for the specified {@link MethodParameter} with a given implementation type. Use this + * variant when the class that declares the method includes generic parameter variables that are satisfied by the + * implementation type. + * + * @param methodParameter the source method parameter (must not be {@code null}) + * @param implementationType the implementation type + * @return a {@link ResolvableType} for the specified method parameter + * @see #forMethodParameter(MethodParameter) + */ + public static ResolvableType forMethodParameter(MethodParameter methodParameter, ResolvableType implementationType) { + LettuceAssert.notNull(methodParameter, "MethodParameter must not be null"); + implementationType = (implementationType != null ? implementationType : forType(methodParameter.getContainingClass())); + ResolvableType owner = implementationType.as(methodParameter.getDeclaringClass()); + return forType(null, new MethodParameterTypeProvider(methodParameter), owner.asVariableResolver()) + .getNested(methodParameter.getNestingLevel(), methodParameter.typeIndexesPerLevel); + } + + /** + * Return a {@link ResolvableType} for the specified {@link MethodParameter}, overriding the target type to resolve with a + * specific given type. + * + * @param methodParameter the source method parameter (must not be {@code null}) + * @param targetType the type to resolve (a part of the method parameter's type) + * @return a {@link ResolvableType} for the specified method parameter + * @see #forMethodParameter(Method, int) + */ + public static ResolvableType forMethodParameter(MethodParameter methodParameter, Type targetType) { + LettuceAssert.notNull(methodParameter, "MethodParameter must not be null"); + ResolvableType owner = forType(methodParameter.getContainingClass()).as(methodParameter.getDeclaringClass()); + return forType(targetType, new MethodParameterTypeProvider(methodParameter), owner.asVariableResolver()) + .getNested(methodParameter.getNestingLevel(), methodParameter.typeIndexesPerLevel); + } + + /** + * Resolve the top-level parameter type of the given {@code MethodParameter}. + * + * @param methodParameter the method parameter to resolve + * @see MethodParameter#setParameterType + */ + static void resolveMethodParameter(MethodParameter methodParameter) { + LettuceAssert.notNull(methodParameter, "MethodParameter must not be null"); + ResolvableType owner = forType(methodParameter.getContainingClass()).as(methodParameter.getDeclaringClass()); + methodParameter.setParameterType( + forType(null, new MethodParameterTypeProvider(methodParameter), owner.asVariableResolver()).resolve()); + } + + /** + * Return a {@link ResolvableType} as a array of the specified {@code componentType}. + * + * @param componentType the component type + * @return a {@link ResolvableType} as an array of the specified component type + */ + public static ResolvableType forArrayComponent(ResolvableType componentType) { + LettuceAssert.notNull(componentType, "Component type must not be null"); + Class arrayClass = Array.newInstance(componentType.resolve(), 0).getClass(); + return new ResolvableType(arrayClass, null, null, componentType); + } + + private static ResolvableType[] forTypes(Type[] types, VariableResolver owner) { + ResolvableType[] result = new ResolvableType[types.length]; + for (int i = 0; i < types.length; i++) { + result[i] = forType(types[i], owner); + } + return result; + } + + /** + * Return a {@link ResolvableType} for the specified {@link Type}. Note: The resulting {@link ResolvableType} may not be + * {@link Serializable}. + * + * @param type the source type or {@code null} + * @return a {@link ResolvableType} for the specified {@link Type} + * @see #forType(Type, ResolvableType) + */ + public static ResolvableType forType(Type type) { + return forType(type, null, null); + } + + /** + * Return a {@link ResolvableType} for the specified {@link Type} backed by the given owner type. Note: The resulting + * {@link ResolvableType} may not be {@link Serializable}. + * + * @param type the source type or {@code null} + * @param owner the owner type used to resolve variables + * @return a {@link ResolvableType} for the specified {@link Type} and owner + * @see #forType(Type) + */ + public static ResolvableType forType(Type type, ResolvableType owner) { + VariableResolver variableResolver = null; + if (owner != null) { + variableResolver = owner.asVariableResolver(); + } + return forType(type, variableResolver); + } + + /** + * Return a {@link ResolvableType} for the specified {@link Type} backed by a given {@link VariableResolver}. + * + * @param type the source type or {@code null} + * @param variableResolver the variable resolver or {@code null} + * @return a {@link ResolvableType} for the specified {@link Type} and {@link VariableResolver} + */ + static ResolvableType forType(Type type, VariableResolver variableResolver) { + return forType(type, null, variableResolver); + } + + /** + * Return a {@link ResolvableType} for the specified {@link Type} backed by a given {@link VariableResolver}. + * + * @param type the source type or {@code null} + * @param typeProvider the type provider or {@code null} + * @param variableResolver the variable resolver or {@code null} + * @return a {@link ResolvableType} for the specified {@link Type} and {@link VariableResolver} + */ + static ResolvableType forType(Type type, TypeProvider typeProvider, VariableResolver variableResolver) { + if (type == null && typeProvider != null) { + type = TypeWrapper.forTypeProvider(typeProvider); + } + if (type == null) { + return NONE; + } + + // For simple Class references, build the wrapper right away - + // no expensive resolution necessary, so not worth caching... + if (type instanceof Class) { + return new ResolvableType(type, typeProvider, variableResolver, null); + } + + return new ResolvableType(type, typeProvider, variableResolver); + } + + /** + * Strategy interface used to resolve {@link TypeVariable}s. + */ + interface VariableResolver extends Serializable { + + /** + * Return the source of the resolver (used for hashCode and equals). + */ + Object getSource(); + + /** + * Resolve the specified variable. + * + * @param variable the variable to resolve + * @return the resolved variable, or {@code null} if not found + */ + ResolvableType resolveVariable(TypeVariable variable); + } + + @SuppressWarnings("serial") + private class DefaultVariableResolver implements VariableResolver { + + @Override + public ResolvableType resolveVariable(TypeVariable variable) { + return ResolvableType.this.resolveVariable(variable); + } + + @Override + public Object getSource() { + return ResolvableType.this; + } + } + + @SuppressWarnings("serial") + private static class TypeVariablesVariableResolver implements VariableResolver { + + private final TypeVariable[] variables; + + private final ResolvableType[] generics; + + public TypeVariablesVariableResolver(TypeVariable[] variables, ResolvableType[] generics) { + this.variables = variables; + this.generics = generics; + } + + @Override + public ResolvableType resolveVariable(TypeVariable variable) { + for (int i = 0; i < this.variables.length; i++) { + if (TypeWrapper.unwrap(this.variables[i]).equals(TypeWrapper.unwrap(variable))) { + return this.generics[i]; + } + } + return null; + } + + @Override + public Object getSource() { + return this.generics; + } + } + + private static final class SyntheticParameterizedType implements ParameterizedType, Serializable { + + private final Type rawType; + + private final Type[] typeArguments; + + public SyntheticParameterizedType(Type rawType, Type[] typeArguments) { + this.rawType = rawType; + this.typeArguments = typeArguments; + } + + @Override + public Type getOwnerType() { + return null; + } + + @Override + public Type getRawType() { + return this.rawType; + } + + @Override + public Type[] getActualTypeArguments() { + return this.typeArguments; + } + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + if (!(other instanceof ParameterizedType)) { + return false; + } + ParameterizedType otherType = (ParameterizedType) other; + return (otherType.getOwnerType() == null && this.rawType.equals(otherType.getRawType()) + && Arrays.equals(this.typeArguments, otherType.getActualTypeArguments())); + } + + @Override + public int hashCode() { + return (this.rawType.hashCode() * 31 + Arrays.hashCode(this.typeArguments)); + } + } + + /** + * Internal helper to handle bounds from {@link WildcardType}s. + */ + private static class WildcardBounds { + + private final Kind kind; + + private final ResolvableType[] bounds; + + /** + * Internal constructor to create a new {@link WildcardBounds} instance. + * + * @param kind the kind of bounds + * @param bounds the bounds + * @see #get(ResolvableType) + */ + public WildcardBounds(Kind kind, ResolvableType[] bounds) { + this.kind = kind; + this.bounds = bounds; + } + + /** + * Return {@code true} if this bounds is the same kind as the specified bounds. + */ + public boolean isSameKind(WildcardBounds bounds) { + return this.kind == bounds.kind; + } + + /** + * Return {@code true} if this bounds is assignable to all the specified types. + * + * @param types the types to test against + * @return {@code true} if this bounds is assignable to all types + */ + public boolean isAssignableFrom(ResolvableType... types) { + for (ResolvableType bound : this.bounds) { + for (ResolvableType type : types) { + if (!isAssignable(bound, type)) { + return false; + } + } + } + return true; + } + + private boolean isAssignable(ResolvableType source, ResolvableType from) { + return (this.kind == Kind.UPPER ? source.isAssignableFrom(from) : from.isAssignableFrom(source)); + } + + /** + * Return the underlying bounds. + */ + public ResolvableType[] getBounds() { + return this.bounds; + } + + /** + * Get a {@link WildcardBounds} instance for the specified type, returning {@code null} if the specified type cannot be + * resolved to a {@link WildcardType}. + * + * @param type the source type + * @return a {@link WildcardBounds} instance or {@code null} + */ + public static WildcardBounds get(ResolvableType type) { + ResolvableType resolveToWildcard = type; + while (!(resolveToWildcard.getType() instanceof WildcardType)) { + if (resolveToWildcard == NONE) { + return null; + } + resolveToWildcard = resolveToWildcard.resolveType(); + } + WildcardType wildcardType = (WildcardType) resolveToWildcard.type; + Kind boundsType = (wildcardType.getLowerBounds().length > 0 ? Kind.LOWER : Kind.UPPER); + Type[] bounds = boundsType == Kind.UPPER ? wildcardType.getUpperBounds() : wildcardType.getLowerBounds(); + ResolvableType[] resolvableBounds = new ResolvableType[bounds.length]; + for (int i = 0; i < bounds.length; i++) { + resolvableBounds[i] = ResolvableType.forType(bounds[i], type.variableResolver); + } + return new WildcardBounds(boundsType, resolvableBounds); + } + + /** + * The various kinds of bounds. + */ + enum Kind { + UPPER, LOWER + } + } + + /** + * Determine if the given objects are equal, returning {@code true} if both are {@code null} or {@code false} if only one is + * {@code null}. + *

    + * Compares arrays with {@code Arrays.equals}, performing an equality check based on the array elements rather than the + * array reference. + * + * @param o1 first Object to compare + * @param o2 second Object to compare + * @return whether the given objects are equal + * @see java.util.Arrays#equals + */ + private static boolean nullSafeEquals(Object o1, Object o2) { + if (o1 == o2) { + return true; + } + if (o1 == null || o2 == null) { + return false; + } + if (o1.equals(o2)) { + return true; + } + if (o1.getClass().isArray() && o2.getClass().isArray()) { + if (o1 instanceof Object[] && o2 instanceof Object[]) { + return Arrays.equals((Object[]) o1, (Object[]) o2); + } + if (o1 instanceof boolean[] && o2 instanceof boolean[]) { + return Arrays.equals((boolean[]) o1, (boolean[]) o2); + } + if (o1 instanceof byte[] && o2 instanceof byte[]) { + return Arrays.equals((byte[]) o1, (byte[]) o2); + } + if (o1 instanceof char[] && o2 instanceof char[]) { + return Arrays.equals((char[]) o1, (char[]) o2); + } + if (o1 instanceof double[] && o2 instanceof double[]) { + return Arrays.equals((double[]) o1, (double[]) o2); + } + if (o1 instanceof float[] && o2 instanceof float[]) { + return Arrays.equals((float[]) o1, (float[]) o2); + } + if (o1 instanceof int[] && o2 instanceof int[]) { + return Arrays.equals((int[]) o1, (int[]) o2); + } + if (o1 instanceof long[] && o2 instanceof long[]) { + return Arrays.equals((long[]) o1, (long[]) o2); + } + if (o1 instanceof short[] && o2 instanceof short[]) { + return Arrays.equals((short[]) o1, (short[]) o2); + } + } + return false; + } + +} diff --git a/src/main/java/com/lambdaworks/redis/dynamic/support/StandardReflectionParameterNameDiscoverer.java b/src/main/java/com/lambdaworks/redis/dynamic/support/StandardReflectionParameterNameDiscoverer.java new file mode 100644 index 0000000000..112f578497 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/dynamic/support/StandardReflectionParameterNameDiscoverer.java @@ -0,0 +1,43 @@ +package com.lambdaworks.redis.dynamic.support; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.lang.reflect.Parameter; + +/** + * {@link ParameterNameDiscoverer} implementation which uses JDK 8's reflection facilities for introspecting parameter names + * (based on the "-parameters" compiler flag). + * + * @see java.lang.reflect.Parameter#getName() + */ +public class StandardReflectionParameterNameDiscoverer implements ParameterNameDiscoverer { + + @Override + public String[] getParameterNames(Method method) { + Parameter[] parameters = method.getParameters(); + String[] parameterNames = new String[parameters.length]; + for (int i = 0; i < parameters.length; i++) { + Parameter param = parameters[i]; + if (!param.isNamePresent()) { + return null; + } + parameterNames[i] = param.getName(); + } + return parameterNames; + } + + @Override + public String[] getParameterNames(Constructor ctor) { + Parameter[] parameters = ctor.getParameters(); + String[] parameterNames = new String[parameters.length]; + for (int i = 0; i < parameters.length; i++) { + Parameter param = parameters[i]; + if (!param.isNamePresent()) { + return null; + } + parameterNames[i] = param.getName(); + } + return parameterNames; + } + +} \ No newline at end of file diff --git a/src/main/java/com/lambdaworks/redis/dynamic/support/TypeDiscoverer.java b/src/main/java/com/lambdaworks/redis/dynamic/support/TypeDiscoverer.java new file mode 100644 index 0000000000..fcd76111ee --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/dynamic/support/TypeDiscoverer.java @@ -0,0 +1,365 @@ +package com.lambdaworks.redis.dynamic.support; + +import java.lang.reflect.*; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + +import com.lambdaworks.redis.internal.LettuceAssert; + +/** + * Basic {@link TypeDiscoverer} that contains basic functionality to discover property types. + */ +class TypeDiscoverer implements TypeInformation { + + private final Type type; + private final Map, Type> typeVariableMap; + private final Map> fieldTypes = new ConcurrentHashMap>(); + private final int hashCode; + + private boolean componentTypeResolved = false; + private TypeInformation componentType; + + private boolean valueTypeResolved = false; + private TypeInformation valueType; + + private Class resolvedType; + + /** + * Creates a ne {@link TypeDiscoverer} for the given type, type variable map and parent. + * + * @param type must not be {@literal null}. + * @param typeVariableMap must not be {@literal null}. + */ + protected TypeDiscoverer(Type type, Map, Type> typeVariableMap) { + + LettuceAssert.notNull(type, "Type must not be null"); + + this.type = type; + this.typeVariableMap = typeVariableMap; + this.hashCode = 17 + (31 * type.hashCode()) + (31 * typeVariableMap.hashCode()); + } + + /** + * Returns the type variable map. + * + * @return + */ + protected Map, Type> getTypeVariableMap() { + return typeVariableMap; + } + + /** + * Creates {@link TypeInformation} for the given {@link Type}. + * + * @param fieldType + * @return + */ + @SuppressWarnings({ "rawtypes", "unchecked", "deprecation" }) + protected TypeInformation createInfo(Type fieldType) { + + if (fieldType.equals(this.type)) { + return this; + } + + if (fieldType instanceof Class) { + return new ClassTypeInformation((Class) fieldType); + } + + Class resolveType = resolveType(fieldType); + Map variableMap = new HashMap(); + variableMap.putAll(GenericTypeResolver.getTypeVariableMap(resolveType)); + + if (fieldType instanceof ParameterizedType) { + + ParameterizedType parameterizedType = (ParameterizedType) fieldType; + + TypeVariable>[] typeParameters = resolveType.getTypeParameters(); + Type[] arguments = parameterizedType.getActualTypeArguments(); + + for (int i = 0; i < typeParameters.length; i++) { + variableMap.put(typeParameters[i], arguments[i]); + } + + return new ParametrizedTypeInformation(parameterizedType, this, variableMap); + } + + if (fieldType instanceof TypeVariable) { + TypeVariable variable = (TypeVariable) fieldType; + return new TypeVariableTypeInformation(variable, type, this, variableMap); + } + + if (fieldType instanceof GenericArrayType) { + return new GenericArrayTypeInformation((GenericArrayType) fieldType, this, variableMap); + } + + if (fieldType instanceof WildcardType) { + + WildcardType wildcardType = (WildcardType) fieldType; + Type[] bounds = wildcardType.getLowerBounds(); + + if (bounds.length > 0) { + return createInfo(bounds[0]); + } + + bounds = wildcardType.getUpperBounds(); + + if (bounds.length > 0) { + return createInfo(bounds[0]); + } + } + + throw new IllegalArgumentException(); + } + + /** + * Resolves the given type into a plain {@link Class}. + * + * @param type + * @return + */ + @SuppressWarnings({ "unchecked", "rawtypes", "deprecation" }) + protected Class resolveType(Type type) { + + Map map = new HashMap(); + map.putAll(getTypeVariableMap()); + + return (Class) ResolvableType.forType(type, new TypeVariableMapVariableResolver(map)).resolve(Object.class); + } + + public List> getParameterTypes(Constructor constructor) { + + LettuceAssert.notNull(constructor, "Constructor must not be null!"); + + Type[] types = constructor.getGenericParameterTypes(); + List> result = new ArrayList>(types.length); + + for (Type parameterType : types) { + result.add(createInfo(parameterType)); + } + + return result; + } + + public Class getType() { + + if (resolvedType == null) { + this.resolvedType = resolveType(type); + } + + return this.resolvedType; + } + + @Override + public ClassTypeInformation getRawTypeInformation() { + return ClassTypeInformation.from(getType()).getRawTypeInformation(); + } + + public TypeInformation getActualType() { + + if (isMap()) { + return getMapValueType(); + } + + if (isCollectionLike()) { + return getComponentType(); + } + + return this; + } + + public boolean isMap() { + return Map.class.isAssignableFrom(getType()); + } + + public TypeInformation getMapValueType() { + + if (!valueTypeResolved) { + this.valueType = doGetMapValueType(); + this.valueTypeResolved = true; + } + + return this.valueType; + } + + protected TypeInformation doGetMapValueType() { + + if (isMap()) { + return getTypeArgument(Map.class, 1); + } + + List> arguments = getTypeArguments(); + + if (arguments.size() > 1) { + return arguments.get(1); + } + + return null; + } + + public boolean isCollectionLike() { + + Class rawType = getType(); + + if (rawType.isArray() || Iterable.class.equals(rawType)) { + return true; + } + + return Collection.class.isAssignableFrom(rawType); + } + + public final TypeInformation getComponentType() { + + if (!componentTypeResolved) { + this.componentType = doGetComponentType(); + this.componentTypeResolved = true; + } + + return this.componentType; + } + + protected TypeInformation doGetComponentType() { + + Class rawType = getType(); + + if (rawType.isArray()) { + return createInfo(rawType.getComponentType()); + } + + if (isMap()) { + return getTypeArgument(Map.class, 0); + } + + if (Iterable.class.isAssignableFrom(rawType)) { + return getTypeArgument(Iterable.class, 0); + } + + List> arguments = getTypeArguments(); + + if (arguments.size() > 0) { + return arguments.get(0); + } + + return null; + } + + public TypeInformation getReturnType(Method method) { + + return createInfo(method.getGenericReturnType()); + } + + public List> getParameterTypes(Method method) { + + LettuceAssert.notNull(method, "Method most not be null!"); + + Type[] types = method.getGenericParameterTypes(); + List> result = new ArrayList>(types.length); + + for (Type parameterType : types) { + result.add(createInfo(parameterType)); + } + + return result; + } + + public TypeInformation getSuperTypeInformation(Class superType) { + + Class rawType = getType(); + + if (!superType.isAssignableFrom(rawType)) { + return null; + } + + if (getType().equals(superType)) { + return this; + } + + List candidates = new ArrayList(); + + Type genericSuperclass = rawType.getGenericSuperclass(); + if (genericSuperclass != null) { + candidates.add(genericSuperclass); + } + candidates.addAll(Arrays.asList(rawType.getGenericInterfaces())); + + for (Type candidate : candidates) { + + TypeInformation candidateInfo = createInfo(candidate); + + if (superType.equals(candidateInfo.getType())) { + return candidateInfo; + } else { + TypeInformation nestedSuperType = candidateInfo.getSuperTypeInformation(superType); + if (nestedSuperType != null) { + return nestedSuperType; + } + } + } + + return null; + } + + public List> getTypeArguments() { + return Collections.emptyList(); + } + + public boolean isAssignableFrom(TypeInformation target) { + return target.getSuperTypeInformation(getType()).equals(this); + } + + public TypeInformation getTypeArgument(Class bound, int index) { + + Class[] arguments = GenericTypeResolver.resolveTypeArguments(getType(), bound); + + if (arguments == null) { + return getSuperTypeInformation(bound) instanceof ParametrizedTypeInformation ? ClassTypeInformation.OBJECT : null; + } + + return createInfo(arguments[index]); + } + + @Override + public boolean equals(Object obj) { + + if (obj == this) { + return true; + } + + if (obj == null) { + return false; + } + + if (!this.getClass().equals(obj.getClass())) { + return false; + } + + TypeDiscoverer that = (TypeDiscoverer) obj; + + return this.type.equals(that.type) && this.typeVariableMap.equals(that.typeVariableMap); + } + + @Override + public int hashCode() { + return hashCode; + } + + @SuppressWarnings({ "serial", "rawtypes" }) + private static class TypeVariableMapVariableResolver implements ResolvableType.VariableResolver { + + private final Map typeVariableMap; + + public TypeVariableMapVariableResolver(Map typeVariableMap) { + this.typeVariableMap = typeVariableMap; + } + + @Override + public ResolvableType resolveVariable(TypeVariable variable) { + Type type = this.typeVariableMap.get(variable); + return (type != null ? ResolvableType.forType(type) : null); + } + + @Override + public Object getSource() { + return this.typeVariableMap; + } + } +} \ No newline at end of file diff --git a/src/main/java/com/lambdaworks/redis/dynamic/support/TypeInformation.java b/src/main/java/com/lambdaworks/redis/dynamic/support/TypeInformation.java new file mode 100644 index 0000000000..1ac8c6b53d --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/dynamic/support/TypeInformation.java @@ -0,0 +1,115 @@ +package com.lambdaworks.redis.dynamic.support; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.util.List; + +/** + * Interface to access types and resolving generics on the way. + */ +public interface TypeInformation { + + /** + * Returns the {@link TypeInformation}s for the parameters of the given {@link Constructor}. + * + * @param constructor must not be {@literal null}. + * @return + */ + List> getParameterTypes(Constructor constructor); + + /** + * Returns whether the type can be considered a collection, which means it's a container of elements, e.g. a + * {@link java.util.Collection} and {@link java.lang.reflect.Array} or anything implementing {@link Iterable}. If this + * returns {@literal true} you can expect {@link #getComponentType()} to return a non-{@literal null} value. + * + * @return + */ + boolean isCollectionLike(); + + /** + * Returns the component type for {@link java.util.Collection}s or the key type for {@link java.util.Map}s. + * + * @return + */ + TypeInformation getComponentType(); + + /** + * Returns whether the property is a {@link java.util.Map}. If this returns {@literal true} you can expect + * {@link #getComponentType()} as well as {@link #getMapValueType()} to return something not {@literal null}. + * + * @return + */ + boolean isMap(); + + /** + * Will return the type of the value in case the underlying type is a {@link java.util.Map}. + * + * @return + */ + TypeInformation getMapValueType(); + + /** + * Returns the type of the property. Will resolve generics and the generic context of + * + * @return + */ + Class getType(); + + /** + * Returns a {@link ClassTypeInformation} to represent the {@link TypeInformation} of the raw type of the current instance. + * + * @return + */ + ClassTypeInformation getRawTypeInformation(); + + /** + * Transparently returns the {@link java.util.Map} value type if the type is a {@link java.util.Map}, returns the component + * type if the type {@link #isCollectionLike()} or the simple type if none of this applies. + * + * @return + */ + TypeInformation getActualType(); + + /** + * Returns a {@link TypeInformation} for the return type of the given {@link Method}. Will potentially resolve generics + * information against the current types type parameter bindings. + * + * @param method must not be {@literal null}. + * @return + */ + TypeInformation getReturnType(Method method); + + /** + * Returns the {@link TypeInformation}s for the parameters of the given {@link Method}. + * + * @param method must not be {@literal null}. + * @return + */ + List> getParameterTypes(Method method); + + /** + * Returns the {@link TypeInformation} for the given raw super type. + * + * @param superType must not be {@literal null}. + * @return the {@link TypeInformation} for the given raw super type or {@literal null} in case the current + * {@link TypeInformation} does not implement the given type. + */ + TypeInformation getSuperTypeInformation(Class superType); + + /** + * Returns if the current {@link TypeInformation} can be safely assigned to the given one. Mimics semantics of + * {@link Class#isAssignableFrom(Class)} but takes generics into account. Thus it will allow to detect that a + * {@code List} is assignable to {@code List}. + * + * @param target + * @return + */ + boolean isAssignableFrom(TypeInformation target); + + /** + * Returns the {@link TypeInformation} for the type arguments of the current {@link TypeInformation}. + * + * @return + */ + List> getTypeArguments(); +} \ No newline at end of file diff --git a/src/main/java/com/lambdaworks/redis/dynamic/support/TypeVariableTypeInformation.java b/src/main/java/com/lambdaworks/redis/dynamic/support/TypeVariableTypeInformation.java new file mode 100644 index 0000000000..7d9c1c9623 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/dynamic/support/TypeVariableTypeInformation.java @@ -0,0 +1,95 @@ +package com.lambdaworks.redis.dynamic.support; + +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.lang.reflect.TypeVariable; +import java.util.Map; + +import com.lambdaworks.redis.internal.LettuceAssert; + +/** + * Special {@link TypeDiscoverer} to determine the actual type for a {@link TypeVariable}. Will consider the context the + * {@link TypeVariable} is being used in. + */ +public class TypeVariableTypeInformation extends ParentTypeAwareTypeInformation { + + private final TypeVariable variable; + private final Type owningType; + + /** + * Creates a bew {@link TypeVariableTypeInformation} for the given {@link TypeVariable} owning {@link Type} and parent + * {@link TypeDiscoverer}. + * + * @param variable must not be {@literal null} + * @param owningType must not be {@literal null} + * @param parent + */ + public TypeVariableTypeInformation(TypeVariable variable, Type owningType, TypeDiscoverer parent, + Map, Type> typeVariableMap) { + + super(variable, parent, typeVariableMap); + + LettuceAssert.notNull(variable, "TypeVariable must not be null"); + + this.variable = variable; + this.owningType = owningType; + } + + @Override + public Class getType() { + + int index = getIndex(variable); + + if (owningType instanceof ParameterizedType && index != -1) { + Type fieldType = ((ParameterizedType) owningType).getActualTypeArguments()[index]; + return resolveType(fieldType); + } + + return resolveType(variable); + } + + /** + * Returns the index of the type parameter binding the given {@link TypeVariable}. + * + * @param variable + * @return + */ + private int getIndex(TypeVariable variable) { + + Class rawType = resolveType(owningType); + TypeVariable[] typeParameters = rawType.getTypeParameters(); + + for (int i = 0; i < typeParameters.length; i++) { + if (variable.equals(typeParameters[i])) { + return i; + } + } + + return -1; + } + + @Override + public boolean equals(Object obj) { + + if (obj == this) { + return true; + } + + if (!(obj instanceof TypeVariableTypeInformation)) { + return false; + } + + TypeVariableTypeInformation that = (TypeVariableTypeInformation) obj; + + return getType().equals(that.getType()); + } + + @Override + public String toString() { + return variable.getName(); + } + + public String getVariableName() { + return variable.getName(); + } +} diff --git a/src/main/java/com/lambdaworks/redis/dynamic/support/TypeWrapper.java b/src/main/java/com/lambdaworks/redis/dynamic/support/TypeWrapper.java new file mode 100644 index 0000000000..7da1badd2b --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/dynamic/support/TypeWrapper.java @@ -0,0 +1,349 @@ +package com.lambdaworks.redis.dynamic.support; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.Serializable; +import java.lang.reflect.*; + +import com.lambdaworks.redis.internal.LettuceAssert; + +/** + * Internal utility class that can be used to obtain wrapped {@link Serializable} variants of {@link java.lang.reflect.Type}s. + * + *

    + * {@link #forField(Field) Fields} or {@link #forMethodParameter(MethodParameter) MethodParameters} can be used as the root + * source for a serializable type. Alternatively the {@link #forGenericSuperclass(Class) superclass}, + * {@link #forGenericInterfaces(Class) interfaces} or {@link #forTypeParameters(Class) type parameters} or a regular + * {@link Class} can also be used as source. + * + *

    + * The returned type will either be a {@link Class} or a serializable proxy of {@link GenericArrayType}, + * {@link ParameterizedType}, {@link TypeVariable} or {@link WildcardType}. With the exception of {@link Class} (which is final) + * calls to methods that return further {@link Type}s (for example {@link GenericArrayType#getGenericComponentType()}) will be + * automatically wrapped. + * + */ +abstract class TypeWrapper { + + private static final Class[] SUPPORTED_SERIALIZABLE_TYPES = { GenericArrayType.class, ParameterizedType.class, + TypeVariable.class, WildcardType.class }; + + /** + * Return a {@link Serializable} variant of {@link Field#getGenericType()}. + */ + public static Type forField(Field field) { + LettuceAssert.notNull(field, "Field must not be null"); + return forTypeProvider(new FieldTypeProvider(field)); + } + + /** + * Return a {@link Serializable} variant of {@link MethodParameter#getGenericParameterType()}. + */ + public static Type forMethodParameter(MethodParameter methodParameter) { + return forTypeProvider(new MethodParameterTypeProvider(methodParameter)); + } + + /** + * Return a {@link Serializable} variant of {@link Class#getGenericSuperclass()}. + */ + @SuppressWarnings("serial") + public static Type forGenericSuperclass(final Class type) { + return forTypeProvider(new DefaultTypeProvider() { + @Override + public Type getType() { + return type.getGenericSuperclass(); + } + }); + } + + /** + * Return a {@link Serializable} variant of {@link Class#getGenericInterfaces()}. + */ + @SuppressWarnings("serial") + public static Type[] forGenericInterfaces(final Class type) { + Type[] result = new Type[type.getGenericInterfaces().length]; + for (int i = 0; i < result.length; i++) { + final int index = i; + result[i] = forTypeProvider(new DefaultTypeProvider() { + @Override + public Type getType() { + return type.getGenericInterfaces()[index]; + } + }); + } + return result; + } + + /** + * Return a {@link Serializable} variant of {@link Class#getTypeParameters()}. + */ + @SuppressWarnings("serial") + public static Type[] forTypeParameters(final Class type) { + Type[] result = new Type[type.getTypeParameters().length]; + for (int i = 0; i < result.length; i++) { + final int index = i; + result[i] = forTypeProvider(new DefaultTypeProvider() { + @Override + public Type getType() { + return type.getTypeParameters()[index]; + } + }); + } + return result; + } + + /** + * Unwrap the given type, effectively returning the original non-serializable type. + * + * @param type the type to unwrap + * @return the original non-serializable type + */ + @SuppressWarnings("unchecked") + public static T unwrap(T type) { + Type unwrapped = type; + while (unwrapped instanceof SerializableTypeProxy) { + unwrapped = ((SerializableTypeProxy) type).getTypeProvider().getType(); + } + return (T) unwrapped; + } + + /** + * Return a {@link Serializable} {@link Type} backed by a {@link TypeProvider} . + */ + static Type forTypeProvider(final TypeProvider provider) { + LettuceAssert.notNull(provider, "Provider must not be null"); + if (provider.getType() instanceof Serializable || provider.getType() == null) { + return provider.getType(); + } + + for (Class type : SUPPORTED_SERIALIZABLE_TYPES) { + if (type.isAssignableFrom(provider.getType().getClass())) { + ClassLoader classLoader = provider.getClass().getClassLoader(); + Class[] interfaces = new Class[] { type, SerializableTypeProxy.class, Serializable.class }; + InvocationHandler handler = new TypeProxyInvocationHandler(provider); + return (Type) Proxy.newProxyInstance(classLoader, interfaces, handler); + } + } + throw new IllegalArgumentException("Unsupported Type class: " + provider.getType().getClass().getName()); + } + + /** + * Additional interface implemented by the type proxy. + */ + interface SerializableTypeProxy { + + /** + * Return the underlying type provider. + */ + TypeProvider getTypeProvider(); + } + + /** + * A {@link Serializable} interface providing access to a {@link Type}. + */ + interface TypeProvider extends Serializable { + + /** + * Return the (possibly non {@link Serializable}) {@link Type}. + */ + Type getType(); + + /** + * Return the source of the type or {@code null}. + */ + Object getSource(); + } + + /** + * Default implementation of {@link TypeProvider} with a {@code null} source. + */ + @SuppressWarnings("serial") + private static abstract class DefaultTypeProvider implements TypeProvider { + + @Override + public Object getSource() { + return null; + } + } + + /** + * {@link Serializable} {@link InvocationHandler} used by the proxied {@link Type}. Provides serialization support and + * enhances any methods that return {@code Type} or {@code Type[]}. + */ + @SuppressWarnings("serial") + private static class TypeProxyInvocationHandler implements InvocationHandler, Serializable { + + private final TypeProvider provider; + + public TypeProxyInvocationHandler(TypeProvider provider) { + this.provider = provider; + } + + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + if (method.getName().equals("equals")) { + Object other = args[0]; + // Unwrap proxies for speed + if (other instanceof Type) { + other = unwrap((Type) other); + } + return this.provider.getType().equals(other); + } else if (method.getName().equals("hashCode")) { + return this.provider.getType().hashCode(); + } else if (method.getName().equals("getTypeProvider")) { + return this.provider; + } + + if (Type.class == method.getReturnType() && args == null) { + return forTypeProvider(new MethodInvokeTypeProvider(this.provider, method, -1)); + } else if (Type[].class == method.getReturnType() && args == null) { + Type[] result = new Type[((Type[]) method.invoke(this.provider.getType(), args)).length]; + for (int i = 0; i < result.length; i++) { + result[i] = forTypeProvider(new MethodInvokeTypeProvider(this.provider, method, i)); + } + return result; + } + + try { + return method.invoke(this.provider.getType(), args); + } catch (InvocationTargetException ex) { + throw ex.getTargetException(); + } + } + } + + /** + * {@link TypeProvider} for {@link Type}s obtained from a {@link Field}. + */ + @SuppressWarnings("serial") + static class FieldTypeProvider implements TypeProvider { + + private final String fieldName; + + private final Class declaringClass; + + private transient Field field; + + public FieldTypeProvider(Field field) { + this.fieldName = field.getName(); + this.declaringClass = field.getDeclaringClass(); + this.field = field; + } + + @Override + public Type getType() { + return this.field.getGenericType(); + } + + @Override + public Object getSource() { + return this.field; + } + + private void readObject(ObjectInputStream inputStream) throws IOException, ClassNotFoundException { + inputStream.defaultReadObject(); + try { + this.field = this.declaringClass.getDeclaredField(this.fieldName); + } catch (Throwable ex) { + throw new IllegalStateException("Could not find original class structure", ex); + } + } + } + + /** + * {@link TypeProvider} for {@link Type}s obtained from a {@link MethodParameter}. + */ + @SuppressWarnings("serial") + static class MethodParameterTypeProvider implements TypeProvider { + + private final String methodName; + + private final Class[] parameterTypes; + + private final Class declaringClass; + + private final int parameterIndex; + + private transient MethodParameter methodParameter; + + public MethodParameterTypeProvider(MethodParameter methodParameter) { + if (methodParameter.getMethod() != null) { + this.methodName = methodParameter.getMethod().getName(); + this.parameterTypes = methodParameter.getMethod().getParameterTypes(); + } else { + this.methodName = null; + this.parameterTypes = methodParameter.getConstructor().getParameterTypes(); + } + this.declaringClass = methodParameter.getDeclaringClass(); + this.parameterIndex = methodParameter.getParameterIndex(); + this.methodParameter = methodParameter; + } + + @Override + public Type getType() { + return this.methodParameter.getGenericParameterType(); + } + + @Override + public Object getSource() { + return this.methodParameter; + } + + private void readObject(ObjectInputStream inputStream) throws IOException, ClassNotFoundException { + inputStream.defaultReadObject(); + try { + if (this.methodName != null) { + this.methodParameter = new MethodParameter( + this.declaringClass.getDeclaredMethod(this.methodName, this.parameterTypes), this.parameterIndex); + } else { + this.methodParameter = new MethodParameter(this.declaringClass.getDeclaredConstructor(this.parameterTypes), + this.parameterIndex); + } + } catch (Throwable ex) { + throw new IllegalStateException("Could not find original class structure", ex); + } + } + } + + /** + * {@link TypeProvider} for {@link Type}s obtained by invoking a no-arg method. + */ + @SuppressWarnings("serial") + static class MethodInvokeTypeProvider implements TypeProvider { + + private final TypeProvider provider; + + private final String methodName; + + private final int index; + + private transient Method method; + + private transient volatile Object result; + + public MethodInvokeTypeProvider(TypeProvider provider, Method method, int index) { + this.provider = provider; + this.methodName = method.getName(); + this.index = index; + this.method = method; + } + + @Override + public Type getType() { + Object result = this.result; + if (result == null) { + // Lazy invocation of the target method on the provided type + result = ReflectionUtils.invokeMethod(this.method, this.provider.getType()); + // Cache the result for further calls to getType() + this.result = result; + } + return (result instanceof Type[] ? ((Type[]) result)[this.index] : (Type) result); + } + + @Override + public Object getSource() { + return null; + } + } + +} diff --git a/src/main/java/com/lambdaworks/redis/dynamic/support/package-info.java b/src/main/java/com/lambdaworks/redis/dynamic/support/package-info.java new file mode 100644 index 0000000000..8ae763c2a2 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/dynamic/support/package-info.java @@ -0,0 +1,4 @@ +/** + * Support classes imported from the Spring Framework. + */ +package com.lambdaworks.redis.dynamic.support; \ No newline at end of file diff --git a/src/main/java/com/lambdaworks/redis/internal/LettuceClassUtils.java b/src/main/java/com/lambdaworks/redis/internal/LettuceClassUtils.java index 947254b752..740775c1f5 100644 --- a/src/main/java/com/lambdaworks/redis/internal/LettuceClassUtils.java +++ b/src/main/java/com/lambdaworks/redis/internal/LettuceClassUtils.java @@ -1,5 +1,10 @@ package com.lambdaworks.redis.internal; +import java.util.IdentityHashMap; +import java.util.Map; + +import org.springframework.util.TypeUtils; + import com.lambdaworks.redis.JavaRuntime; /** @@ -10,6 +15,32 @@ */ public class LettuceClassUtils { + /** The CGLIB class separator character "$$" */ + public static final String CGLIB_CLASS_SEPARATOR = "$$"; + + /** + * Map with primitive wrapper type as key and corresponding primitive type as value, for example: Integer.class -> + * int.class. + */ + private static final Map, Class> primitiveWrapperTypeMap = new IdentityHashMap, Class>(9); + + /** + * Map with primitive type as key and corresponding wrapper type as value, for example: int.class -> Integer.class. + */ + private static final Map, Class> primitiveTypeToWrapperMap = new IdentityHashMap, Class>(9); + + static { + primitiveWrapperTypeMap.put(Boolean.class, boolean.class); + primitiveWrapperTypeMap.put(Byte.class, byte.class); + primitiveWrapperTypeMap.put(Character.class, char.class); + primitiveWrapperTypeMap.put(Double.class, double.class); + primitiveWrapperTypeMap.put(Float.class, float.class); + primitiveWrapperTypeMap.put(Integer.class, int.class); + primitiveWrapperTypeMap.put(Long.class, long.class); + primitiveWrapperTypeMap.put(Short.class, short.class); + primitiveWrapperTypeMap.put(Void.class, void.class); + } + /** * Determine whether the {@link Class} identified by the supplied name is present and can be loaded. Will return * {@code false} if either the class or one of its dependencies is not present or cannot be loaded. @@ -32,6 +63,20 @@ public static boolean isPresent(String className) { * * @param className * @return + */ + public static Class findClass(String className) { + try { + return forName(className, getDefaultClassLoader()); + } catch (ClassNotFoundException e) { + return null; + } + } + + /** + * Loads a class using the {@link #getDefaultClassLoader()}. + * + * @param className + * @return * @throws ClassNotFoundException */ public static Class forName(String className) throws ClassNotFoundException { @@ -75,4 +120,36 @@ private static ClassLoader getDefaultClassLoader() { } return cl; } + + /** + * Check if the right-hand side type may be assigned to the left-hand side type, assuming setting by reflection. Considers + * primitive wrapper classes as assignable to the corresponding primitive types. + * + * @param lhsType the target type + * @param rhsType the value type that should be assigned to the target type + * @return if the target type is assignable from the value type + * @see TypeUtils#isAssignable + */ + public static boolean isAssignable(Class lhsType, Class rhsType) { + + LettuceAssert.notNull(lhsType, "Left-hand side type must not be null"); + LettuceAssert.notNull(rhsType, "Right-hand side type must not be null"); + + if (lhsType.isAssignableFrom(rhsType)) { + return true; + } + + if (lhsType.isPrimitive()) { + Class resolvedPrimitive = primitiveWrapperTypeMap.get(rhsType); + if (lhsType == resolvedPrimitive) { + return true; + } + } else { + Class resolvedWrapper = primitiveTypeToWrapperMap.get(rhsType); + if (resolvedWrapper != null && lhsType.isAssignableFrom(resolvedWrapper)) { + return true; + } + } + return false; + } } diff --git a/src/main/java/com/lambdaworks/redis/protocol/CommandArgs.java b/src/main/java/com/lambdaworks/redis/protocol/CommandArgs.java index 14ebb07d77..5a40e69e28 100644 --- a/src/main/java/com/lambdaworks/redis/protocol/CommandArgs.java +++ b/src/main/java/com/lambdaworks/redis/protocol/CommandArgs.java @@ -4,12 +4,14 @@ import java.nio.ByteBuffer; import java.util.ArrayList; +import java.util.Base64; import java.util.List; import java.util.Map; import com.lambdaworks.redis.codec.ByteArrayCodec; -import com.lambdaworks.redis.codec.ToByteBufEncoder; import com.lambdaworks.redis.codec.RedisCodec; +import com.lambdaworks.redis.codec.StringCodec; +import com.lambdaworks.redis.codec.ToByteBufEncoder; import com.lambdaworks.redis.internal.LettuceAssert; import io.netty.buffer.ByteBuf; @@ -372,6 +374,11 @@ static void writeBytes(ByteBuf buffer, byte[] value) { buffer.writeBytes(value); buffer.writeBytes(CRLF); } + + @Override + public String toString() { + return Base64.getEncoder().encodeToString(val); + } } static class ByteBufferArgument { @@ -421,6 +428,11 @@ void encode(ByteBuf target) { StringArgument.writeString(target, Long.toString(val)); } + @Override + public String toString() { + return "" + val; + } + static void writeInteger(ByteBuf target, long value) { if (value < 10) { @@ -465,6 +477,11 @@ static DoubleArgument of(double val) { void encode(ByteBuf target) { StringArgument.writeString(target, Double.toString(val)); } + + @Override + public String toString() { + return "" + val; + } } static class StringArgument extends SingularArgument { @@ -496,6 +513,11 @@ static void writeString(ByteBuf target, String value) { } target.writeBytes(CRLF); } + + @Override + public String toString() { + return val; + } } static class KeyArgument extends SingularArgument { @@ -534,6 +556,11 @@ void encode(ByteBuf target) { ByteBufferArgument.writeByteBuffer(target, codec.encodeKey(key)); } + + @Override + public String toString() { + return String.format("key<%s>", new StringCodec().decodeKey(codec.encodeKey(key))); + } } static class ValueArgument extends SingularArgument { @@ -572,6 +599,11 @@ void encode(ByteBuf target) { ByteBufferArgument.writeByteBuffer(target, codec.encodeValue(val)); } + + @Override + public String toString() { + return String.format("value<%s>", new StringCodec().decodeValue(codec.encodeValue(val))); + } } /** diff --git a/src/main/java/com/lambdaworks/redis/resource/DefaultClientResources.java b/src/main/java/com/lambdaworks/redis/resource/DefaultClientResources.java index 91a5b06d26..25b464e969 100644 --- a/src/main/java/com/lambdaworks/redis/resource/DefaultClientResources.java +++ b/src/main/java/com/lambdaworks/redis/resource/DefaultClientResources.java @@ -395,8 +395,8 @@ public Builder reconnectDelay(Delay reconnectDelay) { } /** - * Sets the stateful reconnect {@link Supplier} to delay reconnect attempts. Defaults to binary exponential delay capped - * at {@literal 30 SECONDS}. + * Sets the stateful reconnect {@link Supplier} to delay reconnect attempts. Defaults to binary exponential delay capped at + * {@literal 30 SECONDS}. * * @param reconnectDelay the reconnect delay, must not be {@literal null}. * @return this diff --git a/src/test/java/com/lambdaworks/redis/dynamic/CommandMethodTest.java b/src/test/java/com/lambdaworks/redis/dynamic/CommandMethodTest.java new file mode 100644 index 0000000000..76bea6045d --- /dev/null +++ b/src/test/java/com/lambdaworks/redis/dynamic/CommandMethodTest.java @@ -0,0 +1,56 @@ +package com.lambdaworks.redis.dynamic; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.lang.reflect.Method; +import java.util.concurrent.Future; + +import org.junit.Test; + +import reactor.core.publisher.Flux; + +/** + * @author Mark Paluch + */ +public class CommandMethodTest { + + @Test + public void shouldResolveConcreteType() throws Exception { + + CommandMethod commandMethod = new CommandMethod(getMethod("getString")); + + assertThat(commandMethod.getActualReturnType().getType()).isEqualTo(String.class); + assertThat(commandMethod.getReturnType().getType()).isEqualTo(String.class); + } + + @Test + public void shouldResolveFutureComponentType() throws Exception { + + CommandMethod commandMethod = new CommandMethod(getMethod("getFuture")); + + assertThat(commandMethod.getActualReturnType().getType()).isEqualTo(String.class); + assertThat(commandMethod.getReturnType().getType()).isEqualTo(Future.class); + } + + @Test + public void shouldResolveFluxComponentType() throws Exception { + + CommandMethod commandMethod = new CommandMethod(getMethod("getFlux")); + + assertThat(commandMethod.getActualReturnType().getType()).isEqualTo(String.class); + assertThat(commandMethod.getReturnType().getType()).isEqualTo(Flux.class); + } + + private Method getMethod(String name) throws NoSuchMethodException { + return MyInterface.class.getDeclaredMethod(name); + } + + static interface MyInterface { + + String getString(); + + Future getFuture(); + + Flux getFlux(); + } +} \ No newline at end of file diff --git a/src/test/java/com/lambdaworks/redis/dynamic/CommandMethodVerifierTest.java b/src/test/java/com/lambdaworks/redis/dynamic/CommandMethodVerifierTest.java new file mode 100644 index 0000000000..6a18e9c9d4 --- /dev/null +++ b/src/test/java/com/lambdaworks/redis/dynamic/CommandMethodVerifierTest.java @@ -0,0 +1,114 @@ +package com.lambdaworks.redis.dynamic; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Fail.fail; + +import java.lang.reflect.Method; +import java.util.Arrays; + +import org.junit.Before; +import org.junit.Test; + +import com.lambdaworks.redis.dynamic.segment.CommandSegment; +import com.lambdaworks.redis.dynamic.segment.CommandSegments; +import com.lambdaworks.redis.dynamic.support.ReflectionUtils; +import com.lambdaworks.redis.internal.LettuceLists; +import com.lambdaworks.redis.models.command.CommandDetail; + +/** + * @author Mark Paluch + */ +public class CommandMethodVerifierTest { + + private CommandMethodVerifier sut; + + @Before + public void before() { + + CommandDetail mget = new CommandDetail("mget", -2, null, 0, 0, 0); + CommandDetail randomkey = new CommandDetail("randomkey", 1, null, 0, 0, 0); + CommandDetail rpop = new CommandDetail("rpop", 2, null, 0, 0, 0); + + sut = new CommandMethodVerifier(LettuceLists.newList(mget, randomkey, rpop)); + } + + @Test + public void misspelledName() { + + try { + validateMethod("megt"); + fail("Missing CommandMethodSyntaxException"); + } catch (CommandMethodSyntaxException e) { + assertThat(e).hasMessageContaining("Command megt does not exist. Did you mean: MGET?"); + } + } + + @Test + public void tooFewAtLeastParameters() { + + try { + validateMethod("mget"); + fail("Missing CommandMethodSyntaxException"); + } catch (CommandMethodSyntaxException e) { + assertThat(e) + .hasMessageContaining("Command MGET requires at least 1 parameters but method declares 0 parameter(s)"); + } + } + + @Test + public void shouldPassWithCorrectParameterCount() { + + validateMethod("mget", String.class); + validateMethod("randomkey"); + validateMethod("rpop", String.class); + } + + @Test + public void tooManyParameters() { + + try { + validateMethod("rpop", String.class, String.class); + fail("Missing CommandMethodSyntaxException"); + } catch (CommandMethodSyntaxException e) { + assertThat(e).hasMessageContaining("Command RPOP accepts 1 parameters but method declares 2 parameter(s)"); + } + } + + @Test + public void methodDoesNotAcceptParameters() { + + try { + validateMethod("randomkey", String.class); + fail("Missing CommandMethodSyntaxException"); + } catch (CommandMethodSyntaxException e) { + assertThat(e).hasMessageContaining("Command RANDOMKEY accepts no parameters"); + } + } + + private void validateMethod(String methodName, Class... parameterTypes) { + + Method method = ReflectionUtils.findMethod(MyInterface.class, methodName, parameterTypes); + CommandMethod commandMethod = new CommandMethod(method); + + sut.validate(new CommandSegments(Arrays.asList(CommandSegment.constant(methodName))), commandMethod); + } + + static interface MyInterface { + + void megt(); + + void mget(); + + void mget(String key); + + void mget(String key1, String key2); + + void randomkey(); + + void randomkey(String key); + + void rpop(String key); + + void rpop(String key1, String key2); + } +} \ No newline at end of file diff --git a/src/test/java/com/lambdaworks/redis/dynamic/CommandSegmentCommandFactoryTest.java b/src/test/java/com/lambdaworks/redis/dynamic/CommandSegmentCommandFactoryTest.java new file mode 100644 index 0000000000..5e07d53479 --- /dev/null +++ b/src/test/java/com/lambdaworks/redis/dynamic/CommandSegmentCommandFactoryTest.java @@ -0,0 +1,163 @@ +package com.lambdaworks.redis.dynamic; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.fail; + +import java.util.List; +import java.util.concurrent.Future; + +import org.junit.Test; +import org.springframework.test.util.ReflectionTestUtils; + +import com.lambdaworks.redis.SetArgs; +import com.lambdaworks.redis.codec.ByteArrayCodec; +import com.lambdaworks.redis.codec.RedisCodec; +import com.lambdaworks.redis.codec.StringCodec; +import com.lambdaworks.redis.dynamic.annotation.Command; +import com.lambdaworks.redis.dynamic.annotation.Param; +import com.lambdaworks.redis.dynamic.annotation.Value; +import com.lambdaworks.redis.dynamic.domain.Timeout; +import com.lambdaworks.redis.dynamic.output.CodecAwareOutputFactoryResolver; +import com.lambdaworks.redis.dynamic.output.OutputRegistry; +import com.lambdaworks.redis.dynamic.output.OutputRegistryCommandOutputFactoryResolver; +import com.lambdaworks.redis.dynamic.segment.AnnotationCommandSegmentFactory; +import com.lambdaworks.redis.dynamic.segment.CommandSegmentFactory; +import com.lambdaworks.redis.dynamic.support.ReflectionUtils; +import com.lambdaworks.redis.protocol.CommandArgs; +import com.lambdaworks.redis.protocol.RedisCommand; + +/** + * @author Mark Paluch + */ +public class CommandSegmentCommandFactoryTest { + + @Test + public void setKeyValue() { + + RedisCommand command = createCommand(createCommandMethod(Commands.class, "set", String.class, String.class), + new StringCodec(), "key", "value"); + + assertThat(toString(command)).isEqualTo("SET key key"); + } + + @Test + public void setKeyValueWithByteArrayCodec() { + + RedisCommand command = createCommand(createCommandMethod(Commands.class, "set", String.class, String.class), + new ByteArrayCodec(), "key", "value"); + + assertThat(toString(command)).isEqualTo("SET key value"); + } + + @Test + public void setKeyValueWithHintedValue() { + + RedisCommand command = createCommand(createCommandMethod(Commands.class, "set2", String.class, String.class), + new StringCodec(), "key", "value"); + + assertThat(toString(command)).isEqualTo("SET key value"); + } + + @Test + public void setWithArgs() { + + RedisCommand command = createCommand( + createCommandMethod(Commands.class, "set", String.class, String.class, SetArgs.class), new StringCodec(), "key", + "value", SetArgs.Builder.ex(123).nx()); + + assertThat(toString(command)).isEqualTo("SET key key EX 123 NX"); + } + + @Test + public void clientSetname() { + + RedisCommand command = createCommand(createCommandMethod(Commands.class, "clientSetname", String.class), + new ByteArrayCodec(), "name"); + + assertThat(toString(command)).isEqualTo("CLIENT SETNAME name"); + } + + @Test + public void annotatedClientSetname() { + + RedisCommand command = createCommand(createCommandMethod(Commands.class, "woohoo", String.class), + new StringCodec(), "name"); + + assertThat(toString(command)).isEqualTo("CLIENT SETNAME key"); + } + + @Test + public void asyncWithTimeout() { + + try { + createCommand(createCommandMethod(MethodsWithTimeout.class, "async", String.class, Timeout.class), + new StringCodec()); + fail("Missing CommandCreationException"); + } catch (CommandCreationException e) { + assertThat(e).hasMessageContaining("Asynchronous command methods do not support Timeout parameters"); + } + } + + @Test + public void syncWithTimeout() { + + createCommand(createCommandMethod(MethodsWithTimeout.class, "sync", String.class, Timeout.class), new StringCodec(), + "hello", null); + } + + private CommandMethod createCommandMethod(Class commandInterface, String methodName, Class... args) { + return new CommandMethod(ReflectionUtils.findMethod(commandInterface, methodName, args)); + } + + private RedisCommand createCommand(CommandMethod commandMethod, RedisCodec codec, Object... args) { + + CommandSegmentFactory segmentFactory = new AnnotationCommandSegmentFactory(); + CodecAwareOutputFactoryResolver outputFactoryResolver = new CodecAwareOutputFactoryResolver( + new OutputRegistryCommandOutputFactoryResolver(new OutputRegistry()), codec); + CommandSegmentCommandFactory factory = new CommandSegmentCommandFactory( + segmentFactory.createCommandSegments(commandMethod), commandMethod, (RedisCodec) codec, outputFactoryResolver); + + return factory.createCommand(args); + } + + @SuppressWarnings("unchecked") + private String toString(RedisCommand command) { + + StringBuilder builder = new StringBuilder(); + + builder.append(command.getType().name()); + + CommandArgs args = command.getArgs(); + if (args != null) { + List argList = (List) ReflectionTestUtils.getField(args, "singularArguments"); + + for (Object o : argList) { + builder.append(' ').append(o); + } + } + + return builder.toString(); + } + + interface Commands { + + boolean set(String key, String value); + + @Command("SET") + boolean set2(String key, @Value String value); + + boolean set(String key, String value, SetArgs setArgs); + + boolean clientSetname(String connectionName); + + @Command("CLIENT SETNAME :connectionName") + boolean woohoo(@Param("connectionName") String connectionName); + } + + static interface MethodsWithTimeout { + + Future async(String key, Timeout timeout); + + String sync(String key, Timeout timeout); + } +} \ No newline at end of file diff --git a/src/test/java/com/lambdaworks/redis/dynamic/ReactiveCommandSegmentCommandFactoryTest.java b/src/test/java/com/lambdaworks/redis/dynamic/ReactiveCommandSegmentCommandFactoryTest.java new file mode 100644 index 0000000000..9a92d801cc --- /dev/null +++ b/src/test/java/com/lambdaworks/redis/dynamic/ReactiveCommandSegmentCommandFactoryTest.java @@ -0,0 +1,73 @@ +package com.lambdaworks.redis.dynamic; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.fail; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.when; + +import java.lang.reflect.Method; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; +import org.reactivestreams.Publisher; + +import com.lambdaworks.redis.codec.StringCodec; +import com.lambdaworks.redis.dynamic.domain.Timeout; +import com.lambdaworks.redis.dynamic.output.CommandOutputFactory; +import com.lambdaworks.redis.dynamic.output.CommandOutputFactoryResolver; +import com.lambdaworks.redis.dynamic.segment.AnnotationCommandSegmentFactory; +import com.lambdaworks.redis.dynamic.segment.CommandSegments; +import com.lambdaworks.redis.dynamic.support.ReflectionUtils; +import com.lambdaworks.redis.protocol.RedisCommand; + +/** + * @author Mark Paluch + */ +@RunWith(MockitoJUnitRunner.class) +public class ReactiveCommandSegmentCommandFactoryTest { + + @Mock + private CommandOutputFactoryResolver outputFactoryResolver; + + @Mock + private CommandOutputFactory commandOutputFactory; + + @Before + public void before() { + when(outputFactoryResolver.resolveCommandOutput(any())).thenReturn(commandOutputFactory); + } + + @Test + public void commandCreationWithTimeoutShouldFail() { + + try { + createCommand("get", ReactiveWithTimeout.class, String.class, Timeout.class); + fail("Missing CommandCreationException"); + } catch (CommandCreationException e) { + assertThat(e).hasMessageContaining("Reactive command methods do not support Timeout parameters"); + } + } + + protected RedisCommand createCommand(String methodName, Class interfaceClass, Class... parameterTypes) { + + Method method = ReflectionUtils.findMethod(interfaceClass, methodName, parameterTypes); + + CommandMethod commandMethod = new CommandMethod(method); + + AnnotationCommandSegmentFactory segmentFactory = new AnnotationCommandSegmentFactory(); + CommandSegments commandSegments = segmentFactory.createCommandSegments(commandMethod); + + ReactiveCommandSegmentCommandFactory factory = new ReactiveCommandSegmentCommandFactory<>( + commandSegments, commandMethod, new StringCodec(), outputFactoryResolver); + + return factory.createCommand(null); + } + + static interface ReactiveWithTimeout { + + Publisher get(String key, Timeout timeout); + } +} \ No newline at end of file diff --git a/src/test/java/com/lambdaworks/redis/dynamic/RedisCommandsTest.java b/src/test/java/com/lambdaworks/redis/dynamic/RedisCommandsTest.java new file mode 100644 index 0000000000..8edc71e071 --- /dev/null +++ b/src/test/java/com/lambdaworks/redis/dynamic/RedisCommandsTest.java @@ -0,0 +1,106 @@ +package com.lambdaworks.redis.dynamic; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.fail; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; + +import org.junit.Test; + +import com.lambdaworks.redis.AbstractRedisClientTest; +import com.lambdaworks.redis.dynamic.annotation.Command; +import com.lambdaworks.redis.dynamic.domain.Timeout; + +import reactor.core.publisher.Mono; + +/** + * @author Mark Paluch + */ +public class RedisCommandsTest extends AbstractRedisClientTest { + + @Test + public void sync() throws Exception { + + RedisCommandFactory factory = new RedisCommandFactory(redis.getStatefulConnection()); + + TestInterface api = factory.getCommands(TestInterface.class); + + api.setSync("key", "value", Timeout.create(10, TimeUnit.SECONDS)); + assertThat(api.get("key")).isEqualTo("value"); + assertThat(api.getAsBytes("key")).isEqualTo("value".getBytes()); + } + + @Test + public void async() throws Exception { + + RedisCommandFactory factory = new RedisCommandFactory(redis.getStatefulConnection()); + + TestInterface api = factory.getCommands(TestInterface.class); + + Future key = api.set("key", "value"); + assertThat(key).isInstanceOf(CompletableFuture.class); + key.get(); + } + + @Test + public void reactive() throws Exception { + + RedisCommandFactory factory = new RedisCommandFactory(redis.getStatefulConnection()); + + TestInterface api = factory.getCommands(TestInterface.class); + + Mono key = api.setReactive("key", "value"); + assertThat(key.block()).isEqualTo("OK"); + } + + @Test + public void verifierShouldCatchBuggyDeclarations() throws Exception { + + RedisCommandFactory factory = new RedisCommandFactory(redis.getStatefulConnection()); + + try { + factory.getCommands(TooFewParameters.class); + fail("Missing CommandCreationException"); + } catch (CommandCreationException e) { + assertThat(e).hasMessageContaining("Command GET accepts 1 parameters but method declares 0 parameter"); + } + + try { + factory.getCommands(WithTypo.class); + fail("Missing CommandCreationException"); + } catch (CommandCreationException e) { + assertThat(e).hasMessageContaining("Command GAT does not exist."); + } + + } + + static interface TestInterface { + + String get(String key); + + @Command("GET") + byte[] getAsBytes(String key); + + @Command("SET") + String setSync(String key, String value, Timeout timeout); + + Future set(String key, String value); + + @Command("SET") + Mono setReactive(String key, String value); + } + + static interface TooFewParameters { + + String get(); + + } + + static interface WithTypo { + + String gat(String key); + + } +} diff --git a/src/test/java/com/lambdaworks/redis/dynamic/codec/AnnotationRedisCodecResolverTest.java b/src/test/java/com/lambdaworks/redis/dynamic/codec/AnnotationRedisCodecResolverTest.java new file mode 100644 index 0000000000..6c8d4a00f7 --- /dev/null +++ b/src/test/java/com/lambdaworks/redis/dynamic/codec/AnnotationRedisCodecResolverTest.java @@ -0,0 +1,100 @@ +package com.lambdaworks.redis.dynamic.codec; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.List; + +import com.lambdaworks.redis.dynamic.CommandMethod; +import org.junit.Test; + +import com.lambdaworks.redis.dynamic.annotation.Key; +import com.lambdaworks.redis.dynamic.annotation.Value; +import com.lambdaworks.redis.codec.ByteArrayCodec; +import com.lambdaworks.redis.codec.RedisCodec; +import com.lambdaworks.redis.codec.StringCodec; +import com.lambdaworks.redis.dynamic.support.ReflectionUtils; + +/** + * @author Mark Paluch + */ +public class AnnotationRedisCodecResolverTest { + + private List> codecs = Arrays.asList(new StringCodec(), new ByteArrayCodec()); + + @Test + public void shouldResolveFullyHinted() { + + Method method = ReflectionUtils.findMethod(CommandMethods.class, "stringOnly", String.class, String.class); + RedisCodec codec = resolve(method); + + assertThat(codec).isInstanceOf(StringCodec.class); + } + + @Test + public void shouldResolveHintedKey() { + + Method method = ReflectionUtils.findMethod(CommandMethods.class, "annotatedKey", String.class, String.class); + RedisCodec codec = resolve(method); + + assertThat(codec).isInstanceOf(StringCodec.class); + } + + @Test + public void shouldResolveHintedValue() { + + Method method = ReflectionUtils.findMethod(CommandMethods.class, "annotatedValue", String.class, String.class); + RedisCodec codec = resolve(method); + + assertThat(codec).isInstanceOf(StringCodec.class); + } + + @Test + public void shouldResolveWithoutHints() { + + Method method = ReflectionUtils.findMethod(CommandMethods.class, "nothingAnnotated", String.class, String.class); + RedisCodec codec = resolve(method); + + assertThat(codec).isInstanceOf(StringCodec.class); + } + + @Test + public void shouldResolveHintedByteArrayValue() { + + Method method = ReflectionUtils.findMethod(CommandMethods.class, "annotatedByteArrayValue", String.class, byte[].class); + RedisCodec codec = resolve(method); + + assertThat(codec).isInstanceOf(ByteArrayCodec.class); + } + + @Test(expected = IllegalStateException.class) + public void resolutionShouldFail() { + + Method method = ReflectionUtils.findMethod(CommandMethods.class, "mixedTypes", String.class, byte[].class); + resolve(method); + } + + protected RedisCodec resolve(Method method) { + CommandMethod commandMethod = new CommandMethod(method); + AnnotationRedisCodecResolver resolver = new AnnotationRedisCodecResolver(codecs); + + return resolver.resolve(commandMethod); + } + + private static interface CommandMethods { + + String stringOnly(@Key String key, @Value String value); + + String annotatedKey(@Key String key, String value); + + String annotatedValue(String key, @Value String value); + + String annotatedByteArrayValue(String key, @Value byte[] value); + + String nothingAnnotated(String key, String value); + + String mixedTypes(@Key String key, @Value byte[] value); + } + +} \ No newline at end of file diff --git a/src/test/java/com/lambdaworks/redis/dynamic/intercept/InvocationProxyFactoryTest.java b/src/test/java/com/lambdaworks/redis/dynamic/intercept/InvocationProxyFactoryTest.java new file mode 100644 index 0000000000..66e7024a3e --- /dev/null +++ b/src/test/java/com/lambdaworks/redis/dynamic/intercept/InvocationProxyFactoryTest.java @@ -0,0 +1,47 @@ +package com.lambdaworks.redis.dynamic.intercept; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.Test; + +/** + * @author Mark Paluch + */ +public class InvocationProxyFactoryTest { + + @Test + public void shouldDelegateCallsToInterceptor() { + + InvocationProxyFactory factory = new InvocationProxyFactory(); + factory.addInterface(MyInterface.class); + factory.addInterceptor(new ReturnTrueMethodInterceptor()); + + MyInterface myInterface = factory.createProxy(getClass().getClassLoader()); + + assertThat(myInterface.someMethod()).isTrue(); + } + + @Test + public void shouldNotFailWithoutFurtherInterceptors() { + + InvocationProxyFactory factory = new InvocationProxyFactory(); + factory.addInterface(MyInterface.class); + + MyInterface myInterface = factory.createProxy(getClass().getClassLoader()); + + assertThat(myInterface.someMethod()).isNull(); + } + + private interface MyInterface { + + Boolean someMethod(); + } + + private static class ReturnTrueMethodInterceptor implements MethodInterceptor { + + @Override + public Object invoke(MethodInvocation invocation) { + return true; + } + } +} \ No newline at end of file diff --git a/src/test/java/com/lambdaworks/redis/dynamic/output/CodecAwareOutputResolverTest.java b/src/test/java/com/lambdaworks/redis/dynamic/output/CodecAwareOutputResolverTest.java new file mode 100644 index 0000000000..b748fc4cb9 --- /dev/null +++ b/src/test/java/com/lambdaworks/redis/dynamic/output/CodecAwareOutputResolverTest.java @@ -0,0 +1,136 @@ +package com.lambdaworks.redis.dynamic.output; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.lang.reflect.Method; +import java.nio.ByteBuffer; +import java.util.List; +import java.util.Map; + +import org.junit.Test; + +import com.lambdaworks.redis.codec.RedisCodec; +import com.lambdaworks.redis.dynamic.CommandMethod; +import com.lambdaworks.redis.dynamic.support.ClassTypeInformation; +import com.lambdaworks.redis.dynamic.support.ReflectionUtils; +import com.lambdaworks.redis.output.*; + +/** + * @author Mark Paluch + */ +public class CodecAwareOutputResolverTest { + + private CodecAwareOutputFactoryResolver resolver = new CodecAwareOutputFactoryResolver( + new OutputRegistryCommandOutputFactoryResolver(new OutputRegistry()), new ByteBufferAndStringCodec()); + + @Test + public void shouldResolveValueOutput() { + + CommandOutput commandOutput = getCommandOutput("string"); + + assertThat(commandOutput).isInstanceOf(ValueOutput.class); + } + + @Test + public void shouldDetermineKeyType() { + + assertThat(resolver.isKeyType(ClassTypeInformation.from(String.class))).isFalse(); + assertThat(resolver.isKeyType(ClassTypeInformation.from(ByteBuffer.class))).isTrue(); + } + + @Test + public void shouldDetermineValueType() { + + assertThat(resolver.isValueType(ClassTypeInformation.from(String.class))).isTrue(); + assertThat(resolver.isValueType(ClassTypeInformation.from(ByteBuffer.class))).isFalse(); + } + + @Test + public void shouldResolveValueListOutput() { + + assertThat(getCommandOutput("stringList")).isOfAnyClassIn(ValueListOutput.class, StringListOutput.class); + assertThat(getCommandOutput("charSequenceList")).isOfAnyClassIn(ValueListOutput.class, StringListOutput.class); + } + + @Test + public void shouldResolveKeyOutput() { + + CommandOutput commandOutput = getCommandOutput("byteBuffer"); + + assertThat(commandOutput).isInstanceOf(KeyOutput.class); + } + + @Test + public void shouldResolveKeyListOutput() { + + CommandOutput commandOutput = getCommandOutput("byteBufferList"); + + assertThat(commandOutput).isInstanceOf(KeyListOutput.class); + } + + @Test + public void shouldResolveListOfMapsOutput() { + + CommandOutput commandOutput = getCommandOutput("listOfMapsOutput"); + + assertThat(commandOutput).isInstanceOf(ListOfMapsOutput.class); + } + + @Test + public void shouldResolveMapsOutput() { + + CommandOutput commandOutput = getCommandOutput("mapOutput"); + + assertThat(commandOutput).isInstanceOf(MapOutput.class); + } + + protected CommandOutput getCommandOutput(String methodName) { + + Method method = ReflectionUtils.findMethod(CommandMethods.class, methodName); + CommandMethod commandMethod = new CommandMethod(method); + + CommandOutputFactory factory = resolver.resolveCommandOutput(new OutputSelector(commandMethod.getActualReturnType())); + + return factory.create(new ByteBufferAndStringCodec()); + } + + private static interface CommandMethods { + + List stringList(); + + List charSequenceList(); + + List byteBufferList(); + + List> listOfMapsOutput(); + + Map mapOutput(); + + String string(); + + ByteBuffer byteBuffer(); + } + + private static class ByteBufferAndStringCodec implements RedisCodec { + + @Override + public ByteBuffer decodeKey(ByteBuffer bytes) { + return null; + } + + @Override + public String decodeValue(ByteBuffer bytes) { + return null; + } + + @Override + public ByteBuffer encodeKey(ByteBuffer key) { + return null; + } + + @Override + public ByteBuffer encodeValue(String value) { + return null; + } + } +} \ No newline at end of file diff --git a/src/test/java/com/lambdaworks/redis/dynamic/output/OutputRegistryCommandOutputFactoryResolverTest.java b/src/test/java/com/lambdaworks/redis/dynamic/output/OutputRegistryCommandOutputFactoryResolverTest.java new file mode 100644 index 0000000000..3a0a6914d6 --- /dev/null +++ b/src/test/java/com/lambdaworks/redis/dynamic/output/OutputRegistryCommandOutputFactoryResolverTest.java @@ -0,0 +1,129 @@ +package com.lambdaworks.redis.dynamic.output; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.lang.reflect.Method; +import java.util.List; + +import org.junit.Test; + +import com.lambdaworks.redis.GeoCoordinates; +import com.lambdaworks.redis.Value; +import com.lambdaworks.redis.codec.StringCodec; +import com.lambdaworks.redis.dynamic.CommandMethod; +import com.lambdaworks.redis.dynamic.support.ReflectionUtils; +import com.lambdaworks.redis.output.*; + +/** + * @author Mark Paluch + */ +public class OutputRegistryCommandOutputFactoryResolverTest { + + private OutputRegistryCommandOutputFactoryResolver resolver = new OutputRegistryCommandOutputFactoryResolver( + new OutputRegistry()); + + @Test + public void shouldResolveStringListOutput() { + + assertThat(getCommandOutput("stringList")).isInstanceOf(StringListOutput.class); + assertThat(getCommandOutput("stringIterable")).isInstanceOf(StringListOutput.class); + } + + @Test + public void shouldResolveVoidOutput() { + + assertThat(getCommandOutput("voidMethod")).isInstanceOf(VoidOutput.class); + assertThat(getCommandOutput("voidWrapper")).isInstanceOf(VoidOutput.class); + } + + @Test + public void shouldResolveStringValueListOutput() { + + CommandOutput commandOutput = getCommandOutput("stringValueList"); + + assertThat(commandOutput).isInstanceOf(StringValueListOutput.class); + } + + @Test + public void shouldResolveGeoCoordinatesValueOutput() { + + CommandOutput commandOutput = getCommandOutput("geoCoordinatesValueList"); + + assertThat(commandOutput).isInstanceOf(GeoCoordinatesValueListOutput.class); + } + + @Test + public void shouldResolveByteArrayOutput() { + + CommandOutput commandOutput = getCommandOutput("bytes"); + + assertThat(commandOutput).isInstanceOf(ByteArrayOutput.class); + } + + @Test + public void shouldResolveBooleanOutput() { + + CommandOutput commandOutput = getCommandOutput("bool"); + + assertThat(commandOutput).isInstanceOf(BooleanOutput.class); + } + + @Test + public void shouldResolveBooleanWrappedOutput() { + + CommandOutput commandOutput = getCommandOutput("boolWrapper"); + + assertThat(commandOutput).isInstanceOf(BooleanOutput.class); + } + + @Test + public void shouldResolveBooleanListOutput() { + + CommandOutput commandOutput = getCommandOutput("boolList"); + + assertThat(commandOutput).isInstanceOf(BooleanListOutput.class); + } + + @Test + public void shouldResolveListOfMapsOutput() { + + CommandOutput commandOutput = getCommandOutput("listOfMapsOutput"); + + assertThat(commandOutput).isInstanceOf(ListOfMapsOutput.class); + } + + protected CommandOutput getCommandOutput(String methodName) { + + Method method = ReflectionUtils.findMethod(CommandMethods.class, methodName); + CommandMethod commandMethod = new CommandMethod(method); + + CommandOutputFactory factory = resolver.resolveCommandOutput(new OutputSelector(commandMethod.getActualReturnType())); + + return factory.create(new StringCodec()); + } + + private static interface CommandMethods { + + List stringList(); + + Iterable stringIterable(); + + List> stringValueList(); + + List> geoCoordinatesValueList(); + + byte[] bytes(); + + boolean bool(); + + Boolean boolWrapper(); + + void voidMethod(); + + Void voidWrapper(); + + List boolList(); + + ListOfMapsOutput listOfMapsOutput(); + } +} \ No newline at end of file diff --git a/src/test/java/com/lambdaworks/redis/dynamic/output/OutputRegistryTest.java b/src/test/java/com/lambdaworks/redis/dynamic/output/OutputRegistryTest.java new file mode 100644 index 0000000000..eb7941f678 --- /dev/null +++ b/src/test/java/com/lambdaworks/redis/dynamic/output/OutputRegistryTest.java @@ -0,0 +1,64 @@ +package com.lambdaworks.redis.dynamic.output; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.List; + +import com.lambdaworks.redis.dynamic.support.ClassTypeInformation; +import org.junit.Test; + +import com.lambdaworks.redis.Value; +import com.lambdaworks.redis.dynamic.output.OutputRegistry.KeySurrogate; +import com.lambdaworks.redis.output.GeoCoordinatesValueListOutput; +import com.lambdaworks.redis.output.KeyListOutput; +import com.lambdaworks.redis.output.StringListOutput; + +/** + * @author Mark Paluch + */ +public class OutputRegistryTest { + + @Test + public void getStreamingType() throws Exception { + + OutputType streamingType = OutputRegistry.getStreamingType(GeoCoordinatesValueListOutput.class); + + assertThat(streamingType.getPrimaryType()).isEqualTo(Value.class); + } + + @Test + public void getOutputComponentType() throws Exception { + + OutputType outputComponentType = OutputRegistry.getOutputComponentType(GeoCoordinatesValueListOutput.class); + + assertThat(outputComponentType.getPrimaryType()).isEqualTo(List.class); + } + + @Test + public void getKeyStreamingType() throws Exception { + + OutputRegistry.getStreamingType(KeyListOutput.class); + OutputType streamingType = OutputRegistry.getStreamingType(KeyListOutput.class); + + assertThat(streamingType.getPrimaryType()).isEqualTo(KeySurrogate.class); + } + + @Test + public void getKeyOutputType() throws Exception { + + OutputType outputComponentType = OutputRegistry.getOutputComponentType(KeyListOutput.class); + + assertThat(outputComponentType.getPrimaryType()).isEqualTo(KeySurrogate.class); + assertThat(outputComponentType.getTypeInformation().getComponentType().getType()).isEqualTo(Object.class); + } + + @Test + public void getStringListOutputType() throws Exception { + + OutputType outputComponentType = OutputRegistry.getOutputComponentType(StringListOutput.class); + + assertThat(outputComponentType.getPrimaryType()).isEqualTo(List.class); + assertThat(outputComponentType.getTypeInformation().getComponentType()) + .isEqualTo(ClassTypeInformation.from(String.class)); + } +} \ No newline at end of file diff --git a/src/test/java/com/lambdaworks/redis/dynamic/segment/AnnotationCommandSegmentFactoryTest.java b/src/test/java/com/lambdaworks/redis/dynamic/segment/AnnotationCommandSegmentFactoryTest.java new file mode 100644 index 0000000000..c8d1b6f5b7 --- /dev/null +++ b/src/test/java/com/lambdaworks/redis/dynamic/segment/AnnotationCommandSegmentFactoryTest.java @@ -0,0 +1,110 @@ +package com.lambdaworks.redis.dynamic.segment; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.lambdaworks.redis.dynamic.CommandMethod; +import org.junit.Test; + +import com.lambdaworks.redis.dynamic.annotation.Command; +import com.lambdaworks.redis.dynamic.annotation.CommandNaming; +import com.lambdaworks.redis.dynamic.annotation.CommandNaming.LetterCase; +import com.lambdaworks.redis.dynamic.annotation.CommandNaming.Strategy; +import com.lambdaworks.redis.dynamic.support.ReflectionUtils; + +/** + * @author Mark Paluch + */ +public class AnnotationCommandSegmentFactoryTest { + + AnnotationCommandSegmentFactory factory = new AnnotationCommandSegmentFactory(); + + @Test + public void notAnnotatedDotAsIs() { + + CommandMethod commandMethod = new CommandMethod(ReflectionUtils.findMethod(CommandMethods.class, "notAnnotated")); + + CommandSegments commandSegments = factory.createCommandSegments(commandMethod); + + assertThat(commandSegments).isEmpty(); + assertThat(commandSegments.getCommandType().name()).isEqualTo("not.Annotated"); + } + + @Test + public void uppercaseDot() { + + CommandMethod commandMethod = new CommandMethod(ReflectionUtils.findMethod(CommandMethods.class, "upperCase")); + + CommandSegments commandSegments = factory.createCommandSegments(commandMethod); + + assertThat(commandSegments).isEmpty(); + assertThat(commandSegments.getCommandType().name()).isEqualTo("UPPER.CASE"); + } + + @Test + public void methodNameAsIs() { + + CommandMethod commandMethod = new CommandMethod(ReflectionUtils.findMethod(CommandMethods.class, "methodName")); + + CommandSegments commandSegments = factory.createCommandSegments(commandMethod); + + assertThat(commandSegments).isEmpty(); + assertThat(commandSegments.getCommandType().name()).isEqualTo("methodName"); + } + + @Test + public void splitAsIs() { + + CommandMethod commandMethod = new CommandMethod(ReflectionUtils.findMethod(CommandMethods.class, "clientSetname")); + + CommandSegments commandSegments = factory.createCommandSegments(commandMethod); + + assertThat(commandSegments).hasSize(1).extracting(CommandSegment::asString).contains("Setname"); + assertThat(commandSegments.getCommandType().name()).isEqualTo("client"); + } + + @Test + public void commandAnnotation() { + + CommandMethod commandMethod = new CommandMethod(ReflectionUtils.findMethod(CommandMethods.class, "atCommand")); + + CommandSegments commandSegments = factory.createCommandSegments(commandMethod); + + assertThat(commandSegments).hasSize(1).extracting(CommandSegment::asString).contains("WORLD"); + assertThat(commandSegments.getCommandType().name()).isEqualTo("HELLO"); + } + + @Test + public void splitDefault() { + + CommandMethod commandMethod = new CommandMethod(ReflectionUtils.findMethod(Defaulted.class, "clientSetname")); + + CommandSegments commandSegments = factory.createCommandSegments(commandMethod); + + assertThat(commandSegments).hasSize(1).extracting(CommandSegment::asString).contains("SETNAME"); + assertThat(commandSegments.getCommandType().name()).isEqualTo("CLIENT"); + } + + @CommandNaming(strategy = Strategy.DOT, letterCase = LetterCase.AS_IS) + private static interface CommandMethods { + + void notAnnotated(); + + @CommandNaming(letterCase = LetterCase.UPPERCASE) + void upperCase(); + + @CommandNaming(strategy = Strategy.METHOD_NAME) + void methodName(); + + @CommandNaming(strategy = Strategy.SPLIT) + void clientSetname(); + + @Command("HELLO WORLD") + void atCommand(); + } + + private static interface Defaulted { + + void clientSetname(); + } + +} \ No newline at end of file From 95936712d47d8463eb374c6b5353b72d227ac07a Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Mon, 24 Oct 2016 17:03:38 +0200 Subject: [PATCH 057/808] Support lettuce parameter types #381 Add support for built-in parameter types: * ScoredValue, Value and KeyValue * Limit, Range (numeric) * GeoCoordinates --- .../com/lambdaworks/redis/GeoCoordinates.java | 12 ++ .../java/com/lambdaworks/redis/Range.java | 6 + .../CodecAwareMethodParametersAccessor.java | 5 + .../redis/dynamic/CommandMethodVerifier.java | 31 ++- .../DefaultMethodParametersAccessor.java | 21 +- .../redis/dynamic/ParameterBinder.java | 119 +++++++++++- .../redis/dynamic/domain/FlushMode.java | 8 - .../ExecutionSpecificParameters.java | 14 +- .../parameter/MethodParametersAccessor.java | 29 ++- .../redis/dynamic/parameter/Parameters.java | 5 + .../redis/protocol/CommandArgs.java | 14 +- .../dynamic/CommandMethodVerifierTest.java | 16 +- .../CommandSegmentCommandFactoryTest.java | 12 +- .../redis/dynamic/ParameterBinderTest.java | 181 ++++++++++++++++++ 14 files changed, 421 insertions(+), 52 deletions(-) delete mode 100644 src/main/java/com/lambdaworks/redis/dynamic/domain/FlushMode.java create mode 100644 src/test/java/com/lambdaworks/redis/dynamic/ParameterBinderTest.java diff --git a/src/main/java/com/lambdaworks/redis/GeoCoordinates.java b/src/main/java/com/lambdaworks/redis/GeoCoordinates.java index 4be9bc549a..6c600a9f25 100644 --- a/src/main/java/com/lambdaworks/redis/GeoCoordinates.java +++ b/src/main/java/com/lambdaworks/redis/GeoCoordinates.java @@ -14,6 +14,7 @@ public class GeoCoordinates { /** * Creates new {@link GeoCoordinates}. + * * @param x the longitude, must not be {@literal null}. * @param y the latitude, must not be {@literal null}. */ @@ -26,6 +27,17 @@ public GeoCoordinates(Number x, Number y) { this.y = y; } + /** + * Creates new {@link GeoCoordinates}. + * + * @param x the longitude, must not be {@literal null}. + * @param y the latitude, must not be {@literal null}. + * @return {@literal {@link GeoCoordinates}. + */ + public static GeoCoordinates create(Number x, Number y) { + return new GeoCoordinates(x, y); + } + /** * * @return the longitude. diff --git a/src/main/java/com/lambdaworks/redis/Range.java b/src/main/java/com/lambdaworks/redis/Range.java index 05173a0a42..765c8a3cbd 100644 --- a/src/main/java/com/lambdaworks/redis/Range.java +++ b/src/main/java/com/lambdaworks/redis/Range.java @@ -32,6 +32,12 @@ private Range(Boundary lower, Boundary upper) { * @return new {@link Range} */ public static Range create(T lower, T upper) { + + LettuceAssert.isTrue(!(lower instanceof Boundary), + "Lower must not be a Boundary. Use #from(Boundary, Boundary) instead"); + LettuceAssert.isTrue(!(upper instanceof Boundary), + "Upper must not be a Boundary. Use #from(Boundary, Boundary) instead"); + return new Range(Boundary.including(lower), Boundary.including(upper)); } diff --git a/src/main/java/com/lambdaworks/redis/dynamic/CodecAwareMethodParametersAccessor.java b/src/main/java/com/lambdaworks/redis/dynamic/CodecAwareMethodParametersAccessor.java index 0dfc7183aa..653fe7630c 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/CodecAwareMethodParametersAccessor.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/CodecAwareMethodParametersAccessor.java @@ -90,4 +90,9 @@ public Iterator iterator() { public int resolveParameterIndex(String name) { return delegate.resolveParameterIndex(name); } + + @Override + public boolean isBindableNullValue(int index) { + return delegate.isBindableNullValue(index); + } } diff --git a/src/main/java/com/lambdaworks/redis/dynamic/CommandMethodVerifier.java b/src/main/java/com/lambdaworks/redis/dynamic/CommandMethodVerifier.java index 9ee5ee7784..fcf2c8c12e 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/CommandMethodVerifier.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/CommandMethodVerifier.java @@ -5,7 +5,7 @@ import java.util.Optional; import java.util.stream.Collectors; -import com.lambdaworks.redis.LettuceStrings; +import com.lambdaworks.redis.*; import com.lambdaworks.redis.dynamic.parameter.Parameter; import com.lambdaworks.redis.dynamic.segment.CommandSegments; import com.lambdaworks.redis.internal.LettuceAssert; @@ -60,7 +60,7 @@ private void validateParameters(CommandDetail commandDetail, CommandSegments com List bindableParameters = commandMethod.getParameters().getBindableParameters(); - int availableParameterCount = bindableParameters.size() + commandSegments.size(); + int availableParameterCount = calculateAvailableParameterCount(commandSegments, bindableParameters); // exact parameter count if (commandDetail.getArity() - 1 == availableParameterCount) { @@ -94,6 +94,31 @@ private void validateParameters(CommandDetail commandDetail, CommandSegments com throw new CommandMethodSyntaxException(commandMethod, message); } + private int calculateAvailableParameterCount(CommandSegments commandSegments, + List bindableParameters) { + + int count = commandSegments.size(); + + for (Parameter bindableParameter : bindableParameters) { + + if (bindableParameter.isAssignableTo(KeyValue.class) || bindableParameter.isAssignableTo(ScoredValue.class)) { + count++; + } + + if (bindableParameter.isAssignableTo(GeoCoordinates.class) || bindableParameter.isAssignableTo(Range.class)) { + count++; + } + + if (bindableParameter.isAssignableTo(Limit.class)) { + count += 2; + } + + count++; + } + + return count; + } + private CommandMethodSyntaxException syntaxException(String commandName, CommandMethod commandMethod) { CommandMatches commandMatches = CommandMatches.forCommand(commandName, commandDetails); @@ -131,7 +156,7 @@ private static List calculateMatches(String command, List command.toLowerCase()) <= DEFAULT_MAX_DISTANCE) .map(CommandDetail::getName) // .map(String::toUpperCase) // - .sorted((o1, o2) -> calculateStringDistance(o1, o2)).collect(Collectors.toList()); + .sorted(CommandMatches::calculateStringDistance).collect(Collectors.toList()); } public boolean hasMatches() { diff --git a/src/main/java/com/lambdaworks/redis/dynamic/DefaultMethodParametersAccessor.java b/src/main/java/com/lambdaworks/redis/dynamic/DefaultMethodParametersAccessor.java index d6c07070e7..4f1370a502 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/DefaultMethodParametersAccessor.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/DefaultMethodParametersAccessor.java @@ -4,6 +4,7 @@ import java.util.Iterator; import java.util.List; +import com.lambdaworks.redis.*; import com.lambdaworks.redis.dynamic.annotation.Key; import com.lambdaworks.redis.dynamic.annotation.Value; import com.lambdaworks.redis.dynamic.parameter.MethodParametersAccessor; @@ -22,11 +23,13 @@ class DefaultMethodParametersAccessor implements MethodParametersAccessor { private final Parameters parameters; private final List values; - public DefaultMethodParametersAccessor(Parameters parameters, Object[] values) { + public DefaultMethodParametersAccessor(Parameters parameters, Object... values) { + + LettuceAssert.notNull(parameters, "Parameters must not be null"); + LettuceAssert.notNull(values, "Values must not be null"); this.parameters = parameters; this.values = Arrays.asList(values); - } public int getParameterCount() { @@ -71,6 +74,20 @@ public Parameters getParameters() { return parameters; } + @Override + public boolean isBindableNullValue(int index) { + + Parameter bindableParameter = parameters.getBindableParameter(index); + + if (bindableParameter.isAssignableTo(Limit.class) || bindableParameter.isAssignableTo(com.lambdaworks.redis.Value.class) + || bindableParameter.isAssignableTo(KeyValue.class) || bindableParameter.isAssignableTo(ScoredValue.class) + || bindableParameter.isAssignableTo(GeoCoordinates.class) || bindableParameter.isAssignableTo(Range.class)) { + return false; + } + + return true; + } + /** * Iterator class to allow traversing all bindable parameters inside the accessor. */ diff --git a/src/main/java/com/lambdaworks/redis/dynamic/ParameterBinder.java b/src/main/java/com/lambdaworks/redis/dynamic/ParameterBinder.java index ef9cc7980b..39ba93b877 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/ParameterBinder.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/ParameterBinder.java @@ -1,10 +1,12 @@ package com.lambdaworks.redis.dynamic; +import static com.lambdaworks.redis.protocol.CommandKeyword.LIMIT; + import java.util.HashSet; import java.util.Map; import java.util.Set; -import com.lambdaworks.redis.CompositeArgument; +import com.lambdaworks.redis.*; import com.lambdaworks.redis.dynamic.parameter.MethodParametersAccessor; import com.lambdaworks.redis.dynamic.segment.CommandSegment; import com.lambdaworks.redis.dynamic.segment.CommandSegment.ArgumentContribution; @@ -20,6 +22,9 @@ */ class ParameterBinder { + private static final byte[] MINUS_BYTES = { '-' }; + private static final byte[] PLUS_BYTES = { '+' }; + /** * Bind {@link CommandSegments} and method parameters to {@link CommandArgs}. * @@ -63,11 +68,16 @@ CommandArgs bind(CommandArgs args, CommandSegments commandSeg private void bind(CommandArgs args, Object argument, int index, MethodParametersAccessor accessor) { if (argument == null) { - args.add(new byte[0]); + + if (accessor.isBindableNullValue(index)) { + args.add(new byte[0]); + } + return; } if (index != -1) { + if (accessor.isKey(index)) { if (argument instanceof Iterable) { @@ -80,6 +90,10 @@ private void bind(CommandArgs args, Object argument, int index, Met if (accessor.isValue(index)) { + if (argument instanceof Range) { + throw new UnsupportedOperationException("Value Range is not supported."); + } + if (argument instanceof Iterable) { args.addValues((Iterable) argument); } else { @@ -113,8 +127,109 @@ private void bind(CommandArgs args, Object argument, int index, Met return; } + if (argument instanceof ScoredValue) { + + ScoredValue scoredValue = (ScoredValue) argument; + V value = scoredValue.getValueOrElseThrow( + () -> new IllegalArgumentException("Cannot bind empty ScoredValue to a Redis command.")); + + args.add(scoredValue.getScore()); + args.addValue(value); + return; + } + + if (argument instanceof KeyValue) { + + KeyValue keyValue = (KeyValue) argument; + V value = keyValue + .getValueOrElseThrow(() -> new IllegalArgumentException("Cannot bind empty KeyValue to a Redis command.")); + + args.addKey(keyValue.getKey()); + args.addValue(value); + return; + } + + if (argument instanceof Value) { + + Value valueWrapper = (Value) argument; + V value = valueWrapper + .getValueOrElseThrow(() -> new IllegalArgumentException("Cannot bind empty Value to a Redis command.")); + + args.addValue(value); + return; + } + + if (argument instanceof Limit) { + + Limit limit = (Limit) argument; + args.add(LIMIT); + args.add(limit.getOffset()); + args.add(limit.getCount()); + return; + } + + if (argument instanceof Range) { + + Range range = (Range) argument; + + if (range.getLower().getValue() != null && !(range.getLower().getValue() instanceof Number)) { + throw new IllegalArgumentException( + "Cannot bind non-numeric lower range value for a numeric Range. Annotate with @Value if the Range contains a value range."); + } + + if (range.getUpper().getValue() != null && !(range.getUpper().getValue() instanceof Number)) { + throw new IllegalArgumentException( + "Cannot bind non-numeric upper range value for a numeric Range. Annotate with @Value if the Range contains a value range."); + } + + args.add(min((Range) range)); + args.add(max((Range) range)); + + return; + } + + if (argument instanceof GeoCoordinates) { + + GeoCoordinates coordinates = (GeoCoordinates) argument; + args.add(coordinates.getX().doubleValue()); + args.add(coordinates.getY().doubleValue()); + return; + } + if (argument instanceof CompositeArgument) { ((CompositeArgument) argument).build(args); } } + + private String min(Range range) { + + Range.Boundary lower = range.getLower(); + + if (lower.getValue() == null + || lower.getValue() instanceof Double && lower.getValue().doubleValue() == Double.NEGATIVE_INFINITY) { + return "-inf"; + } + + if (!lower.isIncluding()) { + return "(" + lower.getValue(); + } + + return lower.getValue().toString(); + } + + private String max(Range range) { + + Range.Boundary upper = range.getUpper(); + + if (upper.getValue() == null + || upper.getValue() instanceof Double && upper.getValue().doubleValue() == Double.POSITIVE_INFINITY) { + return "+inf"; + } + + if (!upper.isIncluding()) { + return "(" + upper.getValue(); + } + + return upper.getValue().toString(); + } } diff --git a/src/main/java/com/lambdaworks/redis/dynamic/domain/FlushMode.java b/src/main/java/com/lambdaworks/redis/dynamic/domain/FlushMode.java deleted file mode 100644 index d55881ee75..0000000000 --- a/src/main/java/com/lambdaworks/redis/dynamic/domain/FlushMode.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.lambdaworks.redis.dynamic.domain; - -/** - * @author Mark Paluch - */ -public enum FlushMode { - DEFAULT, ENQUEUE, FLUSH; -} diff --git a/src/main/java/com/lambdaworks/redis/dynamic/parameter/ExecutionSpecificParameters.java b/src/main/java/com/lambdaworks/redis/dynamic/parameter/ExecutionSpecificParameters.java index c5ff8b6ab1..0d005d5c93 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/parameter/ExecutionSpecificParameters.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/parameter/ExecutionSpecificParameters.java @@ -4,7 +4,6 @@ import java.util.Arrays; import java.util.List; -import com.lambdaworks.redis.dynamic.domain.FlushMode; import com.lambdaworks.redis.dynamic.domain.Timeout; /** @@ -17,9 +16,8 @@ */ public class ExecutionSpecificParameters extends Parameters { - private static final List> TYPES = Arrays.asList(FlushMode.class, Timeout.class); + private static final List> TYPES = Arrays.asList(Timeout.class); - private final int flushModeIndex; private final int timeoutIndex; /** @@ -31,7 +29,6 @@ public ExecutionSpecificParameters(Method method) { super(method); - int flushModeIndex = -1; int timeoutIndex = -1; List parameters = getParameters(); @@ -44,21 +41,12 @@ public ExecutionSpecificParameters(Method method) { if (methodParameter.isAssignableTo(Timeout.class)) { timeoutIndex = i; } - - if (methodParameter.isAssignableTo(FlushMode.class)) { - flushModeIndex = i; - } } } - this.flushModeIndex = flushModeIndex; this.timeoutIndex = timeoutIndex; } - public int getFlushModeIndex() { - return flushModeIndex; - } - public int getTimeoutIndex() { return timeoutIndex; } diff --git a/src/main/java/com/lambdaworks/redis/dynamic/parameter/MethodParametersAccessor.java b/src/main/java/com/lambdaworks/redis/dynamic/parameter/MethodParametersAccessor.java index 303763b187..b6ee14a87b 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/parameter/MethodParametersAccessor.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/parameter/MethodParametersAccessor.java @@ -1,10 +1,9 @@ package com.lambdaworks.redis.dynamic.parameter; -import com.lambdaworks.redis.dynamic.domain.FlushMode; -import com.lambdaworks.redis.dynamic.domain.Timeout; - import java.util.Iterator; +import com.lambdaworks.redis.dynamic.domain.Timeout; + /** * Accessor interface to method parameters during the actual invocation. * @@ -19,32 +18,32 @@ public interface MethodParametersAccessor { int getParameterCount(); /** - * Returns the bindable value with the given index. Bindable means, that {@link FlushMode} and {@link Timeout} values are - * skipped without noticed in the index. For a method signature taking {@link String}, {@link Timeout} , {@link String}, + * Returns the bindable value with the given index. Bindable means, that {@link Timeout} values are skipped without noticed + * in the index. For a method signature taking {@link String}, {@link Timeout} , {@link String}, * {@code #getBindableParameter(1)} would return the second {@link String} value. * - * @param index + * @param index parameter index. * @return the bindable value. */ Object getBindableValue(int index); /** * - * @param index + * @param index parameter index. * @return {@literal true} if the parameter at {@code index} is a key. */ boolean isKey(int index); /** * - * @param index + * @param index parameter index. * @return {@literal true} if the parameter at {@code index} is a value. */ boolean isValue(int index); /** - * Returns an iterator over all bindable parameters. This means parameters implementing {@link Timeout} or - * {@link FlushMode} will not be included in this {@link Iterator}. + * Returns an iterator over all bindable parameters. This means parameters assignable to {@link Timeout} will not + * be included in this {@link Iterator}. * * @return */ @@ -57,4 +56,14 @@ public interface MethodParametersAccessor { * @return */ int resolveParameterIndex(String name); + + /** + * Return {@literal true} if the parameter at {@code index} is a bindable {@literal null} value that requires a + * {@literal null} value instead of being skipped. + * + * @param index parameter index. + * @return {@literal true} if the parameter at {@code index} is a bindable {@literal null} value that requires a + * {@literal null} value instead of being skipped. + */ + boolean isBindableNullValue(int index); } diff --git a/src/main/java/com/lambdaworks/redis/dynamic/parameter/Parameters.java b/src/main/java/com/lambdaworks/redis/dynamic/parameter/Parameters.java index 1ff3a8a515..81d4019462 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/parameter/Parameters.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/parameter/Parameters.java @@ -1,5 +1,7 @@ package com.lambdaworks.redis.dynamic.parameter; +import com.lambdaworks.redis.internal.LettuceAssert; + import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Iterator; @@ -22,6 +24,8 @@ public abstract class Parameters

    implements Iterable

    { */ public Parameters(Method method) { + LettuceAssert.notNull(method, "Method must not be null"); + this.parameters = new ArrayList<>(method.getParameterCount()); for (int i = 0; i < method.getParameterCount(); i++) { @@ -89,4 +93,5 @@ public List

    getBindableParameters() { public Iterator

    iterator() { return getBindableParameters().iterator(); } + } diff --git a/src/main/java/com/lambdaworks/redis/protocol/CommandArgs.java b/src/main/java/com/lambdaworks/redis/protocol/CommandArgs.java index 5a40e69e28..edbc8e8b26 100644 --- a/src/main/java/com/lambdaworks/redis/protocol/CommandArgs.java +++ b/src/main/java/com/lambdaworks/redis/protocol/CommandArgs.java @@ -8,6 +8,7 @@ import java.util.List; import java.util.Map; +import com.lambdaworks.redis.LettuceStrings; import com.lambdaworks.redis.codec.ByteArrayCodec; import com.lambdaworks.redis.codec.RedisCodec; import com.lambdaworks.redis.codec.StringCodec; @@ -240,7 +241,7 @@ public CommandArgs add(byte[] value) { public CommandArgs add(CommandKeyword keyword) { LettuceAssert.notNull(keyword, "CommandKeyword must not be null"); - return add(keyword.bytes); + return add((ProtocolKeyword) keyword); } /** @@ -286,6 +287,17 @@ public String toString() { return sb.toString(); } + /** + * Returns a command string representation of {@link CommandArgs} with annotated key and value parameters. + * + * {@code args.addKey("mykey").add(2.0)} will return {@code key 2.0}. + * + * @return the command string representation. + */ + public String toCommandString() { + return LettuceStrings.collectionToDelimitedString(singularArguments, " ", "", ""); + } + /** * Returns the first integer argument. * diff --git a/src/test/java/com/lambdaworks/redis/dynamic/CommandMethodVerifierTest.java b/src/test/java/com/lambdaworks/redis/dynamic/CommandMethodVerifierTest.java index 6a18e9c9d4..ff30f8f367 100644 --- a/src/test/java/com/lambdaworks/redis/dynamic/CommandMethodVerifierTest.java +++ b/src/test/java/com/lambdaworks/redis/dynamic/CommandMethodVerifierTest.java @@ -6,6 +6,8 @@ import java.lang.reflect.Method; import java.util.Arrays; +import com.lambdaworks.redis.GeoCoordinates; +import com.lambdaworks.redis.KeyValue; import org.junit.Before; import org.junit.Test; @@ -28,8 +30,10 @@ public void before() { CommandDetail mget = new CommandDetail("mget", -2, null, 0, 0, 0); CommandDetail randomkey = new CommandDetail("randomkey", 1, null, 0, 0, 0); CommandDetail rpop = new CommandDetail("rpop", 2, null, 0, 0, 0); + CommandDetail set = new CommandDetail("set", 3, null, 0, 0, 0); + CommandDetail geoadd = new CommandDetail("geoadd", -4, null, 0, 0, 0); - sut = new CommandMethodVerifier(LettuceLists.newList(mget, randomkey, rpop)); + sut = new CommandMethodVerifier(LettuceLists.newList(mget, randomkey, rpop, set, geoadd)); } @Test @@ -39,7 +43,7 @@ public void misspelledName() { validateMethod("megt"); fail("Missing CommandMethodSyntaxException"); } catch (CommandMethodSyntaxException e) { - assertThat(e).hasMessageContaining("Command megt does not exist. Did you mean: MGET?"); + assertThat(e).hasMessageContaining("Command megt does not exist. Did you mean: MGET, SET?"); } } @@ -61,6 +65,8 @@ public void shouldPassWithCorrectParameterCount() { validateMethod("mget", String.class); validateMethod("randomkey"); validateMethod("rpop", String.class); + validateMethod("set", KeyValue.class); + validateMethod("geoadd", String.class, String.class, GeoCoordinates.class); } @Test @@ -103,6 +109,10 @@ static interface MyInterface { void mget(String key1, String key2); + void set(KeyValue keyValue); + + void geoadd(String key, String member, GeoCoordinates geoCoordinates); + void randomkey(); void randomkey(String key); @@ -111,4 +121,4 @@ static interface MyInterface { void rpop(String key1, String key2); } -} \ No newline at end of file +} diff --git a/src/test/java/com/lambdaworks/redis/dynamic/CommandSegmentCommandFactoryTest.java b/src/test/java/com/lambdaworks/redis/dynamic/CommandSegmentCommandFactoryTest.java index 5e07d53479..8db13a0301 100644 --- a/src/test/java/com/lambdaworks/redis/dynamic/CommandSegmentCommandFactoryTest.java +++ b/src/test/java/com/lambdaworks/redis/dynamic/CommandSegmentCommandFactoryTest.java @@ -126,15 +126,7 @@ private String toString(RedisCommand command) { StringBuilder builder = new StringBuilder(); builder.append(command.getType().name()); - - CommandArgs args = command.getArgs(); - if (args != null) { - List argList = (List) ReflectionTestUtils.getField(args, "singularArguments"); - - for (Object o : argList) { - builder.append(' ').append(o); - } - } + builder.append(' ').append(command.getArgs().toCommandString()); return builder.toString(); } @@ -160,4 +152,4 @@ static interface MethodsWithTimeout { String sync(String key, Timeout timeout); } -} \ No newline at end of file +} diff --git a/src/test/java/com/lambdaworks/redis/dynamic/ParameterBinderTest.java b/src/test/java/com/lambdaworks/redis/dynamic/ParameterBinderTest.java new file mode 100644 index 0000000000..35136798ef --- /dev/null +++ b/src/test/java/com/lambdaworks/redis/dynamic/ParameterBinderTest.java @@ -0,0 +1,181 @@ +package com.lambdaworks.redis.dynamic; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Collections; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.runners.MockitoJUnitRunner; +import org.springframework.util.Base64Utils; +import org.springframework.util.ReflectionUtils; + +import com.lambdaworks.redis.*; +import com.lambdaworks.redis.codec.StringCodec; +import com.lambdaworks.redis.dynamic.segment.CommandSegment; +import com.lambdaworks.redis.dynamic.segment.CommandSegments; +import com.lambdaworks.redis.protocol.CommandArgs; +import com.lambdaworks.redis.protocol.CommandType; + +/** + * @author Mark Paluch + */ +@RunWith(MockitoJUnitRunner.class) +public class ParameterBinderTest { + + private ParameterBinder binder = new ParameterBinder(); + private CommandSegments segments = new CommandSegments(Collections.singletonList(CommandSegment.constant("set"))); + + @Test + public void bindsNullValueAsEmptyByteArray() { + + CommandArgs args = bind(null); + + assertThat(args.toCommandString()).isEqualTo(""); + } + + @Test + public void bindsStringCorrectly() { + + CommandArgs args = bind("string"); + + assertThat(args.toCommandString()).isEqualTo("string"); + } + + @Test + public void bindsValueCorrectly() { + + CommandArgs args = bind(Value.just("string")); + + assertThat(args.toCommandString()).isEqualTo("value"); + } + + @Test(expected = IllegalArgumentException.class) + public void rejectsEmptyValue() { + bind(Value.empty()); + } + + @Test + public void bindsKeyValueCorrectly() { + + CommandArgs args = bind(KeyValue.just("mykey", "string")); + + assertThat(args.toCommandString()).isEqualTo("key value"); + } + + @Test(expected = IllegalArgumentException.class) + public void rejectsEmptyKeyValue() { + bind(KeyValue.empty()); + } + + @Test + public void bindsScoredValueCorrectly() { + + CommandArgs args = bind(ScoredValue.just(20, "string")); + + assertThat(args.toCommandString()).isEqualTo("20.0 value"); + } + + @Test(expected = IllegalArgumentException.class) + public void rejectsEmptyScoredValue() { + bind(ScoredValue.empty()); + } + + @Test + public void bindsLimitCorrectly() { + + CommandArgs args = bind(Limit.create(10, 100)); + + assertThat(args.toCommandString()).isEqualTo("TElNSVQ= 10 100"); + } + + @Test + public void bindsRangeCorrectly() { + + CommandArgs args = bind(Range.from(Range.Boundary.including(10), Range.Boundary.excluding(15))); + + assertThat(args.toCommandString()).isEqualTo("10 (15"); + } + + @Test + public void bindsUnboundedRangeCorrectly() { + + CommandArgs args = bind(Range.unbounded()); + + assertThat(args.toCommandString()).isEqualTo("-inf +inf"); + } + + @Test(expected = IllegalArgumentException.class) + public void rejectsStringLowerValue() { + bind(Range.from(Range.Boundary.including("hello"), Range.Boundary.excluding(15))); + } + + @Test(expected = IllegalArgumentException.class) + public void rejectsStringUpperValue() { + bind(Range.from(Range.Boundary.including(11), Range.Boundary.excluding("hello"))); + } + + @Test(expected = UnsupportedOperationException.class) + public void bindsValueRangeCorrectly() { + + CommandMethod commandMethod = new CommandMethod( + ReflectionUtils.findMethod(MyCommands.class, "someMethod", Range.class)); + + CommandArgs args = bind(commandMethod, + Range.from(Range.Boundary.including("lower"), Range.Boundary.excluding("upper"))); + + assertThat(args.toCommandString()).isEqualTo(String.format("%s %s", Base64Utils.encodeToString("[lower".getBytes()), + Base64Utils.encodeToString("(upper".getBytes()))); + } + + @Test(expected = UnsupportedOperationException.class) + public void bindsUnboundedValueRangeCorrectly() { + + CommandMethod commandMethod = new CommandMethod( + ReflectionUtils.findMethod(MyCommands.class, "someMethod", Range.class)); + + CommandArgs args = bind(commandMethod, Range.unbounded()); + + assertThat(args.toCommandString()).isEqualTo( + String.format("%s %s", Base64Utils.encodeToString("-".getBytes()), Base64Utils.encodeToString("+".getBytes()))); + } + + @Test + public void bindsGeoCoordinatesCorrectly() { + + CommandArgs args = bind(new GeoCoordinates(100, 200)); + + assertThat(args.toCommandString()).isEqualTo("100.0 200.0"); + } + + @Test + public void bindsProtocolKeywordCorrectly() { + + CommandArgs args = bind(CommandType.LINDEX); + + assertThat(args.toCommandString()).isEqualTo(Base64Utils.encodeToString("LINDEX".getBytes())); + } + + private CommandArgs bind(Object object) { + CommandMethod commandMethod = new CommandMethod( + ReflectionUtils.findMethod(MyCommands.class, "someMethod", Object.class)); + return bind(commandMethod, object); + } + + private CommandArgs bind(CommandMethod commandMethod, Object object) { + DefaultMethodParametersAccessor parametersAccessor = new DefaultMethodParametersAccessor(commandMethod.getParameters(), + object); + + CommandArgs args = new CommandArgs<>(new StringCodec()); + binder.bind(args, segments, parametersAccessor); + + return args; + } + + private interface MyCommands { + + void someMethod(Object object); + + void someMethod(@com.lambdaworks.redis.dynamic.annotation.Value Range value); + } +} From 7599817d02b5151b94474e5f8d5f38bb1d44f957 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Wed, 26 Oct 2016 17:54:05 +0200 Subject: [PATCH 058/808] Update license/author headers #387 --- .../java/com/lambdaworks/codec/Base16.java | 17 +++++++++++++-- .../java/com/lambdaworks/codec/CRC16.java | 15 +++++++++++++ .../com/lambdaworks/codec/package-info.java | 2 +- .../redis/AbstractRedisAsyncCommands.java | 17 +++++++++++++-- .../redis/AbstractRedisClient.java | 15 +++++++++++++ .../redis/AbstractRedisReactiveCommands.java | 15 +++++++++++++ .../lambdaworks/redis/BackpressureUtils.java | 17 ++++++++++++++- .../com/lambdaworks/redis/BitFieldArgs.java | 15 +++++++++++++ .../redis/ChannelGroupListener.java | 17 +++++++++++++-- .../com/lambdaworks/redis/ClientOptions.java | 15 +++++++++++++ .../com/lambdaworks/redis/CloseEvents.java | 15 +++++++++++++ .../lambdaworks/redis/CompositeArgument.java | 15 +++++++++++++ .../lambdaworks/redis/ConnectionBuilder.java | 15 +++++++++++++ .../redis/ConnectionEventTrigger.java | 15 +++++++++++++ .../lambdaworks/redis/ConnectionEvents.java | 15 +++++++++++++ .../com/lambdaworks/redis/ConnectionId.java | 15 +++++++++++++ .../lambdaworks/redis/ConnectionPoint.java | 15 +++++++++++++ .../com/lambdaworks/redis/EpollProvider.java | 15 +++++++++++++ .../redis/FutureSyncInvocationHandler.java | 15 +++++++++++++ .../java/com/lambdaworks/redis/GeoArgs.java | 15 +++++++++++++ .../com/lambdaworks/redis/GeoCoordinates.java | 15 +++++++++++++ .../lambdaworks/redis/GeoRadiusStoreArgs.java | 15 +++++++++++++ .../java/com/lambdaworks/redis/GeoWithin.java | 15 +++++++++++++ .../com/lambdaworks/redis/JavaRuntime.java | 15 +++++++++++++ .../com/lambdaworks/redis/KeyScanCursor.java | 15 +++++++++++++ .../java/com/lambdaworks/redis/KeyValue.java | 15 +++++++++++++ .../java/com/lambdaworks/redis/KillArgs.java | 15 +++++++++++++ .../com/lambdaworks/redis/LettuceFutures.java | 15 +++++++++++++ .../com/lambdaworks/redis/LettuceStrings.java | 15 +++++++++++++ .../java/com/lambdaworks/redis/Limit.java | 15 +++++++++++++ .../com/lambdaworks/redis/MapScanCursor.java | 15 +++++++++++++ .../com/lambdaworks/redis/MigrateArgs.java | 15 +++++++++++++ .../redis/PlainChannelInitializer.java | 15 +++++++++++++ .../java/com/lambdaworks/redis/Range.java | 15 +++++++++++++ .../java/com/lambdaworks/redis/ReadFrom.java | 15 +++++++++++++ .../com/lambdaworks/redis/ReadFromImpl.java | 15 +++++++++++++ .../redis/RedisAsyncCommandsImpl.java | 17 +++++++++++++-- .../redis/RedisChannelHandler.java | 15 +++++++++++++ .../redis/RedisChannelInitializer.java | 15 +++++++++++++ .../redis/RedisChannelInitializerImpl.java | 15 +++++++++++++ .../lambdaworks/redis/RedisChannelWriter.java | 15 +++++++++++++ .../com/lambdaworks/redis/RedisClient.java | 17 +++++++++++++-- .../redis/RedisCommandBuilder.java | 15 +++++++++++++ .../redis/RedisCommandExecutionException.java | 15 +++++++++++++ .../RedisCommandInterruptedException.java | 17 +++++++++++++-- .../redis/RedisCommandTimeoutException.java | 15 +++++++++++++ .../redis/RedisConnectionException.java | 15 +++++++++++++ .../redis/RedisConnectionStateListener.java | 18 ++++++++++++++-- .../com/lambdaworks/redis/RedisException.java | 17 +++++++++++++-- .../com/lambdaworks/redis/RedisFuture.java | 15 +++++++++++++ .../com/lambdaworks/redis/RedisPublisher.java | 15 +++++++++++++ .../redis/RedisReactiveCommandsImpl.java | 15 +++++++++++++ .../java/com/lambdaworks/redis/RedisURI.java | 15 +++++++++++++ .../java/com/lambdaworks/redis/ScanArgs.java | 15 +++++++++++++ .../com/lambdaworks/redis/ScanCursor.java | 15 +++++++++++++ .../com/lambdaworks/redis/ScoredValue.java | 15 +++++++++++++ .../redis/ScoredValueScanCursor.java | 15 +++++++++++++ .../lambdaworks/redis/ScriptOutputType.java | 17 +++++++++++++-- .../java/com/lambdaworks/redis/SetArgs.java | 19 ++++++++++++++--- .../com/lambdaworks/redis/SocketOptions.java | 15 +++++++++++++ .../java/com/lambdaworks/redis/SortArgs.java | 17 +++++++++++++-- .../redis/SslConnectionBuilder.java | 15 +++++++++++++ .../com/lambdaworks/redis/SslOptions.java | 15 +++++++++++++ .../redis/StatefulRedisConnectionImpl.java | 15 +++++++++++++ .../lambdaworks/redis/StreamScanCursor.java | 15 +++++++++++++ .../lambdaworks/redis/TransactionResult.java | 15 +++++++++++++ .../java/com/lambdaworks/redis/Value.java | 15 +++++++++++++ .../lambdaworks/redis/ValueScanCursor.java | 15 +++++++++++++ .../java/com/lambdaworks/redis/ZAddArgs.java | 15 +++++++++++++ .../com/lambdaworks/redis/ZStoreArgs.java | 17 +++++++++++++-- .../redis/api/StatefulConnection.java | 15 +++++++++++++ .../redis/api/StatefulRedisConnection.java | 15 +++++++++++++ .../api/async/BaseRedisAsyncCommands.java | 15 +++++++++++++ .../redis/api/async/RedisAsyncCommands.java | 15 +++++++++++++ .../api/async/RedisGeoAsyncCommands.java | 15 +++++++++++++ .../api/async/RedisHLLAsyncCommands.java | 15 +++++++++++++ .../api/async/RedisHashAsyncCommands.java | 15 +++++++++++++ .../api/async/RedisKeyAsyncCommands.java | 15 +++++++++++++ .../api/async/RedisListAsyncCommands.java | 15 +++++++++++++ .../async/RedisScriptingAsyncCommands.java | 15 +++++++++++++ .../api/async/RedisServerAsyncCommands.java | 15 +++++++++++++ .../api/async/RedisSetAsyncCommands.java | 15 +++++++++++++ .../async/RedisSortedSetAsyncCommands.java | 15 +++++++++++++ .../api/async/RedisStringAsyncCommands.java | 15 +++++++++++++ .../RedisTransactionalAsyncCommands.java | 15 +++++++++++++ .../redis/api/async/package-info.java | 2 +- .../lambdaworks/redis/api/package-info.java | 2 +- .../reactive/BaseRedisReactiveCommands.java | 15 +++++++++++++ .../reactive/RedisGeoReactiveCommands.java | 15 +++++++++++++ .../reactive/RedisHLLReactiveCommands.java | 15 +++++++++++++ .../reactive/RedisHashReactiveCommands.java | 15 +++++++++++++ .../reactive/RedisKeyReactiveCommands.java | 15 +++++++++++++ .../reactive/RedisListReactiveCommands.java | 15 +++++++++++++ .../api/reactive/RedisReactiveCommands.java | 15 +++++++++++++ .../RedisScriptingReactiveCommands.java | 15 +++++++++++++ .../reactive/RedisServerReactiveCommands.java | 15 +++++++++++++ .../reactive/RedisSetReactiveCommands.java | 15 +++++++++++++ .../RedisSortedSetReactiveCommands.java | 15 +++++++++++++ .../reactive/RedisStringReactiveCommands.java | 15 +++++++++++++ .../RedisTransactionalReactiveCommands.java | 15 +++++++++++++ .../redis/api/reactive/package-info.java | 2 +- .../redis/api/sync/BaseRedisCommands.java | 15 +++++++++++++ .../redis/api/sync/RedisCommands.java | 15 +++++++++++++ .../redis/api/sync/RedisGeoCommands.java | 15 +++++++++++++ .../redis/api/sync/RedisHLLCommands.java | 15 +++++++++++++ .../redis/api/sync/RedisHashCommands.java | 15 +++++++++++++ .../redis/api/sync/RedisKeyCommands.java | 15 +++++++++++++ .../redis/api/sync/RedisListCommands.java | 15 +++++++++++++ .../api/sync/RedisScriptingCommands.java | 15 +++++++++++++ .../redis/api/sync/RedisServerCommands.java | 15 +++++++++++++ .../redis/api/sync/RedisSetCommands.java | 15 +++++++++++++ .../api/sync/RedisSortedSetCommands.java | 15 +++++++++++++ .../redis/api/sync/RedisStringCommands.java | 15 +++++++++++++ .../api/sync/RedisTransactionalCommands.java | 15 +++++++++++++ .../redis/api/sync/package-info.java | 2 +- .../redis/cluster/AbstractNodeSelection.java | 15 +++++++++++++ .../redis/cluster/AsyncExecutionsImpl.java | 15 +++++++++++++ .../redis/cluster/ClusterClientOptions.java | 15 +++++++++++++ .../redis/cluster/ClusterCommand.java | 15 +++++++++++++ .../cluster/ClusterConnectionProvider.java | 15 +++++++++++++ .../ClusterDistributionChannelWriter.java | 15 +++++++++++++ .../redis/cluster/ClusterEventListener.java | 15 +++++++++++++ .../redis/cluster/ClusterNodeEndpoint.java | 15 +++++++++++++ .../redis/cluster/ClusterScanSupport.java | 15 +++++++++++++ .../ClusterTopologyRefreshOptions.java | 15 +++++++++++++ .../ClusterTopologyRefreshScheduler.java | 15 +++++++++++++ .../cluster/DynamicAsyncNodeSelection.java | 15 +++++++++++++ .../redis/cluster/DynamicNodeSelection.java | 15 +++++++++++++ .../cluster/DynamicSyncNodeSelection.java | 15 +++++++++++++ .../redis/cluster/MultiNodeExecution.java | 15 +++++++++++++ .../NodeSelectionInvocationHandler.java | 15 +++++++++++++ .../redis/cluster/PartitionAccessor.java | 15 +++++++++++++ .../redis/cluster/PartitionsConsensus.java | 15 +++++++++++++ .../cluster/PartitionsConsensusImpl.java | 15 +++++++++++++ .../redis/cluster/PipelinedRedisFuture.java | 15 +++++++++++++ .../PooledClusterConnectionProvider.java | 15 +++++++++++++ .../redis/cluster/ReadOnlyCommands.java | 15 +++++++++++++ .../redis/cluster/ReconnectEventListener.java | 15 +++++++++++++ ...RedisAdvancedClusterAsyncCommandsImpl.java | 15 +++++++++++++ ...isAdvancedClusterReactiveCommandsImpl.java | 15 +++++++++++++ .../redis/cluster/RedisClusterClient.java | 15 +++++++++++++ .../lambdaworks/redis/cluster/RoundRobin.java | 17 ++++++++++++++- .../RoundRobinSocketAddressSupplier.java | 15 +++++++++++++ .../lambdaworks/redis/cluster/SlotHash.java | 17 ++++++++++++++- .../StatefulRedisClusterConnectionImpl.java | 15 +++++++++++++ .../cluster/StaticAsyncNodeSelection.java | 15 +++++++++++++ .../redis/cluster/StaticNodeSelection.java | 15 +++++++++++++ .../cluster/StaticSyncNodeSelection.java | 15 +++++++++++++ .../redis/cluster/SyncExecutionsImpl.java | 15 +++++++++++++ .../cluster/api/NodeSelectionSupport.java | 15 +++++++++++++ .../api/StatefulRedisClusterConnection.java | 15 +++++++++++++ .../cluster/api/async/AsyncExecutions.java | 15 +++++++++++++ .../cluster/api/async/AsyncNodeSelection.java | 15 +++++++++++++ .../async/BaseNodeSelectionAsyncCommands.java | 15 +++++++++++++ .../api/async/NodeSelectionAsyncCommands.java | 15 +++++++++++++ .../async/NodeSelectionGeoAsyncCommands.java | 15 +++++++++++++ .../async/NodeSelectionHLLAsyncCommands.java | 15 +++++++++++++ .../async/NodeSelectionHashAsyncCommands.java | 15 +++++++++++++ .../async/NodeSelectionKeyAsyncCommands.java | 15 +++++++++++++ .../async/NodeSelectionListAsyncCommands.java | 15 +++++++++++++ .../NodeSelectionScriptingAsyncCommands.java | 15 +++++++++++++ .../NodeSelectionServerAsyncCommands.java | 15 +++++++++++++ .../async/NodeSelectionSetAsyncCommands.java | 15 +++++++++++++ .../NodeSelectionSortedSetAsyncCommands.java | 15 +++++++++++++ .../NodeSelectionStringAsyncCommands.java | 15 +++++++++++++ .../RedisAdvancedClusterAsyncCommands.java | 15 +++++++++++++ .../api/async/RedisClusterAsyncCommands.java | 15 +++++++++++++ .../redis/cluster/api/async/package-info.java | 2 +- .../redis/cluster/api/package-info.java | 2 +- .../RedisAdvancedClusterReactiveCommands.java | 17 ++++++++++++++- .../RedisClusterReactiveCommands.java | 17 ++++++++++++++- .../cluster/api/reactive/package-info.java | 2 +- .../api/sync/BaseNodeSelectionCommands.java | 15 +++++++++++++ .../redis/cluster/api/sync/Executions.java | 15 +++++++++++++ .../redis/cluster/api/sync/NodeSelection.java | 15 +++++++++++++ .../api/sync/NodeSelectionCommands.java | 15 +++++++++++++ .../api/sync/NodeSelectionGeoCommands.java | 15 +++++++++++++ .../api/sync/NodeSelectionHLLCommands.java | 15 +++++++++++++ .../api/sync/NodeSelectionHashCommands.java | 15 +++++++++++++ .../api/sync/NodeSelectionKeyCommands.java | 15 +++++++++++++ .../api/sync/NodeSelectionListCommands.java | 15 +++++++++++++ .../sync/NodeSelectionScriptingCommands.java | 15 +++++++++++++ .../api/sync/NodeSelectionServerCommands.java | 15 +++++++++++++ .../api/sync/NodeSelectionSetCommands.java | 15 +++++++++++++ .../sync/NodeSelectionSortedSetCommands.java | 15 +++++++++++++ .../api/sync/NodeSelectionStringCommands.java | 15 +++++++++++++ .../sync/RedisAdvancedClusterCommands.java | 15 +++++++++++++ .../api/sync/RedisClusterCommands.java | 15 +++++++++++++ .../redis/cluster/api/sync/package-info.java | 2 +- .../event/ClusterTopologyChangedEvent.java | 15 +++++++++++++ .../partitions/ClusterPartitionParser.java | 15 +++++++++++++ .../cluster/models/partitions/Partitions.java | 15 +++++++++++++ .../models/partitions/RedisClusterNode.java | 15 +++++++++++++ .../models/partitions/package-info.java | 2 +- .../models/slots/ClusterSlotRange.java | 15 +++++++++++++ .../models/slots/ClusterSlotsParser.java | 15 +++++++++++++ .../cluster/models/slots/package-info.java | 2 +- .../redis/cluster/package-info.java | 2 +- .../topology/ClusterTopologyRefresh.java | 15 +++++++++++++ .../redis/cluster/topology/Connections.java | 15 +++++++++++++ .../topology/NodeConnectionFactory.java | 15 +++++++++++++ .../cluster/topology/NodeTopologyView.java | 15 +++++++++++++ .../cluster/topology/NodeTopologyViews.java | 15 +++++++++++++ .../topology/RedisClusterNodeSnapshot.java | 15 +++++++++++++ .../redis/cluster/topology/Requests.java | 15 +++++++++++++ .../cluster/topology/TimedAsyncCommand.java | 15 +++++++++++++ .../cluster/topology/TopologyComparators.java | 15 +++++++++++++ .../redis/codec/ByteArrayCodec.java | 15 +++++++++++++ .../redis/codec/ByteBufferInputStream.java | 15 +++++++++++++ .../redis/codec/CompressionCodec.java | 15 +++++++++++++ .../lambdaworks/redis/codec/RedisCodec.java | 17 +++++++++++++-- .../lambdaworks/redis/codec/StringCodec.java | 15 +++++++++++++ .../redis/codec/ToByteBufEncoder.java | 15 +++++++++++++ .../redis/codec/Utf8StringCodec.java | 17 +++++++++++++-- .../lambdaworks/redis/codec/package-info.java | 2 +- .../CodecAwareMethodParametersAccessor.java | 15 +++++++++++++ .../dynamic/CommandCreationException.java | 15 +++++++++++++ .../redis/dynamic/CommandFactory.java | 15 +++++++++++++ .../redis/dynamic/CommandMethod.java | 15 +++++++++++++ .../dynamic/CommandMethodSyntaxException.java | 15 +++++++++++++ .../redis/dynamic/CommandMethodVerifier.java | 15 +++++++++++++ .../dynamic/CommandSegmentCommandFactory.java | 15 +++++++++++++ .../DefaultMethodParametersAccessor.java | 15 +++++++++++++ .../dynamic/DefaultRedisCommandsMetadata.java | 15 +++++++++++++ .../redis/dynamic/ParameterBinder.java | 15 +++++++++++++ .../ReactiveCommandSegmentCommandFactory.java | 15 +++++++++++++ .../redis/dynamic/ReactiveWrappers.java | 15 +++++++++++++ .../redis/dynamic/RedisCommandFactory.java | 15 +++++++++++++ .../redis/dynamic/RedisCommandsMetadata.java | 15 +++++++++++++ .../redis/dynamic/annotation/Command.java | 15 +++++++++++++ .../dynamic/annotation/CommandNaming.java | 15 +++++++++++++ .../redis/dynamic/annotation/Key.java | 15 +++++++++++++ .../redis/dynamic/annotation/Param.java | 15 +++++++++++++ .../redis/dynamic/annotation/Value.java | 15 +++++++++++++ .../dynamic/annotation/package-info.java | 2 +- .../codec/AnnotationRedisCodecResolver.java | 15 +++++++++++++ .../dynamic/codec/RedisCodecResolver.java | 15 +++++++++++++ .../redis/dynamic/domain/Timeout.java | 15 +++++++++++++ .../redis/dynamic/domain/package-info.java | 2 +- .../intercept/DefaultMethodInvocation.java | 15 +++++++++++++ .../intercept/InvocationProxyFactory.java | 15 +++++++++++++ .../dynamic/intercept/MethodInterceptor.java | 17 ++++++++++++++- .../dynamic/intercept/MethodInvocation.java | 15 +++++++++++++ .../redis/dynamic/intercept/package-info.java | 2 +- .../CodecAwareOutputFactoryResolver.java | 15 +++++++++++++ .../dynamic/output/CommandOutputFactory.java | 15 +++++++++++++ .../output/CommandOutputFactoryResolver.java | 15 +++++++++++++ .../output/CommandOutputResolverSupport.java | 15 +++++++++++++ .../redis/dynamic/output/OutputRegistry.java | 15 +++++++++++++ ...tRegistryCommandOutputFactoryResolver.java | 15 +++++++++++++ .../redis/dynamic/output/OutputSelector.java | 15 +++++++++++++ .../redis/dynamic/output/OutputType.java | 15 +++++++++++++ .../redis/dynamic/output/VoidOutput.java | 15 +++++++++++++ .../redis/dynamic/output/package-info.java | 2 +- .../redis/dynamic/package-info.java | 2 +- .../ExecutionSpecificParameters.java | 15 +++++++++++++ .../parameter/MethodParametersAccessor.java | 15 +++++++++++++ .../redis/dynamic/parameter/Parameter.java | 15 +++++++++++++ .../redis/dynamic/parameter/Parameters.java | 15 +++++++++++++ .../redis/dynamic/parameter/package-info.java | 2 +- .../AnnotationCommandSegmentFactory.java | 15 +++++++++++++ .../redis/dynamic/segment/CommandSegment.java | 15 +++++++++++++ .../segment/CommandSegmentFactory.java | 15 +++++++++++++ .../dynamic/segment/CommandSegments.java | 15 +++++++++++++ .../redis/dynamic/segment/package-info.java | 2 +- .../AnnotationParameterNameDiscoverer.java | 15 +++++++++++++ .../dynamic/support/ClassTypeInformation.java | 15 +++++++++++++ .../CompositeParameterNameDiscoverer.java | 15 +++++++++++++ .../support/GenericArrayTypeInformation.java | 15 +++++++++++++ .../dynamic/support/GenericTypeResolver.java | 15 +++++++++++++ .../dynamic/support/MethodParameter.java | 15 +++++++++++++ .../support/ParameterNameDiscoverer.java | 15 +++++++++++++ .../support/ParametrizedTypeInformation.java | 15 +++++++++++++ .../ParentTypeAwareTypeInformation.java | 17 ++++++++++++++- .../dynamic/support/ReflectionUtils.java | 15 +++++++++++++ .../redis/dynamic/support/ResolvableType.java | 15 +++++++++++++ ...dardReflectionParameterNameDiscoverer.java | 17 ++++++++++++++- .../redis/dynamic/support/TypeDiscoverer.java | 17 ++++++++++++++- .../dynamic/support/TypeInformation.java | 17 ++++++++++++++- .../support/TypeVariableTypeInformation.java | 15 +++++++++++++ .../redis/dynamic/support/TypeWrapper.java | 15 +++++++++++++ .../redis/dynamic/support/package-info.java | 2 +- .../redis/event/DefaultEventBus.java | 15 +++++++++++++ .../event/DefaultEventPublisherOptions.java | 15 +++++++++++++ .../com/lambdaworks/redis/event/Event.java | 15 +++++++++++++ .../com/lambdaworks/redis/event/EventBus.java | 15 +++++++++++++ .../redis/event/EventPublisherOptions.java | 15 +++++++++++++ .../event/connection/ConnectedEvent.java | 15 +++++++++++++ .../connection/ConnectionActivatedEvent.java | 15 +++++++++++++ .../ConnectionDeactivatedEvent.java | 15 +++++++++++++ .../event/connection/ConnectionEvent.java | 15 +++++++++++++ .../connection/ConnectionEventSupport.java | 15 +++++++++++++ .../event/connection/DisconnectedEvent.java | 15 +++++++++++++ .../event/metrics/CommandLatencyEvent.java | 15 +++++++++++++ .../DefaultCommandLatencyEventPublisher.java | 15 +++++++++++++ .../event/metrics/MetricEventPublisher.java | 15 +++++++++++++ .../internal/AbstractInvocationHandler.java | 15 +++++++++++++ .../redis/internal/HostAndPort.java | 15 +++++++++++++ .../redis/internal/LettuceAssert.java | 15 +++++++++++++ .../redis/internal/LettuceClassUtils.java | 15 +++++++++++++ .../redis/internal/LettuceFactories.java | 15 +++++++++++++ .../redis/internal/LettuceLists.java | 15 +++++++++++++ .../redis/internal/LettuceSets.java | 15 +++++++++++++ .../redis/masterslave/MasterSlave.java | 15 +++++++++++++ .../masterslave/MasterSlaveChannelWriter.java | 15 +++++++++++++ .../MasterSlaveConnectionProvider.java | 15 +++++++++++++ .../MasterSlaveTopologyProvider.java | 15 +++++++++++++ .../MasterSlaveTopologyRefresh.java | 15 +++++++++++++ .../redis/masterslave/MasterSlaveUtils.java | 15 +++++++++++++ .../redis/masterslave/ReadOnlyCommands.java | 15 +++++++++++++ .../masterslave/RedisMasterSlaveNode.java | 15 +++++++++++++ .../masterslave/SentinelTopologyProvider.java | 15 +++++++++++++ .../masterslave/SentinelTopologyRefresh.java | 15 +++++++++++++ .../StatefulRedisMasterSlaveConnection.java | 15 +++++++++++++ ...tatefulRedisMasterSlaveConnectionImpl.java | 15 +++++++++++++ .../StaticMasterSlaveTopologyProvider.java | 15 +++++++++++++ .../redis/masterslave/Timeout.java | 15 +++++++++++++ .../redis/masterslave/TopologyProvider.java | 15 +++++++++++++ .../metrics/CommandLatencyCollector.java | 15 +++++++++++++ .../CommandLatencyCollectorOptions.java | 15 +++++++++++++ .../redis/metrics/CommandLatencyId.java | 15 +++++++++++++ .../redis/metrics/CommandMetrics.java | 15 +++++++++++++ .../DefaultCommandLatencyCollector.java | 15 +++++++++++++ ...DefaultCommandLatencyCollectorOptions.java | 15 +++++++++++++ .../redis/metrics/MetricCollector.java | 15 +++++++++++++ .../redis/models/command/CommandDetail.java | 15 +++++++++++++ .../models/command/CommandDetailParser.java | 15 +++++++++++++ .../redis/models/command/package-info.java | 2 +- .../redis/models/role/RedisInstance.java | 15 +++++++++++++ .../models/role/RedisMasterInstance.java | 15 +++++++++++++ .../models/role/RedisNodeDescription.java | 15 +++++++++++++ .../models/role/RedisSentinelInstance.java | 15 +++++++++++++ .../redis/models/role/RedisSlaveInstance.java | 15 +++++++++++++ .../redis/models/role/ReplicationPartner.java | 15 +++++++++++++ .../redis/models/role/RoleParser.java | 15 +++++++++++++ .../redis/models/role/package-info.java | 2 +- .../lambdaworks/redis/output/ArrayOutput.java | 15 +++++++++++++ .../redis/output/BooleanListOutput.java | 19 ++++++++++++++--- .../redis/output/BooleanOutput.java | 17 +++++++++++++-- .../redis/output/ByteArrayOutput.java | 17 +++++++++++++-- .../redis/output/CommandOutput.java | 19 ++++++++++++++--- .../lambdaworks/redis/output/DateOutput.java | 17 +++++++++++++-- .../output/DefaultTransactionResult.java | 15 +++++++++++++ .../redis/output/DoubleOutput.java | 17 +++++++++++++-- .../output/GeoCoordinatesListOutput.java | 15 +++++++++++++ .../output/GeoCoordinatesValueListOutput.java | 15 +++++++++++++ .../redis/output/GeoWithinListOutput.java | 15 +++++++++++++ .../redis/output/IntegerOutput.java | 17 +++++++++++++-- .../redis/output/KeyListOutput.java | 17 +++++++++++++-- .../lambdaworks/redis/output/KeyOutput.java | 17 +++++++++++++-- .../redis/output/KeyScanOutput.java | 15 +++++++++++++ .../redis/output/KeyScanStreamingOutput.java | 15 +++++++++++++ .../redis/output/KeyStreamingChannel.java | 15 +++++++++++++ .../redis/output/KeyStreamingOutput.java | 15 +++++++++++++ .../redis/output/KeyValueListOutput.java | 15 +++++++++++++ .../redis/output/KeyValueOutput.java | 17 +++++++++++++-- .../output/KeyValueScanStreamingOutput.java | 15 +++++++++++++ .../output/KeyValueStreamingChannel.java | 15 +++++++++++++ .../redis/output/KeyValueStreamingOutput.java | 17 +++++++++++++-- .../redis/output/ListOfMapsOutput.java | 17 +++++++++++++-- .../redis/output/ListSubscriber.java | 15 +++++++++++++ .../lambdaworks/redis/output/MapOutput.java | 17 +++++++++++++-- .../redis/output/MapScanOutput.java | 15 +++++++++++++ .../lambdaworks/redis/output/MultiOutput.java | 17 +++++++++++++-- .../redis/output/NestedMultiOutput.java | 17 +++++++++++++-- .../lambdaworks/redis/output/ScanOutput.java | 15 +++++++++++++ .../redis/output/ScoredValueListOutput.java | 18 +++++++++++++--- .../redis/output/ScoredValueScanOutput.java | 15 +++++++++++++ .../ScoredValueScanStreamingOutput.java | 15 +++++++++++++ .../output/ScoredValueStreamingChannel.java | 15 +++++++++++++ .../output/ScoredValueStreamingOutput.java | 15 +++++++++++++ .../redis/output/StatusOutput.java | 17 +++++++++++++-- .../redis/output/StreamingChannel.java | 15 +++++++++++++ .../redis/output/StreamingOutput.java | 15 +++++++++++++ .../redis/output/StringListOutput.java | 17 +++++++++++++-- .../redis/output/StringValueListOutput.java | 17 +++++++++++++-- .../redis/output/ValueListOutput.java | 17 +++++++++++++-- .../lambdaworks/redis/output/ValueOutput.java | 17 +++++++++++++-- .../redis/output/ValueScanOutput.java | 15 +++++++++++++ .../output/ValueScanStreamingOutput.java | 15 +++++++++++++ .../redis/output/ValueSetOutput.java | 17 +++++++++++++-- .../redis/output/ValueStreamingChannel.java | 15 +++++++++++++ .../redis/output/ValueStreamingOutput.java | 15 +++++++++++++ .../redis/output/ValueValueListOutput.java | 15 +++++++++++++ .../redis/output/package-info.java | 2 +- .../com/lambdaworks/redis/package-info.java | 2 +- .../redis/protocol/AsyncCommand.java | 15 +++++++++++++ .../protocol/BaseRedisCommandBuilder.java | 15 +++++++++++++ .../redis/protocol/ChannelLogDescriptor.java | 15 +++++++++++++ .../lambdaworks/redis/protocol/Command.java | 19 ++++++++++++++--- .../redis/protocol/CommandArgs.java | 17 +++++++++++++-- .../redis/protocol/CommandEncoder.java | 17 +++++++++++++-- .../redis/protocol/CommandHandler.java | 15 +++++++++++++ .../redis/protocol/CommandKeyword.java | 17 +++++++++++++-- .../redis/protocol/CommandType.java | 18 ++++++++++++++-- .../redis/protocol/CommandWrapper.java | 15 +++++++++++++ .../redis/protocol/CompleteableCommand.java | 15 +++++++++++++ .../redis/protocol/ConnectionFacade.java | 15 +++++++++++++ .../redis/protocol/ConnectionWatchdog.java | 17 +++++++++++++-- .../redis/protocol/DecoratedCommand.java | 15 +++++++++++++ .../redis/protocol/DefaultEndpoint.java | 15 +++++++++++++ .../lambdaworks/redis/protocol/Endpoint.java | 15 +++++++++++++ .../redis/protocol/HasQueuedCommands.java | 15 +++++++++++++ .../redis/protocol/LettuceCharsets.java | 17 +++++++++++++-- .../redis/protocol/ProtocolKeyword.java | 15 +++++++++++++ .../redis/protocol/QueuedCommands.java | 15 +++++++++++++ .../redis/protocol/ReconnectionHandler.java | 15 +++++++++++++ .../redis/protocol/ReconnectionListener.java | 15 +++++++++++++ .../redis/protocol/RedisCommand.java | 15 +++++++++++++ .../redis/protocol/RedisStateMachine.java | 17 +++++++++++++-- .../redis/protocol/SharedLock.java | 15 +++++++++++++ .../redis/protocol/TransactionalCommand.java | 15 +++++++++++++ .../redis/protocol/WithLatency.java | 15 +++++++++++++ .../redis/protocol/package-info.java | 2 +- .../redis/pubsub/PubSubCommandArgs.java | 15 +++++++++++++ .../redis/pubsub/PubSubCommandBuilder.java | 15 +++++++++++++ .../redis/pubsub/PubSubCommandHandler.java | 17 +++++++++++++-- .../redis/pubsub/PubSubEndpoint.java | 15 +++++++++++++ .../redis/pubsub/PubSubOutput.java | 17 +++++++++++++-- .../redis/pubsub/RedisPubSubAdapter.java | 17 +++++++++++++-- .../pubsub/RedisPubSubAsyncCommandsImpl.java | 17 +++++++++++++-- .../redis/pubsub/RedisPubSubListener.java | 18 +++++++++++++--- .../RedisPubSubReactiveCommandsImpl.java | 15 +++++++++++++ .../pubsub/StatefulRedisPubSubConnection.java | 15 +++++++++++++ .../StatefulRedisPubSubConnectionImpl.java | 15 +++++++++++++ .../api/async/RedisPubSubAsyncCommands.java | 15 +++++++++++++ .../redis/pubsub/api/async/package-info.java | 2 +- .../pubsub/api/reactive/ChannelMessage.java | 15 +++++++++++++ .../pubsub/api/reactive/PatternMessage.java | 15 +++++++++++++ .../reactive/RedisPubSubReactiveCommands.java | 15 +++++++++++++ .../pubsub/api/reactive/package-info.java | 2 +- .../pubsub/api/sync/RedisPubSubCommands.java | 15 +++++++++++++ .../redis/pubsub/api/sync/package-info.java | 2 +- .../redis/pubsub/package-info.java | 2 +- .../redis/resource/ClientResources.java | 15 +++++++++++++ .../redis/resource/ConstantDelay.java | 15 +++++++++++++ .../resource/DecorrelatedJitterDelay.java | 15 +++++++++++++ .../resource/DefaultClientResources.java | 15 +++++++++++++ .../DefaultEventLoopGroupProvider.java | 15 +++++++++++++ .../com/lambdaworks/redis/resource/Delay.java | 15 +++++++++++++ .../redis/resource/DirContextDnsResolver.java | 15 +++++++++++++ .../redis/resource/DnsResolver.java | 15 +++++++++++++ .../redis/resource/DnsResolvers.java | 15 +++++++++++++ .../redis/resource/EqualJitterDelay.java | 15 +++++++++++++ .../resource/EventLoopGroupProvider.java | 15 +++++++++++++ .../redis/resource/ExponentialDelay.java | 15 +++++++++++++ .../redis/resource/FullJitterDelay.java | 15 +++++++++++++ .../lambdaworks/redis/resource/Futures.java | 15 +++++++++++++ .../redis/resource/SocketAddressResolver.java | 15 +++++++++++++ .../redis/resource/package-info.java | 2 +- .../RedisSentinelAsyncCommandsImpl.java | 15 +++++++++++++ .../RedisSentinelReactiveCommandsImpl.java | 15 +++++++++++++ .../sentinel/SentinelCommandBuilder.java | 15 +++++++++++++ .../StatefulRedisSentinelConnectionImpl.java | 15 +++++++++++++ .../api/StatefulRedisSentinelConnection.java | 15 +++++++++++++ .../api/async/RedisSentinelAsyncCommands.java | 15 +++++++++++++ .../sentinel/api/async/package-info.java | 2 +- .../redis/sentinel/api/package-info.java | 2 +- .../RedisSentinelReactiveCommands.java | 15 +++++++++++++ .../sentinel/api/reactive/package-info.java | 2 +- .../api/sync/RedisSentinelCommands.java | 15 +++++++++++++ .../redis/sentinel/api/sync/package-info.java | 2 +- .../redis/sentinel/package-info.java | 2 +- .../redis/support/AbstractCdiBean.java | 15 +++++++++++++ .../support/ClientResourcesFactoryBean.java | 15 +++++++++++++ .../redis/support/ConnectionPoolSupport.java | 15 +++++++++++++ .../redis/support/LettuceCdiExtension.java | 15 +++++++++++++ .../support/LettuceFactoryBeanSupport.java | 15 +++++++++++++ .../redis/support/RedisClientCdiBean.java | 15 +++++++++++++ .../redis/support/RedisClientFactoryBean.java | 15 +++++++++++++ .../support/RedisClusterClientCdiBean.java | 15 +++++++++++++ .../RedisClusterClientFactoryBean.java | 15 +++++++++++++ .../redis/api/BaseRedisCommands.java | 15 +++++++++++++ .../redis/api/RedisGeoCommands.java | 15 +++++++++++++ .../redis/api/RedisHLLCommands.java | 15 +++++++++++++ .../redis/api/RedisHashCommands.java | 15 +++++++++++++ .../redis/api/RedisKeyCommands.java | 15 +++++++++++++ .../redis/api/RedisListCommands.java | 15 +++++++++++++ .../redis/api/RedisScriptingCommands.java | 15 +++++++++++++ .../redis/api/RedisSentinelCommands.java | 15 +++++++++++++ .../redis/api/RedisServerCommands.java | 15 +++++++++++++ .../redis/api/RedisSetCommands.java | 15 +++++++++++++ .../redis/api/RedisSortedSetCommands.java | 15 +++++++++++++ .../redis/api/RedisStringCommands.java | 15 +++++++++++++ .../redis/api/RedisTransactionalCommands.java | 15 +++++++++++++ .../redis/extensibility/LettuceGeoDemo.java | 15 +++++++++++++ .../extensibility/MyExtendedRedisClient.java | 15 +++++++++++++ .../MyExtendedRedisClientTest.java | 15 +++++++++++++ .../extensibility/MyPubSubConnection.java | 15 +++++++++++++ src/test/java/com/lambdaworks/CanConnect.java | 15 +++++++++++++ .../com/lambdaworks/ConnectionTestUtil.java | 15 +++++++++++++ src/test/java/com/lambdaworks/Delay.java | 15 +++++++++++++ src/test/java/com/lambdaworks/Futures.java | 15 +++++++++++++ .../java/com/lambdaworks/KeysAndValues.java | 15 +++++++++++++ .../java/com/lambdaworks/LoggingTestRule.java | 15 +++++++++++++ src/test/java/com/lambdaworks/Sockets.java | 15 +++++++++++++ src/test/java/com/lambdaworks/SslTest.java | 15 +++++++++++++ .../com/lambdaworks/TestClientResources.java | 15 +++++++++++++ src/test/java/com/lambdaworks/Wait.java | 15 +++++++++++++ .../apigenerator/CompilationUnitFactory.java | 15 +++++++++++++ .../lambdaworks/apigenerator/Constants.java | 15 +++++++++++++ .../apigenerator/CreateAsyncApi.java | 15 +++++++++++++ .../CreateAsyncNodeSelectionClusterApi.java | 15 +++++++++++++ .../apigenerator/CreateReactiveApi.java | 15 +++++++++++++ .../apigenerator/CreateSyncApi.java | 15 +++++++++++++ .../CreateSyncNodeSelectionClusterApi.java | 15 +++++++++++++ .../GenerateCommandInterfaces.java | 15 +++++++++++++ .../com/lambdaworks/category/SlowTests.java | 15 +++++++++++++ .../java/com/lambdaworks/codec/CRC16Test.java | 15 +++++++++++++ .../examples/ConnectToElastiCacheMaster.java | 15 +++++++++++++ ...tToMasterSlaveUsingElastiCacheCluster.java | 15 +++++++++++++ ...onnectToMasterSlaveUsingRedisSentinel.java | 15 +++++++++++++ .../lambdaworks/examples/ConnectToRedis.java | 15 +++++++++++++ .../examples/ConnectToRedisCluster.java | 15 +++++++++++++ .../examples/ConnectToRedisClusterSSL.java | 15 +++++++++++++ ...tToRedisClusterWithTopologyRefreshing.java | 15 +++++++++++++ .../examples/ConnectToRedisSSL.java | 15 +++++++++++++ .../ConnectToRedisUsingRedisSentinel.java | 15 +++++++++++++ .../lambdaworks/examples/MySpringBean.java | 15 +++++++++++++ .../examples/ReadWriteExample.java | 15 +++++++++++++ .../lambdaworks/examples/SpringExample.java | 15 +++++++++++++ .../redis/AbstractRedisClientTest.java | 21 +++++++++++++++++-- .../com/lambdaworks/redis/AbstractTest.java | 15 +++++++++++++ .../com/lambdaworks/redis/AllTheAPIsTest.java | 15 +++++++++++++ .../redis/AsyncConnectionTest.java | 21 +++++++++++++++++-- .../lambdaworks/redis/ClientMetricsTest.java | 15 +++++++++++++ .../lambdaworks/redis/ClientOptionsTest.java | 15 +++++++++++++ .../com/lambdaworks/redis/ClientTest.java | 21 +++++++++++++++++-- .../redis/ConnectionCommandTest.java | 21 +++++++++++++++++-- .../lambdaworks/redis/CustomCodecTest.java | 21 +++++++++++++++++-- .../lambdaworks/redis/DefaultRedisClient.java | 15 +++++++++++++ .../com/lambdaworks/redis/FastShutdown.java | 15 +++++++++++++ .../com/lambdaworks/redis/GeoModelTest.java | 15 +++++++++++++ .../lambdaworks/redis/JavaRuntimeTest.java | 15 +++++++++++++ .../redis/KeyValueStreamingAdapter.java | 15 +++++++++++++ .../com/lambdaworks/redis/KeyValueTest.java | 15 +++++++++++++ .../lambdaworks/redis/LettuceFuturesTest.java | 15 +++++++++++++ .../java/com/lambdaworks/redis/LimitTest.java | 15 +++++++++++++ .../redis/ListStreamingAdapter.java | 15 +++++++++++++ .../com/lambdaworks/redis/PipeliningTest.java | 15 +++++++++++++ .../redis/PrivateAccessorTest.java | 15 +++++++++++++ .../java/com/lambdaworks/redis/RangeTest.java | 15 +++++++++++++ .../redis/ReactiveConnectionTest.java | 15 +++++++++++++ .../redis/ReactiveStreamingOutputTest.java | 15 +++++++++++++ .../redis/RedisClientConnectionTest.java | 15 +++++++++++++ .../redis/RedisClientFactoryBeanTest.java | 15 +++++++++++++ .../redis/RedisClientFactoryTest.java | 15 +++++++++++++ .../lambdaworks/redis/RedisClientTest.java | 15 +++++++++++++ .../redis/RedisURIBuilderTest.java | 15 +++++++++++++ .../com/lambdaworks/redis/RedisURITest.java | 15 +++++++++++++ .../com/lambdaworks/redis/ScanCursorTest.java | 15 +++++++++++++ .../redis/ScoredValueStreamingAdapter.java | 15 +++++++++++++ .../lambdaworks/redis/ScoredValueTest.java | 15 +++++++++++++ .../lambdaworks/redis/SocketOptionsTest.java | 17 ++++++++++++++- .../redis/SyncAsyncApiConvergenceTest.java | 15 +++++++++++++ .../redis/TestEventLoopGroupProvider.java | 15 +++++++++++++ .../lambdaworks/redis/TestRedisPublisher.java | 15 +++++++++++++ .../com/lambdaworks/redis/TestSettings.java | 15 +++++++++++++ .../redis/UnixDomainSocketTest.java | 15 +++++++++++++ .../redis/Utf8StringCodecTest.java | 21 +++++++++++++++++-- .../java/com/lambdaworks/redis/ValueTest.java | 15 +++++++++++++ .../redis/cluster/AbstractClusterTest.java | 15 +++++++++++++ .../cluster/AdvancedClusterClientTest.java | 15 +++++++++++++ .../cluster/AdvancedClusterReactiveTest.java | 15 +++++++++++++ .../redis/cluster/ByteCodecClusterTest.java | 15 +++++++++++++ .../cluster/ClusterClientOptionsTest.java | 15 +++++++++++++ .../cluster/ClusterCommandInternalsTest.java | 15 +++++++++++++ .../redis/cluster/ClusterCommandTest.java | 15 +++++++++++++ .../ClusterDistributionChannelWriterTest.java | 17 ++++++++++++++- .../cluster/ClusterNodeEndpointTest.java | 15 +++++++++++++ .../cluster/ClusterPartiallyDownTest.java | 15 +++++++++++++ .../cluster/ClusterPartitionParserTest.java | 15 +++++++++++++ .../cluster/ClusterReactiveCommandTest.java | 15 +++++++++++++ .../redis/cluster/ClusterRule.java | 15 +++++++++++++ .../redis/cluster/ClusterSetup.java | 15 +++++++++++++ .../redis/cluster/ClusterTestUtil.java | 15 +++++++++++++ .../ClusterTopologyRefreshOptionsTest.java | 17 ++++++++++++++- .../ClusterTopologyRefreshSchedulerTest.java | 15 +++++++++++++ ...ealthyMajorityPartitionsConsensusTest.java | 15 +++++++++++++ .../KnownMajorityPartitionsConsensusTest.java | 15 +++++++++++++ .../redis/cluster/NodeSelectionAsyncTest.java | 15 +++++++++++++ .../redis/cluster/NodeSelectionSyncTest.java | 15 +++++++++++++ .../PartitionsConsensusTestSupport.java | 15 +++++++++++++ .../cluster/PipelinedRedisFutureTest.java | 15 +++++++++++++ .../PooledClusterConnectionProviderTest.java | 17 ++++++++++++++- .../redis/cluster/ReadFromTest.java | 15 +++++++++++++ .../redis/cluster/ReadOnlyCommandsTest.java | 15 +++++++++++++ .../RedisClusterClientFactoryTest.java | 15 +++++++++++++ .../redis/cluster/RedisClusterClientTest.java | 15 +++++++++++++ .../RedisClusterPasswordSecuredSslTest.java | 15 +++++++++++++ .../cluster/RedisClusterReadFromTest.java | 15 +++++++++++++ .../redis/cluster/RedisClusterSetupTest.java | 15 +++++++++++++ .../RedisClusterStressScenariosTest.java | 15 +++++++++++++ .../RedisReactiveClusterClientTest.java | 15 +++++++++++++ .../RoundRobinSocketAddressSupplierTest.java | 15 +++++++++++++ .../redis/cluster/SlotHashTest.java | 15 +++++++++++++ .../commands/CustomClusterCommandTest.java | 15 +++++++++++++ .../commands/GeoClusterCommandTest.java | 15 +++++++++++++ .../commands/HashClusterCommandTest.java | 15 +++++++++++++ .../commands/KeyClusterCommandTest.java | 15 +++++++++++++ .../commands/ListClusterCommandTest.java | 15 +++++++++++++ .../commands/StringClusterCommandTest.java | 15 +++++++++++++ .../HashClusterReactiveCommandTest.java | 15 +++++++++++++ .../KeyClusterReativeCommandTest.java | 15 +++++++++++++ .../ListClusterReactiveCommandTest.java | 15 +++++++++++++ .../StringClusterReactiveCommandTest.java | 15 +++++++++++++ .../models/partitions/PartitionsTest.java | 17 ++++++++++++++- .../partitions/RedisClusterNodeTest.java | 15 +++++++++++++ .../models/slots/ClusterSlotsParserTest.java | 15 +++++++++++++ .../cluster/pubsub/PubSubClusterTest.java | 15 +++++++++++++ .../topology/ClusterTopologyRefreshTest.java | 15 +++++++++++++ .../topology/NodeTopologyViewsTest.java | 17 ++++++++++++++- .../redis/cluster/topology/RequestsTest.java | 17 ++++++++++++++- .../topology/TopologyComparatorsTest.java | 15 +++++++++++++ .../cluster/topology/TopologyRefreshTest.java | 15 +++++++++++++ .../redis/codec/CompressionCodecTest.java | 15 +++++++++++++ .../redis/codec/StringCodecTest.java | 17 ++++++++++++++- .../redis/commands/BitCommandTest.java | 21 +++++++++++++++++-- .../redis/commands/CustomCommandTest.java | 15 +++++++++++++ .../redis/commands/GeoCommandTest.java | 15 +++++++++++++ .../redis/commands/HLLCommandTest.java | 15 +++++++++++++ .../redis/commands/HashCommandTest.java | 21 +++++++++++++++++-- .../redis/commands/KeyCommandTest.java | 21 +++++++++++++++++-- .../redis/commands/ListCommandTest.java | 21 +++++++++++++++++-- .../redis/commands/NumericCommandTest.java | 21 +++++++++++++++++-- .../RunOnlyOnceServerCommandTest.java | 21 +++++++++++++++++-- .../redis/commands/ScriptingCommandTest.java | 21 +++++++++++++++++-- .../redis/commands/ServerCommandTest.java | 21 +++++++++++++++++-- .../redis/commands/SetCommandTest.java | 21 +++++++++++++++++-- .../redis/commands/SortCommandTest.java | 21 +++++++++++++++++-- .../redis/commands/SortedSetCommandTest.java | 21 +++++++++++++++++-- .../redis/commands/StringCommandTest.java | 21 +++++++++++++++++-- .../commands/TransactionCommandTest.java | 21 +++++++++++++++++-- .../reactive/BitReactiveCommandTest.java | 15 +++++++++++++ .../reactive/CustomReactiveCommandTest.java | 15 +++++++++++++ .../reactive/GeoReactiveCommandTest.java | 15 +++++++++++++ .../reactive/HLLReactiveCommandTest.java | 15 +++++++++++++ .../reactive/HashReactiveCommandTest.java | 15 +++++++++++++ .../reactive/KeyReactiveCommandTest.java | 15 +++++++++++++ .../reactive/ListReactiveCommandTest.java | 15 +++++++++++++ .../reactive/NumericReactiveCommandTest.java | 15 +++++++++++++ .../ScriptingReactiveCommandTest.java | 15 +++++++++++++ .../reactive/ServerReactiveCommandTest.java | 15 +++++++++++++ .../reactive/SetReactiveCommandTest.java | 15 +++++++++++++ .../reactive/SortReactiveCommandTest.java | 15 +++++++++++++ .../SortedSetReactiveCommandTest.java | 15 +++++++++++++ .../reactive/StringReactiveCommandTest.java | 15 +++++++++++++ .../TransactionReactiveCommandTest.java | 15 +++++++++++++ .../transactional/BitTxCommandTest.java | 15 +++++++++++++ .../transactional/GeoTxCommandTest.java | 15 +++++++++++++ .../transactional/HLLTxCommandTest.java | 15 +++++++++++++ .../transactional/HashTxCommandTest.java | 15 +++++++++++++ .../transactional/KeyTxCommandTest.java | 15 +++++++++++++ .../transactional/ListTxCommandTest.java | 15 +++++++++++++ .../transactional/SetTxCommandTest.java | 15 +++++++++++++ .../transactional/SortTxCommandTest.java | 15 +++++++++++++ .../transactional/SortedSetTxCommandTest.java | 15 +++++++++++++ .../transactional/StringTxCommandTest.java | 15 +++++++++++++ .../TxSyncInvocationHandler.java | 17 ++++++++++++++- .../redis/dynamic/CommandMethodTest.java | 17 ++++++++++++++- .../dynamic/CommandMethodVerifierTest.java | 15 +++++++++++++ .../CommandSegmentCommandFactoryTest.java | 15 +++++++++++++ .../redis/dynamic/ParameterBinderTest.java | 15 +++++++++++++ ...ctiveCommandSegmentCommandFactoryTest.java | 17 ++++++++++++++- .../redis/dynamic/RedisCommandsTest.java | 15 +++++++++++++ .../AnnotationRedisCodecResolverTest.java | 17 ++++++++++++++- .../intercept/InvocationProxyFactoryTest.java | 17 ++++++++++++++- .../output/CodecAwareOutputResolverTest.java | 17 ++++++++++++++- ...istryCommandOutputFactoryResolverTest.java | 17 ++++++++++++++- .../dynamic/output/OutputRegistryTest.java | 17 ++++++++++++++- .../AnnotationCommandSegmentFactoryTest.java | 17 ++++++++++++++- .../event/ConnectionEventsTriggeredTest.java | 15 +++++++++++++ .../redis/event/DefaultEventBusTest.java | 15 +++++++++++++ .../DefaultEventPublisherOptionsTest.java | 15 +++++++++++++ .../AbstractInvocationHandlerTest.java | 17 ++++++++++++++- .../redis/internal/HostAndPortTest.java | 17 ++++++++++++++- .../masterslave/MasterSlaveSentinelTest.java | 15 +++++++++++++ .../redis/masterslave/MasterSlaveTest.java | 15 +++++++++++++ .../MasterSlaveTopologyProviderTest.java | 15 +++++++++++++ .../masterslave/MasterSlaveUtilsTest.java | 17 ++++++++++++++- .../SentinelTopologyRefreshTest.java | 15 +++++++++++++ .../masterslave/StaticMasterSlaveTest.java | 15 +++++++++++++ .../redis/metrics/CommandLatencyIdTest.java | 15 +++++++++++++ .../DefaultCommandLatencyCollectorTest.java | 15 +++++++++++++ ...ultCommandLatencyCollectorOptionsTest.java | 15 +++++++++++++ .../command/CommandDetailParserTest.java | 15 +++++++++++++ .../redis/models/role/RoleParserTest.java | 15 +++++++++++++ .../redis/output/BooleanListOutputTest.java | 17 ++++++++++++++- .../output/GeoCoordinatesListOutputTest.java | 17 ++++++++++++++- .../GeoCoordinatesValueListOutputTest.java | 17 ++++++++++++++- .../redis/output/GeoWithinListOutputTest.java | 17 ++++++++++++++- .../redis/output/ListOutputTest.java | 17 ++++++++++++++- .../redis/output/NestedMultiOutputTest.java | 17 ++++++++++++++- .../output/ScoredValueListOutputTest.java | 17 ++++++++++++++- .../protocol/AsyncCommandInternalsTest.java | 15 +++++++++++++ .../redis/protocol/CommandArgsTest.java | 17 ++++++++++++++- .../redis/protocol/CommandHandlerTest.java | 15 +++++++++++++ .../redis/protocol/CommandInternalsTest.java | 21 +++++++++++++++++-- .../redis/protocol/ConnectionFailureTest.java | 15 +++++++++++++ .../redis/protocol/DefaultEndpointTest.java | 15 +++++++++++++ .../redis/protocol/StateMachineTest.java | 21 +++++++++++++++++-- .../redis/pubsub/PubSubCommandTest.java | 21 +++++++++++++++++-- .../redis/pubsub/PubSubReactiveTest.java | 15 +++++++++++++ .../reactive/RedisPublisherVerification.java | 17 ++++++++++++++- .../redis/reactive/TestSubscriber.java | 17 ++++++++++++++- .../redis/reliability/AtLeastOnceTest.java | 15 +++++++++++++ .../redis/reliability/AtMostOnceTest.java | 15 +++++++++++++ .../redis/resource/ConstantDelayTest.java | 17 ++++++++++++++- .../resource/DecorrelatedJitterDelayTest.java | 15 +++++++++++++ .../resource/DefaultClientResourcesTest.java | 15 +++++++++++++ .../DefaultEventLoopGroupProviderTest.java | 15 +++++++++++++ .../resource/DirContextDnsResolverTest.java | 15 +++++++++++++ .../redis/resource/EqualJitterDelayTest.java | 15 +++++++++++++ .../redis/resource/ExponentialDelayTest.java | 17 ++++++++++++++- .../redis/resource/FullJitterDelayTest.java | 15 +++++++++++++ .../redis/resource/FuturesTest.java | 15 +++++++++++++ .../redis/sentinel/AbstractSentinelTest.java | 15 +++++++++++++ .../redis/sentinel/SentinelCommandTest.java | 15 +++++++++++++ .../sentinel/SentinelConnectionTest.java | 15 +++++++++++++ .../redis/sentinel/SentinelRule.java | 15 +++++++++++++ .../reactive/SentinelReactiveCommandTest.java | 15 +++++++++++++ .../redis/server/RandomResponseServer.java | 15 +++++++++++++ .../redis/server/RandomServerHandler.java | 17 ++++++++++++++- .../lambdaworks/redis/support/CdiTest.java | 15 +++++++++++++ .../support/ConnectionPoolSupportTest.java | 17 ++++++++++++++- .../redis/support/InjectedClient.java | 15 +++++++++++++ .../lambdaworks/redis/support/PersonDB.java | 15 +++++++++++++ .../RedisClusterClientFactoryBeanTest.java | 15 +++++++++++++ .../lambdaworks/redis/support/SpringTest.java | 15 +++++++++++++ ...ConnectionDecoratingInvocationHandler.java | 15 +++++++++++++ .../util/ReactiveSyncInvocationHandler.java | 17 ++++++++++++++- .../util/RoutingInvocationHandler.java | 15 +++++++++++++ .../cluster/EmptyRedisChannelWriter.java | 15 +++++++++++++ .../cluster/EmptyRedisClusterClient.java | 15 +++++++++++++ .../cluster/EmptyStatefulRedisConnection.java | 15 +++++++++++++ .../com/lambdaworks/redis/codec/JmhMain.java | 15 +++++++++++++ .../redis/codec/StringCodecBenchmark.java | 15 +++++++++++++ .../redis/codec/Utf8StringCodecBenchmark.java | 15 +++++++++++++ .../redis/protocol/CommandBenchmark.java | 15 +++++++++++++ .../protocol/CommandHandlerBenchmark.java | 15 +++++++++++++ .../redis/protocol/EmptyByteBuf.java | 15 +++++++++++++ .../redis/protocol/EmptyClientResources.java | 15 +++++++++++++ .../redis/protocol/EmptyContext.java | 15 +++++++++++++ .../redis/protocol/EmptyFuture.java | 15 +++++++++++++ .../redis/protocol/EmptyPromise.java | 15 +++++++++++++ .../lambdaworks/redis/protocol/JmhMain.java | 15 +++++++++++++ .../protocol/RedisEndpointBenchmark.java | 15 +++++++++++++ .../protocol/RedisStateMachineBenchmark.java | 15 +++++++++++++ 748 files changed, 10855 insertions(+), 229 deletions(-) diff --git a/src/main/java/com/lambdaworks/codec/Base16.java b/src/main/java/com/lambdaworks/codec/Base16.java index f7d606fbf2..39dce556d3 100644 --- a/src/main/java/com/lambdaworks/codec/Base16.java +++ b/src/main/java/com/lambdaworks/codec/Base16.java @@ -1,5 +1,18 @@ -// Copyright (C) 2011 - Will Glozer. All rights reserved. - +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.codec; /** diff --git a/src/main/java/com/lambdaworks/codec/CRC16.java b/src/main/java/com/lambdaworks/codec/CRC16.java index ff5fb4e880..219105a5f5 100644 --- a/src/main/java/com/lambdaworks/codec/CRC16.java +++ b/src/main/java/com/lambdaworks/codec/CRC16.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.codec; /** diff --git a/src/main/java/com/lambdaworks/codec/package-info.java b/src/main/java/com/lambdaworks/codec/package-info.java index d1646d9b5f..c48584f769 100644 --- a/src/main/java/com/lambdaworks/codec/package-info.java +++ b/src/main/java/com/lambdaworks/codec/package-info.java @@ -1,4 +1,4 @@ /** * Base16 and CRC16 codecs. */ -package com.lambdaworks.codec; \ No newline at end of file +package com.lambdaworks.codec; diff --git a/src/main/java/com/lambdaworks/redis/AbstractRedisAsyncCommands.java b/src/main/java/com/lambdaworks/redis/AbstractRedisAsyncCommands.java index 81bdb80876..e7aa3d9a4c 100644 --- a/src/main/java/com/lambdaworks/redis/AbstractRedisAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/AbstractRedisAsyncCommands.java @@ -1,5 +1,18 @@ -// Copyright (C) 2011 - Will Glozer. All rights reserved. - +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import static com.lambdaworks.redis.protocol.CommandType.EXEC; diff --git a/src/main/java/com/lambdaworks/redis/AbstractRedisClient.java b/src/main/java/com/lambdaworks/redis/AbstractRedisClient.java index 99596458c0..3d7ac014c7 100644 --- a/src/main/java/com/lambdaworks/redis/AbstractRedisClient.java +++ b/src/main/java/com/lambdaworks/redis/AbstractRedisClient.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import java.io.Closeable; diff --git a/src/main/java/com/lambdaworks/redis/AbstractRedisReactiveCommands.java b/src/main/java/com/lambdaworks/redis/AbstractRedisReactiveCommands.java index 99dd0fff10..7bff4ee261 100644 --- a/src/main/java/com/lambdaworks/redis/AbstractRedisReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/AbstractRedisReactiveCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import static com.lambdaworks.redis.protocol.CommandType.EXEC; diff --git a/src/main/java/com/lambdaworks/redis/BackpressureUtils.java b/src/main/java/com/lambdaworks/redis/BackpressureUtils.java index df1a872817..227879d205 100644 --- a/src/main/java/com/lambdaworks/redis/BackpressureUtils.java +++ b/src/main/java/com/lambdaworks/redis/BackpressureUtils.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import java.util.concurrent.atomic.AtomicLong; @@ -39,4 +54,4 @@ public static long getAndSub(AtomicLong sequence, long toSub) { return r; } -} \ No newline at end of file +} diff --git a/src/main/java/com/lambdaworks/redis/BitFieldArgs.java b/src/main/java/com/lambdaworks/redis/BitFieldArgs.java index 82ec346ccd..3c1b22d2b2 100644 --- a/src/main/java/com/lambdaworks/redis/BitFieldArgs.java +++ b/src/main/java/com/lambdaworks/redis/BitFieldArgs.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import java.util.ArrayList; diff --git a/src/main/java/com/lambdaworks/redis/ChannelGroupListener.java b/src/main/java/com/lambdaworks/redis/ChannelGroupListener.java index 167301a463..c2e67e9837 100644 --- a/src/main/java/com/lambdaworks/redis/ChannelGroupListener.java +++ b/src/main/java/com/lambdaworks/redis/ChannelGroupListener.java @@ -1,5 +1,18 @@ -// Copyright (C) 2011 - Will Glozer. All rights reserved. - +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import io.netty.channel.ChannelHandler; diff --git a/src/main/java/com/lambdaworks/redis/ClientOptions.java b/src/main/java/com/lambdaworks/redis/ClientOptions.java index bd9f162f39..9a685c065c 100644 --- a/src/main/java/com/lambdaworks/redis/ClientOptions.java +++ b/src/main/java/com/lambdaworks/redis/ClientOptions.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import java.io.Serializable; diff --git a/src/main/java/com/lambdaworks/redis/CloseEvents.java b/src/main/java/com/lambdaworks/redis/CloseEvents.java index 0be034dfcd..2cd4b28498 100644 --- a/src/main/java/com/lambdaworks/redis/CloseEvents.java +++ b/src/main/java/com/lambdaworks/redis/CloseEvents.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import java.util.Set; diff --git a/src/main/java/com/lambdaworks/redis/CompositeArgument.java b/src/main/java/com/lambdaworks/redis/CompositeArgument.java index 8864b65164..d7f2811e59 100644 --- a/src/main/java/com/lambdaworks/redis/CompositeArgument.java +++ b/src/main/java/com/lambdaworks/redis/CompositeArgument.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import com.lambdaworks.redis.protocol.CommandArgs; diff --git a/src/main/java/com/lambdaworks/redis/ConnectionBuilder.java b/src/main/java/com/lambdaworks/redis/ConnectionBuilder.java index 2f6995d25a..767f6fd45f 100644 --- a/src/main/java/com/lambdaworks/redis/ConnectionBuilder.java +++ b/src/main/java/com/lambdaworks/redis/ConnectionBuilder.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import java.net.SocketAddress; diff --git a/src/main/java/com/lambdaworks/redis/ConnectionEventTrigger.java b/src/main/java/com/lambdaworks/redis/ConnectionEventTrigger.java index 1810554d85..2178838e16 100644 --- a/src/main/java/com/lambdaworks/redis/ConnectionEventTrigger.java +++ b/src/main/java/com/lambdaworks/redis/ConnectionEventTrigger.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import java.net.SocketAddress; diff --git a/src/main/java/com/lambdaworks/redis/ConnectionEvents.java b/src/main/java/com/lambdaworks/redis/ConnectionEvents.java index e0309b8b26..64bd6839bb 100644 --- a/src/main/java/com/lambdaworks/redis/ConnectionEvents.java +++ b/src/main/java/com/lambdaworks/redis/ConnectionEvents.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import java.util.Set; diff --git a/src/main/java/com/lambdaworks/redis/ConnectionId.java b/src/main/java/com/lambdaworks/redis/ConnectionId.java index c69da6b514..bb14cd6383 100644 --- a/src/main/java/com/lambdaworks/redis/ConnectionId.java +++ b/src/main/java/com/lambdaworks/redis/ConnectionId.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import java.net.SocketAddress; diff --git a/src/main/java/com/lambdaworks/redis/ConnectionPoint.java b/src/main/java/com/lambdaworks/redis/ConnectionPoint.java index 3d033d181f..832fb4e8fe 100644 --- a/src/main/java/com/lambdaworks/redis/ConnectionPoint.java +++ b/src/main/java/com/lambdaworks/redis/ConnectionPoint.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; /** diff --git a/src/main/java/com/lambdaworks/redis/EpollProvider.java b/src/main/java/com/lambdaworks/redis/EpollProvider.java index b8323666e8..53a4609e3a 100644 --- a/src/main/java/com/lambdaworks/redis/EpollProvider.java +++ b/src/main/java/com/lambdaworks/redis/EpollProvider.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import java.lang.reflect.Constructor; diff --git a/src/main/java/com/lambdaworks/redis/FutureSyncInvocationHandler.java b/src/main/java/com/lambdaworks/redis/FutureSyncInvocationHandler.java index db0091d129..10d8600aea 100644 --- a/src/main/java/com/lambdaworks/redis/FutureSyncInvocationHandler.java +++ b/src/main/java/com/lambdaworks/redis/FutureSyncInvocationHandler.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import java.lang.reflect.InvocationTargetException; diff --git a/src/main/java/com/lambdaworks/redis/GeoArgs.java b/src/main/java/com/lambdaworks/redis/GeoArgs.java index 2780ea6a64..1363207ac3 100644 --- a/src/main/java/com/lambdaworks/redis/GeoArgs.java +++ b/src/main/java/com/lambdaworks/redis/GeoArgs.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import com.lambdaworks.redis.internal.LettuceAssert; diff --git a/src/main/java/com/lambdaworks/redis/GeoCoordinates.java b/src/main/java/com/lambdaworks/redis/GeoCoordinates.java index 6c600a9f25..8fcb4a5061 100644 --- a/src/main/java/com/lambdaworks/redis/GeoCoordinates.java +++ b/src/main/java/com/lambdaworks/redis/GeoCoordinates.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import com.lambdaworks.redis.internal.LettuceAssert; diff --git a/src/main/java/com/lambdaworks/redis/GeoRadiusStoreArgs.java b/src/main/java/com/lambdaworks/redis/GeoRadiusStoreArgs.java index 65ba799269..9f959a4099 100644 --- a/src/main/java/com/lambdaworks/redis/GeoRadiusStoreArgs.java +++ b/src/main/java/com/lambdaworks/redis/GeoRadiusStoreArgs.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import com.lambdaworks.redis.GeoArgs.Sort; diff --git a/src/main/java/com/lambdaworks/redis/GeoWithin.java b/src/main/java/com/lambdaworks/redis/GeoWithin.java index a17b9359b5..5029c91c94 100644 --- a/src/main/java/com/lambdaworks/redis/GeoWithin.java +++ b/src/main/java/com/lambdaworks/redis/GeoWithin.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; /** diff --git a/src/main/java/com/lambdaworks/redis/JavaRuntime.java b/src/main/java/com/lambdaworks/redis/JavaRuntime.java index ed8ee58eb7..a8e19d2aa1 100644 --- a/src/main/java/com/lambdaworks/redis/JavaRuntime.java +++ b/src/main/java/com/lambdaworks/redis/JavaRuntime.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import static com.lambdaworks.redis.internal.LettuceClassUtils.isPresent; diff --git a/src/main/java/com/lambdaworks/redis/KeyScanCursor.java b/src/main/java/com/lambdaworks/redis/KeyScanCursor.java index 0618273719..b668145aaf 100644 --- a/src/main/java/com/lambdaworks/redis/KeyScanCursor.java +++ b/src/main/java/com/lambdaworks/redis/KeyScanCursor.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import java.util.ArrayList; diff --git a/src/main/java/com/lambdaworks/redis/KeyValue.java b/src/main/java/com/lambdaworks/redis/KeyValue.java index 9e79063076..f3cc4e4470 100644 --- a/src/main/java/com/lambdaworks/redis/KeyValue.java +++ b/src/main/java/com/lambdaworks/redis/KeyValue.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import java.util.Optional; diff --git a/src/main/java/com/lambdaworks/redis/KillArgs.java b/src/main/java/com/lambdaworks/redis/KillArgs.java index 1ecd269e74..8de347a246 100644 --- a/src/main/java/com/lambdaworks/redis/KillArgs.java +++ b/src/main/java/com/lambdaworks/redis/KillArgs.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import static com.lambdaworks.redis.protocol.CommandKeyword.*; diff --git a/src/main/java/com/lambdaworks/redis/LettuceFutures.java b/src/main/java/com/lambdaworks/redis/LettuceFutures.java index a85a5cd3bd..93280ad30c 100644 --- a/src/main/java/com/lambdaworks/redis/LettuceFutures.java +++ b/src/main/java/com/lambdaworks/redis/LettuceFutures.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import java.util.concurrent.ExecutionException; diff --git a/src/main/java/com/lambdaworks/redis/LettuceStrings.java b/src/main/java/com/lambdaworks/redis/LettuceStrings.java index 283cf9811e..6a9c668157 100644 --- a/src/main/java/com/lambdaworks/redis/LettuceStrings.java +++ b/src/main/java/com/lambdaworks/redis/LettuceStrings.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import java.nio.ByteBuffer; diff --git a/src/main/java/com/lambdaworks/redis/Limit.java b/src/main/java/com/lambdaworks/redis/Limit.java index 87042362a0..d6c6193a47 100644 --- a/src/main/java/com/lambdaworks/redis/Limit.java +++ b/src/main/java/com/lambdaworks/redis/Limit.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; /** diff --git a/src/main/java/com/lambdaworks/redis/MapScanCursor.java b/src/main/java/com/lambdaworks/redis/MapScanCursor.java index 020dc818cf..a2b96b02fe 100644 --- a/src/main/java/com/lambdaworks/redis/MapScanCursor.java +++ b/src/main/java/com/lambdaworks/redis/MapScanCursor.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import java.util.LinkedHashMap; diff --git a/src/main/java/com/lambdaworks/redis/MigrateArgs.java b/src/main/java/com/lambdaworks/redis/MigrateArgs.java index f9d9b914c9..c8b5f6b660 100644 --- a/src/main/java/com/lambdaworks/redis/MigrateArgs.java +++ b/src/main/java/com/lambdaworks/redis/MigrateArgs.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import java.util.ArrayList; diff --git a/src/main/java/com/lambdaworks/redis/PlainChannelInitializer.java b/src/main/java/com/lambdaworks/redis/PlainChannelInitializer.java index 83131cbf2a..5e9ee9d79e 100644 --- a/src/main/java/com/lambdaworks/redis/PlainChannelInitializer.java +++ b/src/main/java/com/lambdaworks/redis/PlainChannelInitializer.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import static com.lambdaworks.redis.ConnectionEventTrigger.local; diff --git a/src/main/java/com/lambdaworks/redis/Range.java b/src/main/java/com/lambdaworks/redis/Range.java index 765c8a3cbd..1e8c1bdeb5 100644 --- a/src/main/java/com/lambdaworks/redis/Range.java +++ b/src/main/java/com/lambdaworks/redis/Range.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import com.lambdaworks.redis.internal.LettuceAssert; diff --git a/src/main/java/com/lambdaworks/redis/ReadFrom.java b/src/main/java/com/lambdaworks/redis/ReadFrom.java index c727c18a78..2781ca412d 100644 --- a/src/main/java/com/lambdaworks/redis/ReadFrom.java +++ b/src/main/java/com/lambdaworks/redis/ReadFrom.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import java.util.List; diff --git a/src/main/java/com/lambdaworks/redis/ReadFromImpl.java b/src/main/java/com/lambdaworks/redis/ReadFromImpl.java index ec45fae1b1..2aac8034ca 100644 --- a/src/main/java/com/lambdaworks/redis/ReadFromImpl.java +++ b/src/main/java/com/lambdaworks/redis/ReadFromImpl.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import java.util.ArrayList; diff --git a/src/main/java/com/lambdaworks/redis/RedisAsyncCommandsImpl.java b/src/main/java/com/lambdaworks/redis/RedisAsyncCommandsImpl.java index 41c17da718..71284ba949 100644 --- a/src/main/java/com/lambdaworks/redis/RedisAsyncCommandsImpl.java +++ b/src/main/java/com/lambdaworks/redis/RedisAsyncCommandsImpl.java @@ -1,5 +1,18 @@ -// Copyright (C) 2011 - Will Glozer. All rights reserved. - +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import com.lambdaworks.redis.api.StatefulRedisConnection; diff --git a/src/main/java/com/lambdaworks/redis/RedisChannelHandler.java b/src/main/java/com/lambdaworks/redis/RedisChannelHandler.java index f7b2e4c284..36aeb33951 100644 --- a/src/main/java/com/lambdaworks/redis/RedisChannelHandler.java +++ b/src/main/java/com/lambdaworks/redis/RedisChannelHandler.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import java.io.Closeable; diff --git a/src/main/java/com/lambdaworks/redis/RedisChannelInitializer.java b/src/main/java/com/lambdaworks/redis/RedisChannelInitializer.java index e4674d41ef..4614df5550 100644 --- a/src/main/java/com/lambdaworks/redis/RedisChannelInitializer.java +++ b/src/main/java/com/lambdaworks/redis/RedisChannelInitializer.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import java.util.concurrent.Future; diff --git a/src/main/java/com/lambdaworks/redis/RedisChannelInitializerImpl.java b/src/main/java/com/lambdaworks/redis/RedisChannelInitializerImpl.java index 66a7a51601..54143abbf1 100644 --- a/src/main/java/com/lambdaworks/redis/RedisChannelInitializerImpl.java +++ b/src/main/java/com/lambdaworks/redis/RedisChannelInitializerImpl.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import io.netty.channel.ChannelDuplexHandler; diff --git a/src/main/java/com/lambdaworks/redis/RedisChannelWriter.java b/src/main/java/com/lambdaworks/redis/RedisChannelWriter.java index e9ff98b6c8..231eed05a7 100644 --- a/src/main/java/com/lambdaworks/redis/RedisChannelWriter.java +++ b/src/main/java/com/lambdaworks/redis/RedisChannelWriter.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import java.io.Closeable; diff --git a/src/main/java/com/lambdaworks/redis/RedisClient.java b/src/main/java/com/lambdaworks/redis/RedisClient.java index c90d311f2c..591fd723d5 100644 --- a/src/main/java/com/lambdaworks/redis/RedisClient.java +++ b/src/main/java/com/lambdaworks/redis/RedisClient.java @@ -1,5 +1,18 @@ -// Copyright (C) 2011 - Will Glozer. All rights reserved. - +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import static com.lambdaworks.redis.LettuceStrings.isEmpty; diff --git a/src/main/java/com/lambdaworks/redis/RedisCommandBuilder.java b/src/main/java/com/lambdaworks/redis/RedisCommandBuilder.java index e6b43901ab..71878ab8df 100644 --- a/src/main/java/com/lambdaworks/redis/RedisCommandBuilder.java +++ b/src/main/java/com/lambdaworks/redis/RedisCommandBuilder.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import static com.lambdaworks.redis.LettuceStrings.string; diff --git a/src/main/java/com/lambdaworks/redis/RedisCommandExecutionException.java b/src/main/java/com/lambdaworks/redis/RedisCommandExecutionException.java index 7b40d72542..854f5defd0 100644 --- a/src/main/java/com/lambdaworks/redis/RedisCommandExecutionException.java +++ b/src/main/java/com/lambdaworks/redis/RedisCommandExecutionException.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; /** diff --git a/src/main/java/com/lambdaworks/redis/RedisCommandInterruptedException.java b/src/main/java/com/lambdaworks/redis/RedisCommandInterruptedException.java index 2cfb344276..3c6d9cfe35 100644 --- a/src/main/java/com/lambdaworks/redis/RedisCommandInterruptedException.java +++ b/src/main/java/com/lambdaworks/redis/RedisCommandInterruptedException.java @@ -1,5 +1,18 @@ -// Copyright (C) 2011 - Will Glozer. All rights reserved. - +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; /** diff --git a/src/main/java/com/lambdaworks/redis/RedisCommandTimeoutException.java b/src/main/java/com/lambdaworks/redis/RedisCommandTimeoutException.java index 904140d0e4..57c8d4ea1e 100644 --- a/src/main/java/com/lambdaworks/redis/RedisCommandTimeoutException.java +++ b/src/main/java/com/lambdaworks/redis/RedisCommandTimeoutException.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; /** diff --git a/src/main/java/com/lambdaworks/redis/RedisConnectionException.java b/src/main/java/com/lambdaworks/redis/RedisConnectionException.java index 36181cd8b4..ba94c81453 100644 --- a/src/main/java/com/lambdaworks/redis/RedisConnectionException.java +++ b/src/main/java/com/lambdaworks/redis/RedisConnectionException.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; /** diff --git a/src/main/java/com/lambdaworks/redis/RedisConnectionStateListener.java b/src/main/java/com/lambdaworks/redis/RedisConnectionStateListener.java index 66662c9add..9c1f199ee3 100644 --- a/src/main/java/com/lambdaworks/redis/RedisConnectionStateListener.java +++ b/src/main/java/com/lambdaworks/redis/RedisConnectionStateListener.java @@ -1,4 +1,18 @@ -// Copyright (C) 2013 - ze. All rights reserved. +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; /** @@ -31,4 +45,4 @@ public interface RedisConnectionStateListener { * @param cause Caught exception. */ void onRedisExceptionCaught(RedisChannelHandler connection, Throwable cause); -} \ No newline at end of file +} diff --git a/src/main/java/com/lambdaworks/redis/RedisException.java b/src/main/java/com/lambdaworks/redis/RedisException.java index 5400e50426..8eeedf3337 100644 --- a/src/main/java/com/lambdaworks/redis/RedisException.java +++ b/src/main/java/com/lambdaworks/redis/RedisException.java @@ -1,5 +1,18 @@ -// Copyright (C) 2011 - Will Glozer. All rights reserved. - +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; /** diff --git a/src/main/java/com/lambdaworks/redis/RedisFuture.java b/src/main/java/com/lambdaworks/redis/RedisFuture.java index cae755b022..0b7129582f 100644 --- a/src/main/java/com/lambdaworks/redis/RedisFuture.java +++ b/src/main/java/com/lambdaworks/redis/RedisFuture.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import java.util.concurrent.CompletionStage; diff --git a/src/main/java/com/lambdaworks/redis/RedisPublisher.java b/src/main/java/com/lambdaworks/redis/RedisPublisher.java index 9f25888566..c78cd2fa11 100644 --- a/src/main/java/com/lambdaworks/redis/RedisPublisher.java +++ b/src/main/java/com/lambdaworks/redis/RedisPublisher.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import java.io.IOException; diff --git a/src/main/java/com/lambdaworks/redis/RedisReactiveCommandsImpl.java b/src/main/java/com/lambdaworks/redis/RedisReactiveCommandsImpl.java index 08f9e1e394..4e7d7888a5 100644 --- a/src/main/java/com/lambdaworks/redis/RedisReactiveCommandsImpl.java +++ b/src/main/java/com/lambdaworks/redis/RedisReactiveCommandsImpl.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import com.lambdaworks.redis.api.StatefulRedisConnection; diff --git a/src/main/java/com/lambdaworks/redis/RedisURI.java b/src/main/java/com/lambdaworks/redis/RedisURI.java index 68993ce9f3..7461c0ffa3 100644 --- a/src/main/java/com/lambdaworks/redis/RedisURI.java +++ b/src/main/java/com/lambdaworks/redis/RedisURI.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import static com.lambdaworks.redis.LettuceStrings.isEmpty; diff --git a/src/main/java/com/lambdaworks/redis/ScanArgs.java b/src/main/java/com/lambdaworks/redis/ScanArgs.java index 375684bca4..625886517d 100644 --- a/src/main/java/com/lambdaworks/redis/ScanArgs.java +++ b/src/main/java/com/lambdaworks/redis/ScanArgs.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import static com.lambdaworks.redis.protocol.CommandKeyword.COUNT; diff --git a/src/main/java/com/lambdaworks/redis/ScanCursor.java b/src/main/java/com/lambdaworks/redis/ScanCursor.java index 297f8d2ad7..7ce6f744d5 100644 --- a/src/main/java/com/lambdaworks/redis/ScanCursor.java +++ b/src/main/java/com/lambdaworks/redis/ScanCursor.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import com.lambdaworks.redis.internal.LettuceAssert; diff --git a/src/main/java/com/lambdaworks/redis/ScoredValue.java b/src/main/java/com/lambdaworks/redis/ScoredValue.java index c288da7ba3..b18dfd0248 100644 --- a/src/main/java/com/lambdaworks/redis/ScoredValue.java +++ b/src/main/java/com/lambdaworks/redis/ScoredValue.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import java.util.Optional; diff --git a/src/main/java/com/lambdaworks/redis/ScoredValueScanCursor.java b/src/main/java/com/lambdaworks/redis/ScoredValueScanCursor.java index 6cddadfe19..d34e139f6d 100644 --- a/src/main/java/com/lambdaworks/redis/ScoredValueScanCursor.java +++ b/src/main/java/com/lambdaworks/redis/ScoredValueScanCursor.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import java.util.ArrayList; diff --git a/src/main/java/com/lambdaworks/redis/ScriptOutputType.java b/src/main/java/com/lambdaworks/redis/ScriptOutputType.java index 61984e799b..0de83d291d 100644 --- a/src/main/java/com/lambdaworks/redis/ScriptOutputType.java +++ b/src/main/java/com/lambdaworks/redis/ScriptOutputType.java @@ -1,5 +1,18 @@ -// Copyright (C) 2011 - Will Glozer. All rights reserved. - +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; /** diff --git a/src/main/java/com/lambdaworks/redis/SetArgs.java b/src/main/java/com/lambdaworks/redis/SetArgs.java index 2c3f37c92e..46792705d7 100644 --- a/src/main/java/com/lambdaworks/redis/SetArgs.java +++ b/src/main/java/com/lambdaworks/redis/SetArgs.java @@ -1,6 +1,18 @@ -// Copyright (C) 2011 - Will Glozer. All rights reserved. -// Copyright (C) 2013 - Vincent Rischmann. All rights reserved. - +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import com.lambdaworks.redis.protocol.CommandArgs; @@ -9,6 +21,7 @@ * Argument list builder for the new redis SET command starting from Redis 2.6.12. * Static import the methods from {@link Builder} and chain the method calls: {@code ex(10).nx()}. * + * @author Will Glozer * @author Vincent Rischmann */ public class SetArgs implements CompositeArgument { diff --git a/src/main/java/com/lambdaworks/redis/SocketOptions.java b/src/main/java/com/lambdaworks/redis/SocketOptions.java index bf1b1ba266..dc60be33b0 100644 --- a/src/main/java/com/lambdaworks/redis/SocketOptions.java +++ b/src/main/java/com/lambdaworks/redis/SocketOptions.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import java.util.concurrent.TimeUnit; diff --git a/src/main/java/com/lambdaworks/redis/SortArgs.java b/src/main/java/com/lambdaworks/redis/SortArgs.java index 87c4b53aef..fc009c5814 100644 --- a/src/main/java/com/lambdaworks/redis/SortArgs.java +++ b/src/main/java/com/lambdaworks/redis/SortArgs.java @@ -1,5 +1,18 @@ -// Copyright (C) 2011 - Will Glozer. All rights reserved. - +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import static com.lambdaworks.redis.protocol.CommandKeyword.*; diff --git a/src/main/java/com/lambdaworks/redis/SslConnectionBuilder.java b/src/main/java/com/lambdaworks/redis/SslConnectionBuilder.java index 3cbf7bbb10..96e2184c1a 100644 --- a/src/main/java/com/lambdaworks/redis/SslConnectionBuilder.java +++ b/src/main/java/com/lambdaworks/redis/SslConnectionBuilder.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import static com.lambdaworks.redis.ConnectionEventTrigger.local; diff --git a/src/main/java/com/lambdaworks/redis/SslOptions.java b/src/main/java/com/lambdaworks/redis/SslOptions.java index d665f23a03..e09ae13e33 100644 --- a/src/main/java/com/lambdaworks/redis/SslOptions.java +++ b/src/main/java/com/lambdaworks/redis/SslOptions.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import java.io.File; diff --git a/src/main/java/com/lambdaworks/redis/StatefulRedisConnectionImpl.java b/src/main/java/com/lambdaworks/redis/StatefulRedisConnectionImpl.java index 1db6921758..8ce815ca42 100644 --- a/src/main/java/com/lambdaworks/redis/StatefulRedisConnectionImpl.java +++ b/src/main/java/com/lambdaworks/redis/StatefulRedisConnectionImpl.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import static com.lambdaworks.redis.protocol.CommandType.AUTH; diff --git a/src/main/java/com/lambdaworks/redis/StreamScanCursor.java b/src/main/java/com/lambdaworks/redis/StreamScanCursor.java index e3554dbe65..06e9258391 100644 --- a/src/main/java/com/lambdaworks/redis/StreamScanCursor.java +++ b/src/main/java/com/lambdaworks/redis/StreamScanCursor.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; /** diff --git a/src/main/java/com/lambdaworks/redis/TransactionResult.java b/src/main/java/com/lambdaworks/redis/TransactionResult.java index e4103d4d0e..ebc27b6d84 100644 --- a/src/main/java/com/lambdaworks/redis/TransactionResult.java +++ b/src/main/java/com/lambdaworks/redis/TransactionResult.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import java.util.List; diff --git a/src/main/java/com/lambdaworks/redis/Value.java b/src/main/java/com/lambdaworks/redis/Value.java index 61c871bdd5..0c249e2680 100644 --- a/src/main/java/com/lambdaworks/redis/Value.java +++ b/src/main/java/com/lambdaworks/redis/Value.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import java.io.Serializable; diff --git a/src/main/java/com/lambdaworks/redis/ValueScanCursor.java b/src/main/java/com/lambdaworks/redis/ValueScanCursor.java index 090f4db29c..4ce4fc16ba 100644 --- a/src/main/java/com/lambdaworks/redis/ValueScanCursor.java +++ b/src/main/java/com/lambdaworks/redis/ValueScanCursor.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import java.util.ArrayList; diff --git a/src/main/java/com/lambdaworks/redis/ZAddArgs.java b/src/main/java/com/lambdaworks/redis/ZAddArgs.java index f9ca95b348..2137fcd3f1 100644 --- a/src/main/java/com/lambdaworks/redis/ZAddArgs.java +++ b/src/main/java/com/lambdaworks/redis/ZAddArgs.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import com.lambdaworks.redis.protocol.CommandArgs; diff --git a/src/main/java/com/lambdaworks/redis/ZStoreArgs.java b/src/main/java/com/lambdaworks/redis/ZStoreArgs.java index 6be16621da..b0819c5d11 100644 --- a/src/main/java/com/lambdaworks/redis/ZStoreArgs.java +++ b/src/main/java/com/lambdaworks/redis/ZStoreArgs.java @@ -1,5 +1,18 @@ -// Copyright (C) 2011 - Will Glozer. All rights reserved. - +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import static com.lambdaworks.redis.protocol.CommandKeyword.*; diff --git a/src/main/java/com/lambdaworks/redis/api/StatefulConnection.java b/src/main/java/com/lambdaworks/redis/api/StatefulConnection.java index 02c3c01c2a..924a585e6a 100644 --- a/src/main/java/com/lambdaworks/redis/api/StatefulConnection.java +++ b/src/main/java/com/lambdaworks/redis/api/StatefulConnection.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.api; import java.util.concurrent.TimeUnit; diff --git a/src/main/java/com/lambdaworks/redis/api/StatefulRedisConnection.java b/src/main/java/com/lambdaworks/redis/api/StatefulRedisConnection.java index 94cbdeb24a..d0761e46c8 100644 --- a/src/main/java/com/lambdaworks/redis/api/StatefulRedisConnection.java +++ b/src/main/java/com/lambdaworks/redis/api/StatefulRedisConnection.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.api; import com.lambdaworks.redis.api.async.RedisAsyncCommands; diff --git a/src/main/java/com/lambdaworks/redis/api/async/BaseRedisAsyncCommands.java b/src/main/java/com/lambdaworks/redis/api/async/BaseRedisAsyncCommands.java index eecb1630d4..6386425395 100644 --- a/src/main/java/com/lambdaworks/redis/api/async/BaseRedisAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/async/BaseRedisAsyncCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.api.async; import java.util.List; diff --git a/src/main/java/com/lambdaworks/redis/api/async/RedisAsyncCommands.java b/src/main/java/com/lambdaworks/redis/api/async/RedisAsyncCommands.java index 890f2ebc7a..1f22ccf184 100644 --- a/src/main/java/com/lambdaworks/redis/api/async/RedisAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/async/RedisAsyncCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.api.async; import java.util.concurrent.TimeUnit; diff --git a/src/main/java/com/lambdaworks/redis/api/async/RedisGeoAsyncCommands.java b/src/main/java/com/lambdaworks/redis/api/async/RedisGeoAsyncCommands.java index e4a923d8d1..b2a04755de 100644 --- a/src/main/java/com/lambdaworks/redis/api/async/RedisGeoAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/async/RedisGeoAsyncCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.api.async; import com.lambdaworks.redis.*; diff --git a/src/main/java/com/lambdaworks/redis/api/async/RedisHLLAsyncCommands.java b/src/main/java/com/lambdaworks/redis/api/async/RedisHLLAsyncCommands.java index 4fcda15ab6..ce8b5c8d24 100644 --- a/src/main/java/com/lambdaworks/redis/api/async/RedisHLLAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/async/RedisHLLAsyncCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.api.async; import com.lambdaworks.redis.RedisFuture; diff --git a/src/main/java/com/lambdaworks/redis/api/async/RedisHashAsyncCommands.java b/src/main/java/com/lambdaworks/redis/api/async/RedisHashAsyncCommands.java index 03fb42c057..a06772c2a7 100644 --- a/src/main/java/com/lambdaworks/redis/api/async/RedisHashAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/async/RedisHashAsyncCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.api.async; import java.util.List; diff --git a/src/main/java/com/lambdaworks/redis/api/async/RedisKeyAsyncCommands.java b/src/main/java/com/lambdaworks/redis/api/async/RedisKeyAsyncCommands.java index dcd7436618..ed80797eed 100644 --- a/src/main/java/com/lambdaworks/redis/api/async/RedisKeyAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/async/RedisKeyAsyncCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.api.async; import java.util.Date; diff --git a/src/main/java/com/lambdaworks/redis/api/async/RedisListAsyncCommands.java b/src/main/java/com/lambdaworks/redis/api/async/RedisListAsyncCommands.java index 7a719ffbff..944dcd69b7 100644 --- a/src/main/java/com/lambdaworks/redis/api/async/RedisListAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/async/RedisListAsyncCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.api.async; import java.util.List; diff --git a/src/main/java/com/lambdaworks/redis/api/async/RedisScriptingAsyncCommands.java b/src/main/java/com/lambdaworks/redis/api/async/RedisScriptingAsyncCommands.java index 5eed7171c1..b890923184 100644 --- a/src/main/java/com/lambdaworks/redis/api/async/RedisScriptingAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/async/RedisScriptingAsyncCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.api.async; import java.util.List; diff --git a/src/main/java/com/lambdaworks/redis/api/async/RedisServerAsyncCommands.java b/src/main/java/com/lambdaworks/redis/api/async/RedisServerAsyncCommands.java index 18453935e3..dfd6d79389 100644 --- a/src/main/java/com/lambdaworks/redis/api/async/RedisServerAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/async/RedisServerAsyncCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.api.async; import java.util.Date; diff --git a/src/main/java/com/lambdaworks/redis/api/async/RedisSetAsyncCommands.java b/src/main/java/com/lambdaworks/redis/api/async/RedisSetAsyncCommands.java index 5f3125ad92..54c2be87b2 100644 --- a/src/main/java/com/lambdaworks/redis/api/async/RedisSetAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/async/RedisSetAsyncCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.api.async; import java.util.List; diff --git a/src/main/java/com/lambdaworks/redis/api/async/RedisSortedSetAsyncCommands.java b/src/main/java/com/lambdaworks/redis/api/async/RedisSortedSetAsyncCommands.java index 5d86c3ec7a..babe589e87 100644 --- a/src/main/java/com/lambdaworks/redis/api/async/RedisSortedSetAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/async/RedisSortedSetAsyncCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.api.async; import java.util.List; diff --git a/src/main/java/com/lambdaworks/redis/api/async/RedisStringAsyncCommands.java b/src/main/java/com/lambdaworks/redis/api/async/RedisStringAsyncCommands.java index 25cc1523db..90ac8f8c6e 100644 --- a/src/main/java/com/lambdaworks/redis/api/async/RedisStringAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/async/RedisStringAsyncCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.api.async; import java.util.List; diff --git a/src/main/java/com/lambdaworks/redis/api/async/RedisTransactionalAsyncCommands.java b/src/main/java/com/lambdaworks/redis/api/async/RedisTransactionalAsyncCommands.java index 815b350750..71076f08d0 100644 --- a/src/main/java/com/lambdaworks/redis/api/async/RedisTransactionalAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/async/RedisTransactionalAsyncCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.api.async; import java.util.List; diff --git a/src/main/java/com/lambdaworks/redis/api/async/package-info.java b/src/main/java/com/lambdaworks/redis/api/async/package-info.java index 4ac51e1ea8..b6fa5dbcde 100644 --- a/src/main/java/com/lambdaworks/redis/api/async/package-info.java +++ b/src/main/java/com/lambdaworks/redis/api/async/package-info.java @@ -1,4 +1,4 @@ /** * Standalone Redis API for asynchronous executed commands. */ -package com.lambdaworks.redis.api.async; \ No newline at end of file +package com.lambdaworks.redis.api.async; diff --git a/src/main/java/com/lambdaworks/redis/api/package-info.java b/src/main/java/com/lambdaworks/redis/api/package-info.java index a2d9537746..3449aa0a0f 100644 --- a/src/main/java/com/lambdaworks/redis/api/package-info.java +++ b/src/main/java/com/lambdaworks/redis/api/package-info.java @@ -1,4 +1,4 @@ /** * Standalone Redis connection API. */ -package com.lambdaworks.redis.api; \ No newline at end of file +package com.lambdaworks.redis.api; diff --git a/src/main/java/com/lambdaworks/redis/api/reactive/BaseRedisReactiveCommands.java b/src/main/java/com/lambdaworks/redis/api/reactive/BaseRedisReactiveCommands.java index e2ff194e50..76d0fe8161 100644 --- a/src/main/java/com/lambdaworks/redis/api/reactive/BaseRedisReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/reactive/BaseRedisReactiveCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.api.reactive; import java.util.List; diff --git a/src/main/java/com/lambdaworks/redis/api/reactive/RedisGeoReactiveCommands.java b/src/main/java/com/lambdaworks/redis/api/reactive/RedisGeoReactiveCommands.java index f57520c7b4..5eccc74ac6 100644 --- a/src/main/java/com/lambdaworks/redis/api/reactive/RedisGeoReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/reactive/RedisGeoReactiveCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.api.reactive; import com.lambdaworks.redis.*; diff --git a/src/main/java/com/lambdaworks/redis/api/reactive/RedisHLLReactiveCommands.java b/src/main/java/com/lambdaworks/redis/api/reactive/RedisHLLReactiveCommands.java index 9e8696b8bf..953c1080b1 100644 --- a/src/main/java/com/lambdaworks/redis/api/reactive/RedisHLLReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/reactive/RedisHLLReactiveCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.api.reactive; import reactor.core.publisher.Flux; diff --git a/src/main/java/com/lambdaworks/redis/api/reactive/RedisHashReactiveCommands.java b/src/main/java/com/lambdaworks/redis/api/reactive/RedisHashReactiveCommands.java index fe3c4ce58e..2804603b6e 100644 --- a/src/main/java/com/lambdaworks/redis/api/reactive/RedisHashReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/reactive/RedisHashReactiveCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.api.reactive; import java.util.List; diff --git a/src/main/java/com/lambdaworks/redis/api/reactive/RedisKeyReactiveCommands.java b/src/main/java/com/lambdaworks/redis/api/reactive/RedisKeyReactiveCommands.java index bf31d9fd27..d5c232a2da 100644 --- a/src/main/java/com/lambdaworks/redis/api/reactive/RedisKeyReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/reactive/RedisKeyReactiveCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.api.reactive; import java.util.Date; diff --git a/src/main/java/com/lambdaworks/redis/api/reactive/RedisListReactiveCommands.java b/src/main/java/com/lambdaworks/redis/api/reactive/RedisListReactiveCommands.java index c9f8cbbc37..704999d4c3 100644 --- a/src/main/java/com/lambdaworks/redis/api/reactive/RedisListReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/reactive/RedisListReactiveCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.api.reactive; import java.util.List; diff --git a/src/main/java/com/lambdaworks/redis/api/reactive/RedisReactiveCommands.java b/src/main/java/com/lambdaworks/redis/api/reactive/RedisReactiveCommands.java index dbe5053db4..7e93617b93 100644 --- a/src/main/java/com/lambdaworks/redis/api/reactive/RedisReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/reactive/RedisReactiveCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.api.reactive; import java.util.concurrent.TimeUnit; diff --git a/src/main/java/com/lambdaworks/redis/api/reactive/RedisScriptingReactiveCommands.java b/src/main/java/com/lambdaworks/redis/api/reactive/RedisScriptingReactiveCommands.java index 56e3a2ed3a..d8ee26f1a9 100644 --- a/src/main/java/com/lambdaworks/redis/api/reactive/RedisScriptingReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/reactive/RedisScriptingReactiveCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.api.reactive; import java.util.List; diff --git a/src/main/java/com/lambdaworks/redis/api/reactive/RedisServerReactiveCommands.java b/src/main/java/com/lambdaworks/redis/api/reactive/RedisServerReactiveCommands.java index ff02fa90f4..896c8173d4 100644 --- a/src/main/java/com/lambdaworks/redis/api/reactive/RedisServerReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/reactive/RedisServerReactiveCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.api.reactive; import java.util.Date; diff --git a/src/main/java/com/lambdaworks/redis/api/reactive/RedisSetReactiveCommands.java b/src/main/java/com/lambdaworks/redis/api/reactive/RedisSetReactiveCommands.java index 23fbbf65a3..c6bac5e5ef 100644 --- a/src/main/java/com/lambdaworks/redis/api/reactive/RedisSetReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/reactive/RedisSetReactiveCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.api.reactive; import java.util.Set; diff --git a/src/main/java/com/lambdaworks/redis/api/reactive/RedisSortedSetReactiveCommands.java b/src/main/java/com/lambdaworks/redis/api/reactive/RedisSortedSetReactiveCommands.java index 5867b1a04d..4924a4758e 100644 --- a/src/main/java/com/lambdaworks/redis/api/reactive/RedisSortedSetReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/reactive/RedisSortedSetReactiveCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.api.reactive; import java.util.List; diff --git a/src/main/java/com/lambdaworks/redis/api/reactive/RedisStringReactiveCommands.java b/src/main/java/com/lambdaworks/redis/api/reactive/RedisStringReactiveCommands.java index fda40cf542..09366de970 100644 --- a/src/main/java/com/lambdaworks/redis/api/reactive/RedisStringReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/reactive/RedisStringReactiveCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.api.reactive; import java.util.Map; diff --git a/src/main/java/com/lambdaworks/redis/api/reactive/RedisTransactionalReactiveCommands.java b/src/main/java/com/lambdaworks/redis/api/reactive/RedisTransactionalReactiveCommands.java index 561816b98f..1bbc8a2107 100644 --- a/src/main/java/com/lambdaworks/redis/api/reactive/RedisTransactionalReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/reactive/RedisTransactionalReactiveCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.api.reactive; import java.util.List; diff --git a/src/main/java/com/lambdaworks/redis/api/reactive/package-info.java b/src/main/java/com/lambdaworks/redis/api/reactive/package-info.java index 09f535d46b..bd72cba31d 100644 --- a/src/main/java/com/lambdaworks/redis/api/reactive/package-info.java +++ b/src/main/java/com/lambdaworks/redis/api/reactive/package-info.java @@ -1,4 +1,4 @@ /** * Standalone Redis API for commands executed in a reactive manner. */ -package com.lambdaworks.redis.api.reactive; \ No newline at end of file +package com.lambdaworks.redis.api.reactive; diff --git a/src/main/java/com/lambdaworks/redis/api/sync/BaseRedisCommands.java b/src/main/java/com/lambdaworks/redis/api/sync/BaseRedisCommands.java index f1484d0192..fe72ac174b 100644 --- a/src/main/java/com/lambdaworks/redis/api/sync/BaseRedisCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/sync/BaseRedisCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.api.sync; import java.util.List; diff --git a/src/main/java/com/lambdaworks/redis/api/sync/RedisCommands.java b/src/main/java/com/lambdaworks/redis/api/sync/RedisCommands.java index 896bbcc23b..c8ce6c73fe 100644 --- a/src/main/java/com/lambdaworks/redis/api/sync/RedisCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/sync/RedisCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.api.sync; import java.util.concurrent.TimeUnit; diff --git a/src/main/java/com/lambdaworks/redis/api/sync/RedisGeoCommands.java b/src/main/java/com/lambdaworks/redis/api/sync/RedisGeoCommands.java index 88eea5e100..41ef7080e8 100644 --- a/src/main/java/com/lambdaworks/redis/api/sync/RedisGeoCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/sync/RedisGeoCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.api.sync; import com.lambdaworks.redis.*; diff --git a/src/main/java/com/lambdaworks/redis/api/sync/RedisHLLCommands.java b/src/main/java/com/lambdaworks/redis/api/sync/RedisHLLCommands.java index 1c2f72a1f6..aa7386298d 100644 --- a/src/main/java/com/lambdaworks/redis/api/sync/RedisHLLCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/sync/RedisHLLCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.api.sync; /** diff --git a/src/main/java/com/lambdaworks/redis/api/sync/RedisHashCommands.java b/src/main/java/com/lambdaworks/redis/api/sync/RedisHashCommands.java index 1460f29266..f3f535c878 100644 --- a/src/main/java/com/lambdaworks/redis/api/sync/RedisHashCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/sync/RedisHashCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.api.sync; import java.util.List; diff --git a/src/main/java/com/lambdaworks/redis/api/sync/RedisKeyCommands.java b/src/main/java/com/lambdaworks/redis/api/sync/RedisKeyCommands.java index f1b618feb0..07c301ecbc 100644 --- a/src/main/java/com/lambdaworks/redis/api/sync/RedisKeyCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/sync/RedisKeyCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.api.sync; import java.util.Date; diff --git a/src/main/java/com/lambdaworks/redis/api/sync/RedisListCommands.java b/src/main/java/com/lambdaworks/redis/api/sync/RedisListCommands.java index 6baa624022..734dfede07 100644 --- a/src/main/java/com/lambdaworks/redis/api/sync/RedisListCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/sync/RedisListCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.api.sync; import java.util.List; diff --git a/src/main/java/com/lambdaworks/redis/api/sync/RedisScriptingCommands.java b/src/main/java/com/lambdaworks/redis/api/sync/RedisScriptingCommands.java index 8f23f65c7a..69b676b36f 100644 --- a/src/main/java/com/lambdaworks/redis/api/sync/RedisScriptingCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/sync/RedisScriptingCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.api.sync; import java.util.List; diff --git a/src/main/java/com/lambdaworks/redis/api/sync/RedisServerCommands.java b/src/main/java/com/lambdaworks/redis/api/sync/RedisServerCommands.java index 13cccac13e..27a1dfb6d4 100644 --- a/src/main/java/com/lambdaworks/redis/api/sync/RedisServerCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/sync/RedisServerCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.api.sync; import java.util.Date; diff --git a/src/main/java/com/lambdaworks/redis/api/sync/RedisSetCommands.java b/src/main/java/com/lambdaworks/redis/api/sync/RedisSetCommands.java index 6a67e804e2..acdb6856fc 100644 --- a/src/main/java/com/lambdaworks/redis/api/sync/RedisSetCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/sync/RedisSetCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.api.sync; import java.util.List; diff --git a/src/main/java/com/lambdaworks/redis/api/sync/RedisSortedSetCommands.java b/src/main/java/com/lambdaworks/redis/api/sync/RedisSortedSetCommands.java index 182926e7a8..550745ae00 100644 --- a/src/main/java/com/lambdaworks/redis/api/sync/RedisSortedSetCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/sync/RedisSortedSetCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.api.sync; import java.util.List; diff --git a/src/main/java/com/lambdaworks/redis/api/sync/RedisStringCommands.java b/src/main/java/com/lambdaworks/redis/api/sync/RedisStringCommands.java index 6b689e6f2f..26c194e20b 100644 --- a/src/main/java/com/lambdaworks/redis/api/sync/RedisStringCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/sync/RedisStringCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.api.sync; import java.util.List; diff --git a/src/main/java/com/lambdaworks/redis/api/sync/RedisTransactionalCommands.java b/src/main/java/com/lambdaworks/redis/api/sync/RedisTransactionalCommands.java index 197c205807..4a8a67a352 100644 --- a/src/main/java/com/lambdaworks/redis/api/sync/RedisTransactionalCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/sync/RedisTransactionalCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.api.sync; import java.util.List; diff --git a/src/main/java/com/lambdaworks/redis/api/sync/package-info.java b/src/main/java/com/lambdaworks/redis/api/sync/package-info.java index 25444955f5..6e79bb0948 100644 --- a/src/main/java/com/lambdaworks/redis/api/sync/package-info.java +++ b/src/main/java/com/lambdaworks/redis/api/sync/package-info.java @@ -1,4 +1,4 @@ /** * Standalone Redis API for synchronous executed commands. */ -package com.lambdaworks.redis.api.sync; \ No newline at end of file +package com.lambdaworks.redis.api.sync; diff --git a/src/main/java/com/lambdaworks/redis/cluster/AbstractNodeSelection.java b/src/main/java/com/lambdaworks/redis/cluster/AbstractNodeSelection.java index f0f3271315..cbe789b428 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/AbstractNodeSelection.java +++ b/src/main/java/com/lambdaworks/redis/cluster/AbstractNodeSelection.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster; import java.util.List; diff --git a/src/main/java/com/lambdaworks/redis/cluster/AsyncExecutionsImpl.java b/src/main/java/com/lambdaworks/redis/cluster/AsyncExecutionsImpl.java index 69ecbef51c..f655b024bf 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/AsyncExecutionsImpl.java +++ b/src/main/java/com/lambdaworks/redis/cluster/AsyncExecutionsImpl.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster; import java.util.Collection; diff --git a/src/main/java/com/lambdaworks/redis/cluster/ClusterClientOptions.java b/src/main/java/com/lambdaworks/redis/cluster/ClusterClientOptions.java index 9e573f5cdf..084b7fc5a7 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/ClusterClientOptions.java +++ b/src/main/java/com/lambdaworks/redis/cluster/ClusterClientOptions.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster; import java.util.concurrent.TimeUnit; diff --git a/src/main/java/com/lambdaworks/redis/cluster/ClusterCommand.java b/src/main/java/com/lambdaworks/redis/cluster/ClusterCommand.java index 9b8935b299..1db9b7f4b2 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/ClusterCommand.java +++ b/src/main/java/com/lambdaworks/redis/cluster/ClusterCommand.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster; import com.lambdaworks.redis.RedisChannelWriter; diff --git a/src/main/java/com/lambdaworks/redis/cluster/ClusterConnectionProvider.java b/src/main/java/com/lambdaworks/redis/cluster/ClusterConnectionProvider.java index a27f803ad8..261564c5b1 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/ClusterConnectionProvider.java +++ b/src/main/java/com/lambdaworks/redis/cluster/ClusterConnectionProvider.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster; import java.io.Closeable; diff --git a/src/main/java/com/lambdaworks/redis/cluster/ClusterDistributionChannelWriter.java b/src/main/java/com/lambdaworks/redis/cluster/ClusterDistributionChannelWriter.java index 6e85bba035..9513d69529 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/ClusterDistributionChannelWriter.java +++ b/src/main/java/com/lambdaworks/redis/cluster/ClusterDistributionChannelWriter.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster; import static com.lambdaworks.redis.cluster.SlotHash.getSlot; diff --git a/src/main/java/com/lambdaworks/redis/cluster/ClusterEventListener.java b/src/main/java/com/lambdaworks/redis/cluster/ClusterEventListener.java index 852779784f..7dcc1b7976 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/ClusterEventListener.java +++ b/src/main/java/com/lambdaworks/redis/cluster/ClusterEventListener.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster; /** diff --git a/src/main/java/com/lambdaworks/redis/cluster/ClusterNodeEndpoint.java b/src/main/java/com/lambdaworks/redis/cluster/ClusterNodeEndpoint.java index 3604b146e2..9103c6a71a 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/ClusterNodeEndpoint.java +++ b/src/main/java/com/lambdaworks/redis/cluster/ClusterNodeEndpoint.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster; import java.util.ArrayList; diff --git a/src/main/java/com/lambdaworks/redis/cluster/ClusterScanSupport.java b/src/main/java/com/lambdaworks/redis/cluster/ClusterScanSupport.java index afa9cb53fb..65eb194cea 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/ClusterScanSupport.java +++ b/src/main/java/com/lambdaworks/redis/cluster/ClusterScanSupport.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster; import java.util.ArrayList; diff --git a/src/main/java/com/lambdaworks/redis/cluster/ClusterTopologyRefreshOptions.java b/src/main/java/com/lambdaworks/redis/cluster/ClusterTopologyRefreshOptions.java index 25838259a8..f837009a54 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/ClusterTopologyRefreshOptions.java +++ b/src/main/java/com/lambdaworks/redis/cluster/ClusterTopologyRefreshOptions.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster; import java.util.*; diff --git a/src/main/java/com/lambdaworks/redis/cluster/ClusterTopologyRefreshScheduler.java b/src/main/java/com/lambdaworks/redis/cluster/ClusterTopologyRefreshScheduler.java index 07c963ded7..39d6250b6e 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/ClusterTopologyRefreshScheduler.java +++ b/src/main/java/com/lambdaworks/redis/cluster/ClusterTopologyRefreshScheduler.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster; import java.util.concurrent.TimeUnit; diff --git a/src/main/java/com/lambdaworks/redis/cluster/DynamicAsyncNodeSelection.java b/src/main/java/com/lambdaworks/redis/cluster/DynamicAsyncNodeSelection.java index 305d7f29dd..9952c45420 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/DynamicAsyncNodeSelection.java +++ b/src/main/java/com/lambdaworks/redis/cluster/DynamicAsyncNodeSelection.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster; import java.util.HashMap; diff --git a/src/main/java/com/lambdaworks/redis/cluster/DynamicNodeSelection.java b/src/main/java/com/lambdaworks/redis/cluster/DynamicNodeSelection.java index be6fa3fcc5..a290dade50 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/DynamicNodeSelection.java +++ b/src/main/java/com/lambdaworks/redis/cluster/DynamicNodeSelection.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster; import java.util.List; diff --git a/src/main/java/com/lambdaworks/redis/cluster/DynamicSyncNodeSelection.java b/src/main/java/com/lambdaworks/redis/cluster/DynamicSyncNodeSelection.java index d8a1275478..f8d7a5f783 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/DynamicSyncNodeSelection.java +++ b/src/main/java/com/lambdaworks/redis/cluster/DynamicSyncNodeSelection.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster; import java.util.HashMap; diff --git a/src/main/java/com/lambdaworks/redis/cluster/MultiNodeExecution.java b/src/main/java/com/lambdaworks/redis/cluster/MultiNodeExecution.java index 1418b9f554..7f4ee88078 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/MultiNodeExecution.java +++ b/src/main/java/com/lambdaworks/redis/cluster/MultiNodeExecution.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster; import java.lang.reflect.Proxy; diff --git a/src/main/java/com/lambdaworks/redis/cluster/NodeSelectionInvocationHandler.java b/src/main/java/com/lambdaworks/redis/cluster/NodeSelectionInvocationHandler.java index dcec2426d4..ca70b110c4 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/NodeSelectionInvocationHandler.java +++ b/src/main/java/com/lambdaworks/redis/cluster/NodeSelectionInvocationHandler.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster; import java.lang.reflect.InvocationTargetException; diff --git a/src/main/java/com/lambdaworks/redis/cluster/PartitionAccessor.java b/src/main/java/com/lambdaworks/redis/cluster/PartitionAccessor.java index 26b7dd0752..d83ba4baac 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/PartitionAccessor.java +++ b/src/main/java/com/lambdaworks/redis/cluster/PartitionAccessor.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster; import java.util.ArrayList; diff --git a/src/main/java/com/lambdaworks/redis/cluster/PartitionsConsensus.java b/src/main/java/com/lambdaworks/redis/cluster/PartitionsConsensus.java index 47b53d19f3..64276a2e5c 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/PartitionsConsensus.java +++ b/src/main/java/com/lambdaworks/redis/cluster/PartitionsConsensus.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster; import java.util.Map; diff --git a/src/main/java/com/lambdaworks/redis/cluster/PartitionsConsensusImpl.java b/src/main/java/com/lambdaworks/redis/cluster/PartitionsConsensusImpl.java index 8fda339be0..697fc358a8 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/PartitionsConsensusImpl.java +++ b/src/main/java/com/lambdaworks/redis/cluster/PartitionsConsensusImpl.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster; import java.util.ArrayList; diff --git a/src/main/java/com/lambdaworks/redis/cluster/PipelinedRedisFuture.java b/src/main/java/com/lambdaworks/redis/cluster/PipelinedRedisFuture.java index ae83fbd2da..798fbcf014 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/PipelinedRedisFuture.java +++ b/src/main/java/com/lambdaworks/redis/cluster/PipelinedRedisFuture.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster; import java.util.Map; diff --git a/src/main/java/com/lambdaworks/redis/cluster/PooledClusterConnectionProvider.java b/src/main/java/com/lambdaworks/redis/cluster/PooledClusterConnectionProvider.java index 7c4ff9b0e9..22b6887406 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/PooledClusterConnectionProvider.java +++ b/src/main/java/com/lambdaworks/redis/cluster/PooledClusterConnectionProvider.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster; import java.net.InetSocketAddress; diff --git a/src/main/java/com/lambdaworks/redis/cluster/ReadOnlyCommands.java b/src/main/java/com/lambdaworks/redis/cluster/ReadOnlyCommands.java index 92d5a2ad8e..8f708e2a6a 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/ReadOnlyCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/ReadOnlyCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster; import java.util.HashSet; diff --git a/src/main/java/com/lambdaworks/redis/cluster/ReconnectEventListener.java b/src/main/java/com/lambdaworks/redis/cluster/ReconnectEventListener.java index b8891ac9f4..4a19ebde59 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/ReconnectEventListener.java +++ b/src/main/java/com/lambdaworks/redis/cluster/ReconnectEventListener.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster; import com.lambdaworks.redis.ConnectionEvents.Reconnect; diff --git a/src/main/java/com/lambdaworks/redis/cluster/RedisAdvancedClusterAsyncCommandsImpl.java b/src/main/java/com/lambdaworks/redis/cluster/RedisAdvancedClusterAsyncCommandsImpl.java index 8df797e054..cb0867bd86 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/RedisAdvancedClusterAsyncCommandsImpl.java +++ b/src/main/java/com/lambdaworks/redis/cluster/RedisAdvancedClusterAsyncCommandsImpl.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster; import static com.lambdaworks.redis.cluster.ClusterScanSupport.asyncClusterKeyScanCursorMapper; diff --git a/src/main/java/com/lambdaworks/redis/cluster/RedisAdvancedClusterReactiveCommandsImpl.java b/src/main/java/com/lambdaworks/redis/cluster/RedisAdvancedClusterReactiveCommandsImpl.java index be4b0f2068..8d390ab2d0 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/RedisAdvancedClusterReactiveCommandsImpl.java +++ b/src/main/java/com/lambdaworks/redis/cluster/RedisAdvancedClusterReactiveCommandsImpl.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster; import static com.lambdaworks.redis.cluster.ClusterScanSupport.reactiveClusterKeyScanCursorMapper; diff --git a/src/main/java/com/lambdaworks/redis/cluster/RedisClusterClient.java b/src/main/java/com/lambdaworks/redis/cluster/RedisClusterClient.java index 44c97df19c..90093296e0 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/RedisClusterClient.java +++ b/src/main/java/com/lambdaworks/redis/cluster/RedisClusterClient.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster; import java.io.Closeable; diff --git a/src/main/java/com/lambdaworks/redis/cluster/RoundRobin.java b/src/main/java/com/lambdaworks/redis/cluster/RoundRobin.java index a2c311ffd5..7ca004e76d 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/RoundRobin.java +++ b/src/main/java/com/lambdaworks/redis/cluster/RoundRobin.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster; import java.util.Collection; @@ -45,4 +60,4 @@ public V next() { return offset = collection.iterator().next(); } -} \ No newline at end of file +} diff --git a/src/main/java/com/lambdaworks/redis/cluster/RoundRobinSocketAddressSupplier.java b/src/main/java/com/lambdaworks/redis/cluster/RoundRobinSocketAddressSupplier.java index 167d986f73..da553a8425 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/RoundRobinSocketAddressSupplier.java +++ b/src/main/java/com/lambdaworks/redis/cluster/RoundRobinSocketAddressSupplier.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster; import java.net.SocketAddress; diff --git a/src/main/java/com/lambdaworks/redis/cluster/SlotHash.java b/src/main/java/com/lambdaworks/redis/cluster/SlotHash.java index 680f9d3e16..a9df1901bf 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/SlotHash.java +++ b/src/main/java/com/lambdaworks/redis/cluster/SlotHash.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster; import java.nio.ByteBuffer; @@ -135,4 +150,4 @@ static Map getSlots(Map> partitio return result; } -} \ No newline at end of file +} diff --git a/src/main/java/com/lambdaworks/redis/cluster/StatefulRedisClusterConnectionImpl.java b/src/main/java/com/lambdaworks/redis/cluster/StatefulRedisClusterConnectionImpl.java index 09344249f5..ce123aaf02 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/StatefulRedisClusterConnectionImpl.java +++ b/src/main/java/com/lambdaworks/redis/cluster/StatefulRedisClusterConnectionImpl.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster; import static com.lambdaworks.redis.protocol.CommandType.AUTH; diff --git a/src/main/java/com/lambdaworks/redis/cluster/StaticAsyncNodeSelection.java b/src/main/java/com/lambdaworks/redis/cluster/StaticAsyncNodeSelection.java index 33d524d836..4c398ad759 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/StaticAsyncNodeSelection.java +++ b/src/main/java/com/lambdaworks/redis/cluster/StaticAsyncNodeSelection.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster; import java.util.HashMap; diff --git a/src/main/java/com/lambdaworks/redis/cluster/StaticNodeSelection.java b/src/main/java/com/lambdaworks/redis/cluster/StaticNodeSelection.java index d0df121af3..0136524b16 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/StaticNodeSelection.java +++ b/src/main/java/com/lambdaworks/redis/cluster/StaticNodeSelection.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster; import java.util.List; diff --git a/src/main/java/com/lambdaworks/redis/cluster/StaticSyncNodeSelection.java b/src/main/java/com/lambdaworks/redis/cluster/StaticSyncNodeSelection.java index 8633afe788..0eed23e42a 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/StaticSyncNodeSelection.java +++ b/src/main/java/com/lambdaworks/redis/cluster/StaticSyncNodeSelection.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster; import java.util.HashMap; diff --git a/src/main/java/com/lambdaworks/redis/cluster/SyncExecutionsImpl.java b/src/main/java/com/lambdaworks/redis/cluster/SyncExecutionsImpl.java index 1efbad9556..6359874730 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/SyncExecutionsImpl.java +++ b/src/main/java/com/lambdaworks/redis/cluster/SyncExecutionsImpl.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster; import java.util.Collection; diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/NodeSelectionSupport.java b/src/main/java/com/lambdaworks/redis/cluster/api/NodeSelectionSupport.java index fe118badea..0429463909 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/NodeSelectionSupport.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/NodeSelectionSupport.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster.api; import java.util.Map; diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/StatefulRedisClusterConnection.java b/src/main/java/com/lambdaworks/redis/cluster/api/StatefulRedisClusterConnection.java index b1dea48a96..30baedea74 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/StatefulRedisClusterConnection.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/StatefulRedisClusterConnection.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster.api; import com.lambdaworks.redis.ReadFrom; diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/async/AsyncExecutions.java b/src/main/java/com/lambdaworks/redis/cluster/api/async/AsyncExecutions.java index a83f988074..16ac15791e 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/async/AsyncExecutions.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/async/AsyncExecutions.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster.api.async; import java.util.*; diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/async/AsyncNodeSelection.java b/src/main/java/com/lambdaworks/redis/cluster/api/async/AsyncNodeSelection.java index 5a14b7df7e..23a2131197 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/async/AsyncNodeSelection.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/async/AsyncNodeSelection.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster.api.async; import com.lambdaworks.redis.api.async.RedisAsyncCommands; diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/async/BaseNodeSelectionAsyncCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/async/BaseNodeSelectionAsyncCommands.java index fd757d0d91..e5643cf65a 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/async/BaseNodeSelectionAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/async/BaseNodeSelectionAsyncCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster.api.async; import java.util.List; diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionAsyncCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionAsyncCommands.java index 8d8dd297d3..c6b1b62d1c 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionAsyncCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster.api.async; import com.lambdaworks.redis.cluster.api.NodeSelectionSupport; diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionGeoAsyncCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionGeoAsyncCommands.java index 93e0c6e99e..0844bf1732 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionGeoAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionGeoAsyncCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster.api.async; import com.lambdaworks.redis.*; diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionHLLAsyncCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionHLLAsyncCommands.java index c6de42ff6b..391a7db9ea 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionHLLAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionHLLAsyncCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster.api.async; import com.lambdaworks.redis.RedisFuture; diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionHashAsyncCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionHashAsyncCommands.java index 43d9b3935f..2d9e8894f5 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionHashAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionHashAsyncCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster.api.async; import java.util.List; diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionKeyAsyncCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionKeyAsyncCommands.java index a6d7633c2d..7349be15d3 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionKeyAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionKeyAsyncCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster.api.async; import java.util.Date; diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionListAsyncCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionListAsyncCommands.java index 083f1b89ff..d7fa53dea9 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionListAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionListAsyncCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster.api.async; import java.util.List; diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionScriptingAsyncCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionScriptingAsyncCommands.java index 8e84c5f285..b0e8006fb0 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionScriptingAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionScriptingAsyncCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster.api.async; import java.util.List; diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionServerAsyncCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionServerAsyncCommands.java index 7dcf7fd256..fdecccfa25 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionServerAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionServerAsyncCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster.api.async; import java.util.Date; diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionSetAsyncCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionSetAsyncCommands.java index e12c0d5207..f00b8b5fd9 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionSetAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionSetAsyncCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster.api.async; import java.util.List; diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionSortedSetAsyncCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionSortedSetAsyncCommands.java index f3579e7a21..9b62840312 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionSortedSetAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionSortedSetAsyncCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster.api.async; import java.util.List; diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionStringAsyncCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionStringAsyncCommands.java index ef554b017f..382ff7a4e1 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionStringAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionStringAsyncCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster.api.async; import java.util.List; diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/async/RedisAdvancedClusterAsyncCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/async/RedisAdvancedClusterAsyncCommands.java index 0bdacab505..fc913e0941 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/async/RedisAdvancedClusterAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/async/RedisAdvancedClusterAsyncCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster.api.async; import java.util.List; diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/async/RedisClusterAsyncCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/async/RedisClusterAsyncCommands.java index 6f3c8dd841..9e63cd812a 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/async/RedisClusterAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/async/RedisClusterAsyncCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster.api.async; import java.util.List; diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/async/package-info.java b/src/main/java/com/lambdaworks/redis/cluster/api/async/package-info.java index 2cdba3715e..ed12267be8 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/async/package-info.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/async/package-info.java @@ -1,4 +1,4 @@ /** * Redis Cluster API for asynchronous executed commands. */ -package com.lambdaworks.redis.cluster.api.async; \ No newline at end of file +package com.lambdaworks.redis.cluster.api.async; diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/package-info.java b/src/main/java/com/lambdaworks/redis/cluster/api/package-info.java index e2cee2c2c0..cf228a573c 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/package-info.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/package-info.java @@ -1,4 +1,4 @@ /** * Redis Cluster connection API. */ -package com.lambdaworks.redis.cluster.api; \ No newline at end of file +package com.lambdaworks.redis.cluster.api; diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/reactive/RedisAdvancedClusterReactiveCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/reactive/RedisAdvancedClusterReactiveCommands.java index 1987f1d6a0..9da78d7d24 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/reactive/RedisAdvancedClusterReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/reactive/RedisAdvancedClusterReactiveCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster.api.reactive; import java.util.Map; @@ -282,4 +297,4 @@ public interface RedisAdvancedClusterReactiveCommands extends RedisCluster */ Mono touch(K... keys); -} \ No newline at end of file +} diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/reactive/RedisClusterReactiveCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/reactive/RedisClusterReactiveCommands.java index 97f4289a34..0808aacaf8 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/reactive/RedisClusterReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/reactive/RedisClusterReactiveCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster.api.reactive; import java.util.Map; @@ -312,4 +327,4 @@ public interface RedisClusterReactiveCommands extends RedisHashReactiveCom * {@code 1} if the all the keys were set. {@code 0} if no key was set (at least one key already existed). */ Mono msetnx(Map map); -} \ No newline at end of file +} diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/reactive/package-info.java b/src/main/java/com/lambdaworks/redis/cluster/api/reactive/package-info.java index 4cf3456595..30e8b76556 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/reactive/package-info.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/reactive/package-info.java @@ -1,4 +1,4 @@ /** * Redis Cluster API for commands executed in a reactive manner. */ -package com.lambdaworks.redis.cluster.api.reactive; \ No newline at end of file +package com.lambdaworks.redis.cluster.api.reactive; diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/sync/BaseNodeSelectionCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/sync/BaseNodeSelectionCommands.java index d5bc731987..2100440d45 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/sync/BaseNodeSelectionCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/sync/BaseNodeSelectionCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster.api.sync; import java.util.List; diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/sync/Executions.java b/src/main/java/com/lambdaworks/redis/cluster/api/sync/Executions.java index 2b3d889e22..f893cff23d 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/sync/Executions.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/sync/Executions.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster.api.sync; import java.util.*; diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelection.java b/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelection.java index 4aa55752c8..d89d79ac5d 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelection.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelection.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster.api.sync; import com.lambdaworks.redis.api.sync.RedisCommands; diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionCommands.java index fa5929a784..e85baa1f00 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster.api.sync; import com.lambdaworks.redis.cluster.api.NodeSelectionSupport; diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionGeoCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionGeoCommands.java index dac1d65873..3dadf4b9ef 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionGeoCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionGeoCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster.api.sync; import com.lambdaworks.redis.*; diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionHLLCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionHLLCommands.java index 39236a01a1..29f124010a 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionHLLCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionHLLCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster.api.sync; /** diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionHashCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionHashCommands.java index 07942954d7..ef2119b84e 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionHashCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionHashCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster.api.sync; import java.util.List; diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionKeyCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionKeyCommands.java index 24b28c25f8..2494895f3c 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionKeyCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionKeyCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster.api.sync; import java.util.Date; diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionListCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionListCommands.java index 9d4830c0ba..de8a6c67cf 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionListCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionListCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster.api.sync; import java.util.List; diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionScriptingCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionScriptingCommands.java index e89b0132c6..efa3535149 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionScriptingCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionScriptingCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster.api.sync; import java.util.List; diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionServerCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionServerCommands.java index c0554cdbf9..90205f9ec6 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionServerCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionServerCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster.api.sync; import java.util.Date; diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionSetCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionSetCommands.java index ff8ade03ca..da18f015e3 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionSetCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionSetCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster.api.sync; import java.util.List; diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionSortedSetCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionSortedSetCommands.java index 30c15399f2..ef869892f1 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionSortedSetCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionSortedSetCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster.api.sync; import java.util.List; diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionStringCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionStringCommands.java index 98fecb27e7..d37b6344dc 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionStringCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionStringCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster.api.sync; import java.util.List; diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/sync/RedisAdvancedClusterCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/sync/RedisAdvancedClusterCommands.java index 72492ab8ac..f301435685 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/sync/RedisAdvancedClusterCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/sync/RedisAdvancedClusterCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster.api.sync; import java.util.List; diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/sync/RedisClusterCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/sync/RedisClusterCommands.java index 4d9dcf08d3..4621f7d0d1 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/sync/RedisClusterCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/sync/RedisClusterCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster.api.sync; import java.util.List; diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/sync/package-info.java b/src/main/java/com/lambdaworks/redis/cluster/api/sync/package-info.java index 2621d24a0b..8c779ca1f9 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/sync/package-info.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/sync/package-info.java @@ -1,4 +1,4 @@ /** * Redis Cluster API for synchronous executed commands. */ -package com.lambdaworks.redis.cluster.api.sync; \ No newline at end of file +package com.lambdaworks.redis.cluster.api.sync; diff --git a/src/main/java/com/lambdaworks/redis/cluster/event/ClusterTopologyChangedEvent.java b/src/main/java/com/lambdaworks/redis/cluster/event/ClusterTopologyChangedEvent.java index 87c31aca4b..24adfab348 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/event/ClusterTopologyChangedEvent.java +++ b/src/main/java/com/lambdaworks/redis/cluster/event/ClusterTopologyChangedEvent.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster.event; import java.util.Collections; diff --git a/src/main/java/com/lambdaworks/redis/cluster/models/partitions/ClusterPartitionParser.java b/src/main/java/com/lambdaworks/redis/cluster/models/partitions/ClusterPartitionParser.java index 68ad37decf..a3ef6ea978 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/models/partitions/ClusterPartitionParser.java +++ b/src/main/java/com/lambdaworks/redis/cluster/models/partitions/ClusterPartitionParser.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster.models.partitions; import java.util.*; diff --git a/src/main/java/com/lambdaworks/redis/cluster/models/partitions/Partitions.java b/src/main/java/com/lambdaworks/redis/cluster/models/partitions/Partitions.java index 26fd5b2c01..bfe97eaf48 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/models/partitions/Partitions.java +++ b/src/main/java/com/lambdaworks/redis/cluster/models/partitions/Partitions.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster.models.partitions; import java.util.*; diff --git a/src/main/java/com/lambdaworks/redis/cluster/models/partitions/RedisClusterNode.java b/src/main/java/com/lambdaworks/redis/cluster/models/partitions/RedisClusterNode.java index c3991977fe..e86037a1fe 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/models/partitions/RedisClusterNode.java +++ b/src/main/java/com/lambdaworks/redis/cluster/models/partitions/RedisClusterNode.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster.models.partitions; import java.io.Serializable; diff --git a/src/main/java/com/lambdaworks/redis/cluster/models/partitions/package-info.java b/src/main/java/com/lambdaworks/redis/cluster/models/partitions/package-info.java index 12cc10b0b2..761bc33538 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/models/partitions/package-info.java +++ b/src/main/java/com/lambdaworks/redis/cluster/models/partitions/package-info.java @@ -1,4 +1,4 @@ /** * Model and parser for the {@code CLUSTER NODES} and {@code CLUSTER SLAVES} output. */ -package com.lambdaworks.redis.cluster.models.partitions; \ No newline at end of file +package com.lambdaworks.redis.cluster.models.partitions; diff --git a/src/main/java/com/lambdaworks/redis/cluster/models/slots/ClusterSlotRange.java b/src/main/java/com/lambdaworks/redis/cluster/models/slots/ClusterSlotRange.java index fa6e9502de..e09320e577 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/models/slots/ClusterSlotRange.java +++ b/src/main/java/com/lambdaworks/redis/cluster/models/slots/ClusterSlotRange.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster.models.slots; import java.io.Serializable; diff --git a/src/main/java/com/lambdaworks/redis/cluster/models/slots/ClusterSlotsParser.java b/src/main/java/com/lambdaworks/redis/cluster/models/slots/ClusterSlotsParser.java index 38b1743ff0..90ed428d3d 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/models/slots/ClusterSlotsParser.java +++ b/src/main/java/com/lambdaworks/redis/cluster/models/slots/ClusterSlotsParser.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster.models.slots; import java.util.*; diff --git a/src/main/java/com/lambdaworks/redis/cluster/models/slots/package-info.java b/src/main/java/com/lambdaworks/redis/cluster/models/slots/package-info.java index 973d70a9ff..288791e2d9 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/models/slots/package-info.java +++ b/src/main/java/com/lambdaworks/redis/cluster/models/slots/package-info.java @@ -1,4 +1,4 @@ /** * Model and parser for the {@code CLUSTER SLOTS} output. */ -package com.lambdaworks.redis.cluster.models.slots; \ No newline at end of file +package com.lambdaworks.redis.cluster.models.slots; diff --git a/src/main/java/com/lambdaworks/redis/cluster/package-info.java b/src/main/java/com/lambdaworks/redis/cluster/package-info.java index 6f2c3f8807..18a2d1dc02 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/package-info.java +++ b/src/main/java/com/lambdaworks/redis/cluster/package-info.java @@ -1,4 +1,4 @@ /** * Client for Redis Cluster, see {@link com.lambdaworks.redis.cluster.RedisClusterClient}. */ -package com.lambdaworks.redis.cluster; \ No newline at end of file +package com.lambdaworks.redis.cluster; diff --git a/src/main/java/com/lambdaworks/redis/cluster/topology/ClusterTopologyRefresh.java b/src/main/java/com/lambdaworks/redis/cluster/topology/ClusterTopologyRefresh.java index 178bdeebcc..2606a06f93 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/topology/ClusterTopologyRefresh.java +++ b/src/main/java/com/lambdaworks/redis/cluster/topology/ClusterTopologyRefresh.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster.topology; import java.net.SocketAddress; diff --git a/src/main/java/com/lambdaworks/redis/cluster/topology/Connections.java b/src/main/java/com/lambdaworks/redis/cluster/topology/Connections.java index 711f171975..dadfb03c68 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/topology/Connections.java +++ b/src/main/java/com/lambdaworks/redis/cluster/topology/Connections.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster.topology; import java.util.Map; diff --git a/src/main/java/com/lambdaworks/redis/cluster/topology/NodeConnectionFactory.java b/src/main/java/com/lambdaworks/redis/cluster/topology/NodeConnectionFactory.java index 45d6250a87..f2edcac8b0 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/topology/NodeConnectionFactory.java +++ b/src/main/java/com/lambdaworks/redis/cluster/topology/NodeConnectionFactory.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster.topology; import java.net.SocketAddress; diff --git a/src/main/java/com/lambdaworks/redis/cluster/topology/NodeTopologyView.java b/src/main/java/com/lambdaworks/redis/cluster/topology/NodeTopologyView.java index e346b19d78..6fb1b51ceb 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/topology/NodeTopologyView.java +++ b/src/main/java/com/lambdaworks/redis/cluster/topology/NodeTopologyView.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster.topology; import java.util.concurrent.ExecutionException; diff --git a/src/main/java/com/lambdaworks/redis/cluster/topology/NodeTopologyViews.java b/src/main/java/com/lambdaworks/redis/cluster/topology/NodeTopologyViews.java index 3b984f4be9..9a04065935 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/topology/NodeTopologyViews.java +++ b/src/main/java/com/lambdaworks/redis/cluster/topology/NodeTopologyViews.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster.topology; import com.lambdaworks.redis.RedisURI; diff --git a/src/main/java/com/lambdaworks/redis/cluster/topology/RedisClusterNodeSnapshot.java b/src/main/java/com/lambdaworks/redis/cluster/topology/RedisClusterNodeSnapshot.java index 5a66793ef6..694f1e5f09 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/topology/RedisClusterNodeSnapshot.java +++ b/src/main/java/com/lambdaworks/redis/cluster/topology/RedisClusterNodeSnapshot.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster.topology; import com.lambdaworks.redis.cluster.models.partitions.RedisClusterNode; diff --git a/src/main/java/com/lambdaworks/redis/cluster/topology/Requests.java b/src/main/java/com/lambdaworks/redis/cluster/topology/Requests.java index 0e7d9179c7..e49f068a13 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/topology/Requests.java +++ b/src/main/java/com/lambdaworks/redis/cluster/topology/Requests.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster.topology; import java.util.Map; diff --git a/src/main/java/com/lambdaworks/redis/cluster/topology/TimedAsyncCommand.java b/src/main/java/com/lambdaworks/redis/cluster/topology/TimedAsyncCommand.java index d7e5a6e5bd..31900e54c9 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/topology/TimedAsyncCommand.java +++ b/src/main/java/com/lambdaworks/redis/cluster/topology/TimedAsyncCommand.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster.topology; import com.lambdaworks.redis.protocol.AsyncCommand; diff --git a/src/main/java/com/lambdaworks/redis/cluster/topology/TopologyComparators.java b/src/main/java/com/lambdaworks/redis/cluster/topology/TopologyComparators.java index 16e4c94ab0..5eca01d168 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/topology/TopologyComparators.java +++ b/src/main/java/com/lambdaworks/redis/cluster/topology/TopologyComparators.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster.topology; import java.util.Collections; diff --git a/src/main/java/com/lambdaworks/redis/codec/ByteArrayCodec.java b/src/main/java/com/lambdaworks/redis/codec/ByteArrayCodec.java index 23e9d8ee47..ac9622a005 100644 --- a/src/main/java/com/lambdaworks/redis/codec/ByteArrayCodec.java +++ b/src/main/java/com/lambdaworks/redis/codec/ByteArrayCodec.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.codec; import java.nio.ByteBuffer; diff --git a/src/main/java/com/lambdaworks/redis/codec/ByteBufferInputStream.java b/src/main/java/com/lambdaworks/redis/codec/ByteBufferInputStream.java index 805d42dea7..9575f0af21 100644 --- a/src/main/java/com/lambdaworks/redis/codec/ByteBufferInputStream.java +++ b/src/main/java/com/lambdaworks/redis/codec/ByteBufferInputStream.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.codec; import java.io.IOException; diff --git a/src/main/java/com/lambdaworks/redis/codec/CompressionCodec.java b/src/main/java/com/lambdaworks/redis/codec/CompressionCodec.java index 6b166685e6..c710f0efc1 100644 --- a/src/main/java/com/lambdaworks/redis/codec/CompressionCodec.java +++ b/src/main/java/com/lambdaworks/redis/codec/CompressionCodec.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.codec; import java.io.ByteArrayOutputStream; diff --git a/src/main/java/com/lambdaworks/redis/codec/RedisCodec.java b/src/main/java/com/lambdaworks/redis/codec/RedisCodec.java index afcc3771ac..1bbde04db4 100644 --- a/src/main/java/com/lambdaworks/redis/codec/RedisCodec.java +++ b/src/main/java/com/lambdaworks/redis/codec/RedisCodec.java @@ -1,5 +1,18 @@ -// Copyright (C) 2011 - Will Glozer. All rights reserved. - +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.codec; import java.nio.ByteBuffer; diff --git a/src/main/java/com/lambdaworks/redis/codec/StringCodec.java b/src/main/java/com/lambdaworks/redis/codec/StringCodec.java index 08a773fd2b..168ffd2ca2 100644 --- a/src/main/java/com/lambdaworks/redis/codec/StringCodec.java +++ b/src/main/java/com/lambdaworks/redis/codec/StringCodec.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.codec; import java.nio.ByteBuffer; diff --git a/src/main/java/com/lambdaworks/redis/codec/ToByteBufEncoder.java b/src/main/java/com/lambdaworks/redis/codec/ToByteBufEncoder.java index 719001e94d..a25c322813 100644 --- a/src/main/java/com/lambdaworks/redis/codec/ToByteBufEncoder.java +++ b/src/main/java/com/lambdaworks/redis/codec/ToByteBufEncoder.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.codec; import io.netty.buffer.ByteBuf; diff --git a/src/main/java/com/lambdaworks/redis/codec/Utf8StringCodec.java b/src/main/java/com/lambdaworks/redis/codec/Utf8StringCodec.java index 5d258cfd71..3b84c36dec 100644 --- a/src/main/java/com/lambdaworks/redis/codec/Utf8StringCodec.java +++ b/src/main/java/com/lambdaworks/redis/codec/Utf8StringCodec.java @@ -1,5 +1,18 @@ -// Copyright (C) 2011 - Will Glozer. All rights reserved. - +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.codec; import static java.nio.charset.CoderResult.OVERFLOW; diff --git a/src/main/java/com/lambdaworks/redis/codec/package-info.java b/src/main/java/com/lambdaworks/redis/codec/package-info.java index b6f3fa5e50..82dcb30d79 100644 --- a/src/main/java/com/lambdaworks/redis/codec/package-info.java +++ b/src/main/java/com/lambdaworks/redis/codec/package-info.java @@ -1,4 +1,4 @@ /** * Codecs for key/value type conversion. */ -package com.lambdaworks.redis.codec; \ No newline at end of file +package com.lambdaworks.redis.codec; diff --git a/src/main/java/com/lambdaworks/redis/dynamic/CodecAwareMethodParametersAccessor.java b/src/main/java/com/lambdaworks/redis/dynamic/CodecAwareMethodParametersAccessor.java index 653fe7630c..c843058071 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/CodecAwareMethodParametersAccessor.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/CodecAwareMethodParametersAccessor.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.dynamic; import java.util.Iterator; diff --git a/src/main/java/com/lambdaworks/redis/dynamic/CommandCreationException.java b/src/main/java/com/lambdaworks/redis/dynamic/CommandCreationException.java index fb4dcdb736..1a3bdddd77 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/CommandCreationException.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/CommandCreationException.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.dynamic; import com.lambdaworks.redis.RedisException; diff --git a/src/main/java/com/lambdaworks/redis/dynamic/CommandFactory.java b/src/main/java/com/lambdaworks/redis/dynamic/CommandFactory.java index fc9a03adc1..d2043d8ce9 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/CommandFactory.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/CommandFactory.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.dynamic; import com.lambdaworks.redis.protocol.RedisCommand; diff --git a/src/main/java/com/lambdaworks/redis/dynamic/CommandMethod.java b/src/main/java/com/lambdaworks/redis/dynamic/CommandMethod.java index c4bb1a854e..b7a357648d 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/CommandMethod.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/CommandMethod.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.dynamic; import java.lang.annotation.Annotation; diff --git a/src/main/java/com/lambdaworks/redis/dynamic/CommandMethodSyntaxException.java b/src/main/java/com/lambdaworks/redis/dynamic/CommandMethodSyntaxException.java index 43b13024b6..0a5db54566 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/CommandMethodSyntaxException.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/CommandMethodSyntaxException.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.dynamic; /** diff --git a/src/main/java/com/lambdaworks/redis/dynamic/CommandMethodVerifier.java b/src/main/java/com/lambdaworks/redis/dynamic/CommandMethodVerifier.java index fcf2c8c12e..436e6c76c0 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/CommandMethodVerifier.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/CommandMethodVerifier.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.dynamic; import java.util.ArrayList; diff --git a/src/main/java/com/lambdaworks/redis/dynamic/CommandSegmentCommandFactory.java b/src/main/java/com/lambdaworks/redis/dynamic/CommandSegmentCommandFactory.java index 1ef12a7eab..cbd4cada03 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/CommandSegmentCommandFactory.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/CommandSegmentCommandFactory.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.dynamic; import com.lambdaworks.redis.codec.RedisCodec; diff --git a/src/main/java/com/lambdaworks/redis/dynamic/DefaultMethodParametersAccessor.java b/src/main/java/com/lambdaworks/redis/dynamic/DefaultMethodParametersAccessor.java index 4f1370a502..b96b7a6585 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/DefaultMethodParametersAccessor.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/DefaultMethodParametersAccessor.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.dynamic; import java.util.Arrays; diff --git a/src/main/java/com/lambdaworks/redis/dynamic/DefaultRedisCommandsMetadata.java b/src/main/java/com/lambdaworks/redis/dynamic/DefaultRedisCommandsMetadata.java index 749a245727..4cb1297498 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/DefaultRedisCommandsMetadata.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/DefaultRedisCommandsMetadata.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.dynamic; import java.lang.reflect.Method; diff --git a/src/main/java/com/lambdaworks/redis/dynamic/ParameterBinder.java b/src/main/java/com/lambdaworks/redis/dynamic/ParameterBinder.java index 39ba93b877..11707fa617 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/ParameterBinder.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/ParameterBinder.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.dynamic; import static com.lambdaworks.redis.protocol.CommandKeyword.LIMIT; diff --git a/src/main/java/com/lambdaworks/redis/dynamic/ReactiveCommandSegmentCommandFactory.java b/src/main/java/com/lambdaworks/redis/dynamic/ReactiveCommandSegmentCommandFactory.java index 7935a4783b..3799bd2ca4 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/ReactiveCommandSegmentCommandFactory.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/ReactiveCommandSegmentCommandFactory.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.dynamic; import com.lambdaworks.redis.codec.RedisCodec; diff --git a/src/main/java/com/lambdaworks/redis/dynamic/ReactiveWrappers.java b/src/main/java/com/lambdaworks/redis/dynamic/ReactiveWrappers.java index c8fb206aa7..32abe54f4d 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/ReactiveWrappers.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/ReactiveWrappers.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.dynamic; import java.util.HashSet; diff --git a/src/main/java/com/lambdaworks/redis/dynamic/RedisCommandFactory.java b/src/main/java/com/lambdaworks/redis/dynamic/RedisCommandFactory.java index 74a1a3a8b8..eb83ac3dab 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/RedisCommandFactory.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/RedisCommandFactory.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.dynamic; import java.lang.reflect.Method; diff --git a/src/main/java/com/lambdaworks/redis/dynamic/RedisCommandsMetadata.java b/src/main/java/com/lambdaworks/redis/dynamic/RedisCommandsMetadata.java index abc6ebcb88..a0e02acc19 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/RedisCommandsMetadata.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/RedisCommandsMetadata.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.dynamic; import java.lang.reflect.Method; diff --git a/src/main/java/com/lambdaworks/redis/dynamic/annotation/Command.java b/src/main/java/com/lambdaworks/redis/dynamic/annotation/Command.java index 13a4aba102..1fcb8ee625 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/annotation/Command.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/annotation/Command.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.dynamic.annotation; import com.lambdaworks.redis.dynamic.domain.Timeout; diff --git a/src/main/java/com/lambdaworks/redis/dynamic/annotation/CommandNaming.java b/src/main/java/com/lambdaworks/redis/dynamic/annotation/CommandNaming.java index deaba6de23..cc4d4957d0 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/annotation/CommandNaming.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/annotation/CommandNaming.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.dynamic.annotation; import java.lang.annotation.*; diff --git a/src/main/java/com/lambdaworks/redis/dynamic/annotation/Key.java b/src/main/java/com/lambdaworks/redis/dynamic/annotation/Key.java index 3f2d1bbc47..fdc61163e9 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/annotation/Key.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/annotation/Key.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.dynamic.annotation; import java.lang.annotation.*; diff --git a/src/main/java/com/lambdaworks/redis/dynamic/annotation/Param.java b/src/main/java/com/lambdaworks/redis/dynamic/annotation/Param.java index 1f939dbdef..f52117a6da 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/annotation/Param.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/annotation/Param.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.dynamic.annotation; import java.lang.annotation.*; diff --git a/src/main/java/com/lambdaworks/redis/dynamic/annotation/Value.java b/src/main/java/com/lambdaworks/redis/dynamic/annotation/Value.java index 9eef7135e6..729f125193 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/annotation/Value.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/annotation/Value.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.dynamic.annotation; import java.lang.annotation.*; diff --git a/src/main/java/com/lambdaworks/redis/dynamic/annotation/package-info.java b/src/main/java/com/lambdaworks/redis/dynamic/annotation/package-info.java index 492b5ff59c..00242bde76 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/annotation/package-info.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/annotation/package-info.java @@ -1,4 +1,4 @@ /** * Central domain abstractions to be used in combination with Redis Command interfaces. */ -package com.lambdaworks.redis.dynamic.annotation; \ No newline at end of file +package com.lambdaworks.redis.dynamic.annotation; diff --git a/src/main/java/com/lambdaworks/redis/dynamic/codec/AnnotationRedisCodecResolver.java b/src/main/java/com/lambdaworks/redis/dynamic/codec/AnnotationRedisCodecResolver.java index a8a52f78bc..cc39dc3c7c 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/codec/AnnotationRedisCodecResolver.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/codec/AnnotationRedisCodecResolver.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.dynamic.codec; import java.util.Collections; diff --git a/src/main/java/com/lambdaworks/redis/dynamic/codec/RedisCodecResolver.java b/src/main/java/com/lambdaworks/redis/dynamic/codec/RedisCodecResolver.java index 7b463c71e7..593046455a 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/codec/RedisCodecResolver.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/codec/RedisCodecResolver.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.dynamic.codec; import com.lambdaworks.redis.codec.RedisCodec; diff --git a/src/main/java/com/lambdaworks/redis/dynamic/domain/Timeout.java b/src/main/java/com/lambdaworks/redis/dynamic/domain/Timeout.java index 0c8e6b0b7e..513ae812ca 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/domain/Timeout.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/domain/Timeout.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.dynamic.domain; import java.util.concurrent.TimeUnit; diff --git a/src/main/java/com/lambdaworks/redis/dynamic/domain/package-info.java b/src/main/java/com/lambdaworks/redis/dynamic/domain/package-info.java index 86723bb0a4..66a8ab00ad 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/domain/package-info.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/domain/package-info.java @@ -1,4 +1,4 @@ /** * Core annotations to be used with Redis Command interfaces. */ -package com.lambdaworks.redis.dynamic.domain; \ No newline at end of file +package com.lambdaworks.redis.dynamic.domain; diff --git a/src/main/java/com/lambdaworks/redis/dynamic/intercept/DefaultMethodInvocation.java b/src/main/java/com/lambdaworks/redis/dynamic/intercept/DefaultMethodInvocation.java index 7e474e337b..a7698a3101 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/intercept/DefaultMethodInvocation.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/intercept/DefaultMethodInvocation.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.dynamic.intercept; import java.lang.reflect.Method; diff --git a/src/main/java/com/lambdaworks/redis/dynamic/intercept/InvocationProxyFactory.java b/src/main/java/com/lambdaworks/redis/dynamic/intercept/InvocationProxyFactory.java index 38a81d48bc..62427bd4ac 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/intercept/InvocationProxyFactory.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/intercept/InvocationProxyFactory.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.dynamic.intercept; import java.lang.reflect.Method; diff --git a/src/main/java/com/lambdaworks/redis/dynamic/intercept/MethodInterceptor.java b/src/main/java/com/lambdaworks/redis/dynamic/intercept/MethodInterceptor.java index 79d2aa0e28..b7af3a53ad 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/intercept/MethodInterceptor.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/intercept/MethodInterceptor.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.dynamic.intercept; /** @@ -21,4 +36,4 @@ public interface MethodInterceptor { */ Object invoke(MethodInvocation invocation) throws Throwable; -} \ No newline at end of file +} diff --git a/src/main/java/com/lambdaworks/redis/dynamic/intercept/MethodInvocation.java b/src/main/java/com/lambdaworks/redis/dynamic/intercept/MethodInvocation.java index 62c31e921b..c16b5a9baf 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/intercept/MethodInvocation.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/intercept/MethodInvocation.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.dynamic.intercept; import java.lang.reflect.Method; diff --git a/src/main/java/com/lambdaworks/redis/dynamic/intercept/package-info.java b/src/main/java/com/lambdaworks/redis/dynamic/intercept/package-info.java index e3c1fb4dc6..dfeb3d6fa9 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/intercept/package-info.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/intercept/package-info.java @@ -1,4 +1,4 @@ /** * Invocation proxy support. */ -package com.lambdaworks.redis.dynamic.intercept; \ No newline at end of file +package com.lambdaworks.redis.dynamic.intercept; diff --git a/src/main/java/com/lambdaworks/redis/dynamic/output/CodecAwareOutputFactoryResolver.java b/src/main/java/com/lambdaworks/redis/dynamic/output/CodecAwareOutputFactoryResolver.java index a4cb773f54..96d322686a 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/output/CodecAwareOutputFactoryResolver.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/output/CodecAwareOutputFactoryResolver.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.dynamic.output; import java.util.HashMap; diff --git a/src/main/java/com/lambdaworks/redis/dynamic/output/CommandOutputFactory.java b/src/main/java/com/lambdaworks/redis/dynamic/output/CommandOutputFactory.java index 8c5e015e58..ca6c55ed22 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/output/CommandOutputFactory.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/output/CommandOutputFactory.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.dynamic.output; import com.lambdaworks.redis.codec.RedisCodec; diff --git a/src/main/java/com/lambdaworks/redis/dynamic/output/CommandOutputFactoryResolver.java b/src/main/java/com/lambdaworks/redis/dynamic/output/CommandOutputFactoryResolver.java index b850071cf9..95988051a9 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/output/CommandOutputFactoryResolver.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/output/CommandOutputFactoryResolver.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.dynamic.output; /** diff --git a/src/main/java/com/lambdaworks/redis/dynamic/output/CommandOutputResolverSupport.java b/src/main/java/com/lambdaworks/redis/dynamic/output/CommandOutputResolverSupport.java index e6728b00bb..ac42786ddb 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/output/CommandOutputResolverSupport.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/output/CommandOutputResolverSupport.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.dynamic.output; import com.lambdaworks.redis.dynamic.support.TypeInformation; diff --git a/src/main/java/com/lambdaworks/redis/dynamic/output/OutputRegistry.java b/src/main/java/com/lambdaworks/redis/dynamic/output/OutputRegistry.java index faefd91fa6..9db55512bf 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/output/OutputRegistry.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/output/OutputRegistry.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.dynamic.output; import java.util.*; diff --git a/src/main/java/com/lambdaworks/redis/dynamic/output/OutputRegistryCommandOutputFactoryResolver.java b/src/main/java/com/lambdaworks/redis/dynamic/output/OutputRegistryCommandOutputFactoryResolver.java index a2ebdf79be..eac5f588a0 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/output/OutputRegistryCommandOutputFactoryResolver.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/output/OutputRegistryCommandOutputFactoryResolver.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.dynamic.output; import java.util.Collection; diff --git a/src/main/java/com/lambdaworks/redis/dynamic/output/OutputSelector.java b/src/main/java/com/lambdaworks/redis/dynamic/output/OutputSelector.java index f8847004b1..528a399fdb 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/output/OutputSelector.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/output/OutputSelector.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.dynamic.output; import java.util.Collections; diff --git a/src/main/java/com/lambdaworks/redis/dynamic/output/OutputType.java b/src/main/java/com/lambdaworks/redis/dynamic/output/OutputType.java index c4fc40c650..1a90bb556f 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/output/OutputType.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/output/OutputType.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.dynamic.output; import com.lambdaworks.redis.dynamic.support.TypeInformation; diff --git a/src/main/java/com/lambdaworks/redis/dynamic/output/VoidOutput.java b/src/main/java/com/lambdaworks/redis/dynamic/output/VoidOutput.java index e40365cf0f..6a5049154c 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/output/VoidOutput.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/output/VoidOutput.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.dynamic.output; import java.nio.ByteBuffer; diff --git a/src/main/java/com/lambdaworks/redis/dynamic/output/package-info.java b/src/main/java/com/lambdaworks/redis/dynamic/output/package-info.java index a8cd29d577..e558ad6cbf 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/output/package-info.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/output/package-info.java @@ -1,4 +1,4 @@ /** * {@link com.lambdaworks.redis.output.CommandOutput} resolution support. */ -package com.lambdaworks.redis.dynamic.output; \ No newline at end of file +package com.lambdaworks.redis.dynamic.output; diff --git a/src/main/java/com/lambdaworks/redis/dynamic/package-info.java b/src/main/java/com/lambdaworks/redis/dynamic/package-info.java index 7ffe3d5810..d3d087a524 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/package-info.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/package-info.java @@ -1,4 +1,4 @@ /** * Core package for Redis Command Interface support through {@link com.lambdaworks.redis.dynamic.RedisCommandFactory}. */ -package com.lambdaworks.redis.dynamic; \ No newline at end of file +package com.lambdaworks.redis.dynamic; diff --git a/src/main/java/com/lambdaworks/redis/dynamic/parameter/ExecutionSpecificParameters.java b/src/main/java/com/lambdaworks/redis/dynamic/parameter/ExecutionSpecificParameters.java index 0d005d5c93..9ef1364bfa 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/parameter/ExecutionSpecificParameters.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/parameter/ExecutionSpecificParameters.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.dynamic.parameter; import java.lang.reflect.Method; diff --git a/src/main/java/com/lambdaworks/redis/dynamic/parameter/MethodParametersAccessor.java b/src/main/java/com/lambdaworks/redis/dynamic/parameter/MethodParametersAccessor.java index b6ee14a87b..32ca58b0e4 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/parameter/MethodParametersAccessor.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/parameter/MethodParametersAccessor.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.dynamic.parameter; import java.util.Iterator; diff --git a/src/main/java/com/lambdaworks/redis/dynamic/parameter/Parameter.java b/src/main/java/com/lambdaworks/redis/dynamic/parameter/Parameter.java index 194b2b5079..8a19eda8af 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/parameter/Parameter.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/parameter/Parameter.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.dynamic.parameter; import java.lang.annotation.Annotation; diff --git a/src/main/java/com/lambdaworks/redis/dynamic/parameter/Parameters.java b/src/main/java/com/lambdaworks/redis/dynamic/parameter/Parameters.java index 81d4019462..58e321fadb 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/parameter/Parameters.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/parameter/Parameters.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.dynamic.parameter; import com.lambdaworks.redis.internal.LettuceAssert; diff --git a/src/main/java/com/lambdaworks/redis/dynamic/parameter/package-info.java b/src/main/java/com/lambdaworks/redis/dynamic/parameter/package-info.java index 55df8656d4..4ddb28ac0f 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/parameter/package-info.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/parameter/package-info.java @@ -1,4 +1,4 @@ /** * Parameter access and descriptors. */ -package com.lambdaworks.redis.dynamic.parameter; \ No newline at end of file +package com.lambdaworks.redis.dynamic.parameter; diff --git a/src/main/java/com/lambdaworks/redis/dynamic/segment/AnnotationCommandSegmentFactory.java b/src/main/java/com/lambdaworks/redis/dynamic/segment/AnnotationCommandSegmentFactory.java index fa1dffff20..061252a7cb 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/segment/AnnotationCommandSegmentFactory.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/segment/AnnotationCommandSegmentFactory.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.dynamic.segment; import java.util.ArrayList; diff --git a/src/main/java/com/lambdaworks/redis/dynamic/segment/CommandSegment.java b/src/main/java/com/lambdaworks/redis/dynamic/segment/CommandSegment.java index c2ad12ae70..9559682c62 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/segment/CommandSegment.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/segment/CommandSegment.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.dynamic.segment; import com.lambdaworks.redis.dynamic.parameter.MethodParametersAccessor; diff --git a/src/main/java/com/lambdaworks/redis/dynamic/segment/CommandSegmentFactory.java b/src/main/java/com/lambdaworks/redis/dynamic/segment/CommandSegmentFactory.java index 732f3809eb..2a9dd84b66 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/segment/CommandSegmentFactory.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/segment/CommandSegmentFactory.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.dynamic.segment; import com.lambdaworks.redis.dynamic.CommandMethod; diff --git a/src/main/java/com/lambdaworks/redis/dynamic/segment/CommandSegments.java b/src/main/java/com/lambdaworks/redis/dynamic/segment/CommandSegments.java index f5bb6798e0..2ade7d378d 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/segment/CommandSegments.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/segment/CommandSegments.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.dynamic.segment; import java.util.Collections; diff --git a/src/main/java/com/lambdaworks/redis/dynamic/segment/package-info.java b/src/main/java/com/lambdaworks/redis/dynamic/segment/package-info.java index 10ae382b47..2826cdedf7 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/segment/package-info.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/segment/package-info.java @@ -1,4 +1,4 @@ /** * Support for {@link com.lambdaworks.redis.dynamic.segment.CommandSegments} and segment parsing. */ -package com.lambdaworks.redis.dynamic.segment; \ No newline at end of file +package com.lambdaworks.redis.dynamic.segment; diff --git a/src/main/java/com/lambdaworks/redis/dynamic/support/AnnotationParameterNameDiscoverer.java b/src/main/java/com/lambdaworks/redis/dynamic/support/AnnotationParameterNameDiscoverer.java index 83f02ba428..73a33b5a64 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/support/AnnotationParameterNameDiscoverer.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/support/AnnotationParameterNameDiscoverer.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.dynamic.support; import java.lang.annotation.Annotation; diff --git a/src/main/java/com/lambdaworks/redis/dynamic/support/ClassTypeInformation.java b/src/main/java/com/lambdaworks/redis/dynamic/support/ClassTypeInformation.java index 55a060fcbe..b61bd415db 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/support/ClassTypeInformation.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/support/ClassTypeInformation.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.dynamic.support; import java.lang.ref.Reference; diff --git a/src/main/java/com/lambdaworks/redis/dynamic/support/CompositeParameterNameDiscoverer.java b/src/main/java/com/lambdaworks/redis/dynamic/support/CompositeParameterNameDiscoverer.java index 4cf525d656..4d803c6ec4 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/support/CompositeParameterNameDiscoverer.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/support/CompositeParameterNameDiscoverer.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.dynamic.support; import java.lang.reflect.Constructor; diff --git a/src/main/java/com/lambdaworks/redis/dynamic/support/GenericArrayTypeInformation.java b/src/main/java/com/lambdaworks/redis/dynamic/support/GenericArrayTypeInformation.java index 09f6550496..cc67c7743f 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/support/GenericArrayTypeInformation.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/support/GenericArrayTypeInformation.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.dynamic.support; import java.lang.reflect.Array; diff --git a/src/main/java/com/lambdaworks/redis/dynamic/support/GenericTypeResolver.java b/src/main/java/com/lambdaworks/redis/dynamic/support/GenericTypeResolver.java index 72f755316d..b74e13026a 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/support/GenericTypeResolver.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/support/GenericTypeResolver.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.dynamic.support; import java.lang.reflect.ParameterizedType; diff --git a/src/main/java/com/lambdaworks/redis/dynamic/support/MethodParameter.java b/src/main/java/com/lambdaworks/redis/dynamic/support/MethodParameter.java index a930641538..e93c65c263 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/support/MethodParameter.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/support/MethodParameter.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.dynamic.support; import java.lang.annotation.Annotation; diff --git a/src/main/java/com/lambdaworks/redis/dynamic/support/ParameterNameDiscoverer.java b/src/main/java/com/lambdaworks/redis/dynamic/support/ParameterNameDiscoverer.java index e08bd72840..5794365a3a 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/support/ParameterNameDiscoverer.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/support/ParameterNameDiscoverer.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.dynamic.support; import java.lang.reflect.Constructor; diff --git a/src/main/java/com/lambdaworks/redis/dynamic/support/ParametrizedTypeInformation.java b/src/main/java/com/lambdaworks/redis/dynamic/support/ParametrizedTypeInformation.java index aa410bd455..014cb1dc4a 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/support/ParametrizedTypeInformation.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/support/ParametrizedTypeInformation.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.dynamic.support; import java.lang.reflect.ParameterizedType; diff --git a/src/main/java/com/lambdaworks/redis/dynamic/support/ParentTypeAwareTypeInformation.java b/src/main/java/com/lambdaworks/redis/dynamic/support/ParentTypeAwareTypeInformation.java index cc275b940c..935b5064a2 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/support/ParentTypeAwareTypeInformation.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/support/ParentTypeAwareTypeInformation.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.dynamic.support; import java.lang.reflect.Type; @@ -76,4 +91,4 @@ public int hashCode() { return this.hashCode; } -} \ No newline at end of file +} diff --git a/src/main/java/com/lambdaworks/redis/dynamic/support/ReflectionUtils.java b/src/main/java/com/lambdaworks/redis/dynamic/support/ReflectionUtils.java index 5498d76493..4bcd5a6561 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/support/ReflectionUtils.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/support/ReflectionUtils.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.dynamic.support; import java.lang.reflect.*; diff --git a/src/main/java/com/lambdaworks/redis/dynamic/support/ResolvableType.java b/src/main/java/com/lambdaworks/redis/dynamic/support/ResolvableType.java index f07d27ae1a..cdf77b954e 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/support/ResolvableType.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/support/ResolvableType.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.dynamic.support; import java.io.Serializable; diff --git a/src/main/java/com/lambdaworks/redis/dynamic/support/StandardReflectionParameterNameDiscoverer.java b/src/main/java/com/lambdaworks/redis/dynamic/support/StandardReflectionParameterNameDiscoverer.java index 112f578497..a7c826fa48 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/support/StandardReflectionParameterNameDiscoverer.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/support/StandardReflectionParameterNameDiscoverer.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.dynamic.support; import java.lang.reflect.Constructor; @@ -40,4 +55,4 @@ public String[] getParameterNames(Constructor ctor) { return parameterNames; } -} \ No newline at end of file +} diff --git a/src/main/java/com/lambdaworks/redis/dynamic/support/TypeDiscoverer.java b/src/main/java/com/lambdaworks/redis/dynamic/support/TypeDiscoverer.java index fcd76111ee..d3b16a66e2 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/support/TypeDiscoverer.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/support/TypeDiscoverer.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.dynamic.support; import java.lang.reflect.*; @@ -362,4 +377,4 @@ public Object getSource() { return this.typeVariableMap; } } -} \ No newline at end of file +} diff --git a/src/main/java/com/lambdaworks/redis/dynamic/support/TypeInformation.java b/src/main/java/com/lambdaworks/redis/dynamic/support/TypeInformation.java index 1ac8c6b53d..bd615bd4a5 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/support/TypeInformation.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/support/TypeInformation.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.dynamic.support; import java.lang.reflect.Constructor; @@ -112,4 +127,4 @@ public interface TypeInformation { * @return */ List> getTypeArguments(); -} \ No newline at end of file +} diff --git a/src/main/java/com/lambdaworks/redis/dynamic/support/TypeVariableTypeInformation.java b/src/main/java/com/lambdaworks/redis/dynamic/support/TypeVariableTypeInformation.java index 7d9c1c9623..8d94a71bdd 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/support/TypeVariableTypeInformation.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/support/TypeVariableTypeInformation.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.dynamic.support; import java.lang.reflect.ParameterizedType; diff --git a/src/main/java/com/lambdaworks/redis/dynamic/support/TypeWrapper.java b/src/main/java/com/lambdaworks/redis/dynamic/support/TypeWrapper.java index 7da1badd2b..9e784ab900 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/support/TypeWrapper.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/support/TypeWrapper.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.dynamic.support; import java.io.IOException; diff --git a/src/main/java/com/lambdaworks/redis/dynamic/support/package-info.java b/src/main/java/com/lambdaworks/redis/dynamic/support/package-info.java index 8ae763c2a2..283d71df4b 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/support/package-info.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/support/package-info.java @@ -1,4 +1,4 @@ /** * Support classes imported from the Spring Framework. */ -package com.lambdaworks.redis.dynamic.support; \ No newline at end of file +package com.lambdaworks.redis.dynamic.support; diff --git a/src/main/java/com/lambdaworks/redis/event/DefaultEventBus.java b/src/main/java/com/lambdaworks/redis/event/DefaultEventBus.java index 08dea5b637..a80911706a 100644 --- a/src/main/java/com/lambdaworks/redis/event/DefaultEventBus.java +++ b/src/main/java/com/lambdaworks/redis/event/DefaultEventBus.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.event; import reactor.core.publisher.Flux; diff --git a/src/main/java/com/lambdaworks/redis/event/DefaultEventPublisherOptions.java b/src/main/java/com/lambdaworks/redis/event/DefaultEventPublisherOptions.java index c05ca16c91..2283d574a6 100644 --- a/src/main/java/com/lambdaworks/redis/event/DefaultEventPublisherOptions.java +++ b/src/main/java/com/lambdaworks/redis/event/DefaultEventPublisherOptions.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.event; import java.util.concurrent.TimeUnit; diff --git a/src/main/java/com/lambdaworks/redis/event/Event.java b/src/main/java/com/lambdaworks/redis/event/Event.java index 36ea26332c..c6101cadcc 100644 --- a/src/main/java/com/lambdaworks/redis/event/Event.java +++ b/src/main/java/com/lambdaworks/redis/event/Event.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.event; /** diff --git a/src/main/java/com/lambdaworks/redis/event/EventBus.java b/src/main/java/com/lambdaworks/redis/event/EventBus.java index 7f65d7d0e4..758c8ca44f 100644 --- a/src/main/java/com/lambdaworks/redis/event/EventBus.java +++ b/src/main/java/com/lambdaworks/redis/event/EventBus.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.event; import reactor.core.publisher.Flux; diff --git a/src/main/java/com/lambdaworks/redis/event/EventPublisherOptions.java b/src/main/java/com/lambdaworks/redis/event/EventPublisherOptions.java index 91264e4607..5fbeed4fd7 100644 --- a/src/main/java/com/lambdaworks/redis/event/EventPublisherOptions.java +++ b/src/main/java/com/lambdaworks/redis/event/EventPublisherOptions.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.event; import java.util.concurrent.TimeUnit; diff --git a/src/main/java/com/lambdaworks/redis/event/connection/ConnectedEvent.java b/src/main/java/com/lambdaworks/redis/event/connection/ConnectedEvent.java index dddc33fcd5..4f5644113e 100644 --- a/src/main/java/com/lambdaworks/redis/event/connection/ConnectedEvent.java +++ b/src/main/java/com/lambdaworks/redis/event/connection/ConnectedEvent.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.event.connection; import java.net.SocketAddress; diff --git a/src/main/java/com/lambdaworks/redis/event/connection/ConnectionActivatedEvent.java b/src/main/java/com/lambdaworks/redis/event/connection/ConnectionActivatedEvent.java index 1681e35002..0c67cf0a4f 100644 --- a/src/main/java/com/lambdaworks/redis/event/connection/ConnectionActivatedEvent.java +++ b/src/main/java/com/lambdaworks/redis/event/connection/ConnectionActivatedEvent.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.event.connection; import java.net.SocketAddress; diff --git a/src/main/java/com/lambdaworks/redis/event/connection/ConnectionDeactivatedEvent.java b/src/main/java/com/lambdaworks/redis/event/connection/ConnectionDeactivatedEvent.java index 497f8fe833..17ef1a9bc6 100644 --- a/src/main/java/com/lambdaworks/redis/event/connection/ConnectionDeactivatedEvent.java +++ b/src/main/java/com/lambdaworks/redis/event/connection/ConnectionDeactivatedEvent.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.event.connection; import java.net.SocketAddress; diff --git a/src/main/java/com/lambdaworks/redis/event/connection/ConnectionEvent.java b/src/main/java/com/lambdaworks/redis/event/connection/ConnectionEvent.java index b1205cce95..f8a26c0d53 100644 --- a/src/main/java/com/lambdaworks/redis/event/connection/ConnectionEvent.java +++ b/src/main/java/com/lambdaworks/redis/event/connection/ConnectionEvent.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.event.connection; import com.lambdaworks.redis.ConnectionId; diff --git a/src/main/java/com/lambdaworks/redis/event/connection/ConnectionEventSupport.java b/src/main/java/com/lambdaworks/redis/event/connection/ConnectionEventSupport.java index f07be809e8..1834d8572e 100644 --- a/src/main/java/com/lambdaworks/redis/event/connection/ConnectionEventSupport.java +++ b/src/main/java/com/lambdaworks/redis/event/connection/ConnectionEventSupport.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.event.connection; import java.net.SocketAddress; diff --git a/src/main/java/com/lambdaworks/redis/event/connection/DisconnectedEvent.java b/src/main/java/com/lambdaworks/redis/event/connection/DisconnectedEvent.java index cf4b93cebe..d425ae58de 100644 --- a/src/main/java/com/lambdaworks/redis/event/connection/DisconnectedEvent.java +++ b/src/main/java/com/lambdaworks/redis/event/connection/DisconnectedEvent.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.event.connection; import java.net.SocketAddress; diff --git a/src/main/java/com/lambdaworks/redis/event/metrics/CommandLatencyEvent.java b/src/main/java/com/lambdaworks/redis/event/metrics/CommandLatencyEvent.java index 46494f46b2..68acb8f97b 100644 --- a/src/main/java/com/lambdaworks/redis/event/metrics/CommandLatencyEvent.java +++ b/src/main/java/com/lambdaworks/redis/event/metrics/CommandLatencyEvent.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.event.metrics; import java.util.Map; diff --git a/src/main/java/com/lambdaworks/redis/event/metrics/DefaultCommandLatencyEventPublisher.java b/src/main/java/com/lambdaworks/redis/event/metrics/DefaultCommandLatencyEventPublisher.java index a961508d95..3771565a82 100644 --- a/src/main/java/com/lambdaworks/redis/event/metrics/DefaultCommandLatencyEventPublisher.java +++ b/src/main/java/com/lambdaworks/redis/event/metrics/DefaultCommandLatencyEventPublisher.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.event.metrics; import com.lambdaworks.redis.event.EventBus; diff --git a/src/main/java/com/lambdaworks/redis/event/metrics/MetricEventPublisher.java b/src/main/java/com/lambdaworks/redis/event/metrics/MetricEventPublisher.java index c9f3260e13..2ed948a5f4 100644 --- a/src/main/java/com/lambdaworks/redis/event/metrics/MetricEventPublisher.java +++ b/src/main/java/com/lambdaworks/redis/event/metrics/MetricEventPublisher.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.event.metrics; import com.lambdaworks.redis.event.Event; diff --git a/src/main/java/com/lambdaworks/redis/internal/AbstractInvocationHandler.java b/src/main/java/com/lambdaworks/redis/internal/AbstractInvocationHandler.java index 5c65ee40cf..fb3846e4db 100644 --- a/src/main/java/com/lambdaworks/redis/internal/AbstractInvocationHandler.java +++ b/src/main/java/com/lambdaworks/redis/internal/AbstractInvocationHandler.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.internal; import java.lang.reflect.InvocationHandler; diff --git a/src/main/java/com/lambdaworks/redis/internal/HostAndPort.java b/src/main/java/com/lambdaworks/redis/internal/HostAndPort.java index b5517bc943..d6e2fb0c76 100644 --- a/src/main/java/com/lambdaworks/redis/internal/HostAndPort.java +++ b/src/main/java/com/lambdaworks/redis/internal/HostAndPort.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.internal; import com.lambdaworks.redis.LettuceStrings; diff --git a/src/main/java/com/lambdaworks/redis/internal/LettuceAssert.java b/src/main/java/com/lambdaworks/redis/internal/LettuceAssert.java index ae5c415b71..611a6bf4d1 100644 --- a/src/main/java/com/lambdaworks/redis/internal/LettuceAssert.java +++ b/src/main/java/com/lambdaworks/redis/internal/LettuceAssert.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.internal; import com.lambdaworks.redis.LettuceStrings; diff --git a/src/main/java/com/lambdaworks/redis/internal/LettuceClassUtils.java b/src/main/java/com/lambdaworks/redis/internal/LettuceClassUtils.java index 740775c1f5..80708cca51 100644 --- a/src/main/java/com/lambdaworks/redis/internal/LettuceClassUtils.java +++ b/src/main/java/com/lambdaworks/redis/internal/LettuceClassUtils.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.internal; import java.util.IdentityHashMap; diff --git a/src/main/java/com/lambdaworks/redis/internal/LettuceFactories.java b/src/main/java/com/lambdaworks/redis/internal/LettuceFactories.java index dde084d96d..d8f93dd18a 100644 --- a/src/main/java/com/lambdaworks/redis/internal/LettuceFactories.java +++ b/src/main/java/com/lambdaworks/redis/internal/LettuceFactories.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.internal; import java.util.ArrayDeque; diff --git a/src/main/java/com/lambdaworks/redis/internal/LettuceLists.java b/src/main/java/com/lambdaworks/redis/internal/LettuceLists.java index 36a59e37c1..f66374e8f7 100644 --- a/src/main/java/com/lambdaworks/redis/internal/LettuceLists.java +++ b/src/main/java/com/lambdaworks/redis/internal/LettuceLists.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.internal; import java.util.*; diff --git a/src/main/java/com/lambdaworks/redis/internal/LettuceSets.java b/src/main/java/com/lambdaworks/redis/internal/LettuceSets.java index 1392d6d7b1..2499ab4ecc 100644 --- a/src/main/java/com/lambdaworks/redis/internal/LettuceSets.java +++ b/src/main/java/com/lambdaworks/redis/internal/LettuceSets.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.internal; import java.util.Collection; diff --git a/src/main/java/com/lambdaworks/redis/masterslave/MasterSlave.java b/src/main/java/com/lambdaworks/redis/masterslave/MasterSlave.java index 68c3e81a4d..1357f7102a 100644 --- a/src/main/java/com/lambdaworks/redis/masterslave/MasterSlave.java +++ b/src/main/java/com/lambdaworks/redis/masterslave/MasterSlave.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.masterslave; import java.util.*; diff --git a/src/main/java/com/lambdaworks/redis/masterslave/MasterSlaveChannelWriter.java b/src/main/java/com/lambdaworks/redis/masterslave/MasterSlaveChannelWriter.java index a066bd5c4c..a7adcd5f5f 100644 --- a/src/main/java/com/lambdaworks/redis/masterslave/MasterSlaveChannelWriter.java +++ b/src/main/java/com/lambdaworks/redis/masterslave/MasterSlaveChannelWriter.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.masterslave; import com.lambdaworks.redis.ReadFrom; diff --git a/src/main/java/com/lambdaworks/redis/masterslave/MasterSlaveConnectionProvider.java b/src/main/java/com/lambdaworks/redis/masterslave/MasterSlaveConnectionProvider.java index 478ba20023..887537faf7 100644 --- a/src/main/java/com/lambdaworks/redis/masterslave/MasterSlaveConnectionProvider.java +++ b/src/main/java/com/lambdaworks/redis/masterslave/MasterSlaveConnectionProvider.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.masterslave; import static com.lambdaworks.redis.masterslave.MasterSlaveUtils.findNodeByHostAndPort; diff --git a/src/main/java/com/lambdaworks/redis/masterslave/MasterSlaveTopologyProvider.java b/src/main/java/com/lambdaworks/redis/masterslave/MasterSlaveTopologyProvider.java index 2ed40412cd..cdbc5c9508 100644 --- a/src/main/java/com/lambdaworks/redis/masterslave/MasterSlaveTopologyProvider.java +++ b/src/main/java/com/lambdaworks/redis/masterslave/MasterSlaveTopologyProvider.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.masterslave; import java.util.ArrayList; diff --git a/src/main/java/com/lambdaworks/redis/masterslave/MasterSlaveTopologyRefresh.java b/src/main/java/com/lambdaworks/redis/masterslave/MasterSlaveTopologyRefresh.java index bdd72922ed..860e429771 100644 --- a/src/main/java/com/lambdaworks/redis/masterslave/MasterSlaveTopologyRefresh.java +++ b/src/main/java/com/lambdaworks/redis/masterslave/MasterSlaveTopologyRefresh.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.masterslave; import static com.lambdaworks.redis.masterslave.MasterSlaveUtils.findNodeByUri; diff --git a/src/main/java/com/lambdaworks/redis/masterslave/MasterSlaveUtils.java b/src/main/java/com/lambdaworks/redis/masterslave/MasterSlaveUtils.java index 284340cec5..39004c084c 100644 --- a/src/main/java/com/lambdaworks/redis/masterslave/MasterSlaveUtils.java +++ b/src/main/java/com/lambdaworks/redis/masterslave/MasterSlaveUtils.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.masterslave; import java.util.Collection; diff --git a/src/main/java/com/lambdaworks/redis/masterslave/ReadOnlyCommands.java b/src/main/java/com/lambdaworks/redis/masterslave/ReadOnlyCommands.java index c48043db4c..6df5ed08bf 100644 --- a/src/main/java/com/lambdaworks/redis/masterslave/ReadOnlyCommands.java +++ b/src/main/java/com/lambdaworks/redis/masterslave/ReadOnlyCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.masterslave; import java.util.HashSet; diff --git a/src/main/java/com/lambdaworks/redis/masterslave/RedisMasterSlaveNode.java b/src/main/java/com/lambdaworks/redis/masterslave/RedisMasterSlaveNode.java index c92ab7282e..0bfd9b9fa2 100644 --- a/src/main/java/com/lambdaworks/redis/masterslave/RedisMasterSlaveNode.java +++ b/src/main/java/com/lambdaworks/redis/masterslave/RedisMasterSlaveNode.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.masterslave; import com.lambdaworks.redis.RedisURI; diff --git a/src/main/java/com/lambdaworks/redis/masterslave/SentinelTopologyProvider.java b/src/main/java/com/lambdaworks/redis/masterslave/SentinelTopologyProvider.java index 79ec00c98e..f040ba88ae 100644 --- a/src/main/java/com/lambdaworks/redis/masterslave/SentinelTopologyProvider.java +++ b/src/main/java/com/lambdaworks/redis/masterslave/SentinelTopologyProvider.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.masterslave; import static com.lambdaworks.redis.masterslave.MasterSlaveUtils.CODEC; diff --git a/src/main/java/com/lambdaworks/redis/masterslave/SentinelTopologyRefresh.java b/src/main/java/com/lambdaworks/redis/masterslave/SentinelTopologyRefresh.java index 6070aba35c..2dd728f4c3 100644 --- a/src/main/java/com/lambdaworks/redis/masterslave/SentinelTopologyRefresh.java +++ b/src/main/java/com/lambdaworks/redis/masterslave/SentinelTopologyRefresh.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.masterslave; import java.io.Closeable; diff --git a/src/main/java/com/lambdaworks/redis/masterslave/StatefulRedisMasterSlaveConnection.java b/src/main/java/com/lambdaworks/redis/masterslave/StatefulRedisMasterSlaveConnection.java index 4532e1c143..8b6d2d50f3 100644 --- a/src/main/java/com/lambdaworks/redis/masterslave/StatefulRedisMasterSlaveConnection.java +++ b/src/main/java/com/lambdaworks/redis/masterslave/StatefulRedisMasterSlaveConnection.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.masterslave; import com.lambdaworks.redis.ReadFrom; diff --git a/src/main/java/com/lambdaworks/redis/masterslave/StatefulRedisMasterSlaveConnectionImpl.java b/src/main/java/com/lambdaworks/redis/masterslave/StatefulRedisMasterSlaveConnectionImpl.java index 9eb9823641..04cca47e98 100644 --- a/src/main/java/com/lambdaworks/redis/masterslave/StatefulRedisMasterSlaveConnectionImpl.java +++ b/src/main/java/com/lambdaworks/redis/masterslave/StatefulRedisMasterSlaveConnectionImpl.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.masterslave; import java.util.concurrent.TimeUnit; diff --git a/src/main/java/com/lambdaworks/redis/masterslave/StaticMasterSlaveTopologyProvider.java b/src/main/java/com/lambdaworks/redis/masterslave/StaticMasterSlaveTopologyProvider.java index 010d959f34..93e6085311 100644 --- a/src/main/java/com/lambdaworks/redis/masterslave/StaticMasterSlaveTopologyProvider.java +++ b/src/main/java/com/lambdaworks/redis/masterslave/StaticMasterSlaveTopologyProvider.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.masterslave; import java.util.*; diff --git a/src/main/java/com/lambdaworks/redis/masterslave/Timeout.java b/src/main/java/com/lambdaworks/redis/masterslave/Timeout.java index b8c37cbfb7..6cad33ddea 100644 --- a/src/main/java/com/lambdaworks/redis/masterslave/Timeout.java +++ b/src/main/java/com/lambdaworks/redis/masterslave/Timeout.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.masterslave; import java.util.concurrent.TimeUnit; diff --git a/src/main/java/com/lambdaworks/redis/masterslave/TopologyProvider.java b/src/main/java/com/lambdaworks/redis/masterslave/TopologyProvider.java index dd354647e2..7711e382d9 100644 --- a/src/main/java/com/lambdaworks/redis/masterslave/TopologyProvider.java +++ b/src/main/java/com/lambdaworks/redis/masterslave/TopologyProvider.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.masterslave; import java.util.List; diff --git a/src/main/java/com/lambdaworks/redis/metrics/CommandLatencyCollector.java b/src/main/java/com/lambdaworks/redis/metrics/CommandLatencyCollector.java index f3de206bc4..c4761a89b3 100644 --- a/src/main/java/com/lambdaworks/redis/metrics/CommandLatencyCollector.java +++ b/src/main/java/com/lambdaworks/redis/metrics/CommandLatencyCollector.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.metrics; import java.net.SocketAddress; diff --git a/src/main/java/com/lambdaworks/redis/metrics/CommandLatencyCollectorOptions.java b/src/main/java/com/lambdaworks/redis/metrics/CommandLatencyCollectorOptions.java index 8c3c4cd1ab..5f88d11b6d 100644 --- a/src/main/java/com/lambdaworks/redis/metrics/CommandLatencyCollectorOptions.java +++ b/src/main/java/com/lambdaworks/redis/metrics/CommandLatencyCollectorOptions.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.metrics; import java.util.concurrent.TimeUnit; diff --git a/src/main/java/com/lambdaworks/redis/metrics/CommandLatencyId.java b/src/main/java/com/lambdaworks/redis/metrics/CommandLatencyId.java index a468385d3a..a2016c87aa 100644 --- a/src/main/java/com/lambdaworks/redis/metrics/CommandLatencyId.java +++ b/src/main/java/com/lambdaworks/redis/metrics/CommandLatencyId.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.metrics; import java.io.Serializable; diff --git a/src/main/java/com/lambdaworks/redis/metrics/CommandMetrics.java b/src/main/java/com/lambdaworks/redis/metrics/CommandMetrics.java index 49c0f67667..f8747c906c 100644 --- a/src/main/java/com/lambdaworks/redis/metrics/CommandMetrics.java +++ b/src/main/java/com/lambdaworks/redis/metrics/CommandMetrics.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.metrics; import java.util.Map; diff --git a/src/main/java/com/lambdaworks/redis/metrics/DefaultCommandLatencyCollector.java b/src/main/java/com/lambdaworks/redis/metrics/DefaultCommandLatencyCollector.java index 986104373d..46d07a7e90 100644 --- a/src/main/java/com/lambdaworks/redis/metrics/DefaultCommandLatencyCollector.java +++ b/src/main/java/com/lambdaworks/redis/metrics/DefaultCommandLatencyCollector.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.metrics; import com.lambdaworks.redis.metrics.CommandMetrics.CommandLatency; diff --git a/src/main/java/com/lambdaworks/redis/metrics/DefaultCommandLatencyCollectorOptions.java b/src/main/java/com/lambdaworks/redis/metrics/DefaultCommandLatencyCollectorOptions.java index 6723979266..8a56a323d1 100644 --- a/src/main/java/com/lambdaworks/redis/metrics/DefaultCommandLatencyCollectorOptions.java +++ b/src/main/java/com/lambdaworks/redis/metrics/DefaultCommandLatencyCollectorOptions.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.metrics; import java.util.concurrent.TimeUnit; diff --git a/src/main/java/com/lambdaworks/redis/metrics/MetricCollector.java b/src/main/java/com/lambdaworks/redis/metrics/MetricCollector.java index 5dc2147b74..4fde596c65 100644 --- a/src/main/java/com/lambdaworks/redis/metrics/MetricCollector.java +++ b/src/main/java/com/lambdaworks/redis/metrics/MetricCollector.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.metrics; /** diff --git a/src/main/java/com/lambdaworks/redis/models/command/CommandDetail.java b/src/main/java/com/lambdaworks/redis/models/command/CommandDetail.java index ee09ba3be7..215764ca77 100644 --- a/src/main/java/com/lambdaworks/redis/models/command/CommandDetail.java +++ b/src/main/java/com/lambdaworks/redis/models/command/CommandDetail.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.models.command; import java.io.Serializable; diff --git a/src/main/java/com/lambdaworks/redis/models/command/CommandDetailParser.java b/src/main/java/com/lambdaworks/redis/models/command/CommandDetailParser.java index acc4b30515..7689b996b1 100644 --- a/src/main/java/com/lambdaworks/redis/models/command/CommandDetailParser.java +++ b/src/main/java/com/lambdaworks/redis/models/command/CommandDetailParser.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.models.command; import java.util.*; diff --git a/src/main/java/com/lambdaworks/redis/models/command/package-info.java b/src/main/java/com/lambdaworks/redis/models/command/package-info.java index 005f9672b7..d4dacfe222 100644 --- a/src/main/java/com/lambdaworks/redis/models/command/package-info.java +++ b/src/main/java/com/lambdaworks/redis/models/command/package-info.java @@ -1,4 +1,4 @@ /** * Model and parser to for the {@code COMMAND} and {@code COMMAND INFO} output. */ -package com.lambdaworks.redis.models.command; \ No newline at end of file +package com.lambdaworks.redis.models.command; diff --git a/src/main/java/com/lambdaworks/redis/models/role/RedisInstance.java b/src/main/java/com/lambdaworks/redis/models/role/RedisInstance.java index 9f0350037f..0fa1dad871 100644 --- a/src/main/java/com/lambdaworks/redis/models/role/RedisInstance.java +++ b/src/main/java/com/lambdaworks/redis/models/role/RedisInstance.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.models.role; /** diff --git a/src/main/java/com/lambdaworks/redis/models/role/RedisMasterInstance.java b/src/main/java/com/lambdaworks/redis/models/role/RedisMasterInstance.java index 7cf17e9a68..f9d51f709b 100644 --- a/src/main/java/com/lambdaworks/redis/models/role/RedisMasterInstance.java +++ b/src/main/java/com/lambdaworks/redis/models/role/RedisMasterInstance.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.models.role; import java.io.Serializable; diff --git a/src/main/java/com/lambdaworks/redis/models/role/RedisNodeDescription.java b/src/main/java/com/lambdaworks/redis/models/role/RedisNodeDescription.java index 2115a47646..c224aaf64e 100644 --- a/src/main/java/com/lambdaworks/redis/models/role/RedisNodeDescription.java +++ b/src/main/java/com/lambdaworks/redis/models/role/RedisNodeDescription.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.models.role; import com.lambdaworks.redis.RedisURI; diff --git a/src/main/java/com/lambdaworks/redis/models/role/RedisSentinelInstance.java b/src/main/java/com/lambdaworks/redis/models/role/RedisSentinelInstance.java index 9ecb882924..c596d89c53 100644 --- a/src/main/java/com/lambdaworks/redis/models/role/RedisSentinelInstance.java +++ b/src/main/java/com/lambdaworks/redis/models/role/RedisSentinelInstance.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.models.role; import java.io.Serializable; diff --git a/src/main/java/com/lambdaworks/redis/models/role/RedisSlaveInstance.java b/src/main/java/com/lambdaworks/redis/models/role/RedisSlaveInstance.java index 8b25f9a9f2..854cb579ff 100644 --- a/src/main/java/com/lambdaworks/redis/models/role/RedisSlaveInstance.java +++ b/src/main/java/com/lambdaworks/redis/models/role/RedisSlaveInstance.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.models.role; import java.io.Serializable; diff --git a/src/main/java/com/lambdaworks/redis/models/role/ReplicationPartner.java b/src/main/java/com/lambdaworks/redis/models/role/ReplicationPartner.java index aa7f7cad76..524b3cdf41 100644 --- a/src/main/java/com/lambdaworks/redis/models/role/ReplicationPartner.java +++ b/src/main/java/com/lambdaworks/redis/models/role/ReplicationPartner.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.models.role; import java.io.Serializable; diff --git a/src/main/java/com/lambdaworks/redis/models/role/RoleParser.java b/src/main/java/com/lambdaworks/redis/models/role/RoleParser.java index 0f14b00a8a..34e8ac7d81 100644 --- a/src/main/java/com/lambdaworks/redis/models/role/RoleParser.java +++ b/src/main/java/com/lambdaworks/redis/models/role/RoleParser.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.models.role; import java.util.*; diff --git a/src/main/java/com/lambdaworks/redis/models/role/package-info.java b/src/main/java/com/lambdaworks/redis/models/role/package-info.java index b833561008..884e807c15 100644 --- a/src/main/java/com/lambdaworks/redis/models/role/package-info.java +++ b/src/main/java/com/lambdaworks/redis/models/role/package-info.java @@ -1,4 +1,4 @@ /** * Model and parser for the {@code ROLE} output. */ -package com.lambdaworks.redis.models.role; \ No newline at end of file +package com.lambdaworks.redis.models.role; diff --git a/src/main/java/com/lambdaworks/redis/output/ArrayOutput.java b/src/main/java/com/lambdaworks/redis/output/ArrayOutput.java index 19957b2cc5..9f0b91d053 100644 --- a/src/main/java/com/lambdaworks/redis/output/ArrayOutput.java +++ b/src/main/java/com/lambdaworks/redis/output/ArrayOutput.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.output; import java.nio.ByteBuffer; diff --git a/src/main/java/com/lambdaworks/redis/output/BooleanListOutput.java b/src/main/java/com/lambdaworks/redis/output/BooleanListOutput.java index 8c33bd01df..b95fa2e3fa 100644 --- a/src/main/java/com/lambdaworks/redis/output/BooleanListOutput.java +++ b/src/main/java/com/lambdaworks/redis/output/BooleanListOutput.java @@ -1,5 +1,18 @@ -// Copyright (C) 2011 - Will Glozer. All rights reserved. - +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.output; import java.util.ArrayList; @@ -11,9 +24,9 @@ /** * {@link java.util.List} of boolean output. * - * @author Will Glozer * @param Key type. * @param Value type. + * @author Will Glozer */ public class BooleanListOutput extends CommandOutput> implements StreamingOutput { diff --git a/src/main/java/com/lambdaworks/redis/output/BooleanOutput.java b/src/main/java/com/lambdaworks/redis/output/BooleanOutput.java index 42dd2ed102..4a06f52b4e 100644 --- a/src/main/java/com/lambdaworks/redis/output/BooleanOutput.java +++ b/src/main/java/com/lambdaworks/redis/output/BooleanOutput.java @@ -1,5 +1,18 @@ -// Copyright (C) 2011 - Will Glozer. All rights reserved. - +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.output; import java.nio.ByteBuffer; diff --git a/src/main/java/com/lambdaworks/redis/output/ByteArrayOutput.java b/src/main/java/com/lambdaworks/redis/output/ByteArrayOutput.java index 02d9727537..3351d44968 100644 --- a/src/main/java/com/lambdaworks/redis/output/ByteArrayOutput.java +++ b/src/main/java/com/lambdaworks/redis/output/ByteArrayOutput.java @@ -1,5 +1,18 @@ -// Copyright (C) 2012 - Will Glozer. All rights reserved. - +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.output; import java.nio.ByteBuffer; diff --git a/src/main/java/com/lambdaworks/redis/output/CommandOutput.java b/src/main/java/com/lambdaworks/redis/output/CommandOutput.java index 46902888b0..a78970aff2 100644 --- a/src/main/java/com/lambdaworks/redis/output/CommandOutput.java +++ b/src/main/java/com/lambdaworks/redis/output/CommandOutput.java @@ -1,5 +1,18 @@ -// Copyright (C) 2011 - Will Glozer. All rights reserved. - +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.output; import java.nio.ByteBuffer; @@ -13,10 +26,10 @@ * @param Key type. * @param Value type. * @param Output type. - * * @author Will Glozer */ public abstract class CommandOutput { + protected final RedisCodec codec; protected T output; protected String error; diff --git a/src/main/java/com/lambdaworks/redis/output/DateOutput.java b/src/main/java/com/lambdaworks/redis/output/DateOutput.java index 11c522f9b4..ae9403da62 100644 --- a/src/main/java/com/lambdaworks/redis/output/DateOutput.java +++ b/src/main/java/com/lambdaworks/redis/output/DateOutput.java @@ -1,5 +1,18 @@ -// Copyright (C) 2011 - Will Glozer. All rights reserved. - +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.output; import java.util.Date; diff --git a/src/main/java/com/lambdaworks/redis/output/DefaultTransactionResult.java b/src/main/java/com/lambdaworks/redis/output/DefaultTransactionResult.java index 10408b5965..78c14fd7a8 100644 --- a/src/main/java/com/lambdaworks/redis/output/DefaultTransactionResult.java +++ b/src/main/java/com/lambdaworks/redis/output/DefaultTransactionResult.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.output; import java.util.Iterator; diff --git a/src/main/java/com/lambdaworks/redis/output/DoubleOutput.java b/src/main/java/com/lambdaworks/redis/output/DoubleOutput.java index e108d21ebf..b30b3ab642 100644 --- a/src/main/java/com/lambdaworks/redis/output/DoubleOutput.java +++ b/src/main/java/com/lambdaworks/redis/output/DoubleOutput.java @@ -1,5 +1,18 @@ -// Copyright (C) 2011 - Will Glozer. All rights reserved. - +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.output; import java.nio.ByteBuffer; diff --git a/src/main/java/com/lambdaworks/redis/output/GeoCoordinatesListOutput.java b/src/main/java/com/lambdaworks/redis/output/GeoCoordinatesListOutput.java index c080f63555..dcb175549b 100644 --- a/src/main/java/com/lambdaworks/redis/output/GeoCoordinatesListOutput.java +++ b/src/main/java/com/lambdaworks/redis/output/GeoCoordinatesListOutput.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.output; import static java.lang.Double.parseDouble; diff --git a/src/main/java/com/lambdaworks/redis/output/GeoCoordinatesValueListOutput.java b/src/main/java/com/lambdaworks/redis/output/GeoCoordinatesValueListOutput.java index 66beae9741..bd36d82441 100644 --- a/src/main/java/com/lambdaworks/redis/output/GeoCoordinatesValueListOutput.java +++ b/src/main/java/com/lambdaworks/redis/output/GeoCoordinatesValueListOutput.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.output; import static java.lang.Double.parseDouble; diff --git a/src/main/java/com/lambdaworks/redis/output/GeoWithinListOutput.java b/src/main/java/com/lambdaworks/redis/output/GeoWithinListOutput.java index ea9100ac51..f6c1f24caa 100644 --- a/src/main/java/com/lambdaworks/redis/output/GeoWithinListOutput.java +++ b/src/main/java/com/lambdaworks/redis/output/GeoWithinListOutput.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.output; import static java.lang.Double.parseDouble; diff --git a/src/main/java/com/lambdaworks/redis/output/IntegerOutput.java b/src/main/java/com/lambdaworks/redis/output/IntegerOutput.java index 6ccd94b9e7..612cb35104 100644 --- a/src/main/java/com/lambdaworks/redis/output/IntegerOutput.java +++ b/src/main/java/com/lambdaworks/redis/output/IntegerOutput.java @@ -1,5 +1,18 @@ -// Copyright (C) 2011 - Will Glozer. All rights reserved. - +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.output; import java.nio.ByteBuffer; diff --git a/src/main/java/com/lambdaworks/redis/output/KeyListOutput.java b/src/main/java/com/lambdaworks/redis/output/KeyListOutput.java index e74757bd02..bc3d03347e 100644 --- a/src/main/java/com/lambdaworks/redis/output/KeyListOutput.java +++ b/src/main/java/com/lambdaworks/redis/output/KeyListOutput.java @@ -1,5 +1,18 @@ -// Copyright (C) 2011 - Will Glozer. All rights reserved. - +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.output; import java.nio.ByteBuffer; diff --git a/src/main/java/com/lambdaworks/redis/output/KeyOutput.java b/src/main/java/com/lambdaworks/redis/output/KeyOutput.java index e0906c3f50..866a99ecce 100644 --- a/src/main/java/com/lambdaworks/redis/output/KeyOutput.java +++ b/src/main/java/com/lambdaworks/redis/output/KeyOutput.java @@ -1,5 +1,18 @@ -// Copyright (C) 2013 - Will Glozer. All rights reserved. - +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.output; import java.nio.ByteBuffer; diff --git a/src/main/java/com/lambdaworks/redis/output/KeyScanOutput.java b/src/main/java/com/lambdaworks/redis/output/KeyScanOutput.java index b8f7ca9672..022e51c86f 100644 --- a/src/main/java/com/lambdaworks/redis/output/KeyScanOutput.java +++ b/src/main/java/com/lambdaworks/redis/output/KeyScanOutput.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.output; import java.nio.ByteBuffer; diff --git a/src/main/java/com/lambdaworks/redis/output/KeyScanStreamingOutput.java b/src/main/java/com/lambdaworks/redis/output/KeyScanStreamingOutput.java index 61f5a2f167..3d3316ddc1 100644 --- a/src/main/java/com/lambdaworks/redis/output/KeyScanStreamingOutput.java +++ b/src/main/java/com/lambdaworks/redis/output/KeyScanStreamingOutput.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.output; import java.nio.ByteBuffer; diff --git a/src/main/java/com/lambdaworks/redis/output/KeyStreamingChannel.java b/src/main/java/com/lambdaworks/redis/output/KeyStreamingChannel.java index bf97f8ff6b..418b866185 100644 --- a/src/main/java/com/lambdaworks/redis/output/KeyStreamingChannel.java +++ b/src/main/java/com/lambdaworks/redis/output/KeyStreamingChannel.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.output; /** diff --git a/src/main/java/com/lambdaworks/redis/output/KeyStreamingOutput.java b/src/main/java/com/lambdaworks/redis/output/KeyStreamingOutput.java index b24a34d462..9837f4a0e8 100644 --- a/src/main/java/com/lambdaworks/redis/output/KeyStreamingOutput.java +++ b/src/main/java/com/lambdaworks/redis/output/KeyStreamingOutput.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.output; import java.nio.ByteBuffer; diff --git a/src/main/java/com/lambdaworks/redis/output/KeyValueListOutput.java b/src/main/java/com/lambdaworks/redis/output/KeyValueListOutput.java index 2da58e2714..04edc56cd0 100644 --- a/src/main/java/com/lambdaworks/redis/output/KeyValueListOutput.java +++ b/src/main/java/com/lambdaworks/redis/output/KeyValueListOutput.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.output; import java.nio.ByteBuffer; diff --git a/src/main/java/com/lambdaworks/redis/output/KeyValueOutput.java b/src/main/java/com/lambdaworks/redis/output/KeyValueOutput.java index b3519b9c48..0222f2b1da 100644 --- a/src/main/java/com/lambdaworks/redis/output/KeyValueOutput.java +++ b/src/main/java/com/lambdaworks/redis/output/KeyValueOutput.java @@ -1,5 +1,18 @@ -// Copyright (C) 2011 - Will Glozer. All rights reserved. - +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.output; import com.lambdaworks.redis.KeyValue; diff --git a/src/main/java/com/lambdaworks/redis/output/KeyValueScanStreamingOutput.java b/src/main/java/com/lambdaworks/redis/output/KeyValueScanStreamingOutput.java index 3f73e3721e..019cd9473d 100644 --- a/src/main/java/com/lambdaworks/redis/output/KeyValueScanStreamingOutput.java +++ b/src/main/java/com/lambdaworks/redis/output/KeyValueScanStreamingOutput.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.output; import java.nio.ByteBuffer; diff --git a/src/main/java/com/lambdaworks/redis/output/KeyValueStreamingChannel.java b/src/main/java/com/lambdaworks/redis/output/KeyValueStreamingChannel.java index 73ab97729b..94370bd48e 100644 --- a/src/main/java/com/lambdaworks/redis/output/KeyValueStreamingChannel.java +++ b/src/main/java/com/lambdaworks/redis/output/KeyValueStreamingChannel.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.output; /** diff --git a/src/main/java/com/lambdaworks/redis/output/KeyValueStreamingOutput.java b/src/main/java/com/lambdaworks/redis/output/KeyValueStreamingOutput.java index 567b84e8de..366ce5cdb3 100644 --- a/src/main/java/com/lambdaworks/redis/output/KeyValueStreamingOutput.java +++ b/src/main/java/com/lambdaworks/redis/output/KeyValueStreamingOutput.java @@ -1,5 +1,18 @@ -// Copyright (C) 2011 - Will Glozer. All rights reserved. - +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.output; import java.nio.ByteBuffer; diff --git a/src/main/java/com/lambdaworks/redis/output/ListOfMapsOutput.java b/src/main/java/com/lambdaworks/redis/output/ListOfMapsOutput.java index 214164a420..ce021060cf 100644 --- a/src/main/java/com/lambdaworks/redis/output/ListOfMapsOutput.java +++ b/src/main/java/com/lambdaworks/redis/output/ListOfMapsOutput.java @@ -1,5 +1,18 @@ -// Copyright (C) 2011 - Will Glozer. All rights reserved. - +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.output; import java.nio.ByteBuffer; diff --git a/src/main/java/com/lambdaworks/redis/output/ListSubscriber.java b/src/main/java/com/lambdaworks/redis/output/ListSubscriber.java index 6dbd8fea1f..b2a54d40d4 100644 --- a/src/main/java/com/lambdaworks/redis/output/ListSubscriber.java +++ b/src/main/java/com/lambdaworks/redis/output/ListSubscriber.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.output; import java.util.List; diff --git a/src/main/java/com/lambdaworks/redis/output/MapOutput.java b/src/main/java/com/lambdaworks/redis/output/MapOutput.java index 781871ed23..5344c5bc52 100644 --- a/src/main/java/com/lambdaworks/redis/output/MapOutput.java +++ b/src/main/java/com/lambdaworks/redis/output/MapOutput.java @@ -1,5 +1,18 @@ -// Copyright (C) 2011 - Will Glozer. All rights reserved. - +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.output; import java.nio.ByteBuffer; diff --git a/src/main/java/com/lambdaworks/redis/output/MapScanOutput.java b/src/main/java/com/lambdaworks/redis/output/MapScanOutput.java index 45a440f8ab..1844e2d827 100644 --- a/src/main/java/com/lambdaworks/redis/output/MapScanOutput.java +++ b/src/main/java/com/lambdaworks/redis/output/MapScanOutput.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.output; import java.nio.ByteBuffer; diff --git a/src/main/java/com/lambdaworks/redis/output/MultiOutput.java b/src/main/java/com/lambdaworks/redis/output/MultiOutput.java index 728005da56..3cdfd0100e 100644 --- a/src/main/java/com/lambdaworks/redis/output/MultiOutput.java +++ b/src/main/java/com/lambdaworks/redis/output/MultiOutput.java @@ -1,5 +1,18 @@ -// Copyright (C) 2011 - Will Glozer. All rights reserved. - +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.output; import java.nio.ByteBuffer; diff --git a/src/main/java/com/lambdaworks/redis/output/NestedMultiOutput.java b/src/main/java/com/lambdaworks/redis/output/NestedMultiOutput.java index 7f8b725c10..d72a2bc399 100644 --- a/src/main/java/com/lambdaworks/redis/output/NestedMultiOutput.java +++ b/src/main/java/com/lambdaworks/redis/output/NestedMultiOutput.java @@ -1,5 +1,18 @@ -// Copyright (C) 2011 - Will Glozer. All rights reserved. - +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.output; import java.nio.ByteBuffer; diff --git a/src/main/java/com/lambdaworks/redis/output/ScanOutput.java b/src/main/java/com/lambdaworks/redis/output/ScanOutput.java index 975c6f4bf6..5b38f8da5d 100644 --- a/src/main/java/com/lambdaworks/redis/output/ScanOutput.java +++ b/src/main/java/com/lambdaworks/redis/output/ScanOutput.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.output; import java.nio.ByteBuffer; diff --git a/src/main/java/com/lambdaworks/redis/output/ScoredValueListOutput.java b/src/main/java/com/lambdaworks/redis/output/ScoredValueListOutput.java index 26ee186a43..2d30b990e4 100644 --- a/src/main/java/com/lambdaworks/redis/output/ScoredValueListOutput.java +++ b/src/main/java/com/lambdaworks/redis/output/ScoredValueListOutput.java @@ -1,5 +1,18 @@ -// Copyright (C) 2011 - Will Glozer. All rights reserved. - +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.output; import java.nio.ByteBuffer; @@ -15,7 +28,6 @@ * * @param Key type. * @param Value type. - * * @author Will Glozer */ public class ScoredValueListOutput extends CommandOutput>> diff --git a/src/main/java/com/lambdaworks/redis/output/ScoredValueScanOutput.java b/src/main/java/com/lambdaworks/redis/output/ScoredValueScanOutput.java index bb59960891..87ea706fed 100644 --- a/src/main/java/com/lambdaworks/redis/output/ScoredValueScanOutput.java +++ b/src/main/java/com/lambdaworks/redis/output/ScoredValueScanOutput.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.output; import java.nio.ByteBuffer; diff --git a/src/main/java/com/lambdaworks/redis/output/ScoredValueScanStreamingOutput.java b/src/main/java/com/lambdaworks/redis/output/ScoredValueScanStreamingOutput.java index 571284884a..11e5174b10 100644 --- a/src/main/java/com/lambdaworks/redis/output/ScoredValueScanStreamingOutput.java +++ b/src/main/java/com/lambdaworks/redis/output/ScoredValueScanStreamingOutput.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.output; import java.nio.ByteBuffer; diff --git a/src/main/java/com/lambdaworks/redis/output/ScoredValueStreamingChannel.java b/src/main/java/com/lambdaworks/redis/output/ScoredValueStreamingChannel.java index ba7db3c2ba..33eaa2b3c1 100644 --- a/src/main/java/com/lambdaworks/redis/output/ScoredValueStreamingChannel.java +++ b/src/main/java/com/lambdaworks/redis/output/ScoredValueStreamingChannel.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.output; import com.lambdaworks.redis.ScoredValue; diff --git a/src/main/java/com/lambdaworks/redis/output/ScoredValueStreamingOutput.java b/src/main/java/com/lambdaworks/redis/output/ScoredValueStreamingOutput.java index 90ac7cca3f..782b0987de 100644 --- a/src/main/java/com/lambdaworks/redis/output/ScoredValueStreamingOutput.java +++ b/src/main/java/com/lambdaworks/redis/output/ScoredValueStreamingOutput.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.output; import java.nio.ByteBuffer; diff --git a/src/main/java/com/lambdaworks/redis/output/StatusOutput.java b/src/main/java/com/lambdaworks/redis/output/StatusOutput.java index 39046a018c..32d52e27a1 100644 --- a/src/main/java/com/lambdaworks/redis/output/StatusOutput.java +++ b/src/main/java/com/lambdaworks/redis/output/StatusOutput.java @@ -1,5 +1,18 @@ -// Copyright (C) 2011 - Will Glozer. All rights reserved. - +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.output; import java.nio.ByteBuffer; diff --git a/src/main/java/com/lambdaworks/redis/output/StreamingChannel.java b/src/main/java/com/lambdaworks/redis/output/StreamingChannel.java index 91aca606b9..2fc0bbe3c9 100644 --- a/src/main/java/com/lambdaworks/redis/output/StreamingChannel.java +++ b/src/main/java/com/lambdaworks/redis/output/StreamingChannel.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.output; /** diff --git a/src/main/java/com/lambdaworks/redis/output/StreamingOutput.java b/src/main/java/com/lambdaworks/redis/output/StreamingOutput.java index 4b84752f2b..0849803bfb 100644 --- a/src/main/java/com/lambdaworks/redis/output/StreamingOutput.java +++ b/src/main/java/com/lambdaworks/redis/output/StreamingOutput.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.output; /** diff --git a/src/main/java/com/lambdaworks/redis/output/StringListOutput.java b/src/main/java/com/lambdaworks/redis/output/StringListOutput.java index c1fef0a6f1..206d45a930 100644 --- a/src/main/java/com/lambdaworks/redis/output/StringListOutput.java +++ b/src/main/java/com/lambdaworks/redis/output/StringListOutput.java @@ -1,5 +1,18 @@ -// Copyright (C) 2011 - Will Glozer. All rights reserved. - +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.output; import java.nio.ByteBuffer; diff --git a/src/main/java/com/lambdaworks/redis/output/StringValueListOutput.java b/src/main/java/com/lambdaworks/redis/output/StringValueListOutput.java index 14b18755f0..7a669dabfa 100644 --- a/src/main/java/com/lambdaworks/redis/output/StringValueListOutput.java +++ b/src/main/java/com/lambdaworks/redis/output/StringValueListOutput.java @@ -1,5 +1,18 @@ -// Copyright (C) 2011 - Will Glozer. All rights reserved. - +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.output; import java.nio.ByteBuffer; diff --git a/src/main/java/com/lambdaworks/redis/output/ValueListOutput.java b/src/main/java/com/lambdaworks/redis/output/ValueListOutput.java index a22e0b129d..5a3a302a83 100644 --- a/src/main/java/com/lambdaworks/redis/output/ValueListOutput.java +++ b/src/main/java/com/lambdaworks/redis/output/ValueListOutput.java @@ -1,5 +1,18 @@ -// Copyright (C) 2011 - Will Glozer. All rights reserved. - +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.output; import java.nio.ByteBuffer; diff --git a/src/main/java/com/lambdaworks/redis/output/ValueOutput.java b/src/main/java/com/lambdaworks/redis/output/ValueOutput.java index b250ce6e95..d8ee0bdc44 100644 --- a/src/main/java/com/lambdaworks/redis/output/ValueOutput.java +++ b/src/main/java/com/lambdaworks/redis/output/ValueOutput.java @@ -1,5 +1,18 @@ -// Copyright (C) 2011 - Will Glozer. All rights reserved. - +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.output; import java.nio.ByteBuffer; diff --git a/src/main/java/com/lambdaworks/redis/output/ValueScanOutput.java b/src/main/java/com/lambdaworks/redis/output/ValueScanOutput.java index 1a7e976682..eabfeb2ae8 100644 --- a/src/main/java/com/lambdaworks/redis/output/ValueScanOutput.java +++ b/src/main/java/com/lambdaworks/redis/output/ValueScanOutput.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.output; import java.nio.ByteBuffer; diff --git a/src/main/java/com/lambdaworks/redis/output/ValueScanStreamingOutput.java b/src/main/java/com/lambdaworks/redis/output/ValueScanStreamingOutput.java index e3415fa530..4abc1feda2 100644 --- a/src/main/java/com/lambdaworks/redis/output/ValueScanStreamingOutput.java +++ b/src/main/java/com/lambdaworks/redis/output/ValueScanStreamingOutput.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.output; import java.nio.ByteBuffer; diff --git a/src/main/java/com/lambdaworks/redis/output/ValueSetOutput.java b/src/main/java/com/lambdaworks/redis/output/ValueSetOutput.java index 92afce5cc1..2870303e50 100644 --- a/src/main/java/com/lambdaworks/redis/output/ValueSetOutput.java +++ b/src/main/java/com/lambdaworks/redis/output/ValueSetOutput.java @@ -1,5 +1,18 @@ -// Copyright (C) 2011 - Will Glozer. All rights reserved. - +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.output; import java.nio.ByteBuffer; diff --git a/src/main/java/com/lambdaworks/redis/output/ValueStreamingChannel.java b/src/main/java/com/lambdaworks/redis/output/ValueStreamingChannel.java index 0ce8633de7..e90e5db115 100644 --- a/src/main/java/com/lambdaworks/redis/output/ValueStreamingChannel.java +++ b/src/main/java/com/lambdaworks/redis/output/ValueStreamingChannel.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.output; /** diff --git a/src/main/java/com/lambdaworks/redis/output/ValueStreamingOutput.java b/src/main/java/com/lambdaworks/redis/output/ValueStreamingOutput.java index bcb7a9c179..0fae37d092 100644 --- a/src/main/java/com/lambdaworks/redis/output/ValueStreamingOutput.java +++ b/src/main/java/com/lambdaworks/redis/output/ValueStreamingOutput.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.output; import java.nio.ByteBuffer; diff --git a/src/main/java/com/lambdaworks/redis/output/ValueValueListOutput.java b/src/main/java/com/lambdaworks/redis/output/ValueValueListOutput.java index 1f0b4d6d9a..030edba528 100644 --- a/src/main/java/com/lambdaworks/redis/output/ValueValueListOutput.java +++ b/src/main/java/com/lambdaworks/redis/output/ValueValueListOutput.java @@ -1,4 +1,19 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.output; import java.nio.ByteBuffer; diff --git a/src/main/java/com/lambdaworks/redis/output/package-info.java b/src/main/java/com/lambdaworks/redis/output/package-info.java index b966f88ce3..988528e46d 100644 --- a/src/main/java/com/lambdaworks/redis/output/package-info.java +++ b/src/main/java/com/lambdaworks/redis/output/package-info.java @@ -1,4 +1,4 @@ /** * Implementation of different output protocols including the Streaming API. */ -package com.lambdaworks.redis.output; \ No newline at end of file +package com.lambdaworks.redis.output; diff --git a/src/main/java/com/lambdaworks/redis/package-info.java b/src/main/java/com/lambdaworks/redis/package-info.java index 82adf0e005..a55a3a7f0f 100644 --- a/src/main/java/com/lambdaworks/redis/package-info.java +++ b/src/main/java/com/lambdaworks/redis/package-info.java @@ -1,4 +1,4 @@ /** * The redis client package containing {@link com.lambdaworks.redis.RedisClient} for regular and sentinel operations. */ -package com.lambdaworks.redis; \ No newline at end of file +package com.lambdaworks.redis; diff --git a/src/main/java/com/lambdaworks/redis/protocol/AsyncCommand.java b/src/main/java/com/lambdaworks/redis/protocol/AsyncCommand.java index 50773f9923..8018ada89f 100644 --- a/src/main/java/com/lambdaworks/redis/protocol/AsyncCommand.java +++ b/src/main/java/com/lambdaworks/redis/protocol/AsyncCommand.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.protocol; import java.util.concurrent.CompletableFuture; diff --git a/src/main/java/com/lambdaworks/redis/protocol/BaseRedisCommandBuilder.java b/src/main/java/com/lambdaworks/redis/protocol/BaseRedisCommandBuilder.java index 7aab8637f7..bc574c6d52 100644 --- a/src/main/java/com/lambdaworks/redis/protocol/BaseRedisCommandBuilder.java +++ b/src/main/java/com/lambdaworks/redis/protocol/BaseRedisCommandBuilder.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.protocol; import com.lambdaworks.redis.RedisException; diff --git a/src/main/java/com/lambdaworks/redis/protocol/ChannelLogDescriptor.java b/src/main/java/com/lambdaworks/redis/protocol/ChannelLogDescriptor.java index adfeac8ea7..28b2936a72 100644 --- a/src/main/java/com/lambdaworks/redis/protocol/ChannelLogDescriptor.java +++ b/src/main/java/com/lambdaworks/redis/protocol/ChannelLogDescriptor.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.protocol; import io.netty.channel.Channel; diff --git a/src/main/java/com/lambdaworks/redis/protocol/Command.java b/src/main/java/com/lambdaworks/redis/protocol/Command.java index 26fdfd5e2b..aea8e5de0d 100644 --- a/src/main/java/com/lambdaworks/redis/protocol/Command.java +++ b/src/main/java/com/lambdaworks/redis/protocol/Command.java @@ -1,5 +1,18 @@ -// Copyright (C) 2011 - Will Glozer. All rights reserved. - +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.protocol; import com.lambdaworks.redis.internal.LettuceAssert; @@ -191,4 +204,4 @@ public long getFirstResponse() { public long getCompleted() { return completedNs; } -} \ No newline at end of file +} diff --git a/src/main/java/com/lambdaworks/redis/protocol/CommandArgs.java b/src/main/java/com/lambdaworks/redis/protocol/CommandArgs.java index edbc8e8b26..21878cf8cf 100644 --- a/src/main/java/com/lambdaworks/redis/protocol/CommandArgs.java +++ b/src/main/java/com/lambdaworks/redis/protocol/CommandArgs.java @@ -1,5 +1,18 @@ -// Copyright (C) 2011 - Will Glozer. All rights reserved. - +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.protocol; import java.nio.ByteBuffer; diff --git a/src/main/java/com/lambdaworks/redis/protocol/CommandEncoder.java b/src/main/java/com/lambdaworks/redis/protocol/CommandEncoder.java index 1562f3ea7c..a9eb2430b9 100644 --- a/src/main/java/com/lambdaworks/redis/protocol/CommandEncoder.java +++ b/src/main/java/com/lambdaworks/redis/protocol/CommandEncoder.java @@ -1,5 +1,18 @@ -// Copyright (C) 2011 - Will Glozer. All rights reserved. - +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.protocol; import java.nio.charset.Charset; diff --git a/src/main/java/com/lambdaworks/redis/protocol/CommandHandler.java b/src/main/java/com/lambdaworks/redis/protocol/CommandHandler.java index 13db3aeec8..8a8533a040 100644 --- a/src/main/java/com/lambdaworks/redis/protocol/CommandHandler.java +++ b/src/main/java/com/lambdaworks/redis/protocol/CommandHandler.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.protocol; import java.io.IOException; diff --git a/src/main/java/com/lambdaworks/redis/protocol/CommandKeyword.java b/src/main/java/com/lambdaworks/redis/protocol/CommandKeyword.java index de906e0b13..990b48daa7 100644 --- a/src/main/java/com/lambdaworks/redis/protocol/CommandKeyword.java +++ b/src/main/java/com/lambdaworks/redis/protocol/CommandKeyword.java @@ -1,5 +1,18 @@ -// Copyright (C) 2011 - Will Glozer. All rights reserved. - +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.protocol; /** diff --git a/src/main/java/com/lambdaworks/redis/protocol/CommandType.java b/src/main/java/com/lambdaworks/redis/protocol/CommandType.java index e21d1366c7..5e087a0cde 100644 --- a/src/main/java/com/lambdaworks/redis/protocol/CommandType.java +++ b/src/main/java/com/lambdaworks/redis/protocol/CommandType.java @@ -1,11 +1,25 @@ -// Copyright (C) 2011 - Will Glozer. All rights reserved. - +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.protocol; /** * Redis commands. * * @author Will Glozer + * @author Mark Paluch */ public enum CommandType implements ProtocolKeyword { // Connection diff --git a/src/main/java/com/lambdaworks/redis/protocol/CommandWrapper.java b/src/main/java/com/lambdaworks/redis/protocol/CommandWrapper.java index c05f0ea1b4..56d1ad0806 100644 --- a/src/main/java/com/lambdaworks/redis/protocol/CommandWrapper.java +++ b/src/main/java/com/lambdaworks/redis/protocol/CommandWrapper.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.protocol; import java.util.ArrayList; diff --git a/src/main/java/com/lambdaworks/redis/protocol/CompleteableCommand.java b/src/main/java/com/lambdaworks/redis/protocol/CompleteableCommand.java index 3d2479c549..f3747dd315 100644 --- a/src/main/java/com/lambdaworks/redis/protocol/CompleteableCommand.java +++ b/src/main/java/com/lambdaworks/redis/protocol/CompleteableCommand.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.protocol; import java.util.function.Consumer; diff --git a/src/main/java/com/lambdaworks/redis/protocol/ConnectionFacade.java b/src/main/java/com/lambdaworks/redis/protocol/ConnectionFacade.java index 5040f9622b..9ab1ae349e 100644 --- a/src/main/java/com/lambdaworks/redis/protocol/ConnectionFacade.java +++ b/src/main/java/com/lambdaworks/redis/protocol/ConnectionFacade.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.protocol; /** diff --git a/src/main/java/com/lambdaworks/redis/protocol/ConnectionWatchdog.java b/src/main/java/com/lambdaworks/redis/protocol/ConnectionWatchdog.java index 254367a555..8699004b30 100644 --- a/src/main/java/com/lambdaworks/redis/protocol/ConnectionWatchdog.java +++ b/src/main/java/com/lambdaworks/redis/protocol/ConnectionWatchdog.java @@ -1,5 +1,18 @@ -// Copyright (C) 2011 - Will Glozer. All rights reserved. - +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.protocol; import java.net.SocketAddress; diff --git a/src/main/java/com/lambdaworks/redis/protocol/DecoratedCommand.java b/src/main/java/com/lambdaworks/redis/protocol/DecoratedCommand.java index ca2968156b..56f46acf0c 100644 --- a/src/main/java/com/lambdaworks/redis/protocol/DecoratedCommand.java +++ b/src/main/java/com/lambdaworks/redis/protocol/DecoratedCommand.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.protocol; /** diff --git a/src/main/java/com/lambdaworks/redis/protocol/DefaultEndpoint.java b/src/main/java/com/lambdaworks/redis/protocol/DefaultEndpoint.java index 8f0b46b394..d03091b20f 100644 --- a/src/main/java/com/lambdaworks/redis/protocol/DefaultEndpoint.java +++ b/src/main/java/com/lambdaworks/redis/protocol/DefaultEndpoint.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.protocol; import static com.lambdaworks.redis.protocol.CommandHandler.SUPPRESS_IO_EXCEPTION_MESSAGES; diff --git a/src/main/java/com/lambdaworks/redis/protocol/Endpoint.java b/src/main/java/com/lambdaworks/redis/protocol/Endpoint.java index 294257fe67..0ac5736e15 100644 --- a/src/main/java/com/lambdaworks/redis/protocol/Endpoint.java +++ b/src/main/java/com/lambdaworks/redis/protocol/Endpoint.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.protocol; import java.util.Optional; diff --git a/src/main/java/com/lambdaworks/redis/protocol/HasQueuedCommands.java b/src/main/java/com/lambdaworks/redis/protocol/HasQueuedCommands.java index 05eb9bcadf..37beac56ab 100644 --- a/src/main/java/com/lambdaworks/redis/protocol/HasQueuedCommands.java +++ b/src/main/java/com/lambdaworks/redis/protocol/HasQueuedCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.protocol; import java.util.Queue; diff --git a/src/main/java/com/lambdaworks/redis/protocol/LettuceCharsets.java b/src/main/java/com/lambdaworks/redis/protocol/LettuceCharsets.java index f3b785952a..e6724aeb4b 100644 --- a/src/main/java/com/lambdaworks/redis/protocol/LettuceCharsets.java +++ b/src/main/java/com/lambdaworks/redis/protocol/LettuceCharsets.java @@ -1,5 +1,18 @@ -// Copyright (C) 2011 - Will Glozer. All rights reserved. - +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.protocol; import java.nio.ByteBuffer; diff --git a/src/main/java/com/lambdaworks/redis/protocol/ProtocolKeyword.java b/src/main/java/com/lambdaworks/redis/protocol/ProtocolKeyword.java index 39ee43f1f6..13398a58c4 100644 --- a/src/main/java/com/lambdaworks/redis/protocol/ProtocolKeyword.java +++ b/src/main/java/com/lambdaworks/redis/protocol/ProtocolKeyword.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.protocol; /** diff --git a/src/main/java/com/lambdaworks/redis/protocol/QueuedCommands.java b/src/main/java/com/lambdaworks/redis/protocol/QueuedCommands.java index 6353f740e8..67094a0c89 100644 --- a/src/main/java/com/lambdaworks/redis/protocol/QueuedCommands.java +++ b/src/main/java/com/lambdaworks/redis/protocol/QueuedCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.protocol; import java.util.ArrayList; diff --git a/src/main/java/com/lambdaworks/redis/protocol/ReconnectionHandler.java b/src/main/java/com/lambdaworks/redis/protocol/ReconnectionHandler.java index aac7e43823..3b8a9a4dc9 100644 --- a/src/main/java/com/lambdaworks/redis/protocol/ReconnectionHandler.java +++ b/src/main/java/com/lambdaworks/redis/protocol/ReconnectionHandler.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.protocol; import java.net.SocketAddress; diff --git a/src/main/java/com/lambdaworks/redis/protocol/ReconnectionListener.java b/src/main/java/com/lambdaworks/redis/protocol/ReconnectionListener.java index 533cd13609..902bc6f279 100644 --- a/src/main/java/com/lambdaworks/redis/protocol/ReconnectionListener.java +++ b/src/main/java/com/lambdaworks/redis/protocol/ReconnectionListener.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.protocol; import com.lambdaworks.redis.ConnectionEvents; diff --git a/src/main/java/com/lambdaworks/redis/protocol/RedisCommand.java b/src/main/java/com/lambdaworks/redis/protocol/RedisCommand.java index 507b678918..a5dac8dfc0 100644 --- a/src/main/java/com/lambdaworks/redis/protocol/RedisCommand.java +++ b/src/main/java/com/lambdaworks/redis/protocol/RedisCommand.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.protocol; import com.lambdaworks.redis.output.CommandOutput; diff --git a/src/main/java/com/lambdaworks/redis/protocol/RedisStateMachine.java b/src/main/java/com/lambdaworks/redis/protocol/RedisStateMachine.java index a8d96f5869..f0a096b481 100644 --- a/src/main/java/com/lambdaworks/redis/protocol/RedisStateMachine.java +++ b/src/main/java/com/lambdaworks/redis/protocol/RedisStateMachine.java @@ -1,5 +1,18 @@ -// Copyright (C) 2011 - Will Glozer. All rights reserved. - +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.protocol; import static com.lambdaworks.redis.protocol.LettuceCharsets.buffer; diff --git a/src/main/java/com/lambdaworks/redis/protocol/SharedLock.java b/src/main/java/com/lambdaworks/redis/protocol/SharedLock.java index 55956ba3ab..10446df6cd 100644 --- a/src/main/java/com/lambdaworks/redis/protocol/SharedLock.java +++ b/src/main/java/com/lambdaworks/redis/protocol/SharedLock.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.protocol; import java.util.concurrent.atomic.AtomicLong; diff --git a/src/main/java/com/lambdaworks/redis/protocol/TransactionalCommand.java b/src/main/java/com/lambdaworks/redis/protocol/TransactionalCommand.java index 8630e8af2c..2a281f7ffb 100644 --- a/src/main/java/com/lambdaworks/redis/protocol/TransactionalCommand.java +++ b/src/main/java/com/lambdaworks/redis/protocol/TransactionalCommand.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.protocol; import java.util.concurrent.CountDownLatch; diff --git a/src/main/java/com/lambdaworks/redis/protocol/WithLatency.java b/src/main/java/com/lambdaworks/redis/protocol/WithLatency.java index 7f8ed7c7df..cad57a5ce7 100644 --- a/src/main/java/com/lambdaworks/redis/protocol/WithLatency.java +++ b/src/main/java/com/lambdaworks/redis/protocol/WithLatency.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.protocol; /** diff --git a/src/main/java/com/lambdaworks/redis/protocol/package-info.java b/src/main/java/com/lambdaworks/redis/protocol/package-info.java index 07967b0b47..a84a938889 100644 --- a/src/main/java/com/lambdaworks/redis/protocol/package-info.java +++ b/src/main/java/com/lambdaworks/redis/protocol/package-info.java @@ -1,4 +1,4 @@ /** * Redis protocol layer abstraction. */ -package com.lambdaworks.redis.protocol; \ No newline at end of file +package com.lambdaworks.redis.protocol; diff --git a/src/main/java/com/lambdaworks/redis/pubsub/PubSubCommandArgs.java b/src/main/java/com/lambdaworks/redis/pubsub/PubSubCommandArgs.java index d20788e73d..d6ddd852d7 100644 --- a/src/main/java/com/lambdaworks/redis/pubsub/PubSubCommandArgs.java +++ b/src/main/java/com/lambdaworks/redis/pubsub/PubSubCommandArgs.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.pubsub; import java.nio.ByteBuffer; diff --git a/src/main/java/com/lambdaworks/redis/pubsub/PubSubCommandBuilder.java b/src/main/java/com/lambdaworks/redis/pubsub/PubSubCommandBuilder.java index 3bba1b8f0c..72793d2625 100644 --- a/src/main/java/com/lambdaworks/redis/pubsub/PubSubCommandBuilder.java +++ b/src/main/java/com/lambdaworks/redis/pubsub/PubSubCommandBuilder.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.pubsub; import static com.lambdaworks.redis.protocol.CommandKeyword.CHANNELS; diff --git a/src/main/java/com/lambdaworks/redis/pubsub/PubSubCommandHandler.java b/src/main/java/com/lambdaworks/redis/pubsub/PubSubCommandHandler.java index 0b03c2e9fa..752c7788fe 100644 --- a/src/main/java/com/lambdaworks/redis/pubsub/PubSubCommandHandler.java +++ b/src/main/java/com/lambdaworks/redis/pubsub/PubSubCommandHandler.java @@ -1,5 +1,18 @@ -// Copyright (C) 2011 - Will Glozer. All rights reserved. - +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.pubsub; import com.lambdaworks.redis.codec.RedisCodec; diff --git a/src/main/java/com/lambdaworks/redis/pubsub/PubSubEndpoint.java b/src/main/java/com/lambdaworks/redis/pubsub/PubSubEndpoint.java index a35ed3c8b8..ffc3682013 100644 --- a/src/main/java/com/lambdaworks/redis/pubsub/PubSubEndpoint.java +++ b/src/main/java/com/lambdaworks/redis/pubsub/PubSubEndpoint.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.pubsub; import java.util.List; diff --git a/src/main/java/com/lambdaworks/redis/pubsub/PubSubOutput.java b/src/main/java/com/lambdaworks/redis/pubsub/PubSubOutput.java index aace0280c2..2060d771dd 100644 --- a/src/main/java/com/lambdaworks/redis/pubsub/PubSubOutput.java +++ b/src/main/java/com/lambdaworks/redis/pubsub/PubSubOutput.java @@ -1,5 +1,18 @@ -// Copyright (C) 2011 - Will Glozer. All rights reserved. - +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.pubsub; import java.nio.ByteBuffer; diff --git a/src/main/java/com/lambdaworks/redis/pubsub/RedisPubSubAdapter.java b/src/main/java/com/lambdaworks/redis/pubsub/RedisPubSubAdapter.java index de04d28b52..bd7e0133dc 100644 --- a/src/main/java/com/lambdaworks/redis/pubsub/RedisPubSubAdapter.java +++ b/src/main/java/com/lambdaworks/redis/pubsub/RedisPubSubAdapter.java @@ -1,5 +1,18 @@ -// Copyright (C) 2011 - Will Glozer. All rights reserved. - +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.pubsub; /** diff --git a/src/main/java/com/lambdaworks/redis/pubsub/RedisPubSubAsyncCommandsImpl.java b/src/main/java/com/lambdaworks/redis/pubsub/RedisPubSubAsyncCommandsImpl.java index 1a11b1e1ed..81f0897173 100644 --- a/src/main/java/com/lambdaworks/redis/pubsub/RedisPubSubAsyncCommandsImpl.java +++ b/src/main/java/com/lambdaworks/redis/pubsub/RedisPubSubAsyncCommandsImpl.java @@ -1,5 +1,18 @@ -// Copyright (C) 2011 - Will Glozer. All rights reserved. - +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.pubsub; import java.util.List; diff --git a/src/main/java/com/lambdaworks/redis/pubsub/RedisPubSubListener.java b/src/main/java/com/lambdaworks/redis/pubsub/RedisPubSubListener.java index 8a94f3afd4..32c29d4e39 100644 --- a/src/main/java/com/lambdaworks/redis/pubsub/RedisPubSubListener.java +++ b/src/main/java/com/lambdaworks/redis/pubsub/RedisPubSubListener.java @@ -1,5 +1,18 @@ -// Copyright (C) 2011 - Will Glozer. All rights reserved. - +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.pubsub; /** @@ -7,7 +20,6 @@ * * @param Key type. * @param Value type. - * * @author Will Glozer */ public interface RedisPubSubListener { diff --git a/src/main/java/com/lambdaworks/redis/pubsub/RedisPubSubReactiveCommandsImpl.java b/src/main/java/com/lambdaworks/redis/pubsub/RedisPubSubReactiveCommandsImpl.java index 6677f6cbdc..53d76d2d23 100644 --- a/src/main/java/com/lambdaworks/redis/pubsub/RedisPubSubReactiveCommandsImpl.java +++ b/src/main/java/com/lambdaworks/redis/pubsub/RedisPubSubReactiveCommandsImpl.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.pubsub; import java.util.Map; diff --git a/src/main/java/com/lambdaworks/redis/pubsub/StatefulRedisPubSubConnection.java b/src/main/java/com/lambdaworks/redis/pubsub/StatefulRedisPubSubConnection.java index f71b755729..3a0729cd80 100644 --- a/src/main/java/com/lambdaworks/redis/pubsub/StatefulRedisPubSubConnection.java +++ b/src/main/java/com/lambdaworks/redis/pubsub/StatefulRedisPubSubConnection.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.pubsub; import com.lambdaworks.redis.api.StatefulRedisConnection; diff --git a/src/main/java/com/lambdaworks/redis/pubsub/StatefulRedisPubSubConnectionImpl.java b/src/main/java/com/lambdaworks/redis/pubsub/StatefulRedisPubSubConnectionImpl.java index 938b34a0d5..b7a0c06a06 100644 --- a/src/main/java/com/lambdaworks/redis/pubsub/StatefulRedisPubSubConnectionImpl.java +++ b/src/main/java/com/lambdaworks/redis/pubsub/StatefulRedisPubSubConnectionImpl.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.pubsub; import java.lang.reflect.Array; diff --git a/src/main/java/com/lambdaworks/redis/pubsub/api/async/RedisPubSubAsyncCommands.java b/src/main/java/com/lambdaworks/redis/pubsub/api/async/RedisPubSubAsyncCommands.java index 68a7f2d2a4..0d5b35a31d 100644 --- a/src/main/java/com/lambdaworks/redis/pubsub/api/async/RedisPubSubAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/pubsub/api/async/RedisPubSubAsyncCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.pubsub.api.async; import com.lambdaworks.redis.RedisFuture; diff --git a/src/main/java/com/lambdaworks/redis/pubsub/api/async/package-info.java b/src/main/java/com/lambdaworks/redis/pubsub/api/async/package-info.java index b29a6841e0..f82360b4bb 100644 --- a/src/main/java/com/lambdaworks/redis/pubsub/api/async/package-info.java +++ b/src/main/java/com/lambdaworks/redis/pubsub/api/async/package-info.java @@ -1,4 +1,4 @@ /** * Pub/Sub Redis API for asynchronous executed commands. */ -package com.lambdaworks.redis.pubsub.api.async; \ No newline at end of file +package com.lambdaworks.redis.pubsub.api.async; diff --git a/src/main/java/com/lambdaworks/redis/pubsub/api/reactive/ChannelMessage.java b/src/main/java/com/lambdaworks/redis/pubsub/api/reactive/ChannelMessage.java index ee2e2f3e37..32a7ca75b5 100644 --- a/src/main/java/com/lambdaworks/redis/pubsub/api/reactive/ChannelMessage.java +++ b/src/main/java/com/lambdaworks/redis/pubsub/api/reactive/ChannelMessage.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.pubsub.api.reactive; /** diff --git a/src/main/java/com/lambdaworks/redis/pubsub/api/reactive/PatternMessage.java b/src/main/java/com/lambdaworks/redis/pubsub/api/reactive/PatternMessage.java index d210c5b7d7..135166ca7c 100644 --- a/src/main/java/com/lambdaworks/redis/pubsub/api/reactive/PatternMessage.java +++ b/src/main/java/com/lambdaworks/redis/pubsub/api/reactive/PatternMessage.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.pubsub.api.reactive; /** diff --git a/src/main/java/com/lambdaworks/redis/pubsub/api/reactive/RedisPubSubReactiveCommands.java b/src/main/java/com/lambdaworks/redis/pubsub/api/reactive/RedisPubSubReactiveCommands.java index d4dc4d613d..4fb69e964c 100644 --- a/src/main/java/com/lambdaworks/redis/pubsub/api/reactive/RedisPubSubReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/pubsub/api/reactive/RedisPubSubReactiveCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.pubsub.api.reactive; import com.lambdaworks.redis.api.reactive.RedisReactiveCommands; diff --git a/src/main/java/com/lambdaworks/redis/pubsub/api/reactive/package-info.java b/src/main/java/com/lambdaworks/redis/pubsub/api/reactive/package-info.java index 4a134068c8..17e7b200e6 100644 --- a/src/main/java/com/lambdaworks/redis/pubsub/api/reactive/package-info.java +++ b/src/main/java/com/lambdaworks/redis/pubsub/api/reactive/package-info.java @@ -1,4 +1,4 @@ /** * Pub/Sub Redis API for commands executed in a reactive manner. */ -package com.lambdaworks.redis.pubsub.api.reactive; \ No newline at end of file +package com.lambdaworks.redis.pubsub.api.reactive; diff --git a/src/main/java/com/lambdaworks/redis/pubsub/api/sync/RedisPubSubCommands.java b/src/main/java/com/lambdaworks/redis/pubsub/api/sync/RedisPubSubCommands.java index f124325d46..77b6b0aed1 100644 --- a/src/main/java/com/lambdaworks/redis/pubsub/api/sync/RedisPubSubCommands.java +++ b/src/main/java/com/lambdaworks/redis/pubsub/api/sync/RedisPubSubCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.pubsub.api.sync; import com.lambdaworks.redis.api.sync.RedisCommands; diff --git a/src/main/java/com/lambdaworks/redis/pubsub/api/sync/package-info.java b/src/main/java/com/lambdaworks/redis/pubsub/api/sync/package-info.java index ece5c9d7e5..3def5e254a 100644 --- a/src/main/java/com/lambdaworks/redis/pubsub/api/sync/package-info.java +++ b/src/main/java/com/lambdaworks/redis/pubsub/api/sync/package-info.java @@ -1,4 +1,4 @@ /** * Pub/Sub Redis API for synchronous executed commands. */ -package com.lambdaworks.redis.pubsub.api.sync; \ No newline at end of file +package com.lambdaworks.redis.pubsub.api.sync; diff --git a/src/main/java/com/lambdaworks/redis/pubsub/package-info.java b/src/main/java/com/lambdaworks/redis/pubsub/package-info.java index d68879e934..b698510a89 100644 --- a/src/main/java/com/lambdaworks/redis/pubsub/package-info.java +++ b/src/main/java/com/lambdaworks/redis/pubsub/package-info.java @@ -1,4 +1,4 @@ /** * Pub/Sub connection classes. */ -package com.lambdaworks.redis.pubsub; \ No newline at end of file +package com.lambdaworks.redis.pubsub; diff --git a/src/main/java/com/lambdaworks/redis/resource/ClientResources.java b/src/main/java/com/lambdaworks/redis/resource/ClientResources.java index 10e258caf7..1070fa7901 100644 --- a/src/main/java/com/lambdaworks/redis/resource/ClientResources.java +++ b/src/main/java/com/lambdaworks/redis/resource/ClientResources.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.resource; import java.util.concurrent.TimeUnit; diff --git a/src/main/java/com/lambdaworks/redis/resource/ConstantDelay.java b/src/main/java/com/lambdaworks/redis/resource/ConstantDelay.java index 51cb3d3ab2..4776e2050a 100644 --- a/src/main/java/com/lambdaworks/redis/resource/ConstantDelay.java +++ b/src/main/java/com/lambdaworks/redis/resource/ConstantDelay.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.resource; import java.util.concurrent.TimeUnit; diff --git a/src/main/java/com/lambdaworks/redis/resource/DecorrelatedJitterDelay.java b/src/main/java/com/lambdaworks/redis/resource/DecorrelatedJitterDelay.java index 370ae51bd9..5e0b072fb0 100644 --- a/src/main/java/com/lambdaworks/redis/resource/DecorrelatedJitterDelay.java +++ b/src/main/java/com/lambdaworks/redis/resource/DecorrelatedJitterDelay.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.resource; import java.util.concurrent.TimeUnit; diff --git a/src/main/java/com/lambdaworks/redis/resource/DefaultClientResources.java b/src/main/java/com/lambdaworks/redis/resource/DefaultClientResources.java index 25b464e969..da71c46ecb 100644 --- a/src/main/java/com/lambdaworks/redis/resource/DefaultClientResources.java +++ b/src/main/java/com/lambdaworks/redis/resource/DefaultClientResources.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.resource; import static com.lambdaworks.redis.resource.Futures.toBooleanPromise; diff --git a/src/main/java/com/lambdaworks/redis/resource/DefaultEventLoopGroupProvider.java b/src/main/java/com/lambdaworks/redis/resource/DefaultEventLoopGroupProvider.java index c51dc914ed..1059262c3a 100644 --- a/src/main/java/com/lambdaworks/redis/resource/DefaultEventLoopGroupProvider.java +++ b/src/main/java/com/lambdaworks/redis/resource/DefaultEventLoopGroupProvider.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.resource; import static com.lambdaworks.redis.resource.Futures.toBooleanPromise; diff --git a/src/main/java/com/lambdaworks/redis/resource/Delay.java b/src/main/java/com/lambdaworks/redis/resource/Delay.java index 4d7ee3e5f9..d1c8ca4773 100644 --- a/src/main/java/com/lambdaworks/redis/resource/Delay.java +++ b/src/main/java/com/lambdaworks/redis/resource/Delay.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.resource; import java.util.concurrent.ThreadLocalRandom; diff --git a/src/main/java/com/lambdaworks/redis/resource/DirContextDnsResolver.java b/src/main/java/com/lambdaworks/redis/resource/DirContextDnsResolver.java index 08eaa61798..64cf2d2bea 100644 --- a/src/main/java/com/lambdaworks/redis/resource/DirContextDnsResolver.java +++ b/src/main/java/com/lambdaworks/redis/resource/DirContextDnsResolver.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.resource; import java.io.Closeable; diff --git a/src/main/java/com/lambdaworks/redis/resource/DnsResolver.java b/src/main/java/com/lambdaworks/redis/resource/DnsResolver.java index 59c71b4b9e..5412201d31 100644 --- a/src/main/java/com/lambdaworks/redis/resource/DnsResolver.java +++ b/src/main/java/com/lambdaworks/redis/resource/DnsResolver.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.resource; import java.net.InetAddress; diff --git a/src/main/java/com/lambdaworks/redis/resource/DnsResolvers.java b/src/main/java/com/lambdaworks/redis/resource/DnsResolvers.java index d342c6fc58..8d971ef01f 100644 --- a/src/main/java/com/lambdaworks/redis/resource/DnsResolvers.java +++ b/src/main/java/com/lambdaworks/redis/resource/DnsResolvers.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.resource; import java.net.InetAddress; diff --git a/src/main/java/com/lambdaworks/redis/resource/EqualJitterDelay.java b/src/main/java/com/lambdaworks/redis/resource/EqualJitterDelay.java index 500200dc5a..954dbe581e 100644 --- a/src/main/java/com/lambdaworks/redis/resource/EqualJitterDelay.java +++ b/src/main/java/com/lambdaworks/redis/resource/EqualJitterDelay.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.resource; import java.util.concurrent.TimeUnit; diff --git a/src/main/java/com/lambdaworks/redis/resource/EventLoopGroupProvider.java b/src/main/java/com/lambdaworks/redis/resource/EventLoopGroupProvider.java index f9368462e1..5f7cf33fba 100644 --- a/src/main/java/com/lambdaworks/redis/resource/EventLoopGroupProvider.java +++ b/src/main/java/com/lambdaworks/redis/resource/EventLoopGroupProvider.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.resource; import java.util.concurrent.TimeUnit; diff --git a/src/main/java/com/lambdaworks/redis/resource/ExponentialDelay.java b/src/main/java/com/lambdaworks/redis/resource/ExponentialDelay.java index 87449415bd..445588ed79 100644 --- a/src/main/java/com/lambdaworks/redis/resource/ExponentialDelay.java +++ b/src/main/java/com/lambdaworks/redis/resource/ExponentialDelay.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.resource; import java.util.concurrent.TimeUnit; diff --git a/src/main/java/com/lambdaworks/redis/resource/FullJitterDelay.java b/src/main/java/com/lambdaworks/redis/resource/FullJitterDelay.java index c1843360cc..428fdcc662 100644 --- a/src/main/java/com/lambdaworks/redis/resource/FullJitterDelay.java +++ b/src/main/java/com/lambdaworks/redis/resource/FullJitterDelay.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.resource; import java.util.concurrent.TimeUnit; diff --git a/src/main/java/com/lambdaworks/redis/resource/Futures.java b/src/main/java/com/lambdaworks/redis/resource/Futures.java index e3a5de9893..c9df5ab771 100644 --- a/src/main/java/com/lambdaworks/redis/resource/Futures.java +++ b/src/main/java/com/lambdaworks/redis/resource/Futures.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.resource; import java.util.LinkedHashSet; diff --git a/src/main/java/com/lambdaworks/redis/resource/SocketAddressResolver.java b/src/main/java/com/lambdaworks/redis/resource/SocketAddressResolver.java index 041fb724fa..35ed36580a 100644 --- a/src/main/java/com/lambdaworks/redis/resource/SocketAddressResolver.java +++ b/src/main/java/com/lambdaworks/redis/resource/SocketAddressResolver.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.resource; import java.net.InetAddress; diff --git a/src/main/java/com/lambdaworks/redis/resource/package-info.java b/src/main/java/com/lambdaworks/redis/resource/package-info.java index fed7ad5ff9..6fdd5e515f 100644 --- a/src/main/java/com/lambdaworks/redis/resource/package-info.java +++ b/src/main/java/com/lambdaworks/redis/resource/package-info.java @@ -1,4 +1,4 @@ /** * Client resource infrastructure providers. */ -package com.lambdaworks.redis.resource; \ No newline at end of file +package com.lambdaworks.redis.resource; diff --git a/src/main/java/com/lambdaworks/redis/sentinel/RedisSentinelAsyncCommandsImpl.java b/src/main/java/com/lambdaworks/redis/sentinel/RedisSentinelAsyncCommandsImpl.java index 5c3aeeb1e9..7eb0e135c2 100644 --- a/src/main/java/com/lambdaworks/redis/sentinel/RedisSentinelAsyncCommandsImpl.java +++ b/src/main/java/com/lambdaworks/redis/sentinel/RedisSentinelAsyncCommandsImpl.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.sentinel; import java.net.InetSocketAddress; diff --git a/src/main/java/com/lambdaworks/redis/sentinel/RedisSentinelReactiveCommandsImpl.java b/src/main/java/com/lambdaworks/redis/sentinel/RedisSentinelReactiveCommandsImpl.java index 2a168de5f4..e0e5d426c5 100644 --- a/src/main/java/com/lambdaworks/redis/sentinel/RedisSentinelReactiveCommandsImpl.java +++ b/src/main/java/com/lambdaworks/redis/sentinel/RedisSentinelReactiveCommandsImpl.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.sentinel; import java.net.InetSocketAddress; diff --git a/src/main/java/com/lambdaworks/redis/sentinel/SentinelCommandBuilder.java b/src/main/java/com/lambdaworks/redis/sentinel/SentinelCommandBuilder.java index 57001f983c..b26203c3d8 100644 --- a/src/main/java/com/lambdaworks/redis/sentinel/SentinelCommandBuilder.java +++ b/src/main/java/com/lambdaworks/redis/sentinel/SentinelCommandBuilder.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.sentinel; import static com.lambdaworks.redis.protocol.CommandKeyword.FAILOVER; diff --git a/src/main/java/com/lambdaworks/redis/sentinel/StatefulRedisSentinelConnectionImpl.java b/src/main/java/com/lambdaworks/redis/sentinel/StatefulRedisSentinelConnectionImpl.java index 8be3d00d42..a0e2254c02 100644 --- a/src/main/java/com/lambdaworks/redis/sentinel/StatefulRedisSentinelConnectionImpl.java +++ b/src/main/java/com/lambdaworks/redis/sentinel/StatefulRedisSentinelConnectionImpl.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.sentinel; import java.util.concurrent.TimeUnit; diff --git a/src/main/java/com/lambdaworks/redis/sentinel/api/StatefulRedisSentinelConnection.java b/src/main/java/com/lambdaworks/redis/sentinel/api/StatefulRedisSentinelConnection.java index 034ba3396e..e559f47483 100644 --- a/src/main/java/com/lambdaworks/redis/sentinel/api/StatefulRedisSentinelConnection.java +++ b/src/main/java/com/lambdaworks/redis/sentinel/api/StatefulRedisSentinelConnection.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.sentinel.api; import com.lambdaworks.redis.api.StatefulConnection; diff --git a/src/main/java/com/lambdaworks/redis/sentinel/api/async/RedisSentinelAsyncCommands.java b/src/main/java/com/lambdaworks/redis/sentinel/api/async/RedisSentinelAsyncCommands.java index 677012500d..73fe33bc13 100644 --- a/src/main/java/com/lambdaworks/redis/sentinel/api/async/RedisSentinelAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/sentinel/api/async/RedisSentinelAsyncCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.sentinel.api.async; import java.net.SocketAddress; diff --git a/src/main/java/com/lambdaworks/redis/sentinel/api/async/package-info.java b/src/main/java/com/lambdaworks/redis/sentinel/api/async/package-info.java index 96dfcd1ffa..b58008bef1 100644 --- a/src/main/java/com/lambdaworks/redis/sentinel/api/async/package-info.java +++ b/src/main/java/com/lambdaworks/redis/sentinel/api/async/package-info.java @@ -1,4 +1,4 @@ /** * Redis Sentinel API for asynchronous executed commands. */ -package com.lambdaworks.redis.sentinel.api.async; \ No newline at end of file +package com.lambdaworks.redis.sentinel.api.async; diff --git a/src/main/java/com/lambdaworks/redis/sentinel/api/package-info.java b/src/main/java/com/lambdaworks/redis/sentinel/api/package-info.java index e00fe614b6..088f267527 100644 --- a/src/main/java/com/lambdaworks/redis/sentinel/api/package-info.java +++ b/src/main/java/com/lambdaworks/redis/sentinel/api/package-info.java @@ -1,4 +1,4 @@ /** * Redis Sentinel connection API. */ -package com.lambdaworks.redis.sentinel.api; \ No newline at end of file +package com.lambdaworks.redis.sentinel.api; diff --git a/src/main/java/com/lambdaworks/redis/sentinel/api/reactive/RedisSentinelReactiveCommands.java b/src/main/java/com/lambdaworks/redis/sentinel/api/reactive/RedisSentinelReactiveCommands.java index ab430d1d4d..c623cf36b3 100644 --- a/src/main/java/com/lambdaworks/redis/sentinel/api/reactive/RedisSentinelReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/sentinel/api/reactive/RedisSentinelReactiveCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.sentinel.api.reactive; import java.net.SocketAddress; diff --git a/src/main/java/com/lambdaworks/redis/sentinel/api/reactive/package-info.java b/src/main/java/com/lambdaworks/redis/sentinel/api/reactive/package-info.java index fe9fedf806..09c4f53bb4 100644 --- a/src/main/java/com/lambdaworks/redis/sentinel/api/reactive/package-info.java +++ b/src/main/java/com/lambdaworks/redis/sentinel/api/reactive/package-info.java @@ -1,4 +1,4 @@ /** * Redis Sentinel API for commands executed in a reactive manner. */ -package com.lambdaworks.redis.sentinel.api.reactive; \ No newline at end of file +package com.lambdaworks.redis.sentinel.api.reactive; diff --git a/src/main/java/com/lambdaworks/redis/sentinel/api/sync/RedisSentinelCommands.java b/src/main/java/com/lambdaworks/redis/sentinel/api/sync/RedisSentinelCommands.java index 918bf1f92b..249d320ad3 100644 --- a/src/main/java/com/lambdaworks/redis/sentinel/api/sync/RedisSentinelCommands.java +++ b/src/main/java/com/lambdaworks/redis/sentinel/api/sync/RedisSentinelCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.sentinel.api.sync; import java.net.SocketAddress; diff --git a/src/main/java/com/lambdaworks/redis/sentinel/api/sync/package-info.java b/src/main/java/com/lambdaworks/redis/sentinel/api/sync/package-info.java index 9f53e21bc0..cba7adbd66 100644 --- a/src/main/java/com/lambdaworks/redis/sentinel/api/sync/package-info.java +++ b/src/main/java/com/lambdaworks/redis/sentinel/api/sync/package-info.java @@ -1,4 +1,4 @@ /** * Redis Sentinel API for synchronous executed commands. */ -package com.lambdaworks.redis.sentinel.api.sync; \ No newline at end of file +package com.lambdaworks.redis.sentinel.api.sync; diff --git a/src/main/java/com/lambdaworks/redis/sentinel/package-info.java b/src/main/java/com/lambdaworks/redis/sentinel/package-info.java index 5341dd5776..223b2531d3 100644 --- a/src/main/java/com/lambdaworks/redis/sentinel/package-info.java +++ b/src/main/java/com/lambdaworks/redis/sentinel/package-info.java @@ -1,4 +1,4 @@ /** * Redis Sentinel connection classes. */ -package com.lambdaworks.redis.sentinel; \ No newline at end of file +package com.lambdaworks.redis.sentinel; diff --git a/src/main/java/com/lambdaworks/redis/support/AbstractCdiBean.java b/src/main/java/com/lambdaworks/redis/support/AbstractCdiBean.java index f9c50af1f2..8655992a3c 100644 --- a/src/main/java/com/lambdaworks/redis/support/AbstractCdiBean.java +++ b/src/main/java/com/lambdaworks/redis/support/AbstractCdiBean.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.support; import java.lang.annotation.Annotation; diff --git a/src/main/java/com/lambdaworks/redis/support/ClientResourcesFactoryBean.java b/src/main/java/com/lambdaworks/redis/support/ClientResourcesFactoryBean.java index dfa01b6d71..9a7a9aade9 100644 --- a/src/main/java/com/lambdaworks/redis/support/ClientResourcesFactoryBean.java +++ b/src/main/java/com/lambdaworks/redis/support/ClientResourcesFactoryBean.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.support; import org.springframework.beans.factory.FactoryBean; diff --git a/src/main/java/com/lambdaworks/redis/support/ConnectionPoolSupport.java b/src/main/java/com/lambdaworks/redis/support/ConnectionPoolSupport.java index 5cb18ea4cb..f7c68b4dba 100644 --- a/src/main/java/com/lambdaworks/redis/support/ConnectionPoolSupport.java +++ b/src/main/java/com/lambdaworks/redis/support/ConnectionPoolSupport.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.support; import java.lang.reflect.InvocationTargetException; diff --git a/src/main/java/com/lambdaworks/redis/support/LettuceCdiExtension.java b/src/main/java/com/lambdaworks/redis/support/LettuceCdiExtension.java index 7ab123ca8c..8f5fad902d 100644 --- a/src/main/java/com/lambdaworks/redis/support/LettuceCdiExtension.java +++ b/src/main/java/com/lambdaworks/redis/support/LettuceCdiExtension.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.support; import java.lang.annotation.Annotation; diff --git a/src/main/java/com/lambdaworks/redis/support/LettuceFactoryBeanSupport.java b/src/main/java/com/lambdaworks/redis/support/LettuceFactoryBeanSupport.java index 492bfb4284..56958af9c9 100644 --- a/src/main/java/com/lambdaworks/redis/support/LettuceFactoryBeanSupport.java +++ b/src/main/java/com/lambdaworks/redis/support/LettuceFactoryBeanSupport.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.support; import java.net.URI; diff --git a/src/main/java/com/lambdaworks/redis/support/RedisClientCdiBean.java b/src/main/java/com/lambdaworks/redis/support/RedisClientCdiBean.java index 147240167a..dd17c9f6dc 100644 --- a/src/main/java/com/lambdaworks/redis/support/RedisClientCdiBean.java +++ b/src/main/java/com/lambdaworks/redis/support/RedisClientCdiBean.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.support; import java.lang.annotation.Annotation; diff --git a/src/main/java/com/lambdaworks/redis/support/RedisClientFactoryBean.java b/src/main/java/com/lambdaworks/redis/support/RedisClientFactoryBean.java index e04ca4456d..ba97203f6a 100644 --- a/src/main/java/com/lambdaworks/redis/support/RedisClientFactoryBean.java +++ b/src/main/java/com/lambdaworks/redis/support/RedisClientFactoryBean.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.support; import static com.lambdaworks.redis.LettuceStrings.isNotEmpty; diff --git a/src/main/java/com/lambdaworks/redis/support/RedisClusterClientCdiBean.java b/src/main/java/com/lambdaworks/redis/support/RedisClusterClientCdiBean.java index ee5227551b..56d5c5b493 100644 --- a/src/main/java/com/lambdaworks/redis/support/RedisClusterClientCdiBean.java +++ b/src/main/java/com/lambdaworks/redis/support/RedisClusterClientCdiBean.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.support; import java.lang.annotation.Annotation; diff --git a/src/main/java/com/lambdaworks/redis/support/RedisClusterClientFactoryBean.java b/src/main/java/com/lambdaworks/redis/support/RedisClusterClientFactoryBean.java index 5af28496b6..07b0fb9b9e 100644 --- a/src/main/java/com/lambdaworks/redis/support/RedisClusterClientFactoryBean.java +++ b/src/main/java/com/lambdaworks/redis/support/RedisClusterClientFactoryBean.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.support; import static com.lambdaworks.redis.LettuceStrings.isNotEmpty; diff --git a/src/main/templates/com/lambdaworks/redis/api/BaseRedisCommands.java b/src/main/templates/com/lambdaworks/redis/api/BaseRedisCommands.java index 38731b21dd..22671507a7 100644 --- a/src/main/templates/com/lambdaworks/redis/api/BaseRedisCommands.java +++ b/src/main/templates/com/lambdaworks/redis/api/BaseRedisCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import java.util.List; diff --git a/src/main/templates/com/lambdaworks/redis/api/RedisGeoCommands.java b/src/main/templates/com/lambdaworks/redis/api/RedisGeoCommands.java index 205093706f..2071b92634 100644 --- a/src/main/templates/com/lambdaworks/redis/api/RedisGeoCommands.java +++ b/src/main/templates/com/lambdaworks/redis/api/RedisGeoCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import com.lambdaworks.redis.GeoArgs; diff --git a/src/main/templates/com/lambdaworks/redis/api/RedisHLLCommands.java b/src/main/templates/com/lambdaworks/redis/api/RedisHLLCommands.java index a83f8bff4b..f3fdc6bd48 100644 --- a/src/main/templates/com/lambdaworks/redis/api/RedisHLLCommands.java +++ b/src/main/templates/com/lambdaworks/redis/api/RedisHLLCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.api; /** diff --git a/src/main/templates/com/lambdaworks/redis/api/RedisHashCommands.java b/src/main/templates/com/lambdaworks/redis/api/RedisHashCommands.java index 340de0b50b..b392fce6b8 100644 --- a/src/main/templates/com/lambdaworks/redis/api/RedisHashCommands.java +++ b/src/main/templates/com/lambdaworks/redis/api/RedisHashCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.api; import java.util.List; diff --git a/src/main/templates/com/lambdaworks/redis/api/RedisKeyCommands.java b/src/main/templates/com/lambdaworks/redis/api/RedisKeyCommands.java index bcf563fc1c..9e809c9fc1 100644 --- a/src/main/templates/com/lambdaworks/redis/api/RedisKeyCommands.java +++ b/src/main/templates/com/lambdaworks/redis/api/RedisKeyCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.api; import java.util.Date; diff --git a/src/main/templates/com/lambdaworks/redis/api/RedisListCommands.java b/src/main/templates/com/lambdaworks/redis/api/RedisListCommands.java index d1dbee8ac2..f2d97520b9 100644 --- a/src/main/templates/com/lambdaworks/redis/api/RedisListCommands.java +++ b/src/main/templates/com/lambdaworks/redis/api/RedisListCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.api; import java.util.List; diff --git a/src/main/templates/com/lambdaworks/redis/api/RedisScriptingCommands.java b/src/main/templates/com/lambdaworks/redis/api/RedisScriptingCommands.java index 2ce605c5af..f5c562eafe 100644 --- a/src/main/templates/com/lambdaworks/redis/api/RedisScriptingCommands.java +++ b/src/main/templates/com/lambdaworks/redis/api/RedisScriptingCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.api; import java.util.List; diff --git a/src/main/templates/com/lambdaworks/redis/api/RedisSentinelCommands.java b/src/main/templates/com/lambdaworks/redis/api/RedisSentinelCommands.java index ac71032723..255c2f0060 100644 --- a/src/main/templates/com/lambdaworks/redis/api/RedisSentinelCommands.java +++ b/src/main/templates/com/lambdaworks/redis/api/RedisSentinelCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import java.net.SocketAddress; diff --git a/src/main/templates/com/lambdaworks/redis/api/RedisServerCommands.java b/src/main/templates/com/lambdaworks/redis/api/RedisServerCommands.java index 790e7a0087..d0e92d1d21 100644 --- a/src/main/templates/com/lambdaworks/redis/api/RedisServerCommands.java +++ b/src/main/templates/com/lambdaworks/redis/api/RedisServerCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.api; import java.util.Date; diff --git a/src/main/templates/com/lambdaworks/redis/api/RedisSetCommands.java b/src/main/templates/com/lambdaworks/redis/api/RedisSetCommands.java index 17025aa0f2..0db16cdb97 100644 --- a/src/main/templates/com/lambdaworks/redis/api/RedisSetCommands.java +++ b/src/main/templates/com/lambdaworks/redis/api/RedisSetCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.api; import java.util.List; diff --git a/src/main/templates/com/lambdaworks/redis/api/RedisSortedSetCommands.java b/src/main/templates/com/lambdaworks/redis/api/RedisSortedSetCommands.java index 6e26962c72..2d0ef979f5 100644 --- a/src/main/templates/com/lambdaworks/redis/api/RedisSortedSetCommands.java +++ b/src/main/templates/com/lambdaworks/redis/api/RedisSortedSetCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.api; import java.util.List; diff --git a/src/main/templates/com/lambdaworks/redis/api/RedisStringCommands.java b/src/main/templates/com/lambdaworks/redis/api/RedisStringCommands.java index c087d0aca6..1e84a6d89f 100644 --- a/src/main/templates/com/lambdaworks/redis/api/RedisStringCommands.java +++ b/src/main/templates/com/lambdaworks/redis/api/RedisStringCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.api; import java.util.List; diff --git a/src/main/templates/com/lambdaworks/redis/api/RedisTransactionalCommands.java b/src/main/templates/com/lambdaworks/redis/api/RedisTransactionalCommands.java index e6ef5e1c36..54f499100a 100644 --- a/src/main/templates/com/lambdaworks/redis/api/RedisTransactionalCommands.java +++ b/src/main/templates/com/lambdaworks/redis/api/RedisTransactionalCommands.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.api; import java.util.List; diff --git a/src/test/java/biz/paluch/redis/extensibility/LettuceGeoDemo.java b/src/test/java/biz/paluch/redis/extensibility/LettuceGeoDemo.java index cc15040672..ec0308e6b6 100644 --- a/src/test/java/biz/paluch/redis/extensibility/LettuceGeoDemo.java +++ b/src/test/java/biz/paluch/redis/extensibility/LettuceGeoDemo.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package biz.paluch.redis.extensibility; import java.util.List; diff --git a/src/test/java/biz/paluch/redis/extensibility/MyExtendedRedisClient.java b/src/test/java/biz/paluch/redis/extensibility/MyExtendedRedisClient.java index 76f2487192..32735c92fc 100644 --- a/src/test/java/biz/paluch/redis/extensibility/MyExtendedRedisClient.java +++ b/src/test/java/biz/paluch/redis/extensibility/MyExtendedRedisClient.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package biz.paluch.redis.extensibility; import java.util.concurrent.TimeUnit; diff --git a/src/test/java/biz/paluch/redis/extensibility/MyExtendedRedisClientTest.java b/src/test/java/biz/paluch/redis/extensibility/MyExtendedRedisClientTest.java index a28f804d20..71b2e1b528 100644 --- a/src/test/java/biz/paluch/redis/extensibility/MyExtendedRedisClientTest.java +++ b/src/test/java/biz/paluch/redis/extensibility/MyExtendedRedisClientTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package biz.paluch.redis.extensibility; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/biz/paluch/redis/extensibility/MyPubSubConnection.java b/src/test/java/biz/paluch/redis/extensibility/MyPubSubConnection.java index dd3e9933d7..674d21dc0e 100644 --- a/src/test/java/biz/paluch/redis/extensibility/MyPubSubConnection.java +++ b/src/test/java/biz/paluch/redis/extensibility/MyPubSubConnection.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package biz.paluch.redis.extensibility; import java.util.concurrent.TimeUnit; diff --git a/src/test/java/com/lambdaworks/CanConnect.java b/src/test/java/com/lambdaworks/CanConnect.java index 764cd2c267..8788791377 100644 --- a/src/test/java/com/lambdaworks/CanConnect.java +++ b/src/test/java/com/lambdaworks/CanConnect.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks; import java.io.IOException; diff --git a/src/test/java/com/lambdaworks/ConnectionTestUtil.java b/src/test/java/com/lambdaworks/ConnectionTestUtil.java index 47fb6216f0..a2c4c36c12 100644 --- a/src/test/java/com/lambdaworks/ConnectionTestUtil.java +++ b/src/test/java/com/lambdaworks/ConnectionTestUtil.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks; import java.util.Queue; diff --git a/src/test/java/com/lambdaworks/Delay.java b/src/test/java/com/lambdaworks/Delay.java index b1d36361d6..4935f3646e 100644 --- a/src/test/java/com/lambdaworks/Delay.java +++ b/src/test/java/com/lambdaworks/Delay.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks; import com.google.code.tempusfugit.temporal.Duration; diff --git a/src/test/java/com/lambdaworks/Futures.java b/src/test/java/com/lambdaworks/Futures.java index 4bb354538b..42d603fcc8 100644 --- a/src/test/java/com/lambdaworks/Futures.java +++ b/src/test/java/com/lambdaworks/Futures.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks; import java.util.Collection; diff --git a/src/test/java/com/lambdaworks/KeysAndValues.java b/src/test/java/com/lambdaworks/KeysAndValues.java index 9c0019cba4..381969f309 100644 --- a/src/test/java/com/lambdaworks/KeysAndValues.java +++ b/src/test/java/com/lambdaworks/KeysAndValues.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks; import java.util.*; diff --git a/src/test/java/com/lambdaworks/LoggingTestRule.java b/src/test/java/com/lambdaworks/LoggingTestRule.java index f18befd8c8..a1c054c78a 100644 --- a/src/test/java/com/lambdaworks/LoggingTestRule.java +++ b/src/test/java/com/lambdaworks/LoggingTestRule.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks; import java.io.ByteArrayOutputStream; diff --git a/src/test/java/com/lambdaworks/Sockets.java b/src/test/java/com/lambdaworks/Sockets.java index c6fef47ce5..63f0f73987 100644 --- a/src/test/java/com/lambdaworks/Sockets.java +++ b/src/test/java/com/lambdaworks/Sockets.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks; import java.io.IOException; diff --git a/src/test/java/com/lambdaworks/SslTest.java b/src/test/java/com/lambdaworks/SslTest.java index de0baa3158..be52145474 100644 --- a/src/test/java/com/lambdaworks/SslTest.java +++ b/src/test/java/com/lambdaworks/SslTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks; import static com.lambdaworks.redis.TestSettings.host; diff --git a/src/test/java/com/lambdaworks/TestClientResources.java b/src/test/java/com/lambdaworks/TestClientResources.java index 8820292dfc..2acd2530db 100644 --- a/src/test/java/com/lambdaworks/TestClientResources.java +++ b/src/test/java/com/lambdaworks/TestClientResources.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks; import java.util.concurrent.TimeUnit; diff --git a/src/test/java/com/lambdaworks/Wait.java b/src/test/java/com/lambdaworks/Wait.java index 12f941f157..2512ceb65f 100644 --- a/src/test/java/com/lambdaworks/Wait.java +++ b/src/test/java/com/lambdaworks/Wait.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks; import java.util.concurrent.ExecutionException; diff --git a/src/test/java/com/lambdaworks/apigenerator/CompilationUnitFactory.java b/src/test/java/com/lambdaworks/apigenerator/CompilationUnitFactory.java index fdb6225951..fe132bfbc0 100644 --- a/src/test/java/com/lambdaworks/apigenerator/CompilationUnitFactory.java +++ b/src/test/java/com/lambdaworks/apigenerator/CompilationUnitFactory.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.apigenerator; import java.io.File; diff --git a/src/test/java/com/lambdaworks/apigenerator/Constants.java b/src/test/java/com/lambdaworks/apigenerator/Constants.java index 3f60c1dceb..26535efaf5 100644 --- a/src/test/java/com/lambdaworks/apigenerator/Constants.java +++ b/src/test/java/com/lambdaworks/apigenerator/Constants.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.apigenerator; import java.io.File; diff --git a/src/test/java/com/lambdaworks/apigenerator/CreateAsyncApi.java b/src/test/java/com/lambdaworks/apigenerator/CreateAsyncApi.java index d102af1d56..c9f1ce7abd 100644 --- a/src/test/java/com/lambdaworks/apigenerator/CreateAsyncApi.java +++ b/src/test/java/com/lambdaworks/apigenerator/CreateAsyncApi.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.apigenerator; import java.io.File; diff --git a/src/test/java/com/lambdaworks/apigenerator/CreateAsyncNodeSelectionClusterApi.java b/src/test/java/com/lambdaworks/apigenerator/CreateAsyncNodeSelectionClusterApi.java index af4796334e..507e4ddd98 100644 --- a/src/test/java/com/lambdaworks/apigenerator/CreateAsyncNodeSelectionClusterApi.java +++ b/src/test/java/com/lambdaworks/apigenerator/CreateAsyncNodeSelectionClusterApi.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.apigenerator; import java.io.File; diff --git a/src/test/java/com/lambdaworks/apigenerator/CreateReactiveApi.java b/src/test/java/com/lambdaworks/apigenerator/CreateReactiveApi.java index e1fffc81af..dae8a7b7ef 100644 --- a/src/test/java/com/lambdaworks/apigenerator/CreateReactiveApi.java +++ b/src/test/java/com/lambdaworks/apigenerator/CreateReactiveApi.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.apigenerator; import java.io.File; diff --git a/src/test/java/com/lambdaworks/apigenerator/CreateSyncApi.java b/src/test/java/com/lambdaworks/apigenerator/CreateSyncApi.java index 59edd075c9..843dff8191 100644 --- a/src/test/java/com/lambdaworks/apigenerator/CreateSyncApi.java +++ b/src/test/java/com/lambdaworks/apigenerator/CreateSyncApi.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.apigenerator; import java.io.File; diff --git a/src/test/java/com/lambdaworks/apigenerator/CreateSyncNodeSelectionClusterApi.java b/src/test/java/com/lambdaworks/apigenerator/CreateSyncNodeSelectionClusterApi.java index 40e913ed75..7487e21f2f 100644 --- a/src/test/java/com/lambdaworks/apigenerator/CreateSyncNodeSelectionClusterApi.java +++ b/src/test/java/com/lambdaworks/apigenerator/CreateSyncNodeSelectionClusterApi.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.apigenerator; import java.io.File; diff --git a/src/test/java/com/lambdaworks/apigenerator/GenerateCommandInterfaces.java b/src/test/java/com/lambdaworks/apigenerator/GenerateCommandInterfaces.java index 8e40107cfd..e3e25f79b2 100644 --- a/src/test/java/com/lambdaworks/apigenerator/GenerateCommandInterfaces.java +++ b/src/test/java/com/lambdaworks/apigenerator/GenerateCommandInterfaces.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.apigenerator; import org.junit.runner.RunWith; diff --git a/src/test/java/com/lambdaworks/category/SlowTests.java b/src/test/java/com/lambdaworks/category/SlowTests.java index 026b2b6ceb..77d4836f2c 100644 --- a/src/test/java/com/lambdaworks/category/SlowTests.java +++ b/src/test/java/com/lambdaworks/category/SlowTests.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.category; /** diff --git a/src/test/java/com/lambdaworks/codec/CRC16Test.java b/src/test/java/com/lambdaworks/codec/CRC16Test.java index 96676b0d3a..94399b7df0 100644 --- a/src/test/java/com/lambdaworks/codec/CRC16Test.java +++ b/src/test/java/com/lambdaworks/codec/CRC16Test.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.codec; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/com/lambdaworks/examples/ConnectToElastiCacheMaster.java b/src/test/java/com/lambdaworks/examples/ConnectToElastiCacheMaster.java index 98fc3a35fd..fd78c38de3 100644 --- a/src/test/java/com/lambdaworks/examples/ConnectToElastiCacheMaster.java +++ b/src/test/java/com/lambdaworks/examples/ConnectToElastiCacheMaster.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.examples; import com.lambdaworks.redis.RedisClient; diff --git a/src/test/java/com/lambdaworks/examples/ConnectToMasterSlaveUsingElastiCacheCluster.java b/src/test/java/com/lambdaworks/examples/ConnectToMasterSlaveUsingElastiCacheCluster.java index 533c3b6255..145db6ab12 100644 --- a/src/test/java/com/lambdaworks/examples/ConnectToMasterSlaveUsingElastiCacheCluster.java +++ b/src/test/java/com/lambdaworks/examples/ConnectToMasterSlaveUsingElastiCacheCluster.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.examples; import java.util.Arrays; diff --git a/src/test/java/com/lambdaworks/examples/ConnectToMasterSlaveUsingRedisSentinel.java b/src/test/java/com/lambdaworks/examples/ConnectToMasterSlaveUsingRedisSentinel.java index 279e79e44f..caeca3c0aa 100644 --- a/src/test/java/com/lambdaworks/examples/ConnectToMasterSlaveUsingRedisSentinel.java +++ b/src/test/java/com/lambdaworks/examples/ConnectToMasterSlaveUsingRedisSentinel.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.examples; import com.lambdaworks.redis.ReadFrom; diff --git a/src/test/java/com/lambdaworks/examples/ConnectToRedis.java b/src/test/java/com/lambdaworks/examples/ConnectToRedis.java index b8b3d66237..2592209929 100644 --- a/src/test/java/com/lambdaworks/examples/ConnectToRedis.java +++ b/src/test/java/com/lambdaworks/examples/ConnectToRedis.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.examples; import com.lambdaworks.redis.RedisClient; diff --git a/src/test/java/com/lambdaworks/examples/ConnectToRedisCluster.java b/src/test/java/com/lambdaworks/examples/ConnectToRedisCluster.java index 2eb5701ad7..d9a9e568e4 100644 --- a/src/test/java/com/lambdaworks/examples/ConnectToRedisCluster.java +++ b/src/test/java/com/lambdaworks/examples/ConnectToRedisCluster.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.examples; import com.lambdaworks.redis.cluster.RedisClusterClient; diff --git a/src/test/java/com/lambdaworks/examples/ConnectToRedisClusterSSL.java b/src/test/java/com/lambdaworks/examples/ConnectToRedisClusterSSL.java index 858329e045..1ea69e6087 100644 --- a/src/test/java/com/lambdaworks/examples/ConnectToRedisClusterSSL.java +++ b/src/test/java/com/lambdaworks/examples/ConnectToRedisClusterSSL.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.examples; import com.lambdaworks.redis.RedisURI; diff --git a/src/test/java/com/lambdaworks/examples/ConnectToRedisClusterWithTopologyRefreshing.java b/src/test/java/com/lambdaworks/examples/ConnectToRedisClusterWithTopologyRefreshing.java index 10faa5da8b..cb0d5179e1 100644 --- a/src/test/java/com/lambdaworks/examples/ConnectToRedisClusterWithTopologyRefreshing.java +++ b/src/test/java/com/lambdaworks/examples/ConnectToRedisClusterWithTopologyRefreshing.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.examples; import java.util.concurrent.TimeUnit; diff --git a/src/test/java/com/lambdaworks/examples/ConnectToRedisSSL.java b/src/test/java/com/lambdaworks/examples/ConnectToRedisSSL.java index 9182c6a4ad..2fa7390a53 100644 --- a/src/test/java/com/lambdaworks/examples/ConnectToRedisSSL.java +++ b/src/test/java/com/lambdaworks/examples/ConnectToRedisSSL.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.examples; import com.lambdaworks.redis.RedisClient; diff --git a/src/test/java/com/lambdaworks/examples/ConnectToRedisUsingRedisSentinel.java b/src/test/java/com/lambdaworks/examples/ConnectToRedisUsingRedisSentinel.java index f6c2227211..9e6f6455c4 100644 --- a/src/test/java/com/lambdaworks/examples/ConnectToRedisUsingRedisSentinel.java +++ b/src/test/java/com/lambdaworks/examples/ConnectToRedisUsingRedisSentinel.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.examples; import com.lambdaworks.redis.RedisClient; diff --git a/src/test/java/com/lambdaworks/examples/MySpringBean.java b/src/test/java/com/lambdaworks/examples/MySpringBean.java index b4ef6ca145..abced3b3d3 100644 --- a/src/test/java/com/lambdaworks/examples/MySpringBean.java +++ b/src/test/java/com/lambdaworks/examples/MySpringBean.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.examples; import com.lambdaworks.redis.*; diff --git a/src/test/java/com/lambdaworks/examples/ReadWriteExample.java b/src/test/java/com/lambdaworks/examples/ReadWriteExample.java index 2761532f83..49449ee206 100644 --- a/src/test/java/com/lambdaworks/examples/ReadWriteExample.java +++ b/src/test/java/com/lambdaworks/examples/ReadWriteExample.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.examples; import com.lambdaworks.redis.RedisClient; diff --git a/src/test/java/com/lambdaworks/examples/SpringExample.java b/src/test/java/com/lambdaworks/examples/SpringExample.java index 9ac1c334c8..4e32dacb3c 100644 --- a/src/test/java/com/lambdaworks/examples/SpringExample.java +++ b/src/test/java/com/lambdaworks/examples/SpringExample.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.examples; import org.springframework.context.support.ClassPathXmlApplicationContext; diff --git a/src/test/java/com/lambdaworks/redis/AbstractRedisClientTest.java b/src/test/java/com/lambdaworks/redis/AbstractRedisClientTest.java index b93781465d..23a4b3d9c7 100644 --- a/src/test/java/com/lambdaworks/redis/AbstractRedisClientTest.java +++ b/src/test/java/com/lambdaworks/redis/AbstractRedisClientTest.java @@ -1,5 +1,18 @@ -// Copyright (C) 2011 - Will Glozer. All rights reserved. - +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import com.lambdaworks.TestClientResources; @@ -10,6 +23,10 @@ import com.lambdaworks.redis.api.sync.RedisCommands; +/** + * @author Will Glozer + * @author Mark Paluch + */ public abstract class AbstractRedisClientTest extends AbstractTest { protected static RedisClient client; diff --git a/src/test/java/com/lambdaworks/redis/AbstractTest.java b/src/test/java/com/lambdaworks/redis/AbstractTest.java index a1d693e015..df3e32a3c7 100644 --- a/src/test/java/com/lambdaworks/redis/AbstractTest.java +++ b/src/test/java/com/lambdaworks/redis/AbstractTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import java.util.Arrays; diff --git a/src/test/java/com/lambdaworks/redis/AllTheAPIsTest.java b/src/test/java/com/lambdaworks/redis/AllTheAPIsTest.java index f71741a34b..f35c04559c 100644 --- a/src/test/java/com/lambdaworks/redis/AllTheAPIsTest.java +++ b/src/test/java/com/lambdaworks/redis/AllTheAPIsTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import com.lambdaworks.TestClientResources; diff --git a/src/test/java/com/lambdaworks/redis/AsyncConnectionTest.java b/src/test/java/com/lambdaworks/redis/AsyncConnectionTest.java index 052535163c..3805e1a61a 100644 --- a/src/test/java/com/lambdaworks/redis/AsyncConnectionTest.java +++ b/src/test/java/com/lambdaworks/redis/AsyncConnectionTest.java @@ -1,5 +1,18 @@ -// Copyright (C) 2011 - Will Glozer. All rights reserved. - +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import static org.assertj.core.api.Assertions.assertThat; @@ -17,6 +30,10 @@ import com.lambdaworks.redis.api.async.RedisAsyncCommands; +/** + * @author Will Glozer + * @author Mark Paluch + */ public class AsyncConnectionTest extends AbstractRedisClientTest { private RedisAsyncCommands async; diff --git a/src/test/java/com/lambdaworks/redis/ClientMetricsTest.java b/src/test/java/com/lambdaworks/redis/ClientMetricsTest.java index ddc5c212be..4f3eadfc69 100644 --- a/src/test/java/com/lambdaworks/redis/ClientMetricsTest.java +++ b/src/test/java/com/lambdaworks/redis/ClientMetricsTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import static com.lambdaworks.redis.AbstractRedisClientTest.client; diff --git a/src/test/java/com/lambdaworks/redis/ClientOptionsTest.java b/src/test/java/com/lambdaworks/redis/ClientOptionsTest.java index a53dd74b4f..1f3838f4f0 100644 --- a/src/test/java/com/lambdaworks/redis/ClientOptionsTest.java +++ b/src/test/java/com/lambdaworks/redis/ClientOptionsTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import static com.lambdaworks.ConnectionTestUtil.getChannel; diff --git a/src/test/java/com/lambdaworks/redis/ClientTest.java b/src/test/java/com/lambdaworks/redis/ClientTest.java index 47c773cc7f..b0fe55932c 100644 --- a/src/test/java/com/lambdaworks/redis/ClientTest.java +++ b/src/test/java/com/lambdaworks/redis/ClientTest.java @@ -1,5 +1,18 @@ -// Copyright (C) 2011 - Will Glozer. All rights reserved. - +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import static com.google.code.tempusfugit.temporal.Duration.seconds; @@ -20,6 +33,10 @@ import com.lambdaworks.redis.api.StatefulRedisConnection; import com.lambdaworks.redis.api.async.RedisAsyncCommands; +/** + * @author Will Glozer + * @author Mark Paluch + */ @FixMethodOrder(MethodSorters.NAME_ASCENDING) public class ClientTest extends AbstractRedisClientTest { @Rule diff --git a/src/test/java/com/lambdaworks/redis/ConnectionCommandTest.java b/src/test/java/com/lambdaworks/redis/ConnectionCommandTest.java index 5efbefc87e..342a450f9b 100644 --- a/src/test/java/com/lambdaworks/redis/ConnectionCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/ConnectionCommandTest.java @@ -1,5 +1,18 @@ -// Copyright (C) 2011 - Will Glozer. All rights reserved. - +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import static org.assertj.core.api.Assertions.assertThat; @@ -16,6 +29,10 @@ import com.lambdaworks.redis.api.async.RedisAsyncCommands; import com.lambdaworks.redis.api.sync.RedisCommands; +/** + * @author Will Glozer + * @author Mark Paluch + */ @FixMethodOrder(MethodSorters.NAME_ASCENDING) public class ConnectionCommandTest extends AbstractRedisClientTest { @Test diff --git a/src/test/java/com/lambdaworks/redis/CustomCodecTest.java b/src/test/java/com/lambdaworks/redis/CustomCodecTest.java index f0e71b9308..c83e386585 100644 --- a/src/test/java/com/lambdaworks/redis/CustomCodecTest.java +++ b/src/test/java/com/lambdaworks/redis/CustomCodecTest.java @@ -1,5 +1,18 @@ -// Copyright (C) 2011 - Will Glozer. All rights reserved. - +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import static org.assertj.core.api.Assertions.assertThat; @@ -23,6 +36,10 @@ import com.lambdaworks.redis.codec.CompressionCodec; import com.lambdaworks.redis.codec.RedisCodec; +/** + * @author Will Glozer + * @author Mark Paluch + */ public class CustomCodecTest extends AbstractRedisClientTest { @Test diff --git a/src/test/java/com/lambdaworks/redis/DefaultRedisClient.java b/src/test/java/com/lambdaworks/redis/DefaultRedisClient.java index 0a0014246d..c539c20314 100644 --- a/src/test/java/com/lambdaworks/redis/DefaultRedisClient.java +++ b/src/test/java/com/lambdaworks/redis/DefaultRedisClient.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import java.util.concurrent.TimeUnit; diff --git a/src/test/java/com/lambdaworks/redis/FastShutdown.java b/src/test/java/com/lambdaworks/redis/FastShutdown.java index ab93ea4af3..8f8a67b57d 100644 --- a/src/test/java/com/lambdaworks/redis/FastShutdown.java +++ b/src/test/java/com/lambdaworks/redis/FastShutdown.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import java.util.concurrent.TimeUnit; diff --git a/src/test/java/com/lambdaworks/redis/GeoModelTest.java b/src/test/java/com/lambdaworks/redis/GeoModelTest.java index a6168e7ad9..be531c99bd 100644 --- a/src/test/java/com/lambdaworks/redis/GeoModelTest.java +++ b/src/test/java/com/lambdaworks/redis/GeoModelTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import static org.assertj.core.api.Assertions.*; diff --git a/src/test/java/com/lambdaworks/redis/JavaRuntimeTest.java b/src/test/java/com/lambdaworks/redis/JavaRuntimeTest.java index 5f49d528ab..76d6b69888 100644 --- a/src/test/java/com/lambdaworks/redis/JavaRuntimeTest.java +++ b/src/test/java/com/lambdaworks/redis/JavaRuntimeTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/com/lambdaworks/redis/KeyValueStreamingAdapter.java b/src/test/java/com/lambdaworks/redis/KeyValueStreamingAdapter.java index 36ee2a4bc1..463cbb59ea 100644 --- a/src/test/java/com/lambdaworks/redis/KeyValueStreamingAdapter.java +++ b/src/test/java/com/lambdaworks/redis/KeyValueStreamingAdapter.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import java.util.LinkedHashMap; diff --git a/src/test/java/com/lambdaworks/redis/KeyValueTest.java b/src/test/java/com/lambdaworks/redis/KeyValueTest.java index 59a81ba8c2..99e53789ee 100644 --- a/src/test/java/com/lambdaworks/redis/KeyValueTest.java +++ b/src/test/java/com/lambdaworks/redis/KeyValueTest.java @@ -1,4 +1,19 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/com/lambdaworks/redis/LettuceFuturesTest.java b/src/test/java/com/lambdaworks/redis/LettuceFuturesTest.java index 7e833be163..aa605c13d9 100644 --- a/src/test/java/com/lambdaworks/redis/LettuceFuturesTest.java +++ b/src/test/java/com/lambdaworks/redis/LettuceFuturesTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import org.junit.Before; diff --git a/src/test/java/com/lambdaworks/redis/LimitTest.java b/src/test/java/com/lambdaworks/redis/LimitTest.java index a5e1595219..e6f3e75f80 100644 --- a/src/test/java/com/lambdaworks/redis/LimitTest.java +++ b/src/test/java/com/lambdaworks/redis/LimitTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/com/lambdaworks/redis/ListStreamingAdapter.java b/src/test/java/com/lambdaworks/redis/ListStreamingAdapter.java index c4be19abc9..9129f0c6fc 100644 --- a/src/test/java/com/lambdaworks/redis/ListStreamingAdapter.java +++ b/src/test/java/com/lambdaworks/redis/ListStreamingAdapter.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import java.util.ArrayList; diff --git a/src/test/java/com/lambdaworks/redis/PipeliningTest.java b/src/test/java/com/lambdaworks/redis/PipeliningTest.java index eaa42e89c2..36fb41036f 100644 --- a/src/test/java/com/lambdaworks/redis/PipeliningTest.java +++ b/src/test/java/com/lambdaworks/redis/PipeliningTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/com/lambdaworks/redis/PrivateAccessorTest.java b/src/test/java/com/lambdaworks/redis/PrivateAccessorTest.java index 4bf98f434d..95908f1b16 100644 --- a/src/test/java/com/lambdaworks/redis/PrivateAccessorTest.java +++ b/src/test/java/com/lambdaworks/redis/PrivateAccessorTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/com/lambdaworks/redis/RangeTest.java b/src/test/java/com/lambdaworks/redis/RangeTest.java index d250338145..44d5726b1d 100644 --- a/src/test/java/com/lambdaworks/redis/RangeTest.java +++ b/src/test/java/com/lambdaworks/redis/RangeTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import static com.lambdaworks.redis.Range.Boundary.excluding; diff --git a/src/test/java/com/lambdaworks/redis/ReactiveConnectionTest.java b/src/test/java/com/lambdaworks/redis/ReactiveConnectionTest.java index 8ca90b8d21..c95498c5e3 100644 --- a/src/test/java/com/lambdaworks/redis/ReactiveConnectionTest.java +++ b/src/test/java/com/lambdaworks/redis/ReactiveConnectionTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import static com.google.code.tempusfugit.temporal.Duration.millis; diff --git a/src/test/java/com/lambdaworks/redis/ReactiveStreamingOutputTest.java b/src/test/java/com/lambdaworks/redis/ReactiveStreamingOutputTest.java index 1e19c554f3..55d8bb9e11 100644 --- a/src/test/java/com/lambdaworks/redis/ReactiveStreamingOutputTest.java +++ b/src/test/java/com/lambdaworks/redis/ReactiveStreamingOutputTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; diff --git a/src/test/java/com/lambdaworks/redis/RedisClientConnectionTest.java b/src/test/java/com/lambdaworks/redis/RedisClientConnectionTest.java index 81b713dd5b..e5bf5c9426 100644 --- a/src/test/java/com/lambdaworks/redis/RedisClientConnectionTest.java +++ b/src/test/java/com/lambdaworks/redis/RedisClientConnectionTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import static com.lambdaworks.redis.RedisURI.Builder.redis; diff --git a/src/test/java/com/lambdaworks/redis/RedisClientFactoryBeanTest.java b/src/test/java/com/lambdaworks/redis/RedisClientFactoryBeanTest.java index c8728f8b82..876b9daf08 100644 --- a/src/test/java/com/lambdaworks/redis/RedisClientFactoryBeanTest.java +++ b/src/test/java/com/lambdaworks/redis/RedisClientFactoryBeanTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/com/lambdaworks/redis/RedisClientFactoryTest.java b/src/test/java/com/lambdaworks/redis/RedisClientFactoryTest.java index 6a1e0a9a10..372bd09c7c 100644 --- a/src/test/java/com/lambdaworks/redis/RedisClientFactoryTest.java +++ b/src/test/java/com/lambdaworks/redis/RedisClientFactoryTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import com.lambdaworks.TestClientResources; diff --git a/src/test/java/com/lambdaworks/redis/RedisClientTest.java b/src/test/java/com/lambdaworks/redis/RedisClientTest.java index 16b8ca7e23..a488f3677a 100644 --- a/src/test/java/com/lambdaworks/redis/RedisClientTest.java +++ b/src/test/java/com/lambdaworks/redis/RedisClientTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/com/lambdaworks/redis/RedisURIBuilderTest.java b/src/test/java/com/lambdaworks/redis/RedisURIBuilderTest.java index d6b3e1c1f6..6dd30fbd5b 100644 --- a/src/test/java/com/lambdaworks/redis/RedisURIBuilderTest.java +++ b/src/test/java/com/lambdaworks/redis/RedisURIBuilderTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/com/lambdaworks/redis/RedisURITest.java b/src/test/java/com/lambdaworks/redis/RedisURITest.java index 7845c8d11a..7174f20879 100644 --- a/src/test/java/com/lambdaworks/redis/RedisURITest.java +++ b/src/test/java/com/lambdaworks/redis/RedisURITest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/com/lambdaworks/redis/ScanCursorTest.java b/src/test/java/com/lambdaworks/redis/ScanCursorTest.java index 3b7a5f7906..e47fbd5ceb 100644 --- a/src/test/java/com/lambdaworks/redis/ScanCursorTest.java +++ b/src/test/java/com/lambdaworks/redis/ScanCursorTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/com/lambdaworks/redis/ScoredValueStreamingAdapter.java b/src/test/java/com/lambdaworks/redis/ScoredValueStreamingAdapter.java index 51a211c22c..1b03ac06ee 100644 --- a/src/test/java/com/lambdaworks/redis/ScoredValueStreamingAdapter.java +++ b/src/test/java/com/lambdaworks/redis/ScoredValueStreamingAdapter.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import java.util.ArrayList; diff --git a/src/test/java/com/lambdaworks/redis/ScoredValueTest.java b/src/test/java/com/lambdaworks/redis/ScoredValueTest.java index f711d9a354..438e831809 100644 --- a/src/test/java/com/lambdaworks/redis/ScoredValueTest.java +++ b/src/test/java/com/lambdaworks/redis/ScoredValueTest.java @@ -1,4 +1,19 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/com/lambdaworks/redis/SocketOptionsTest.java b/src/test/java/com/lambdaworks/redis/SocketOptionsTest.java index eedbbf3222..85051e8740 100644 --- a/src/test/java/com/lambdaworks/redis/SocketOptionsTest.java +++ b/src/test/java/com/lambdaworks/redis/SocketOptionsTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import static org.assertj.core.api.Assertions.assertThat; @@ -67,4 +82,4 @@ public void testConnectTimeout() { } } } -} \ No newline at end of file +} diff --git a/src/test/java/com/lambdaworks/redis/SyncAsyncApiConvergenceTest.java b/src/test/java/com/lambdaworks/redis/SyncAsyncApiConvergenceTest.java index 33febca596..905d46c805 100644 --- a/src/test/java/com/lambdaworks/redis/SyncAsyncApiConvergenceTest.java +++ b/src/test/java/com/lambdaworks/redis/SyncAsyncApiConvergenceTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/com/lambdaworks/redis/TestEventLoopGroupProvider.java b/src/test/java/com/lambdaworks/redis/TestEventLoopGroupProvider.java index dd47f7bbe5..0c5b218ec4 100644 --- a/src/test/java/com/lambdaworks/redis/TestEventLoopGroupProvider.java +++ b/src/test/java/com/lambdaworks/redis/TestEventLoopGroupProvider.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import java.util.concurrent.TimeUnit; diff --git a/src/test/java/com/lambdaworks/redis/TestRedisPublisher.java b/src/test/java/com/lambdaworks/redis/TestRedisPublisher.java index 3f6777ed2d..ff14a1321a 100644 --- a/src/test/java/com/lambdaworks/redis/TestRedisPublisher.java +++ b/src/test/java/com/lambdaworks/redis/TestRedisPublisher.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import java.util.function.Supplier; diff --git a/src/test/java/com/lambdaworks/redis/TestSettings.java b/src/test/java/com/lambdaworks/redis/TestSettings.java index b15ef373d3..a8942940af 100644 --- a/src/test/java/com/lambdaworks/redis/TestSettings.java +++ b/src/test/java/com/lambdaworks/redis/TestSettings.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import java.net.Inet4Address; diff --git a/src/test/java/com/lambdaworks/redis/UnixDomainSocketTest.java b/src/test/java/com/lambdaworks/redis/UnixDomainSocketTest.java index 91bf46432e..b3444fd554 100644 --- a/src/test/java/com/lambdaworks/redis/UnixDomainSocketTest.java +++ b/src/test/java/com/lambdaworks/redis/UnixDomainSocketTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/com/lambdaworks/redis/Utf8StringCodecTest.java b/src/test/java/com/lambdaworks/redis/Utf8StringCodecTest.java index bd04ef84cd..908240ae33 100644 --- a/src/test/java/com/lambdaworks/redis/Utf8StringCodecTest.java +++ b/src/test/java/com/lambdaworks/redis/Utf8StringCodecTest.java @@ -1,5 +1,18 @@ -// Copyright (C) 2011 - Will Glozer. All rights reserved. - +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import static org.assertj.core.api.Assertions.assertThat; @@ -8,6 +21,10 @@ import org.junit.Test; +/** + * @author Will Glozer + * @author Mark Paluch + */ public class Utf8StringCodecTest extends AbstractRedisClientTest { @Test public void decodeHugeBuffer() throws Exception { diff --git a/src/test/java/com/lambdaworks/redis/ValueTest.java b/src/test/java/com/lambdaworks/redis/ValueTest.java index 5bfa8361d4..19fd545e11 100644 --- a/src/test/java/com/lambdaworks/redis/ValueTest.java +++ b/src/test/java/com/lambdaworks/redis/ValueTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/com/lambdaworks/redis/cluster/AbstractClusterTest.java b/src/test/java/com/lambdaworks/redis/cluster/AbstractClusterTest.java index ca2f927d9f..dfb94151f7 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/AbstractClusterTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/AbstractClusterTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster; import com.lambdaworks.TestClientResources; diff --git a/src/test/java/com/lambdaworks/redis/cluster/AdvancedClusterClientTest.java b/src/test/java/com/lambdaworks/redis/cluster/AdvancedClusterClientTest.java index 0e93178897..6631c6f848 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/AdvancedClusterClientTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/AdvancedClusterClientTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/com/lambdaworks/redis/cluster/AdvancedClusterReactiveTest.java b/src/test/java/com/lambdaworks/redis/cluster/AdvancedClusterReactiveTest.java index 81d4db86e1..a7292f35f6 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/AdvancedClusterReactiveTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/AdvancedClusterReactiveTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/com/lambdaworks/redis/cluster/ByteCodecClusterTest.java b/src/test/java/com/lambdaworks/redis/cluster/ByteCodecClusterTest.java index c7ba6665fa..0180a1875a 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/ByteCodecClusterTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/ByteCodecClusterTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/com/lambdaworks/redis/cluster/ClusterClientOptionsTest.java b/src/test/java/com/lambdaworks/redis/cluster/ClusterClientOptionsTest.java index 79e0e893e8..c196599c42 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/ClusterClientOptionsTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/ClusterClientOptionsTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/com/lambdaworks/redis/cluster/ClusterCommandInternalsTest.java b/src/test/java/com/lambdaworks/redis/cluster/ClusterCommandInternalsTest.java index 2a60483451..8a9c2c06c8 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/ClusterCommandInternalsTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/ClusterCommandInternalsTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/com/lambdaworks/redis/cluster/ClusterCommandTest.java b/src/test/java/com/lambdaworks/redis/cluster/ClusterCommandTest.java index 61c29e1a75..67dc03b200 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/ClusterCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/ClusterCommandTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster; import static com.google.code.tempusfugit.temporal.Duration.seconds; diff --git a/src/test/java/com/lambdaworks/redis/cluster/ClusterDistributionChannelWriterTest.java b/src/test/java/com/lambdaworks/redis/cluster/ClusterDistributionChannelWriterTest.java index 0aa168270f..a2d77cdfa4 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/ClusterDistributionChannelWriterTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/ClusterDistributionChannelWriterTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster; import static org.assertj.core.api.Assertions.assertThat; @@ -46,4 +61,4 @@ public void shouldParseIPv6MovedTargetCorrectly() throws Exception { assertThat(moveTarget.getHostText()).isEqualTo("1:2:3:4::6"); assertThat(moveTarget.getPort()).isEqualTo(6381); } -} \ No newline at end of file +} diff --git a/src/test/java/com/lambdaworks/redis/cluster/ClusterNodeEndpointTest.java b/src/test/java/com/lambdaworks/redis/cluster/ClusterNodeEndpointTest.java index 564595e50a..d7ecaceeef 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/ClusterNodeEndpointTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/ClusterNodeEndpointTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; diff --git a/src/test/java/com/lambdaworks/redis/cluster/ClusterPartiallyDownTest.java b/src/test/java/com/lambdaworks/redis/cluster/ClusterPartiallyDownTest.java index a4cb0b0f2b..bfea690cea 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/ClusterPartiallyDownTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/ClusterPartiallyDownTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/com/lambdaworks/redis/cluster/ClusterPartitionParserTest.java b/src/test/java/com/lambdaworks/redis/cluster/ClusterPartitionParserTest.java index d89abff6b6..924e159c98 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/ClusterPartitionParserTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/ClusterPartitionParserTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/com/lambdaworks/redis/cluster/ClusterReactiveCommandTest.java b/src/test/java/com/lambdaworks/redis/cluster/ClusterReactiveCommandTest.java index c0f5d2a81a..84a9e39155 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/ClusterReactiveCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/ClusterReactiveCommandTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster; import static com.lambdaworks.redis.cluster.ClusterTestUtil.getNodeId; diff --git a/src/test/java/com/lambdaworks/redis/cluster/ClusterRule.java b/src/test/java/com/lambdaworks/redis/cluster/ClusterRule.java index d3c8d3cb9a..b420e702ed 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/ClusterRule.java +++ b/src/test/java/com/lambdaworks/redis/cluster/ClusterRule.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster; import java.net.InetSocketAddress; diff --git a/src/test/java/com/lambdaworks/redis/cluster/ClusterSetup.java b/src/test/java/com/lambdaworks/redis/cluster/ClusterSetup.java index ad27046be2..9afc44cf56 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/ClusterSetup.java +++ b/src/test/java/com/lambdaworks/redis/cluster/ClusterSetup.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster; import java.util.concurrent.ExecutionException; diff --git a/src/test/java/com/lambdaworks/redis/cluster/ClusterTestUtil.java b/src/test/java/com/lambdaworks/redis/cluster/ClusterTestUtil.java index fd3405d370..32874e98f2 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/ClusterTestUtil.java +++ b/src/test/java/com/lambdaworks/redis/cluster/ClusterTestUtil.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster; import java.lang.reflect.InvocationHandler; diff --git a/src/test/java/com/lambdaworks/redis/cluster/ClusterTopologyRefreshOptionsTest.java b/src/test/java/com/lambdaworks/redis/cluster/ClusterTopologyRefreshOptionsTest.java index a69c254bb6..6e967cbb85 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/ClusterTopologyRefreshOptionsTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/ClusterTopologyRefreshOptionsTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster; import static org.assertj.core.api.Assertions.assertThat; @@ -92,4 +107,4 @@ public void testEnabled() throws Exception { assertThat(options.getAdaptiveRefreshTriggers()).contains(RefreshTrigger.ASK_REDIRECT, RefreshTrigger.MOVED_REDIRECT, RefreshTrigger.PERSISTENT_RECONNECTS); } -} \ No newline at end of file +} diff --git a/src/test/java/com/lambdaworks/redis/cluster/ClusterTopologyRefreshSchedulerTest.java b/src/test/java/com/lambdaworks/redis/cluster/ClusterTopologyRefreshSchedulerTest.java index b51813a7c7..59ecfe7168 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/ClusterTopologyRefreshSchedulerTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/ClusterTopologyRefreshSchedulerTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster; import static org.mockito.Matchers.any; diff --git a/src/test/java/com/lambdaworks/redis/cluster/HealthyMajorityPartitionsConsensusTest.java b/src/test/java/com/lambdaworks/redis/cluster/HealthyMajorityPartitionsConsensusTest.java index b8cbd9df5d..a4eed8edad 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/HealthyMajorityPartitionsConsensusTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/HealthyMajorityPartitionsConsensusTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster; import static com.lambdaworks.redis.cluster.PartitionsConsensusTestSupport.createMap; diff --git a/src/test/java/com/lambdaworks/redis/cluster/KnownMajorityPartitionsConsensusTest.java b/src/test/java/com/lambdaworks/redis/cluster/KnownMajorityPartitionsConsensusTest.java index 08192f04ca..1449cc017b 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/KnownMajorityPartitionsConsensusTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/KnownMajorityPartitionsConsensusTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster; import static com.lambdaworks.redis.cluster.PartitionsConsensusTestSupport.createMap; diff --git a/src/test/java/com/lambdaworks/redis/cluster/NodeSelectionAsyncTest.java b/src/test/java/com/lambdaworks/redis/cluster/NodeSelectionAsyncTest.java index f04f440e1f..abdf8b76f2 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/NodeSelectionAsyncTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/NodeSelectionAsyncTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster; import static com.lambdaworks.redis.ScriptOutputType.STATUS; diff --git a/src/test/java/com/lambdaworks/redis/cluster/NodeSelectionSyncTest.java b/src/test/java/com/lambdaworks/redis/cluster/NodeSelectionSyncTest.java index ff491e4211..30c9a59205 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/NodeSelectionSyncTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/NodeSelectionSyncTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster; import static com.lambdaworks.redis.ScriptOutputType.STATUS; diff --git a/src/test/java/com/lambdaworks/redis/cluster/PartitionsConsensusTestSupport.java b/src/test/java/com/lambdaworks/redis/cluster/PartitionsConsensusTestSupport.java index 94bb244045..3e65683f76 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/PartitionsConsensusTestSupport.java +++ b/src/test/java/com/lambdaworks/redis/cluster/PartitionsConsensusTestSupport.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster; import java.util.*; diff --git a/src/test/java/com/lambdaworks/redis/cluster/PipelinedRedisFutureTest.java b/src/test/java/com/lambdaworks/redis/cluster/PipelinedRedisFutureTest.java index d6a770d2f8..dd41522887 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/PipelinedRedisFutureTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/PipelinedRedisFutureTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/com/lambdaworks/redis/cluster/PooledClusterConnectionProviderTest.java b/src/test/java/com/lambdaworks/redis/cluster/PooledClusterConnectionProviderTest.java index 08458f3a59..a042fa033a 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/PooledClusterConnectionProviderTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/PooledClusterConnectionProviderTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster; import static org.assertj.core.api.Assertions.assertThat; @@ -138,4 +153,4 @@ public void shouldRetryConnectionAttemptAfterConnectionAttemptWasBroken() throws verify(clientMock, times(2)).connectToNode(eq(CODEC), eq("localhost:2"), any(), any()); } -} \ No newline at end of file +} diff --git a/src/test/java/com/lambdaworks/redis/cluster/ReadFromTest.java b/src/test/java/com/lambdaworks/redis/cluster/ReadFromTest.java index 8837029a88..d6542e1fb7 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/ReadFromTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/ReadFromTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/com/lambdaworks/redis/cluster/ReadOnlyCommandsTest.java b/src/test/java/com/lambdaworks/redis/cluster/ReadOnlyCommandsTest.java index 2922439042..528efd5564 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/ReadOnlyCommandsTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/ReadOnlyCommandsTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/com/lambdaworks/redis/cluster/RedisClusterClientFactoryTest.java b/src/test/java/com/lambdaworks/redis/cluster/RedisClusterClientFactoryTest.java index 271f0120a0..900841164d 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/RedisClusterClientFactoryTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/RedisClusterClientFactoryTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster; import java.util.Arrays; diff --git a/src/test/java/com/lambdaworks/redis/cluster/RedisClusterClientTest.java b/src/test/java/com/lambdaworks/redis/cluster/RedisClusterClientTest.java index 755da79b8e..b79872966c 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/RedisClusterClientTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/RedisClusterClientTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster; import static com.lambdaworks.redis.RedisClientConnectionTest.CODEC; diff --git a/src/test/java/com/lambdaworks/redis/cluster/RedisClusterPasswordSecuredSslTest.java b/src/test/java/com/lambdaworks/redis/cluster/RedisClusterPasswordSecuredSslTest.java index 3fff656970..a7558b2bab 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/RedisClusterPasswordSecuredSslTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/RedisClusterPasswordSecuredSslTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster; import static com.lambdaworks.redis.TestSettings.*; diff --git a/src/test/java/com/lambdaworks/redis/cluster/RedisClusterReadFromTest.java b/src/test/java/com/lambdaworks/redis/cluster/RedisClusterReadFromTest.java index d873a27916..f30c28c8a6 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/RedisClusterReadFromTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/RedisClusterReadFromTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/com/lambdaworks/redis/cluster/RedisClusterSetupTest.java b/src/test/java/com/lambdaworks/redis/cluster/RedisClusterSetupTest.java index 92fd365343..e18fef4175 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/RedisClusterSetupTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/RedisClusterSetupTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster; import static com.google.code.tempusfugit.temporal.Duration.seconds; diff --git a/src/test/java/com/lambdaworks/redis/cluster/RedisClusterStressScenariosTest.java b/src/test/java/com/lambdaworks/redis/cluster/RedisClusterStressScenariosTest.java index 59c0ff9578..8dc5931f8e 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/RedisClusterStressScenariosTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/RedisClusterStressScenariosTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster; import static com.google.code.tempusfugit.temporal.Duration.seconds; diff --git a/src/test/java/com/lambdaworks/redis/cluster/RedisReactiveClusterClientTest.java b/src/test/java/com/lambdaworks/redis/cluster/RedisReactiveClusterClientTest.java index f194e990d9..cddc34bd01 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/RedisReactiveClusterClientTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/RedisReactiveClusterClientTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster; import static com.lambdaworks.redis.cluster.ClusterTestUtil.getOwnPartition; diff --git a/src/test/java/com/lambdaworks/redis/cluster/RoundRobinSocketAddressSupplierTest.java b/src/test/java/com/lambdaworks/redis/cluster/RoundRobinSocketAddressSupplierTest.java index fa8c9ce5a1..410b7a0e51 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/RoundRobinSocketAddressSupplierTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/RoundRobinSocketAddressSupplierTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/com/lambdaworks/redis/cluster/SlotHashTest.java b/src/test/java/com/lambdaworks/redis/cluster/SlotHashTest.java index 39c5010e2e..a27f40347b 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/SlotHashTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/SlotHashTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster; import static org.assertj.core.api.Assertions.*; diff --git a/src/test/java/com/lambdaworks/redis/cluster/commands/CustomClusterCommandTest.java b/src/test/java/com/lambdaworks/redis/cluster/commands/CustomClusterCommandTest.java index aa1283f099..4384a7dfdc 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/commands/CustomClusterCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/commands/CustomClusterCommandTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster.commands; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/com/lambdaworks/redis/cluster/commands/GeoClusterCommandTest.java b/src/test/java/com/lambdaworks/redis/cluster/commands/GeoClusterCommandTest.java index 5d4f01c8a5..c9b055a9e7 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/commands/GeoClusterCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/commands/GeoClusterCommandTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster.commands; import static com.lambdaworks.redis.cluster.ClusterTestUtil.flushDatabaseOfAllNodes; diff --git a/src/test/java/com/lambdaworks/redis/cluster/commands/HashClusterCommandTest.java b/src/test/java/com/lambdaworks/redis/cluster/commands/HashClusterCommandTest.java index 31c4a576fd..31b560c282 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/commands/HashClusterCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/commands/HashClusterCommandTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster.commands; import com.lambdaworks.TestClientResources; diff --git a/src/test/java/com/lambdaworks/redis/cluster/commands/KeyClusterCommandTest.java b/src/test/java/com/lambdaworks/redis/cluster/commands/KeyClusterCommandTest.java index 2b4bfb3bed..564cdf8874 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/commands/KeyClusterCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/commands/KeyClusterCommandTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster.commands; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/com/lambdaworks/redis/cluster/commands/ListClusterCommandTest.java b/src/test/java/com/lambdaworks/redis/cluster/commands/ListClusterCommandTest.java index 8be0f120a0..ecf7cd0b57 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/commands/ListClusterCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/commands/ListClusterCommandTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster.commands; import com.lambdaworks.TestClientResources; diff --git a/src/test/java/com/lambdaworks/redis/cluster/commands/StringClusterCommandTest.java b/src/test/java/com/lambdaworks/redis/cluster/commands/StringClusterCommandTest.java index 1c89ef9cc7..43e7068059 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/commands/StringClusterCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/commands/StringClusterCommandTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster.commands; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/com/lambdaworks/redis/cluster/commands/reactive/HashClusterReactiveCommandTest.java b/src/test/java/com/lambdaworks/redis/cluster/commands/reactive/HashClusterReactiveCommandTest.java index d6f2d98be3..7f2a7c10db 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/commands/reactive/HashClusterReactiveCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/commands/reactive/HashClusterReactiveCommandTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster.commands.reactive; import org.junit.AfterClass; diff --git a/src/test/java/com/lambdaworks/redis/cluster/commands/reactive/KeyClusterReativeCommandTest.java b/src/test/java/com/lambdaworks/redis/cluster/commands/reactive/KeyClusterReativeCommandTest.java index aa3f4c15b1..4849012feb 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/commands/reactive/KeyClusterReativeCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/commands/reactive/KeyClusterReativeCommandTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster.commands.reactive; import com.lambdaworks.TestClientResources; diff --git a/src/test/java/com/lambdaworks/redis/cluster/commands/reactive/ListClusterReactiveCommandTest.java b/src/test/java/com/lambdaworks/redis/cluster/commands/reactive/ListClusterReactiveCommandTest.java index 2eae3213a8..13748e51d9 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/commands/reactive/ListClusterReactiveCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/commands/reactive/ListClusterReactiveCommandTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster.commands.reactive; import org.junit.AfterClass; diff --git a/src/test/java/com/lambdaworks/redis/cluster/commands/reactive/StringClusterReactiveCommandTest.java b/src/test/java/com/lambdaworks/redis/cluster/commands/reactive/StringClusterReactiveCommandTest.java index 9624658558..52d72da7f1 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/commands/reactive/StringClusterReactiveCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/commands/reactive/StringClusterReactiveCommandTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster.commands.reactive; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/com/lambdaworks/redis/cluster/models/partitions/PartitionsTest.java b/src/test/java/com/lambdaworks/redis/cluster/models/partitions/PartitionsTest.java index 17b3317a18..a2aef43e2a 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/models/partitions/PartitionsTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/models/partitions/PartitionsTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster.models.partitions; import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; @@ -317,4 +332,4 @@ public void testToString() throws Exception { assertThat(partitions.toString()).startsWith("Partitions ["); } -} \ No newline at end of file +} diff --git a/src/test/java/com/lambdaworks/redis/cluster/models/partitions/RedisClusterNodeTest.java b/src/test/java/com/lambdaworks/redis/cluster/models/partitions/RedisClusterNodeTest.java index 759a965dee..ec02b1c15f 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/models/partitions/RedisClusterNodeTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/models/partitions/RedisClusterNodeTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster.models.partitions; import static org.assertj.core.api.Assertions.*; diff --git a/src/test/java/com/lambdaworks/redis/cluster/models/slots/ClusterSlotsParserTest.java b/src/test/java/com/lambdaworks/redis/cluster/models/slots/ClusterSlotsParserTest.java index 2766f5e80f..6e7281b931 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/models/slots/ClusterSlotsParserTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/models/slots/ClusterSlotsParserTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster.models.slots; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/com/lambdaworks/redis/cluster/pubsub/PubSubClusterTest.java b/src/test/java/com/lambdaworks/redis/cluster/pubsub/PubSubClusterTest.java index 98530cbdcd..96b4ffc0e3 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/pubsub/PubSubClusterTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/pubsub/PubSubClusterTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster.pubsub; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/com/lambdaworks/redis/cluster/topology/ClusterTopologyRefreshTest.java b/src/test/java/com/lambdaworks/redis/cluster/topology/ClusterTopologyRefreshTest.java index a0216c668e..6a1123c3fc 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/topology/ClusterTopologyRefreshTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/topology/ClusterTopologyRefreshTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster.topology; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/com/lambdaworks/redis/cluster/topology/NodeTopologyViewsTest.java b/src/test/java/com/lambdaworks/redis/cluster/topology/NodeTopologyViewsTest.java index 3f926654da..c2e1e34416 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/topology/NodeTopologyViewsTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/topology/NodeTopologyViewsTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster.topology; import static org.assertj.core.api.Assertions.assertThat; @@ -48,4 +63,4 @@ public void shouldFailWithoutOwnPartition() throws Exception { new NodeTopologyView(localhost, viewByLocalhost, "", 0); } -} \ No newline at end of file +} diff --git a/src/test/java/com/lambdaworks/redis/cluster/topology/RequestsTest.java b/src/test/java/com/lambdaworks/redis/cluster/topology/RequestsTest.java index 52835654db..89e62d564b 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/topology/RequestsTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/topology/RequestsTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster.topology; import static org.assertj.core.api.Assertions.assertThat; @@ -97,4 +112,4 @@ private TimedAsyncCommand getCommand(String response) { timedAsyncCommand.complete(); return timedAsyncCommand; } -} \ No newline at end of file +} diff --git a/src/test/java/com/lambdaworks/redis/cluster/topology/TopologyComparatorsTest.java b/src/test/java/com/lambdaworks/redis/cluster/topology/TopologyComparatorsTest.java index 2859785e7c..4512f5c5cf 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/topology/TopologyComparatorsTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/topology/TopologyComparatorsTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster.topology; import static com.lambdaworks.redis.cluster.topology.TopologyComparators.isChanged; diff --git a/src/test/java/com/lambdaworks/redis/cluster/topology/TopologyRefreshTest.java b/src/test/java/com/lambdaworks/redis/cluster/topology/TopologyRefreshTest.java index 35f5024717..6c7ce2f9f1 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/topology/TopologyRefreshTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/topology/TopologyRefreshTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster.topology; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/com/lambdaworks/redis/codec/CompressionCodecTest.java b/src/test/java/com/lambdaworks/redis/codec/CompressionCodecTest.java index c058e0c04e..e1198aef64 100644 --- a/src/test/java/com/lambdaworks/redis/codec/CompressionCodecTest.java +++ b/src/test/java/com/lambdaworks/redis/codec/CompressionCodecTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.codec; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/com/lambdaworks/redis/codec/StringCodecTest.java b/src/test/java/com/lambdaworks/redis/codec/StringCodecTest.java index ec067ee3fa..81c38dddc5 100644 --- a/src/test/java/com/lambdaworks/redis/codec/StringCodecTest.java +++ b/src/test/java/com/lambdaworks/redis/codec/StringCodecTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.codec; import static org.assertj.core.api.Assertions.assertThat; @@ -102,4 +117,4 @@ public void estimateSize() throws Exception { assertThat(new StringCodec(LettuceCharsets.ASCII).estimateSize(teststring)).isEqualTo(teststring.length()); assertThat(new StringCodec(StandardCharsets.ISO_8859_1).estimateSize(teststring)).isEqualTo(teststring.length()); } -} \ No newline at end of file +} diff --git a/src/test/java/com/lambdaworks/redis/commands/BitCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/BitCommandTest.java index bb4272792e..96c432a495 100644 --- a/src/test/java/com/lambdaworks/redis/commands/BitCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/BitCommandTest.java @@ -1,5 +1,18 @@ -// Copyright (C) 2012 - Will Glozer. All rights reserved. - +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.commands; import static com.lambdaworks.redis.BitFieldArgs.offset; @@ -19,6 +32,10 @@ import com.lambdaworks.redis.api.sync.RedisCommands; import com.lambdaworks.redis.codec.Utf8StringCodec; +/** + * @author Will Glozer + * @author Mark Paluch + */ public class BitCommandTest extends AbstractRedisClientTest { protected RedisCommands bitstring; diff --git a/src/test/java/com/lambdaworks/redis/commands/CustomCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/CustomCommandTest.java index da084f63a9..163bf1f91d 100644 --- a/src/test/java/com/lambdaworks/redis/commands/CustomCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/CustomCommandTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.commands; import static com.lambdaworks.redis.protocol.CommandType.ZRANGEBYLEX; diff --git a/src/test/java/com/lambdaworks/redis/commands/GeoCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/GeoCommandTest.java index 0fa9d3c01f..c7ce5e06b4 100644 --- a/src/test/java/com/lambdaworks/redis/commands/GeoCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/GeoCommandTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.commands; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/com/lambdaworks/redis/commands/HLLCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/HLLCommandTest.java index 949f490402..28075f4a06 100644 --- a/src/test/java/com/lambdaworks/redis/commands/HLLCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/HLLCommandTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.commands; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/com/lambdaworks/redis/commands/HashCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/HashCommandTest.java index 0a60e32a06..afc3dc969e 100644 --- a/src/test/java/com/lambdaworks/redis/commands/HashCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/HashCommandTest.java @@ -1,5 +1,18 @@ -// Copyright (C) 2011 - Will Glozer. All rights reserved. - +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.commands; import static org.assertj.core.api.Assertions.assertThat; @@ -15,6 +28,10 @@ import com.lambdaworks.redis.*; +/** + * @author Will Glozer + * @author Mark Paluch + */ public class HashCommandTest extends AbstractRedisClientTest { @Test diff --git a/src/test/java/com/lambdaworks/redis/commands/KeyCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/KeyCommandTest.java index 5920de93a9..bafb01aa18 100644 --- a/src/test/java/com/lambdaworks/redis/commands/KeyCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/KeyCommandTest.java @@ -1,5 +1,18 @@ -// Copyright (C) 2011 - Will Glozer. All rights reserved. - +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.commands; import static org.assertj.core.api.Assertions.assertThat; @@ -13,6 +26,10 @@ import com.lambdaworks.redis.*; +/** + * @author Will Glozer + * @author Mark Paluch + */ public class KeyCommandTest extends AbstractRedisClientTest { @Rule diff --git a/src/test/java/com/lambdaworks/redis/commands/ListCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/ListCommandTest.java index 8f9e07c1c3..ae18b23c2c 100644 --- a/src/test/java/com/lambdaworks/redis/commands/ListCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/ListCommandTest.java @@ -1,5 +1,18 @@ -// Copyright (C) 2011 - Will Glozer. All rights reserved. - +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.commands; import static org.assertj.core.api.Assertions.assertThat; @@ -12,6 +25,10 @@ import org.assertj.core.api.Assertions; import org.junit.Test; +/** + * @author Will Glozer + * @author Mark Paluch + */ public class ListCommandTest extends AbstractRedisClientTest { @Test public void blpop() throws Exception { diff --git a/src/test/java/com/lambdaworks/redis/commands/NumericCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/NumericCommandTest.java index 1c3ef506e1..93306c6079 100644 --- a/src/test/java/com/lambdaworks/redis/commands/NumericCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/NumericCommandTest.java @@ -1,5 +1,18 @@ -// Copyright (C) 2011 - Will Glozer. All rights reserved. - +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.commands; import static org.assertj.core.api.Assertions.*; @@ -10,6 +23,10 @@ import org.assertj.core.api.Assertions; import org.junit.Test; +/** + * @author Will Glozer + * @author Mark Paluch + */ public class NumericCommandTest extends AbstractRedisClientTest { @Test public void decr() throws Exception { diff --git a/src/test/java/com/lambdaworks/redis/commands/RunOnlyOnceServerCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/RunOnlyOnceServerCommandTest.java index 650e182609..fedf43693c 100644 --- a/src/test/java/com/lambdaworks/redis/commands/RunOnlyOnceServerCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/RunOnlyOnceServerCommandTest.java @@ -1,5 +1,18 @@ -// Copyright (C) 2011 - Will Glozer. All rights reserved. - +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.commands; import static com.google.code.tempusfugit.temporal.Duration.seconds; @@ -23,6 +36,10 @@ import com.lambdaworks.redis.TestSettings; import com.lambdaworks.redis.api.async.RedisAsyncCommands; +/** + * @author Will Glozer + * @author Mark Paluch + */ @FixMethodOrder(MethodSorters.NAME_ASCENDING) public class RunOnlyOnceServerCommandTest extends AbstractRedisClientTest { diff --git a/src/test/java/com/lambdaworks/redis/commands/ScriptingCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/ScriptingCommandTest.java index ffbd5cc800..d41050c1f5 100644 --- a/src/test/java/com/lambdaworks/redis/commands/ScriptingCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/ScriptingCommandTest.java @@ -1,5 +1,18 @@ -// Copyright (C) 2011 - Will Glozer. All rights reserved. - +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.commands; import static com.lambdaworks.redis.ScriptOutputType.*; @@ -19,6 +32,10 @@ import com.lambdaworks.redis.RedisException; import com.lambdaworks.redis.api.StatefulRedisConnection; +/** + * @author Will Glozer + * @author Mark Paluch + */ @FixMethodOrder(MethodSorters.NAME_ASCENDING) public class ScriptingCommandTest extends AbstractRedisClientTest { @Rule diff --git a/src/test/java/com/lambdaworks/redis/commands/ServerCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/ServerCommandTest.java index a6e78641a6..c6cc1cd9f5 100644 --- a/src/test/java/com/lambdaworks/redis/commands/ServerCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/ServerCommandTest.java @@ -1,5 +1,18 @@ -// Copyright (C) 2011 - Will Glozer. All rights reserved. - +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.commands; import static org.assertj.core.api.Assertions.assertThat; @@ -26,6 +39,10 @@ import com.lambdaworks.redis.models.role.RoleParser; import com.lambdaworks.redis.protocol.CommandType; +/** + * @author Will Glozer + * @author Mark Paluch + */ @FixMethodOrder(MethodSorters.NAME_ASCENDING) public class ServerCommandTest extends AbstractRedisClientTest { @Test diff --git a/src/test/java/com/lambdaworks/redis/commands/SetCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/SetCommandTest.java index f390738fe7..032b292c0e 100644 --- a/src/test/java/com/lambdaworks/redis/commands/SetCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/SetCommandTest.java @@ -1,5 +1,18 @@ -// Copyright (C) 2011 - Will Glozer. All rights reserved. - +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.commands; import static org.assertj.core.api.Assertions.assertThat; @@ -13,6 +26,10 @@ import com.lambdaworks.redis.*; +/** + * @author Will Glozer + * @author Mark Paluch + */ public class SetCommandTest extends AbstractRedisClientTest { @Test diff --git a/src/test/java/com/lambdaworks/redis/commands/SortCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/SortCommandTest.java index 7e0665a993..bc267bb2ea 100644 --- a/src/test/java/com/lambdaworks/redis/commands/SortCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/SortCommandTest.java @@ -1,5 +1,18 @@ -// Copyright (C) 2011 - Will Glozer. All rights reserved. - +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.commands; import static com.lambdaworks.redis.SortArgs.Builder.alpha; @@ -15,6 +28,10 @@ import org.assertj.core.api.Assertions; import org.junit.Test; +/** + * @author Will Glozer + * @author Mark Paluch + */ public class SortCommandTest extends AbstractRedisClientTest { @Test public void sort() throws Exception { diff --git a/src/test/java/com/lambdaworks/redis/commands/SortedSetCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/SortedSetCommandTest.java index 08f08b53c7..74d88c4b3d 100644 --- a/src/test/java/com/lambdaworks/redis/commands/SortedSetCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/SortedSetCommandTest.java @@ -1,5 +1,18 @@ -// Copyright (C) 2011 - Will Glozer. All rights reserved. - +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.commands; import static com.lambdaworks.redis.ZStoreArgs.Builder.max; @@ -19,6 +32,10 @@ import com.lambdaworks.redis.*; import com.lambdaworks.redis.Range.Boundary; +/** + * @author Will Glozer + * @author Mark Paluch + */ public class SortedSetCommandTest extends AbstractRedisClientTest { @Test diff --git a/src/test/java/com/lambdaworks/redis/commands/StringCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/StringCommandTest.java index 0b4455505e..c49b726eb0 100644 --- a/src/test/java/com/lambdaworks/redis/commands/StringCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/StringCommandTest.java @@ -1,5 +1,18 @@ -// Copyright (C) 2011 - Will Glozer. All rights reserved. - +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.commands; import static com.lambdaworks.redis.SetArgs.Builder.ex; @@ -18,6 +31,10 @@ import org.junit.Test; import org.junit.rules.ExpectedException; +/** + * @author Will Glozer + * @author Mark Paluch + */ public class StringCommandTest extends AbstractRedisClientTest { @Rule public ExpectedException exception = ExpectedException.none(); diff --git a/src/test/java/com/lambdaworks/redis/commands/TransactionCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/TransactionCommandTest.java index 9b89a9a946..e777f41d26 100644 --- a/src/test/java/com/lambdaworks/redis/commands/TransactionCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/TransactionCommandTest.java @@ -1,5 +1,18 @@ -// Copyright (C) 2011 - Will Glozer. All rights reserved. - +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.commands; import static org.assertj.core.api.Assertions.assertThat; @@ -17,6 +30,10 @@ import com.lambdaworks.redis.RedisException; import com.lambdaworks.redis.api.sync.RedisCommands; +/** + * @author Will Glozer + * @author Mark Paluch + */ public class TransactionCommandTest extends AbstractRedisClientTest { @Rule public ExpectedException exception = ExpectedException.none(); diff --git a/src/test/java/com/lambdaworks/redis/commands/reactive/BitReactiveCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/reactive/BitReactiveCommandTest.java index 76d3032ee1..797764f5db 100644 --- a/src/test/java/com/lambdaworks/redis/commands/reactive/BitReactiveCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/reactive/BitReactiveCommandTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.commands.reactive; import static com.lambdaworks.redis.BitFieldArgs.offset; diff --git a/src/test/java/com/lambdaworks/redis/commands/reactive/CustomReactiveCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/reactive/CustomReactiveCommandTest.java index 43ca857766..3601b140f4 100644 --- a/src/test/java/com/lambdaworks/redis/commands/reactive/CustomReactiveCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/reactive/CustomReactiveCommandTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.commands.reactive; import org.junit.Test; diff --git a/src/test/java/com/lambdaworks/redis/commands/reactive/GeoReactiveCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/reactive/GeoReactiveCommandTest.java index 16ac5a0f90..1291adece4 100644 --- a/src/test/java/com/lambdaworks/redis/commands/reactive/GeoReactiveCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/reactive/GeoReactiveCommandTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.commands.reactive; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/com/lambdaworks/redis/commands/reactive/HLLReactiveCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/reactive/HLLReactiveCommandTest.java index 47ce5648c4..bf2a83b507 100644 --- a/src/test/java/com/lambdaworks/redis/commands/reactive/HLLReactiveCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/reactive/HLLReactiveCommandTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.commands.reactive; import com.lambdaworks.redis.api.sync.RedisCommands; diff --git a/src/test/java/com/lambdaworks/redis/commands/reactive/HashReactiveCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/reactive/HashReactiveCommandTest.java index 6273435d9f..58ce441207 100644 --- a/src/test/java/com/lambdaworks/redis/commands/reactive/HashReactiveCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/reactive/HashReactiveCommandTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.commands.reactive; import com.lambdaworks.redis.api.sync.RedisCommands; diff --git a/src/test/java/com/lambdaworks/redis/commands/reactive/KeyReactiveCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/reactive/KeyReactiveCommandTest.java index 4e6e825b4c..7e6afc1e83 100644 --- a/src/test/java/com/lambdaworks/redis/commands/reactive/KeyReactiveCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/reactive/KeyReactiveCommandTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.commands.reactive; import com.lambdaworks.redis.api.sync.RedisCommands; diff --git a/src/test/java/com/lambdaworks/redis/commands/reactive/ListReactiveCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/reactive/ListReactiveCommandTest.java index 89a3b8fc28..f8cce9ed1d 100644 --- a/src/test/java/com/lambdaworks/redis/commands/reactive/ListReactiveCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/reactive/ListReactiveCommandTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.commands.reactive; import com.lambdaworks.redis.api.sync.RedisCommands; diff --git a/src/test/java/com/lambdaworks/redis/commands/reactive/NumericReactiveCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/reactive/NumericReactiveCommandTest.java index 3da291297d..8a830a0028 100644 --- a/src/test/java/com/lambdaworks/redis/commands/reactive/NumericReactiveCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/reactive/NumericReactiveCommandTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.commands.reactive; import com.lambdaworks.redis.api.sync.RedisCommands; diff --git a/src/test/java/com/lambdaworks/redis/commands/reactive/ScriptingReactiveCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/reactive/ScriptingReactiveCommandTest.java index fe4f8a6d95..112012bb2b 100644 --- a/src/test/java/com/lambdaworks/redis/commands/reactive/ScriptingReactiveCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/reactive/ScriptingReactiveCommandTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.commands.reactive; import com.lambdaworks.redis.api.sync.RedisCommands; diff --git a/src/test/java/com/lambdaworks/redis/commands/reactive/ServerReactiveCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/reactive/ServerReactiveCommandTest.java index b8432a2dec..891bb89e60 100644 --- a/src/test/java/com/lambdaworks/redis/commands/reactive/ServerReactiveCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/reactive/ServerReactiveCommandTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.commands.reactive; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/com/lambdaworks/redis/commands/reactive/SetReactiveCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/reactive/SetReactiveCommandTest.java index 9c163bdbf4..4e18646bb1 100644 --- a/src/test/java/com/lambdaworks/redis/commands/reactive/SetReactiveCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/reactive/SetReactiveCommandTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.commands.reactive; import com.lambdaworks.redis.api.sync.RedisCommands; diff --git a/src/test/java/com/lambdaworks/redis/commands/reactive/SortReactiveCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/reactive/SortReactiveCommandTest.java index 41ccaaa8e8..28d02b8177 100644 --- a/src/test/java/com/lambdaworks/redis/commands/reactive/SortReactiveCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/reactive/SortReactiveCommandTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.commands.reactive; import com.lambdaworks.redis.api.sync.RedisCommands; diff --git a/src/test/java/com/lambdaworks/redis/commands/reactive/SortedSetReactiveCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/reactive/SortedSetReactiveCommandTest.java index 7f2d9468c6..5b82a25fca 100644 --- a/src/test/java/com/lambdaworks/redis/commands/reactive/SortedSetReactiveCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/reactive/SortedSetReactiveCommandTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.commands.reactive; import com.lambdaworks.redis.api.sync.RedisCommands; diff --git a/src/test/java/com/lambdaworks/redis/commands/reactive/StringReactiveCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/reactive/StringReactiveCommandTest.java index a0ebaa15f8..65ab8deab4 100644 --- a/src/test/java/com/lambdaworks/redis/commands/reactive/StringReactiveCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/reactive/StringReactiveCommandTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.commands.reactive; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/com/lambdaworks/redis/commands/reactive/TransactionReactiveCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/reactive/TransactionReactiveCommandTest.java index 605b3c6b41..9335b0198b 100644 --- a/src/test/java/com/lambdaworks/redis/commands/reactive/TransactionReactiveCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/reactive/TransactionReactiveCommandTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.commands.reactive; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/com/lambdaworks/redis/commands/transactional/BitTxCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/transactional/BitTxCommandTest.java index 23a9df92f5..1c72912cc3 100644 --- a/src/test/java/com/lambdaworks/redis/commands/transactional/BitTxCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/transactional/BitTxCommandTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.commands.transactional; import com.lambdaworks.redis.api.sync.RedisCommands; diff --git a/src/test/java/com/lambdaworks/redis/commands/transactional/GeoTxCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/transactional/GeoTxCommandTest.java index 26462c321d..f513054081 100644 --- a/src/test/java/com/lambdaworks/redis/commands/transactional/GeoTxCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/transactional/GeoTxCommandTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.commands.transactional; import org.junit.Ignore; diff --git a/src/test/java/com/lambdaworks/redis/commands/transactional/HLLTxCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/transactional/HLLTxCommandTest.java index 2ea20437c9..31c9feb2e4 100644 --- a/src/test/java/com/lambdaworks/redis/commands/transactional/HLLTxCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/transactional/HLLTxCommandTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.commands.transactional; import com.lambdaworks.redis.api.sync.RedisCommands; diff --git a/src/test/java/com/lambdaworks/redis/commands/transactional/HashTxCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/transactional/HashTxCommandTest.java index b7759cd74b..1c641e71b0 100644 --- a/src/test/java/com/lambdaworks/redis/commands/transactional/HashTxCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/transactional/HashTxCommandTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.commands.transactional; import com.lambdaworks.redis.api.sync.RedisCommands; diff --git a/src/test/java/com/lambdaworks/redis/commands/transactional/KeyTxCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/transactional/KeyTxCommandTest.java index 0ce7887367..d93386a252 100644 --- a/src/test/java/com/lambdaworks/redis/commands/transactional/KeyTxCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/transactional/KeyTxCommandTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.commands.transactional; import org.junit.Ignore; diff --git a/src/test/java/com/lambdaworks/redis/commands/transactional/ListTxCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/transactional/ListTxCommandTest.java index 1019e34e9f..b803506e83 100644 --- a/src/test/java/com/lambdaworks/redis/commands/transactional/ListTxCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/transactional/ListTxCommandTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.commands.transactional; import com.lambdaworks.redis.api.sync.RedisCommands; diff --git a/src/test/java/com/lambdaworks/redis/commands/transactional/SetTxCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/transactional/SetTxCommandTest.java index 96c01706dc..50f9849276 100644 --- a/src/test/java/com/lambdaworks/redis/commands/transactional/SetTxCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/transactional/SetTxCommandTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.commands.transactional; import com.lambdaworks.redis.api.sync.RedisCommands; diff --git a/src/test/java/com/lambdaworks/redis/commands/transactional/SortTxCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/transactional/SortTxCommandTest.java index eaf5bafa07..837ecb0dd1 100644 --- a/src/test/java/com/lambdaworks/redis/commands/transactional/SortTxCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/transactional/SortTxCommandTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.commands.transactional; import com.lambdaworks.redis.api.sync.RedisCommands; diff --git a/src/test/java/com/lambdaworks/redis/commands/transactional/SortedSetTxCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/transactional/SortedSetTxCommandTest.java index 5d6f39970d..61ccebb74a 100644 --- a/src/test/java/com/lambdaworks/redis/commands/transactional/SortedSetTxCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/transactional/SortedSetTxCommandTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.commands.transactional; import com.lambdaworks.redis.api.sync.RedisCommands; diff --git a/src/test/java/com/lambdaworks/redis/commands/transactional/StringTxCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/transactional/StringTxCommandTest.java index 41d4ff15bb..da6f4a6746 100644 --- a/src/test/java/com/lambdaworks/redis/commands/transactional/StringTxCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/transactional/StringTxCommandTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.commands.transactional; import com.lambdaworks.redis.api.sync.RedisCommands; diff --git a/src/test/java/com/lambdaworks/redis/commands/transactional/TxSyncInvocationHandler.java b/src/test/java/com/lambdaworks/redis/commands/transactional/TxSyncInvocationHandler.java index 90f3a3ee24..b1fe12c5dd 100644 --- a/src/test/java/com/lambdaworks/redis/commands/transactional/TxSyncInvocationHandler.java +++ b/src/test/java/com/lambdaworks/redis/commands/transactional/TxSyncInvocationHandler.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.commands.transactional; import java.lang.reflect.InvocationTargetException; @@ -101,4 +116,4 @@ public static RedisCommands sync(StatefulRedisConnection conn throw new IllegalStateException(e); } } -} \ No newline at end of file +} diff --git a/src/test/java/com/lambdaworks/redis/dynamic/CommandMethodTest.java b/src/test/java/com/lambdaworks/redis/dynamic/CommandMethodTest.java index 76bea6045d..eda6b87a85 100644 --- a/src/test/java/com/lambdaworks/redis/dynamic/CommandMethodTest.java +++ b/src/test/java/com/lambdaworks/redis/dynamic/CommandMethodTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.dynamic; import static org.assertj.core.api.Assertions.assertThat; @@ -53,4 +68,4 @@ static interface MyInterface { Flux getFlux(); } -} \ No newline at end of file +} diff --git a/src/test/java/com/lambdaworks/redis/dynamic/CommandMethodVerifierTest.java b/src/test/java/com/lambdaworks/redis/dynamic/CommandMethodVerifierTest.java index ff30f8f367..789d2fe3bb 100644 --- a/src/test/java/com/lambdaworks/redis/dynamic/CommandMethodVerifierTest.java +++ b/src/test/java/com/lambdaworks/redis/dynamic/CommandMethodVerifierTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.dynamic; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/com/lambdaworks/redis/dynamic/CommandSegmentCommandFactoryTest.java b/src/test/java/com/lambdaworks/redis/dynamic/CommandSegmentCommandFactoryTest.java index 8db13a0301..b773a497b8 100644 --- a/src/test/java/com/lambdaworks/redis/dynamic/CommandSegmentCommandFactoryTest.java +++ b/src/test/java/com/lambdaworks/redis/dynamic/CommandSegmentCommandFactoryTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.dynamic; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/com/lambdaworks/redis/dynamic/ParameterBinderTest.java b/src/test/java/com/lambdaworks/redis/dynamic/ParameterBinderTest.java index 35136798ef..5ba7a037e4 100644 --- a/src/test/java/com/lambdaworks/redis/dynamic/ParameterBinderTest.java +++ b/src/test/java/com/lambdaworks/redis/dynamic/ParameterBinderTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.dynamic; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/com/lambdaworks/redis/dynamic/ReactiveCommandSegmentCommandFactoryTest.java b/src/test/java/com/lambdaworks/redis/dynamic/ReactiveCommandSegmentCommandFactoryTest.java index 9a92d801cc..80b02d39d6 100644 --- a/src/test/java/com/lambdaworks/redis/dynamic/ReactiveCommandSegmentCommandFactoryTest.java +++ b/src/test/java/com/lambdaworks/redis/dynamic/ReactiveCommandSegmentCommandFactoryTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.dynamic; import static org.assertj.core.api.Assertions.assertThat; @@ -70,4 +85,4 @@ static interface ReactiveWithTimeout { Publisher get(String key, Timeout timeout); } -} \ No newline at end of file +} diff --git a/src/test/java/com/lambdaworks/redis/dynamic/RedisCommandsTest.java b/src/test/java/com/lambdaworks/redis/dynamic/RedisCommandsTest.java index 8edc71e071..51dba6236e 100644 --- a/src/test/java/com/lambdaworks/redis/dynamic/RedisCommandsTest.java +++ b/src/test/java/com/lambdaworks/redis/dynamic/RedisCommandsTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.dynamic; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/com/lambdaworks/redis/dynamic/codec/AnnotationRedisCodecResolverTest.java b/src/test/java/com/lambdaworks/redis/dynamic/codec/AnnotationRedisCodecResolverTest.java index 6c8d4a00f7..8747fdfadb 100644 --- a/src/test/java/com/lambdaworks/redis/dynamic/codec/AnnotationRedisCodecResolverTest.java +++ b/src/test/java/com/lambdaworks/redis/dynamic/codec/AnnotationRedisCodecResolverTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.dynamic.codec; import static org.assertj.core.api.Assertions.assertThat; @@ -97,4 +112,4 @@ private static interface CommandMethods { String mixedTypes(@Key String key, @Value byte[] value); } -} \ No newline at end of file +} diff --git a/src/test/java/com/lambdaworks/redis/dynamic/intercept/InvocationProxyFactoryTest.java b/src/test/java/com/lambdaworks/redis/dynamic/intercept/InvocationProxyFactoryTest.java index 66e7024a3e..0a47a71632 100644 --- a/src/test/java/com/lambdaworks/redis/dynamic/intercept/InvocationProxyFactoryTest.java +++ b/src/test/java/com/lambdaworks/redis/dynamic/intercept/InvocationProxyFactoryTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.dynamic.intercept; import static org.assertj.core.api.Assertions.assertThat; @@ -44,4 +59,4 @@ public Object invoke(MethodInvocation invocation) { return true; } } -} \ No newline at end of file +} diff --git a/src/test/java/com/lambdaworks/redis/dynamic/output/CodecAwareOutputResolverTest.java b/src/test/java/com/lambdaworks/redis/dynamic/output/CodecAwareOutputResolverTest.java index b748fc4cb9..a5a19dc7df 100644 --- a/src/test/java/com/lambdaworks/redis/dynamic/output/CodecAwareOutputResolverTest.java +++ b/src/test/java/com/lambdaworks/redis/dynamic/output/CodecAwareOutputResolverTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.dynamic.output; import static org.assertj.core.api.Assertions.assertThat; @@ -133,4 +148,4 @@ public ByteBuffer encodeValue(String value) { return null; } } -} \ No newline at end of file +} diff --git a/src/test/java/com/lambdaworks/redis/dynamic/output/OutputRegistryCommandOutputFactoryResolverTest.java b/src/test/java/com/lambdaworks/redis/dynamic/output/OutputRegistryCommandOutputFactoryResolverTest.java index 3a0a6914d6..133a48a10c 100644 --- a/src/test/java/com/lambdaworks/redis/dynamic/output/OutputRegistryCommandOutputFactoryResolverTest.java +++ b/src/test/java/com/lambdaworks/redis/dynamic/output/OutputRegistryCommandOutputFactoryResolverTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.dynamic.output; import static org.assertj.core.api.Assertions.assertThat; @@ -126,4 +141,4 @@ private static interface CommandMethods { ListOfMapsOutput listOfMapsOutput(); } -} \ No newline at end of file +} diff --git a/src/test/java/com/lambdaworks/redis/dynamic/output/OutputRegistryTest.java b/src/test/java/com/lambdaworks/redis/dynamic/output/OutputRegistryTest.java index eb7941f678..cfd9bcae8f 100644 --- a/src/test/java/com/lambdaworks/redis/dynamic/output/OutputRegistryTest.java +++ b/src/test/java/com/lambdaworks/redis/dynamic/output/OutputRegistryTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.dynamic.output; import static org.assertj.core.api.Assertions.assertThat; @@ -61,4 +76,4 @@ public void getStringListOutputType() throws Exception { assertThat(outputComponentType.getTypeInformation().getComponentType()) .isEqualTo(ClassTypeInformation.from(String.class)); } -} \ No newline at end of file +} diff --git a/src/test/java/com/lambdaworks/redis/dynamic/segment/AnnotationCommandSegmentFactoryTest.java b/src/test/java/com/lambdaworks/redis/dynamic/segment/AnnotationCommandSegmentFactoryTest.java index c8d1b6f5b7..f7085678d1 100644 --- a/src/test/java/com/lambdaworks/redis/dynamic/segment/AnnotationCommandSegmentFactoryTest.java +++ b/src/test/java/com/lambdaworks/redis/dynamic/segment/AnnotationCommandSegmentFactoryTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.dynamic.segment; import static org.assertj.core.api.Assertions.assertThat; @@ -107,4 +122,4 @@ private static interface Defaulted { void clientSetname(); } -} \ No newline at end of file +} diff --git a/src/test/java/com/lambdaworks/redis/event/ConnectionEventsTriggeredTest.java b/src/test/java/com/lambdaworks/redis/event/ConnectionEventsTriggeredTest.java index 76fc7650a1..5d8547c9e6 100644 --- a/src/test/java/com/lambdaworks/redis/event/ConnectionEventsTriggeredTest.java +++ b/src/test/java/com/lambdaworks/redis/event/ConnectionEventsTriggeredTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.event; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/com/lambdaworks/redis/event/DefaultEventBusTest.java b/src/test/java/com/lambdaworks/redis/event/DefaultEventBusTest.java index 0135d080e5..c624a0223d 100644 --- a/src/test/java/com/lambdaworks/redis/event/DefaultEventBusTest.java +++ b/src/test/java/com/lambdaworks/redis/event/DefaultEventBusTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.event; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/com/lambdaworks/redis/event/DefaultEventPublisherOptionsTest.java b/src/test/java/com/lambdaworks/redis/event/DefaultEventPublisherOptionsTest.java index ccb0ce6621..ecc9e22ad6 100644 --- a/src/test/java/com/lambdaworks/redis/event/DefaultEventPublisherOptionsTest.java +++ b/src/test/java/com/lambdaworks/redis/event/DefaultEventPublisherOptionsTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.event; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/com/lambdaworks/redis/internal/AbstractInvocationHandlerTest.java b/src/test/java/com/lambdaworks/redis/internal/AbstractInvocationHandlerTest.java index 410875e257..10c62102a7 100644 --- a/src/test/java/com/lambdaworks/redis/internal/AbstractInvocationHandlerTest.java +++ b/src/test/java/com/lambdaworks/redis/internal/AbstractInvocationHandlerTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.internal; import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; @@ -63,4 +78,4 @@ static interface ReturnOne { int returnOne(); } -} \ No newline at end of file +} diff --git a/src/test/java/com/lambdaworks/redis/internal/HostAndPortTest.java b/src/test/java/com/lambdaworks/redis/internal/HostAndPortTest.java index c78cab34b6..61ffeff438 100644 --- a/src/test/java/com/lambdaworks/redis/internal/HostAndPortTest.java +++ b/src/test/java/com/lambdaworks/redis/internal/HostAndPortTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.internal; import static org.assertj.core.api.Assertions.assertThat; @@ -168,4 +183,4 @@ private static void checkFromCompatCase(String hpString, String expectHost, int assertThat(hostAndPort.getPort()).isEqualTo(expectPort); } -} \ No newline at end of file +} diff --git a/src/test/java/com/lambdaworks/redis/masterslave/MasterSlaveSentinelTest.java b/src/test/java/com/lambdaworks/redis/masterslave/MasterSlaveSentinelTest.java index 55aac7e02c..05779d808d 100644 --- a/src/test/java/com/lambdaworks/redis/masterslave/MasterSlaveSentinelTest.java +++ b/src/test/java/com/lambdaworks/redis/masterslave/MasterSlaveSentinelTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.masterslave; import static com.lambdaworks.redis.TestSettings.port; diff --git a/src/test/java/com/lambdaworks/redis/masterslave/MasterSlaveTest.java b/src/test/java/com/lambdaworks/redis/masterslave/MasterSlaveTest.java index f5229e7f16..3bd186ba91 100644 --- a/src/test/java/com/lambdaworks/redis/masterslave/MasterSlaveTest.java +++ b/src/test/java/com/lambdaworks/redis/masterslave/MasterSlaveTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.masterslave; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/com/lambdaworks/redis/masterslave/MasterSlaveTopologyProviderTest.java b/src/test/java/com/lambdaworks/redis/masterslave/MasterSlaveTopologyProviderTest.java index 0b0879299e..59c93c9783 100644 --- a/src/test/java/com/lambdaworks/redis/masterslave/MasterSlaveTopologyProviderTest.java +++ b/src/test/java/com/lambdaworks/redis/masterslave/MasterSlaveTopologyProviderTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.masterslave; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/com/lambdaworks/redis/masterslave/MasterSlaveUtilsTest.java b/src/test/java/com/lambdaworks/redis/masterslave/MasterSlaveUtilsTest.java index 70149343eb..d7b11a00bf 100644 --- a/src/test/java/com/lambdaworks/redis/masterslave/MasterSlaveUtilsTest.java +++ b/src/test/java/com/lambdaworks/redis/masterslave/MasterSlaveUtilsTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.masterslave; import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; @@ -83,4 +98,4 @@ public void isChangedShouldReturnTrueBecauseRolesSwitched() throws Exception { assertThat(MasterSlaveUtils.isChanged(Arrays.asList(master, slave), Arrays.asList(newmaster, newslave))).isTrue(); assertThat(MasterSlaveUtils.isChanged(Arrays.asList(master, slave), Arrays.asList(newslave, newmaster))).isTrue(); } -} \ No newline at end of file +} diff --git a/src/test/java/com/lambdaworks/redis/masterslave/SentinelTopologyRefreshTest.java b/src/test/java/com/lambdaworks/redis/masterslave/SentinelTopologyRefreshTest.java index ac589fa70c..f26e8a7b35 100644 --- a/src/test/java/com/lambdaworks/redis/masterslave/SentinelTopologyRefreshTest.java +++ b/src/test/java/com/lambdaworks/redis/masterslave/SentinelTopologyRefreshTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.masterslave; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/com/lambdaworks/redis/masterslave/StaticMasterSlaveTest.java b/src/test/java/com/lambdaworks/redis/masterslave/StaticMasterSlaveTest.java index 31942a6faf..13d78ce0cf 100644 --- a/src/test/java/com/lambdaworks/redis/masterslave/StaticMasterSlaveTest.java +++ b/src/test/java/com/lambdaworks/redis/masterslave/StaticMasterSlaveTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.masterslave; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/com/lambdaworks/redis/metrics/CommandLatencyIdTest.java b/src/test/java/com/lambdaworks/redis/metrics/CommandLatencyIdTest.java index e25ef6b65d..5d1cae1fb5 100644 --- a/src/test/java/com/lambdaworks/redis/metrics/CommandLatencyIdTest.java +++ b/src/test/java/com/lambdaworks/redis/metrics/CommandLatencyIdTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.metrics; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/com/lambdaworks/redis/metrics/DefaultCommandLatencyCollectorTest.java b/src/test/java/com/lambdaworks/redis/metrics/DefaultCommandLatencyCollectorTest.java index 5b51a802d1..d9ac17bf57 100644 --- a/src/test/java/com/lambdaworks/redis/metrics/DefaultCommandLatencyCollectorTest.java +++ b/src/test/java/com/lambdaworks/redis/metrics/DefaultCommandLatencyCollectorTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.metrics; import static java.util.concurrent.TimeUnit.MICROSECONDS; diff --git a/src/test/java/com/lambdaworks/redis/metrics/DefaultDefaultCommandLatencyCollectorOptionsTest.java b/src/test/java/com/lambdaworks/redis/metrics/DefaultDefaultCommandLatencyCollectorOptionsTest.java index 65fe4760c1..4b9cc2b05c 100644 --- a/src/test/java/com/lambdaworks/redis/metrics/DefaultDefaultCommandLatencyCollectorOptionsTest.java +++ b/src/test/java/com/lambdaworks/redis/metrics/DefaultDefaultCommandLatencyCollectorOptionsTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.metrics; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/com/lambdaworks/redis/models/command/CommandDetailParserTest.java b/src/test/java/com/lambdaworks/redis/models/command/CommandDetailParserTest.java index f4a7daf50a..cb52aad822 100644 --- a/src/test/java/com/lambdaworks/redis/models/command/CommandDetailParserTest.java +++ b/src/test/java/com/lambdaworks/redis/models/command/CommandDetailParserTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.models.command; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/com/lambdaworks/redis/models/role/RoleParserTest.java b/src/test/java/com/lambdaworks/redis/models/role/RoleParserTest.java index 2a70cc9ad2..b4cdc3ce32 100644 --- a/src/test/java/com/lambdaworks/redis/models/role/RoleParserTest.java +++ b/src/test/java/com/lambdaworks/redis/models/role/RoleParserTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.models.role; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/com/lambdaworks/redis/output/BooleanListOutputTest.java b/src/test/java/com/lambdaworks/redis/output/BooleanListOutputTest.java index 9be0a51607..09f7d85106 100644 --- a/src/test/java/com/lambdaworks/redis/output/BooleanListOutputTest.java +++ b/src/test/java/com/lambdaworks/redis/output/BooleanListOutputTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.output; import static org.assertj.core.api.Assertions.*; @@ -34,4 +49,4 @@ public void commandOutputCorrectlyDecoded() throws Exception { public void setByteNotImplemented() throws Exception { sut.set(ByteBuffer.wrap("4.567".getBytes())); } -} \ No newline at end of file +} diff --git a/src/test/java/com/lambdaworks/redis/output/GeoCoordinatesListOutputTest.java b/src/test/java/com/lambdaworks/redis/output/GeoCoordinatesListOutputTest.java index 9612ea3462..a93d3d7b12 100644 --- a/src/test/java/com/lambdaworks/redis/output/GeoCoordinatesListOutputTest.java +++ b/src/test/java/com/lambdaworks/redis/output/GeoCoordinatesListOutputTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.output; import static org.assertj.core.api.Assertions.assertThat; @@ -30,4 +45,4 @@ public void commandOutputCorrectlyDecoded() throws Exception { assertThat(sut.get()).contains(new GeoCoordinates(1.234, 4.567)); } -} \ No newline at end of file +} diff --git a/src/test/java/com/lambdaworks/redis/output/GeoCoordinatesValueListOutputTest.java b/src/test/java/com/lambdaworks/redis/output/GeoCoordinatesValueListOutputTest.java index c6c0bfaa2f..d46f158ac2 100644 --- a/src/test/java/com/lambdaworks/redis/output/GeoCoordinatesValueListOutputTest.java +++ b/src/test/java/com/lambdaworks/redis/output/GeoCoordinatesValueListOutputTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.output; import static org.assertj.core.api.Assertions.assertThat; @@ -36,4 +51,4 @@ public void commandOutputCorrectlyDecoded() throws Exception { assertThat(sut.get()).contains(Value.just(new GeoCoordinates(1.234, 4.567))); } -} \ No newline at end of file +} diff --git a/src/test/java/com/lambdaworks/redis/output/GeoWithinListOutputTest.java b/src/test/java/com/lambdaworks/redis/output/GeoWithinListOutputTest.java index 59703a7cf6..e5e45617ca 100644 --- a/src/test/java/com/lambdaworks/redis/output/GeoWithinListOutputTest.java +++ b/src/test/java/com/lambdaworks/redis/output/GeoWithinListOutputTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.output; import static org.assertj.core.api.Assertions.*; @@ -81,4 +96,4 @@ public void commandOutputKeyAndCoordinatesDecoded() throws Exception { assertThat(sut.get()).contains(new GeoWithin<>("key", null, null, new GeoCoordinates(1.234, 4.567))); } -} \ No newline at end of file +} diff --git a/src/test/java/com/lambdaworks/redis/output/ListOutputTest.java b/src/test/java/com/lambdaworks/redis/output/ListOutputTest.java index 53893bfd08..755732f602 100644 --- a/src/test/java/com/lambdaworks/redis/output/ListOutputTest.java +++ b/src/test/java/com/lambdaworks/redis/output/ListOutputTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.output; import static org.assertj.core.api.Assertions.*; @@ -73,4 +88,4 @@ public void setValueShouldConvert() throws Exception { assertThat(commandOutput.get()).contains(value); } -} \ No newline at end of file +} diff --git a/src/test/java/com/lambdaworks/redis/output/NestedMultiOutputTest.java b/src/test/java/com/lambdaworks/redis/output/NestedMultiOutputTest.java index df9b626173..9c2f915d67 100644 --- a/src/test/java/com/lambdaworks/redis/output/NestedMultiOutputTest.java +++ b/src/test/java/com/lambdaworks/redis/output/NestedMultiOutputTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.output; import static com.lambdaworks.redis.protocol.LettuceCharsets.buffer; @@ -23,4 +38,4 @@ public void nestedMultiError() throws Exception { assertThat(output.getError()).isNotNull(); } -} \ No newline at end of file +} diff --git a/src/test/java/com/lambdaworks/redis/output/ScoredValueListOutputTest.java b/src/test/java/com/lambdaworks/redis/output/ScoredValueListOutputTest.java index dc0436d725..71dfe783ce 100644 --- a/src/test/java/com/lambdaworks/redis/output/ScoredValueListOutputTest.java +++ b/src/test/java/com/lambdaworks/redis/output/ScoredValueListOutputTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.output; import static org.assertj.core.api.Assertions.*; @@ -35,4 +50,4 @@ public void commandOutputCorrectlyDecoded() throws Exception { assertThat(sut.get()).contains(ScoredValue.fromNullable(4.567, "key")); } -} \ No newline at end of file +} diff --git a/src/test/java/com/lambdaworks/redis/protocol/AsyncCommandInternalsTest.java b/src/test/java/com/lambdaworks/redis/protocol/AsyncCommandInternalsTest.java index 0e26b7d365..ec9ef31d75 100644 --- a/src/test/java/com/lambdaworks/redis/protocol/AsyncCommandInternalsTest.java +++ b/src/test/java/com/lambdaworks/redis/protocol/AsyncCommandInternalsTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.protocol; import static com.lambdaworks.redis.protocol.LettuceCharsets.buffer; diff --git a/src/test/java/com/lambdaworks/redis/protocol/CommandArgsTest.java b/src/test/java/com/lambdaworks/redis/protocol/CommandArgsTest.java index 3b7cfa1e4f..416cef16f6 100644 --- a/src/test/java/com/lambdaworks/redis/protocol/CommandArgsTest.java +++ b/src/test/java/com/lambdaworks/redis/protocol/CommandArgsTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.protocol; import static org.assertj.core.api.Assertions.assertThat; @@ -185,4 +200,4 @@ public void addKeyUsingByteCodec() throws Exception { assertThat(buffer.toString(LettuceCharsets.ASCII)).isEqualTo(expected.toString(LettuceCharsets.ASCII)); } -} \ No newline at end of file +} diff --git a/src/test/java/com/lambdaworks/redis/protocol/CommandHandlerTest.java b/src/test/java/com/lambdaworks/redis/protocol/CommandHandlerTest.java index ab73b1e9dd..80d0da96df 100644 --- a/src/test/java/com/lambdaworks/redis/protocol/CommandHandlerTest.java +++ b/src/test/java/com/lambdaworks/redis/protocol/CommandHandlerTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.protocol; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/com/lambdaworks/redis/protocol/CommandInternalsTest.java b/src/test/java/com/lambdaworks/redis/protocol/CommandInternalsTest.java index c06b7a49c9..fdb612e4b1 100644 --- a/src/test/java/com/lambdaworks/redis/protocol/CommandInternalsTest.java +++ b/src/test/java/com/lambdaworks/redis/protocol/CommandInternalsTest.java @@ -1,5 +1,18 @@ -// Copyright (C) 2011 - Will Glozer. All rights reserved. - +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.protocol; import static com.lambdaworks.redis.protocol.LettuceCharsets.buffer; @@ -15,6 +28,10 @@ import com.lambdaworks.redis.output.NestedMultiOutput; import com.lambdaworks.redis.output.StatusOutput; +/** + * @author Will Glozer + * @author Mark Paluch + */ public class CommandInternalsTest { protected RedisCodec codec = new Utf8StringCodec(); protected Command sut; diff --git a/src/test/java/com/lambdaworks/redis/protocol/ConnectionFailureTest.java b/src/test/java/com/lambdaworks/redis/protocol/ConnectionFailureTest.java index f41c63fc2b..1129c2ee9d 100644 --- a/src/test/java/com/lambdaworks/redis/protocol/ConnectionFailureTest.java +++ b/src/test/java/com/lambdaworks/redis/protocol/ConnectionFailureTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.protocol; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/com/lambdaworks/redis/protocol/DefaultEndpointTest.java b/src/test/java/com/lambdaworks/redis/protocol/DefaultEndpointTest.java index 44ab5f8702..f83f585ab1 100644 --- a/src/test/java/com/lambdaworks/redis/protocol/DefaultEndpointTest.java +++ b/src/test/java/com/lambdaworks/redis/protocol/DefaultEndpointTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.protocol; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/com/lambdaworks/redis/protocol/StateMachineTest.java b/src/test/java/com/lambdaworks/redis/protocol/StateMachineTest.java index c71fa41d48..c6033962e7 100644 --- a/src/test/java/com/lambdaworks/redis/protocol/StateMachineTest.java +++ b/src/test/java/com/lambdaworks/redis/protocol/StateMachineTest.java @@ -1,5 +1,18 @@ -// Copyright (C) 2011 - Will Glozer. All rights reserved. - +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.protocol; import static com.lambdaworks.redis.protocol.RedisStateMachine.State; @@ -27,6 +40,10 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; +/** + * @author Will Glozer + * @author Mark Paluch + */ public class StateMachineTest { protected RedisCodec codec = new Utf8StringCodec(); protected Charset charset = Charset.forName("UTF-8"); diff --git a/src/test/java/com/lambdaworks/redis/pubsub/PubSubCommandTest.java b/src/test/java/com/lambdaworks/redis/pubsub/PubSubCommandTest.java index ae6e4fde2e..9cf8ffd16a 100644 --- a/src/test/java/com/lambdaworks/redis/pubsub/PubSubCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/pubsub/PubSubCommandTest.java @@ -1,5 +1,18 @@ -// Copyright (C) 2011 - Will Glozer. All rights reserved. - +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.pubsub; import static org.assertj.core.api.Assertions.assertThat; @@ -24,6 +37,10 @@ import com.lambdaworks.redis.internal.LettuceFactories; import com.lambdaworks.redis.pubsub.api.async.RedisPubSubAsyncCommands; +/** + * @author Will Glozer + * @author Mark Paluch + */ public class PubSubCommandTest extends AbstractRedisClientTest implements RedisPubSubListener { private RedisPubSubAsyncCommands pubsub; diff --git a/src/test/java/com/lambdaworks/redis/pubsub/PubSubReactiveTest.java b/src/test/java/com/lambdaworks/redis/pubsub/PubSubReactiveTest.java index 5834dda498..124249fd1a 100644 --- a/src/test/java/com/lambdaworks/redis/pubsub/PubSubReactiveTest.java +++ b/src/test/java/com/lambdaworks/redis/pubsub/PubSubReactiveTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.pubsub; import static com.google.code.tempusfugit.temporal.Duration.millis; diff --git a/src/test/java/com/lambdaworks/redis/reactive/RedisPublisherVerification.java b/src/test/java/com/lambdaworks/redis/reactive/RedisPublisherVerification.java index 7700a7625d..1d6ebaa84a 100644 --- a/src/test/java/com/lambdaworks/redis/reactive/RedisPublisherVerification.java +++ b/src/test/java/com/lambdaworks/redis/reactive/RedisPublisherVerification.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.reactive; import static com.lambdaworks.redis.protocol.CommandType.LRANGE; @@ -83,4 +98,4 @@ public Publisher createFailedPublisher() { return null; } -} \ No newline at end of file +} diff --git a/src/test/java/com/lambdaworks/redis/reactive/TestSubscriber.java b/src/test/java/com/lambdaworks/redis/reactive/TestSubscriber.java index f866135eca..814174dde9 100644 --- a/src/test/java/com/lambdaworks/redis/reactive/TestSubscriber.java +++ b/src/test/java/com/lambdaworks/redis/reactive/TestSubscriber.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.reactive; import java.time.Duration; @@ -1125,4 +1140,4 @@ protected final String valueAndClass(Object o) { return o + " (" + o.getClass().getSimpleName() + ")"; } -} \ No newline at end of file +} diff --git a/src/test/java/com/lambdaworks/redis/reliability/AtLeastOnceTest.java b/src/test/java/com/lambdaworks/redis/reliability/AtLeastOnceTest.java index dcb95c560e..fa6e156a34 100644 --- a/src/test/java/com/lambdaworks/redis/reliability/AtLeastOnceTest.java +++ b/src/test/java/com/lambdaworks/redis/reliability/AtLeastOnceTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.reliability; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/com/lambdaworks/redis/reliability/AtMostOnceTest.java b/src/test/java/com/lambdaworks/redis/reliability/AtMostOnceTest.java index 6561e72ec5..fadf76ad05 100644 --- a/src/test/java/com/lambdaworks/redis/reliability/AtMostOnceTest.java +++ b/src/test/java/com/lambdaworks/redis/reliability/AtMostOnceTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.reliability; import static com.google.code.tempusfugit.temporal.Duration.millis; diff --git a/src/test/java/com/lambdaworks/redis/resource/ConstantDelayTest.java b/src/test/java/com/lambdaworks/redis/resource/ConstantDelayTest.java index 200492beeb..ce8e96dfd1 100644 --- a/src/test/java/com/lambdaworks/redis/resource/ConstantDelayTest.java +++ b/src/test/java/com/lambdaworks/redis/resource/ConstantDelayTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.resource; import static org.assertj.core.api.Assertions.assertThat; @@ -33,4 +48,4 @@ public void shouldCreateConstantDelay() throws Exception { assertThat(delay.createDelay(0)).isEqualTo(100); assertThat(delay.createDelay(5)).isEqualTo(100); } -} \ No newline at end of file +} diff --git a/src/test/java/com/lambdaworks/redis/resource/DecorrelatedJitterDelayTest.java b/src/test/java/com/lambdaworks/redis/resource/DecorrelatedJitterDelayTest.java index 3a09ff59c3..9750c98f15 100644 --- a/src/test/java/com/lambdaworks/redis/resource/DecorrelatedJitterDelayTest.java +++ b/src/test/java/com/lambdaworks/redis/resource/DecorrelatedJitterDelayTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.resource; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/com/lambdaworks/redis/resource/DefaultClientResourcesTest.java b/src/test/java/com/lambdaworks/redis/resource/DefaultClientResourcesTest.java index 258a15f380..58ebcbafcb 100644 --- a/src/test/java/com/lambdaworks/redis/resource/DefaultClientResourcesTest.java +++ b/src/test/java/com/lambdaworks/redis/resource/DefaultClientResourcesTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.resource; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/com/lambdaworks/redis/resource/DefaultEventLoopGroupProviderTest.java b/src/test/java/com/lambdaworks/redis/resource/DefaultEventLoopGroupProviderTest.java index 0677d335c4..4010a44c9e 100644 --- a/src/test/java/com/lambdaworks/redis/resource/DefaultEventLoopGroupProviderTest.java +++ b/src/test/java/com/lambdaworks/redis/resource/DefaultEventLoopGroupProviderTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.resource; import java.util.concurrent.TimeUnit; diff --git a/src/test/java/com/lambdaworks/redis/resource/DirContextDnsResolverTest.java b/src/test/java/com/lambdaworks/redis/resource/DirContextDnsResolverTest.java index 1a22c49c69..4fa79e5715 100644 --- a/src/test/java/com/lambdaworks/redis/resource/DirContextDnsResolverTest.java +++ b/src/test/java/com/lambdaworks/redis/resource/DirContextDnsResolverTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.resource; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; diff --git a/src/test/java/com/lambdaworks/redis/resource/EqualJitterDelayTest.java b/src/test/java/com/lambdaworks/redis/resource/EqualJitterDelayTest.java index 8a77969593..42cd096f7d 100644 --- a/src/test/java/com/lambdaworks/redis/resource/EqualJitterDelayTest.java +++ b/src/test/java/com/lambdaworks/redis/resource/EqualJitterDelayTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.resource; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/com/lambdaworks/redis/resource/ExponentialDelayTest.java b/src/test/java/com/lambdaworks/redis/resource/ExponentialDelayTest.java index 6d8d16164c..8ff5da7aba 100644 --- a/src/test/java/com/lambdaworks/redis/resource/ExponentialDelayTest.java +++ b/src/test/java/com/lambdaworks/redis/resource/ExponentialDelayTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.resource; import static org.assertj.core.api.Assertions.assertThat; @@ -81,4 +96,4 @@ public void testPow10Delays() throws Exception { assertThat(delay.createDelay(5)).isEqualTo(10000); assertThat(delay.createDelay(Integer.MAX_VALUE)).isEqualTo(10000); } -} \ No newline at end of file +} diff --git a/src/test/java/com/lambdaworks/redis/resource/FullJitterDelayTest.java b/src/test/java/com/lambdaworks/redis/resource/FullJitterDelayTest.java index 5a01edd06b..c5c1106378 100644 --- a/src/test/java/com/lambdaworks/redis/resource/FullJitterDelayTest.java +++ b/src/test/java/com/lambdaworks/redis/resource/FullJitterDelayTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.resource; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/com/lambdaworks/redis/resource/FuturesTest.java b/src/test/java/com/lambdaworks/redis/resource/FuturesTest.java index bd82907df9..4a9310fd52 100644 --- a/src/test/java/com/lambdaworks/redis/resource/FuturesTest.java +++ b/src/test/java/com/lambdaworks/redis/resource/FuturesTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.resource; import static com.google.code.tempusfugit.temporal.Duration.seconds; diff --git a/src/test/java/com/lambdaworks/redis/sentinel/AbstractSentinelTest.java b/src/test/java/com/lambdaworks/redis/sentinel/AbstractSentinelTest.java index b55e077c37..7018859b0c 100644 --- a/src/test/java/com/lambdaworks/redis/sentinel/AbstractSentinelTest.java +++ b/src/test/java/com/lambdaworks/redis/sentinel/AbstractSentinelTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.sentinel; import org.junit.After; diff --git a/src/test/java/com/lambdaworks/redis/sentinel/SentinelCommandTest.java b/src/test/java/com/lambdaworks/redis/sentinel/SentinelCommandTest.java index 76f19d3869..47c944a357 100644 --- a/src/test/java/com/lambdaworks/redis/sentinel/SentinelCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/sentinel/SentinelCommandTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.sentinel; import static com.lambdaworks.redis.TestSettings.hostAddr; diff --git a/src/test/java/com/lambdaworks/redis/sentinel/SentinelConnectionTest.java b/src/test/java/com/lambdaworks/redis/sentinel/SentinelConnectionTest.java index fb5cae9f88..e59e031d3b 100644 --- a/src/test/java/com/lambdaworks/redis/sentinel/SentinelConnectionTest.java +++ b/src/test/java/com/lambdaworks/redis/sentinel/SentinelConnectionTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.sentinel; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/com/lambdaworks/redis/sentinel/SentinelRule.java b/src/test/java/com/lambdaworks/redis/sentinel/SentinelRule.java index a9c9c4486a..6dee9a1697 100644 --- a/src/test/java/com/lambdaworks/redis/sentinel/SentinelRule.java +++ b/src/test/java/com/lambdaworks/redis/sentinel/SentinelRule.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.sentinel; import static com.google.code.tempusfugit.temporal.Duration.seconds; diff --git a/src/test/java/com/lambdaworks/redis/sentinel/reactive/SentinelReactiveCommandTest.java b/src/test/java/com/lambdaworks/redis/sentinel/reactive/SentinelReactiveCommandTest.java index a7c2ec784a..4f8e1319ea 100644 --- a/src/test/java/com/lambdaworks/redis/sentinel/reactive/SentinelReactiveCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/sentinel/reactive/SentinelReactiveCommandTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.sentinel.reactive; import static com.lambdaworks.redis.TestSettings.hostAddr; diff --git a/src/test/java/com/lambdaworks/redis/server/RandomResponseServer.java b/src/test/java/com/lambdaworks/redis/server/RandomResponseServer.java index 027861ffbe..ee181acc18 100644 --- a/src/test/java/com/lambdaworks/redis/server/RandomResponseServer.java +++ b/src/test/java/com/lambdaworks/redis/server/RandomResponseServer.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.server; import java.util.concurrent.TimeUnit; diff --git a/src/test/java/com/lambdaworks/redis/server/RandomServerHandler.java b/src/test/java/com/lambdaworks/redis/server/RandomServerHandler.java index d1bf180094..4743e7dd2c 100644 --- a/src/test/java/com/lambdaworks/redis/server/RandomServerHandler.java +++ b/src/test/java/com/lambdaworks/redis/server/RandomServerHandler.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.server; import java.security.SecureRandom; @@ -43,4 +58,4 @@ public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { cause.printStackTrace(); ctx.close(); } -} \ No newline at end of file +} diff --git a/src/test/java/com/lambdaworks/redis/support/CdiTest.java b/src/test/java/com/lambdaworks/redis/support/CdiTest.java index 863bf7f31e..dc28b3d18c 100644 --- a/src/test/java/com/lambdaworks/redis/support/CdiTest.java +++ b/src/test/java/com/lambdaworks/redis/support/CdiTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.support; import static org.assertj.core.api.Assertions.assertThat; diff --git a/src/test/java/com/lambdaworks/redis/support/ConnectionPoolSupportTest.java b/src/test/java/com/lambdaworks/redis/support/ConnectionPoolSupportTest.java index a9bf9246f8..09fe78f5cc 100644 --- a/src/test/java/com/lambdaworks/redis/support/ConnectionPoolSupportTest.java +++ b/src/test/java/com/lambdaworks/redis/support/ConnectionPoolSupportTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.support; import static org.assertj.core.api.Assertions.assertThat; @@ -205,4 +220,4 @@ public void wrappedObjectClosedAfterReturn() throws Exception { pool.close(); } -} \ No newline at end of file +} diff --git a/src/test/java/com/lambdaworks/redis/support/InjectedClient.java b/src/test/java/com/lambdaworks/redis/support/InjectedClient.java index 0a81ac8d1e..25c86e3572 100644 --- a/src/test/java/com/lambdaworks/redis/support/InjectedClient.java +++ b/src/test/java/com/lambdaworks/redis/support/InjectedClient.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.support; import javax.annotation.PostConstruct; diff --git a/src/test/java/com/lambdaworks/redis/support/PersonDB.java b/src/test/java/com/lambdaworks/redis/support/PersonDB.java index 004935fb48..5963a96928 100644 --- a/src/test/java/com/lambdaworks/redis/support/PersonDB.java +++ b/src/test/java/com/lambdaworks/redis/support/PersonDB.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.support; import java.lang.annotation.Retention; diff --git a/src/test/java/com/lambdaworks/redis/support/RedisClusterClientFactoryBeanTest.java b/src/test/java/com/lambdaworks/redis/support/RedisClusterClientFactoryBeanTest.java index 2d0be0017a..fdcde9f968 100644 --- a/src/test/java/com/lambdaworks/redis/support/RedisClusterClientFactoryBeanTest.java +++ b/src/test/java/com/lambdaworks/redis/support/RedisClusterClientFactoryBeanTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.support; import static org.assertj.core.api.Assertions.*; diff --git a/src/test/java/com/lambdaworks/redis/support/SpringTest.java b/src/test/java/com/lambdaworks/redis/support/SpringTest.java index d63d5a95f1..b5629463c9 100644 --- a/src/test/java/com/lambdaworks/redis/support/SpringTest.java +++ b/src/test/java/com/lambdaworks/redis/support/SpringTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.support; import static org.assertj.core.api.Assertions.*; diff --git a/src/test/java/com/lambdaworks/util/ConnectionDecoratingInvocationHandler.java b/src/test/java/com/lambdaworks/util/ConnectionDecoratingInvocationHandler.java index 378bdc3b30..745a07d325 100644 --- a/src/test/java/com/lambdaworks/util/ConnectionDecoratingInvocationHandler.java +++ b/src/test/java/com/lambdaworks/util/ConnectionDecoratingInvocationHandler.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.util; import java.lang.reflect.Method; diff --git a/src/test/java/com/lambdaworks/util/ReactiveSyncInvocationHandler.java b/src/test/java/com/lambdaworks/util/ReactiveSyncInvocationHandler.java index 3eec42fb0e..36c854bd2c 100644 --- a/src/test/java/com/lambdaworks/util/ReactiveSyncInvocationHandler.java +++ b/src/test/java/com/lambdaworks/util/ReactiveSyncInvocationHandler.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.util; import java.lang.reflect.InvocationTargetException; @@ -114,4 +129,4 @@ public static RedisSentinelCommands sync(StatefulRedisSentinelConne return (RedisSentinelCommands) Proxy.newProxyInstance(handler.getClass().getClassLoader(), new Class[] { RedisSentinelCommands.class }, handler); } -} \ No newline at end of file +} diff --git a/src/test/java/com/lambdaworks/util/RoutingInvocationHandler.java b/src/test/java/com/lambdaworks/util/RoutingInvocationHandler.java index df73250a24..00088fea55 100644 --- a/src/test/java/com/lambdaworks/util/RoutingInvocationHandler.java +++ b/src/test/java/com/lambdaworks/util/RoutingInvocationHandler.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.util; import java.lang.reflect.InvocationHandler; diff --git a/src/test/jmh/com/lambdaworks/redis/cluster/EmptyRedisChannelWriter.java b/src/test/jmh/com/lambdaworks/redis/cluster/EmptyRedisChannelWriter.java index 7cecaab844..b3c4a7099c 100644 --- a/src/test/jmh/com/lambdaworks/redis/cluster/EmptyRedisChannelWriter.java +++ b/src/test/jmh/com/lambdaworks/redis/cluster/EmptyRedisChannelWriter.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster; import com.lambdaworks.redis.RedisChannelWriter; diff --git a/src/test/jmh/com/lambdaworks/redis/cluster/EmptyRedisClusterClient.java b/src/test/jmh/com/lambdaworks/redis/cluster/EmptyRedisClusterClient.java index e6cc25a240..00908a42a6 100644 --- a/src/test/jmh/com/lambdaworks/redis/cluster/EmptyRedisClusterClient.java +++ b/src/test/jmh/com/lambdaworks/redis/cluster/EmptyRedisClusterClient.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster; import java.net.SocketAddress; diff --git a/src/test/jmh/com/lambdaworks/redis/cluster/EmptyStatefulRedisConnection.java b/src/test/jmh/com/lambdaworks/redis/cluster/EmptyStatefulRedisConnection.java index fd5d860d80..9d62892ba7 100644 --- a/src/test/jmh/com/lambdaworks/redis/cluster/EmptyStatefulRedisConnection.java +++ b/src/test/jmh/com/lambdaworks/redis/cluster/EmptyStatefulRedisConnection.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.cluster; import com.lambdaworks.redis.ClientOptions; diff --git a/src/test/jmh/com/lambdaworks/redis/codec/JmhMain.java b/src/test/jmh/com/lambdaworks/redis/codec/JmhMain.java index 8819aa6c97..15e902a6bf 100644 --- a/src/test/jmh/com/lambdaworks/redis/codec/JmhMain.java +++ b/src/test/jmh/com/lambdaworks/redis/codec/JmhMain.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.codec; import java.io.IOException; diff --git a/src/test/jmh/com/lambdaworks/redis/codec/StringCodecBenchmark.java b/src/test/jmh/com/lambdaworks/redis/codec/StringCodecBenchmark.java index 24c617ea98..c435f3111a 100644 --- a/src/test/jmh/com/lambdaworks/redis/codec/StringCodecBenchmark.java +++ b/src/test/jmh/com/lambdaworks/redis/codec/StringCodecBenchmark.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.codec; import java.nio.ByteBuffer; diff --git a/src/test/jmh/com/lambdaworks/redis/codec/Utf8StringCodecBenchmark.java b/src/test/jmh/com/lambdaworks/redis/codec/Utf8StringCodecBenchmark.java index abc8de1802..3d19ce10a8 100644 --- a/src/test/jmh/com/lambdaworks/redis/codec/Utf8StringCodecBenchmark.java +++ b/src/test/jmh/com/lambdaworks/redis/codec/Utf8StringCodecBenchmark.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.codec; import java.nio.ByteBuffer; diff --git a/src/test/jmh/com/lambdaworks/redis/protocol/CommandBenchmark.java b/src/test/jmh/com/lambdaworks/redis/protocol/CommandBenchmark.java index 82d5b6afd6..cb5c728c4a 100644 --- a/src/test/jmh/com/lambdaworks/redis/protocol/CommandBenchmark.java +++ b/src/test/jmh/com/lambdaworks/redis/protocol/CommandBenchmark.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.protocol; import com.lambdaworks.redis.codec.StringCodec; diff --git a/src/test/jmh/com/lambdaworks/redis/protocol/CommandHandlerBenchmark.java b/src/test/jmh/com/lambdaworks/redis/protocol/CommandHandlerBenchmark.java index 1ebad7ea84..e2e7451439 100644 --- a/src/test/jmh/com/lambdaworks/redis/protocol/CommandHandlerBenchmark.java +++ b/src/test/jmh/com/lambdaworks/redis/protocol/CommandHandlerBenchmark.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.protocol; import org.openjdk.jmh.annotations.Benchmark; diff --git a/src/test/jmh/com/lambdaworks/redis/protocol/EmptyByteBuf.java b/src/test/jmh/com/lambdaworks/redis/protocol/EmptyByteBuf.java index b7d0eff3ea..7ede2e4cc5 100644 --- a/src/test/jmh/com/lambdaworks/redis/protocol/EmptyByteBuf.java +++ b/src/test/jmh/com/lambdaworks/redis/protocol/EmptyByteBuf.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.protocol; import io.netty.buffer.AbstractByteBuf; diff --git a/src/test/jmh/com/lambdaworks/redis/protocol/EmptyClientResources.java b/src/test/jmh/com/lambdaworks/redis/protocol/EmptyClientResources.java index 7dd3a7d959..effeec0d2e 100644 --- a/src/test/jmh/com/lambdaworks/redis/protocol/EmptyClientResources.java +++ b/src/test/jmh/com/lambdaworks/redis/protocol/EmptyClientResources.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.protocol; import java.net.SocketAddress; diff --git a/src/test/jmh/com/lambdaworks/redis/protocol/EmptyContext.java b/src/test/jmh/com/lambdaworks/redis/protocol/EmptyContext.java index 51131a8fe2..89cf7a089c 100644 --- a/src/test/jmh/com/lambdaworks/redis/protocol/EmptyContext.java +++ b/src/test/jmh/com/lambdaworks/redis/protocol/EmptyContext.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.protocol; import io.netty.buffer.ByteBuf; diff --git a/src/test/jmh/com/lambdaworks/redis/protocol/EmptyFuture.java b/src/test/jmh/com/lambdaworks/redis/protocol/EmptyFuture.java index c827eeeae6..39943f0eec 100644 --- a/src/test/jmh/com/lambdaworks/redis/protocol/EmptyFuture.java +++ b/src/test/jmh/com/lambdaworks/redis/protocol/EmptyFuture.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.protocol; import io.netty.channel.Channel; diff --git a/src/test/jmh/com/lambdaworks/redis/protocol/EmptyPromise.java b/src/test/jmh/com/lambdaworks/redis/protocol/EmptyPromise.java index baba2c0daa..372eed8a42 100644 --- a/src/test/jmh/com/lambdaworks/redis/protocol/EmptyPromise.java +++ b/src/test/jmh/com/lambdaworks/redis/protocol/EmptyPromise.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.protocol; import java.util.concurrent.ExecutionException; diff --git a/src/test/jmh/com/lambdaworks/redis/protocol/JmhMain.java b/src/test/jmh/com/lambdaworks/redis/protocol/JmhMain.java index 97e41efffa..c9bb2b3e9a 100644 --- a/src/test/jmh/com/lambdaworks/redis/protocol/JmhMain.java +++ b/src/test/jmh/com/lambdaworks/redis/protocol/JmhMain.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.protocol; import java.io.IOException; diff --git a/src/test/jmh/com/lambdaworks/redis/protocol/RedisEndpointBenchmark.java b/src/test/jmh/com/lambdaworks/redis/protocol/RedisEndpointBenchmark.java index 3f6bb8286b..c47ccd51b2 100644 --- a/src/test/jmh/com/lambdaworks/redis/protocol/RedisEndpointBenchmark.java +++ b/src/test/jmh/com/lambdaworks/redis/protocol/RedisEndpointBenchmark.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.protocol; import com.lambdaworks.redis.cluster.EmptyStatefulRedisConnection; diff --git a/src/test/jmh/com/lambdaworks/redis/protocol/RedisStateMachineBenchmark.java b/src/test/jmh/com/lambdaworks/redis/protocol/RedisStateMachineBenchmark.java index 10e39ad6dc..1a81c186a1 100644 --- a/src/test/jmh/com/lambdaworks/redis/protocol/RedisStateMachineBenchmark.java +++ b/src/test/jmh/com/lambdaworks/redis/protocol/RedisStateMachineBenchmark.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.lambdaworks.redis.protocol; import java.nio.ByteBuffer; From c7e2d46e13f0c594bef1013e0e1b407de976ac58 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Thu, 27 Oct 2016 20:52:31 +0200 Subject: [PATCH 059/808] Upgrade to netty 4.0.42.Final/4.1.6.Final #390 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index fadd047171..26e868e16a 100644 --- a/pom.xml +++ b/pom.xml @@ -57,7 +57,7 @@ true 4.2.2.Final 3.5.0.Final - 4.1.5.Final + 4.1.6.Final @@ -285,7 +285,7 @@ netty-40 - 4.0.41.Final + 4.0.42.Final From 030182c834e93784c5a1a84556e0abbf42f70f62 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Fri, 28 Oct 2016 10:48:34 +0200 Subject: [PATCH 060/808] Add release notes --- RELEASE-NOTES.md | 580 +++++++++++++++++++++++++++++------------------ 1 file changed, 363 insertions(+), 217 deletions(-) diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md index 8eb845b561..b2a51a4e72 100644 --- a/RELEASE-NOTES.md +++ b/RELEASE-NOTES.md @@ -1,206 +1,335 @@ -lettuce 4.2.0 RELEASE NOTES -=========================== +lettuce 5.0.0 Beta 1 RELEASE NOTES +================================== -That's the zero behind 4.2? Well, that's to not break OSGi support. Now let's -talk about the more interesting things. Lettuce 4.2.0 is a major release and -completes development of several notable enhancements. +This is a major release coming with several breaking changes and new interesting +features. It's similar to the simultaneously released version 4.3.0 but +comes with major changes. -This release comes with SSL support, Publish/Subscribe and adaptive topology -refreshing for Redis Cluster. It features a major refactoring of the command -handling and several improvements for Cloud-based Redis services and -improvements to the Master/Slave API. +Lettuce 5.0 removes deprecated interfaces RedisConnection and RedisAsyncConnection +and their segregated interfaces in favor of StatefulRedisConnection and RedisCommands et al. -The usage of Guava was reduced for the most parts. Only the `LoadingCache`, -`InetAddresses` and `HostAndPort` components are still in use. A future lettuce -5.0 version will eliminate the use of Guava completely. +This release removes dependencies to Guava. Lettuce requires only Netty and Project Reactor +which brings us to the next change. The reactive API is based on Reactive Streams by using +Project Reactor types `Mono` and `Flux` instead of RxJava 1 and `Observable`. +Existing users can convert `Mono` and `Flux` by using `rxjava-reactive-streams`. -**Important note for users of connection-pooling and latency tracking** +Finally, this release introduces the dynamic Redis Commands API. This programming +model enables you to declare command methods and invoke commands to your needs and +support Redis Modules without waiting for lettuce to support new commands. -Dependencies were streamlined with this release. Apache's `commons-pool2` and -`latencyutils` are now _optional_ dependencies. If you use connection-pooling or -latency tracking, please include these dependencies explicitly otherwise these -features will be disabled. +This beta/candidate release is to give you a chance to try out new features, +get feedback and improve for the final release. -Lettuce 4.2.0 was verified with several Cloud-based Redis services. It works -with different AWS ElastiCache usage patterns and is known to work with the -Azure Redis Cluster service supporting SSL and authentication (see below). +You will find the full change log at the end of this document. -lettuce 4.2.0 is fully binary compatible with the last release and can be used -as a drop-in replacement for 4.1.x. This update is strongly recommended for -lettuce 4.x users as it fixes some critical connection synchronization bugs. +Thanks to all contributors that made lettuce 5.0.0 possible. -Thanks to all contributors that made lettuce 4.2.0 possible. +lettuce 5.0.0 requires Java 8 and cannot be used with Java 6 or 7. -lettuce 4.2.0 requires Java 8 and cannot be used with Java 6 or 7. +Good bye, Guava +--------------- -Redis Cluster Publish/Subscribe -------------------------------- -Redis Cluster -provides Publish/Subscribe features to broadcast messages across the cluster. -Using the standalone client allows using Publish/Subscribe with Redis Cluster -but comes with the limitation of high-availability/failover. - -If a node goes down, the connection is lost until the node is available again. -lettuce addresses this issue with Redis Cluster Publish/Subscribe and provides a -failover mechanism. - -Publish/Subscribe messages and subscriptions are operated on the default cluster -connection. The default connection is established with the node with the least -client connections to achieve a homogeneous connection distribution. It also -uses the cluster topology to failover if the currently connected node is down. - -Publishing a message using the regular cluster connection is still possible -(since 4.0). The regular cluster connection calculates a slot-hash from the -channel (which is the key in this case). Publishing always connects to the -master node which is responsible for the slot although `PUBLISH` is not affected -by the keyspace/slot-hash rule. - -Read more: https://github.com/mp911de/lettuce/wiki/Pub-Sub-%284.0%29 - - -Redis Cluster and SSL ---------------------- -Redis introduces an option to announce a specific IP address/port using -`cluster-announce-ip` and `cluster-announce-port`. This is useful for -Docker and NAT'ed setups. Furthermore, you can "hide" your Redis Cluster nodes -behind any other proxy like `stunnel`. A Redis Cluster node will announce the -specified port/IP which can map to `stunnel`, and you get an SSL-protected -Redis Cluster. Please note that `cluster-announce-ip` is not part of Redis 3.2 -but will be released in future versions. - -Redis Cluster SSL works pretty much the same as Redis Standalone with SSL. You -can configure SSL and other SSL/TLS options using `RedisURI`. +Lettuce 5.0 no longer uses Google's Guava library. Guava was a good friend +back in the Java 6-compatible days where `Future` synchronization and callbacks +were no fun to use. That changed with Java 8 and `CompletableFuture`. + +Other uses like `HostAndPort` or `LoadingCache` could be either inlined or +replaced by Java 8's Collection framework. + + +Removal of deprecated interfaces and methods +-------------------------------------------- + +This release removes deprecated interfaces `RedisConnection` and `RedisAsyncConnection` +and their segregated interfaces in favor of `StatefulRedisConnection` and `RedisCommands`. + +You will notice slight differences when using that API. Transactional commands and +database selection are no longer available through the Redis Cluster API as the +old API was derived from the standalone API. `RedisCommands` and `RedisAsyncCommands` +are no longer `Closeable`. Please use `commands.getStatefulConnection().close()` to +close a connection. This change removes ambiguity over closing the commands interface +over closing the connection. + + +Migration to Reactive Streams (Project Reactor) +----------------------------------------------- + +Lettuce 4.0 introduced a reactive API based on RxJava 1 and `Observable`. +This was the beginning of reactive Redis support. Lettuce used `Observable` +all over the place as other reactive types like `Single` and `Completable` were +still beta or in development. + +Since that time, a lot changed in the reactive space. RxJava 2 is still in the +works towards a final release supporting Reactive Streams, while other composition +libraries are already available and polish on sharp edges. This means, +it was just a matter of time that lettuce adopts Reactive Streams. + +This also means, no `null` values and usage of dedicated value types to express +value multiplicity (`0|1` and `0|1|N`) on the API. + +With lettuce 5.0, the reactive API uses Project Reactor, `Mono` and `Flux`. + +**4.3 and earlier** ```java -RedisURI redisURI = RedisURI.Builder.redis(host(), 7443) - .withSsl(true) - .withVerifyPeer(false) - .build(); +Observable del(K... keys); + +Observable keys(K pattern); + +Observable mget(K... keys); -RedisClusterClient redisClusterClient = RedisClusterClient.create(redisURI); -StatefulRedisClusterConnection connection = redisClusterClient.connect(); ``` -You should disable the `verifyPeer` option if the SSL endpoints cannot provide a -valid certificate. When creating a `RedisClusterClient` using -`RedisClusterClientFactoryBean` the `verifyPeer` option is disabled by default. +**5.0** -Lettuce was successfully tested with Azure Redis with SSL and authentication. +```java +Mono del(K... keys); -Read more: https://github.com/mp911de/lettuce/wiki/Redis-Cluster-%284.0%29 +Flux keys(K pattern); +Flux> mget(K... keys); +``` -Redis Cluster Topology Discovery and Refreshing ----------------------------------------------- -The lettuce Redis Cluster Client -allows regular topology updates. lettuce 4.2.0 improves the existing topology -updates with adaptive refreshing and dynamic/static topology discovery. +Switching from RxJava 1 to Project Reactor use requires switching the library. Most +operators use similar or even same names. If you're required to stick to RxJava 1, +the use `rxjava-reactive-streams` to adopt reactive types (RxJava 1 <-> Reactive Streams). -Adaptive refresh initiates topology view updates based on events happened during -Redis Cluster operations. Adaptive triggers lead to an immediate topology -refresh. Adaptive updates are rate-limited using a timeout since events can -happen on a large scale. Adaptive refresh triggers are disabled by default and -can be enabled selectively: +Migrating to Reactive Streams requires value wrapping to indicate absence of values. +You will find differences in comparison to the previous API and to the sync/async API +in cases where commands can return `null` values. Lettuce 5.0 comes with +new `Value` types that are monads encapsulating a value (or their absence). -* `MOVED_REDIRECT` -* `ASK_REDIRECT` -* `PERSISTENT_RECONNECTS` +See also: https://github.com/mp911de/lettuce/wiki/Reactive-API-%285.0%29 -Dynamic/static topology discovery sources are the second change to topology -refresh. lettuce uses by default dynamic discovery. Dynamic discovery retrieves -the initial topology from the seed nodes and determines additional nodes to -request their topology view. That is to reduce split-brain views by choosing the -view which is shared by the majority of cluster nodes. -Dynamic topology discovery also provides latency data and client count for each -node in the cluster. These details are useful for calculating the nearest node -or the least used node. +Value, KeyValue, and other value types +-------------------------------------- -Dynamic topology discovery can get expensive when running large Redis Clusters -as all nodes from the topology are queried for their view. Static topology -refresh sources limit the nodes to the initial seed node set. Limiting nodes is -friendly to large clusters but it will provide latency and client count only for -the seed nodes. +This release enhances existing value types and introduces new types +to reduce `null` usage and facilitate functional programming. -Read more: https://github.com/mp911de/lettuce/wiki/Client-options#adaptive-cluster-topology-refresh +Value types are based on `Value` and `KeyValue`/`ScoredValue` extend from there. +Value is a wrapper type encapsulating a value or its absence. A `Value` can +be created in different ways: +```java +Value value = Value.from(Optional.of("hello")); -Redis Modules -------------- +Value value = Value.fromNullable(null); -Redis module support is a very young feature. lettuce provides a custom command -API to dispatch own commands. `StatefulConnection` already allows sending of -commands but requires wrapping of commands into the appropriate synchronization -wrapper (Future, Reactive, Fire+Forget). +Value value = Value.just("hello"); -lettuce provides with 4.2.0 `dispatch(…)` methods on each API type to provide a -simpler interface. +KeyValue value = KeyValue.from(1L, Optional.of("hello")); + +KeyValue value = KeyValue.just("key", "hello"); +``` + +It transforms to `Optional` and `Stream` to integrate with other +functional uses and allows value mapping. ```java -RedisCodec codec = new Utf8StringCodec(); +Value.just("hello").stream().filter(…).count(); -String response = redis.dispatch(CommandType.SET, - new StatusOutput<>(codec), - new CommandArgs<>(codec) - .addKey(key) - .addValue(value)); -``` +KeyValue.just("hello").optional().isPresent(); -Calls to `dispatch(…)` on the synchronous API are blocking calls, calls on the -asynchronous API return a `RedisFuture` and calls on the Reactive API return -an `Observable` which flat-maps collection responses. +Value.from(Optional.of("hello")).map(s -> s + "-world").getValue(); -Using `dispatch(…)` allows to invoke arbitrary commands and works together -within transactions and Redis Cluster. Exposing this API also allows choosing a -different `RedisCodec` for particular operations. +ScoredValue.just(42, "hello").mapScore(number -> number.doubleValue() * 3.14d).getScore(); +``` -Read more: https://github.com/mp911de/lettuce/wiki/Custom-commands%2C-outputs-and-command-mechanics +You will also find that all public fields of value types are encapsulated with +getters and these fields are no longer accessible. -CommandHandler refactoring +Dynamic Redis Commands API -------------------------- -Command sending, buffering, encoding and receiving was refactored on a large scale. -Command encoding is performed in a separate handler and outside of `CommandHandler`. -It does not longer allocate an additional buffer to encode its arguments, but -arguments are directly written to the command buffer that is used to encode -single command/batch of commands. Fewer memory allocations help improving -performance and do not duplicate data. -Synchronization and locking were reworked as well. The critical path used for -writing commands is no longer locked exclusively but uses a shared locking with -almost lock-free synchronization. +The Redis Command Interface abstraction provides a dynamic way for typesafe Redis +command invocation. It allows you to declare an interface with command methods to +significantly reduce boilerplate code required to invoke a Redis command. + +Redis is a data store supporting over 190 documented commands and over 450 command permutations. +Command growth and keeping track with upcoming modules are challenging for client +developers and Redis user as there is no full command coverage for each module in a single Redis client. + +Invoking a custom command with lettuce several lines of code to define command structures +pass in arguments and specify the return type. + +```java +RedisCodec codec = new StringCodec(); +RedisCommands commands = ... + +String response = redis.dispatch(CommandType.SET, new StatusOutput<>(codec), + new CommandArgs<>(codec) + .addKey(key) + .addValue(value)); +``` + +The central interface in lettuce Command Interface abstraction is `Commands`. +This interface acts primarily as a marker interface to help you to discover +interfaces that extend this one. You can declare your own command interfaces +and argument sequences where the command name is derived from the method name or +provided with `@Command`. Introduction of new commands does not require you +to wait for a new lettuce release but they can invoke commands through own declaration. +That interface could be also supporting different key and value types, depending on the use-case. + +Commands are executed applying synchronization, asynchronous and in a reactive fashion, +depending on the method declaration. + +```java +public interface MyRedisCommands extends Commands { + + String get(String key); // Synchronous Execution of GET + + @Command("GET") + byte[] getAsBytes(String key); // Synchronous Execution of GET returning data as byte array + + @Command("SET") // synchronous execution applying a Timeout + String setSync(String key, String value, Timeout timeout); + + Future set(String key, String value); // asynchronous SET execution + + @Command("SET") + Mono setReactive(String key, String value); // reactive SET execution using SetArgs + + @CommandNaming(split = DOT) // support for Redis Module command notation -> NR.RUN + double nrRun(String key, int... indexes); +} + +RedisCommandFactory factory = new RedisCommandFactory(connection); + +MyRedisCommands commands = factory.getCommands(MyRedisCommands.class); + +String value = commands.get("key"); +``` + +You get a whole lot new possibilities with Redis Command Interfaces. This release +provides initial support. Future versions are likely to support RxJava 1/2 reactive +types so RxJava 1 users have a migration path that allows using native types without +further conversion. + +See also: https://github.com/mp911de/lettuce/wiki/Redis-Command-Interfaces + + +Backoff/Delay strategies +------------------------ +_Thanks to @jongyeol_ -Improvements to Master/Slave connections +When running cloud-based services with a multitude of services that use Redis, +then network partitions impact Redis server connection heavily once +the partition ends. A network partition impacts all disconnected applications +at the same time and all nodes start reconnecting more or less at the same time. + +As soon as the partition ends, the majority of applications reconnect at the same time. +Jitter backoff strategies leverage the impact as the time of reconnecting is randomized. + +Lettuce comes with various backoff implementations: + +* Equal Jitter +* Full Jitter +* Decorrelated Jitter + +These are configured in `ClientResources`: + +```java +DefaultClientResources.builder() + .reconnectDelay(Delay.decorrelatedJitter()) + .build(); + +DefaultClientResources.builder() + .reconnectDelay(Delay.equalJitter()) + .build(); +``` + +See also: https://www.awsarchitectureblog.com/2015/03/backoff.html and +https://github.com/mp911de/lettuce/wiki/Configuring-Client-resources + + +New API for Z...RANGE commands +------------------------------- + +Sorted Sets range commands come with a streamlined API regarding method overloads. +Commands like `ZRANGEBYSCORE`, `ZRANGEBYLEX`, `ZREMRANGEBYLEX` and several others +now declare methods accepting `Range` and `Limit` objects instead of an growing +parameter list. The new `Range` allows score and value types applying the proper +binary encoding. + +**4.2 and earlier** + +```java +commands.zcount(key, 1.0, 3.0) + +commands.zrangebyscore(key, "-inf", "+inf") + +commands.zrangebyscoreWithScores(key, "[1.0", "(4.0") + +commands.zrangebyscoreWithScores(key, "-inf", "+inf", 2, 2) +``` + +**Since 4.3** + +```java +commands.zcount(key, Range.create(1.0, 3.0)); + +commands.zrangebyscore(key, Range.unbounded()); + +commands.zrangebyscoreWithScores(key, Range.from(Boundary.including(1.0), Boundary.excluding(4.0)); + +commands.zrangebyscoreWithScores(key, Range.unbounded(), Limit.create(2, 2)); +``` + + +Connection pooling deprecation +------------------------------ + +It took quite a while but 4.3 finally deprecates Lettuce's existing connection pooling +support. That are in particular `RedisClient.pool(…)` and `RedisClient.asyncPool(…)`. +These methods are removed with lettuce 5.0. + +Connection pooling had very limited support and would require additional overloads +that clutter the API to expose pooling for all supported connections. +This release brings a replacement, that is customizable +and does not pollute the API. `ConnectionPoolSupport` provides methods to +create a connection pool accepting a factory method and pool configuration. + +Returned connection objects are proxies that return the connection to its pool +when calling `close()`. `StatefulConnection` implement `Closeable` to +allow usage of try-with-resources. + +```java +GenericObjectPool> pool = ConnectionPoolSupport + .createGenericObjectPool(() -> client.connect(), new GenericObjectPoolConfig()); + + +try(StatefulRedisConnection connection = pool.borrowObject()) { + // Work +} + + +pool.close(); +``` + + +Redis Cluster topology refresh consensus ---------------------------------------- -lettuce introduced with 4.1 a Master/Slave API which is now more dynamic. It's -no longer required to connect to a Master node when using Master/Slave without -Sentinel as the Master/Slave API will discover the master by itself. Providing -one seed node enables dynamic lookup. The API is internally prepared for dynamic -updates which are used with Redis Sentinel. - -A Sentinel-managed Master/Slave setup discovers configuration changes based on -Sentinel events and updates its topology accordingly. - -Another change is the broader support of AWS ElastiCache Master/Slave setups. -AWS ElastiCache allows various patterns for usage. One of them is the automatic -failover. AWS ElastiCache exposes a connection point hostname and updates the -DNS record to point to the current master node. Since the JVM has a built-in -cache it's not trivial to adjust the DNS lookup and caching to the special needs -which are valid only for AWS ElastiCache connections. lettuce exposes a DNS -Lookup API that defaults to the JVM lookup. Lettuce ships also with -`DirContextDnsResolver` that allows own DNS lookups using either the -system-configured DNS or external DNS servers. This implementation comes without -caching and is suitable for AWS ElastiCache. - -Another pattern is using AWS ElastiCache slaves. Before 4.2.0, a static setup -was required. Clients had to point to the appropriate node. The Master/Slave API -allows specifying a set of nodes which form a static Master/Slave setup. Lettuce -discovers the roles from the provided nodes and routes read/write commands -according to `ReadFrom` settings. - -Read more: https://github.com/mp911de/lettuce/wiki/Master-Slave + +Cluster topology refreshing can lead in some cases (dynamic topology sources) +to orphaning. This can happen if a cluster node is removed from the cluster and +lettuce decides to accept the topology view of that removed node. Lettuce +gets stuck with that node and is not able to use the remaining cluster. + +This release introduces `PartitionsConsensus` strategies to determine the most +appropriate topology view if multiple views are acquired. The strategy can be +customized by overriding +`RedisClusterClient.determinePartitions(Partitions, Map)`. + +Lettuce defaults choosing the topology view with the majority of previously known +cluster nodes. This helps lettuce to stick with the cluster that consists of the +most nodes. + +See also: https://github.com/mp911de/lettuce/issues/355 If you need any support, meet lettuce at: @@ -212,71 +341,88 @@ If you need any support, meet lettuce at: Commands -------- -* Add support for CLUSTER BUMPEPOCH command #179 -* Support extended MIGRATE syntax #197 -* Add support for GEORADIUS STORE and STOREDIST options #199 -* Support SCAN in RedisCluster #201 -* Add support for BITFIELD command #206 -* Add zadd method accepting ScoredValue #210 -* Add support for SPOP key count #235 -* Add support for GEOHASH command #239 -* Add simple interface for custom command invocation for sync/async/reactive APIs #245 +* Add support for TOUCH command #270 +* Add support for variadic LPUSHX and RPUSHX #267 +* Provide a more conceise API for Sorted Set query operations using Range/Limit #363 +* Add support for ZREVRANGEBYLEX command #369 (Thanks to @christophstrobl) +* Add support for SWAPDB #375 Enhancements ------------ -* Cluster pub/sub and resilient subscriptions #138 (Thanks to @jpennell) -* Reactive API: Emit items during command processing #178 -* Allow configuration of max redirect count for cluster connections #191 -* Improve SCAN API #208 -* Support Redis Cluster with SSL #209 -* Improve CommandHandler locking #211 -* Improve command encoding of singular commands and command batches #212 (Thanks to @cwolfinger) -* Add log statement for resolved address #218 (Thanks to @mzapletal) -* Apply configured password/database number in MasterSlave connection #220 -* Improve command draining in flushCommands #228 (Thanks to @CodingFabian) -* Support dynamic master/slave connections #233 -* Expose DNS Resolver #236 -* Make latencyutils and commons-pool2 dependencies optional #237 -* Support adaptive cluster topology refreshing and static refresh sources #240 (Thanks to @RahulBabbar) -* Add static builder() methods to builders enhancement #248 -* Add factory for reconnection delay enhancement #250 -* Add integer cache for CommandArgs enhancement #251 +* Remove deprecated interfaces and methods #156 +* Remove Google Guava usage #217 +* Add SocketOptions to ClientOptions #269 +* Add support for OpenSSL as SSL provider #249 +* Replacement support for connection pooling #264 +* Add ToByteBufEncoder and improved StringCodec #275 +* Allow configuration of a trust store password #292 +* Replace Guava Cache by ConcurrentHashMap #300 +* Eager initialization of API wrappers in stateful connections #302 (Thanks to @jongyeol) +* Change MethodTranslator's loadfactor to 1.0 for sync APIs performance #305 (Thanks to @jongyeol) +* Reattempt initially failed Sentinel connections in Master/Slave API #306 +* Decouple CommandHandler #317 +* Use TransactionResult for transaction results #320 +* Replace synchronized setters with volatile fields #326 (Thanks to @guperrot) +* Add workaround for IPv6 parsing #332 +* Provide multi-key-routing for exists and unlink commands using Redis Cluster #334 +* Migrate lettuce reactive API to Reactive Streams #349 +* Provide Value types #350 +* Add ConnectionWatchdog as last handler #335 +* Provide Timer as part of ClientResources #354 (Thanks to @plokhotnyuk) +* Add support for topology consensus #355 +* Use Limit in SortArgs #364 +* Add jitter backoff strategies for spreading reconnection timing #365 (Thanks to @jongyeol) +* Add EVAL and EVALSHA to ReadOnlyCommands #366 (Thanks to @amilnarski) +* Add support for ZADD INCR with ZAddArgs #367 (Thanks to @christophstrobl) +* Accept double in ZStoreArgs.weights #368 (Thanks to @christophstrobl) +* Consider role changes as trigger for update using MasterSlave connections #370 +* Provide a dynamic Redis Command API #371 +* Support lettuce parameter types #381 +* Expose Value.map methods #386 Fixes ----- -* pfmerge invokes PFADD instead of PFMERGE #158 (Thanks to @christophstrobl) -* Fix NPE in when command output is null #187 (Thanks to @rovarghe) -* Set interrupted bit after catching InterruptedException #192 -* Lettuce fails sometimes at shutdown: DefaultClientResources.shutdown #194 -* Extensive calls to PooledClusterConnectionProvider.closeStaleConnections #195 -* Shared resources are closed altough still users are present #196 -* Lettuce 4.1 does not repackage new dependencies #198 (Thanks to @ CodingFabian) -* Fix NPE in CommandHandler.write (Thanks to @cinnom) #213 -* Gracefully shutdown DefaultCommandLatencyCollector.PAUSE_DETECTOR #223 (Thanks to @sf-git and @johnou) -* RedisClient.connect(RedisURI) fails for unix socket based URIs #229 (Thanks to @nivekastoreth) -* HdrHistogram and LatencyUtils are not included in binary distribution #231 -* Cache update in Partitions is not thread-safe #234 -* GEORADIUSBYMEMBER, GEORADIUS and GEOPOS run into NPE when using Redis Transactions #241 -* LettuceFutures.awaitAll throws RedisCommandInterruptedException when awaiting failed commands #242 -* Fix command sequence on connection activation #253 (Thanks to @long-xuan-nguyen) -* Cluster topology refresh: Failed connections are not closed bug #255 -* Cluster topology refresh tries to connect twice for failed connection attempts #256 -* Connection lifecycle state DISCONNECTED is considered a connected sate #257 -* Writing commands while a disconnect is in progress leads to a race-condition #258 -* Canceled commands lead to connection desynchronization #262 (Thanks to @long-xuan-nguyen) +* Fix JavaDoc for blocking list commands #272 +* Guard key parameters against null values #287 +* CommandArgs.ExperimentalByteArrayCodec fails to encode bulk string #288 +* Guard value parameters against null values #291 (Thanks to @christophstrobl) +* Allow MasterSlave connection using Sentinel if some Sentinels are not available #304 (Thanks to @RahulBabbar) +* Allow coordinated cross-slot execution using Iterable #303 (Thanks to @agodet) +* Use at least 3 Threads when configuring default thread count #309 +* Replace own partition host and port only if the reported connection point is empty #312 +* Lettuce RedisClusterClient calls AUTH twice #313 +* CommandHandler notifications called out of order #315 +* Disable SYNC command #319 +* Record sent-time on command queueing #314 (Thanks to @HaloFour) +* ASK bit not set on ASK redirection #321 (Thanks to @kaibaemon) +* Check for isUnsubscribed() before calling subscriber methods #323 (Thanks to @vleushin) +* Avoid timeouts for cancelling command #325 (Thanks to @jongyeol) +* Guard command completion against exceptions #331 +* Store error at output-level when using NestedMultiOutput #328 (Thanks to @jongyeol) +* Fix master and slave address parsing for IPv6 addresses #329 (Thanks to @maksimlikharev) +* Fix srandmember return type from Set to List #330 (Thanks to @jongyeol) +* Add synchronization to Partitions/Use read-view for consistent Partition usage during Partitions updates #333 (Thanks to @OutOfBrain) +* Run cluster command redirects on event executor threads #340 (Thanks to @oklahomer) +* Close connections in PooledClusterConnectionProvider on connection failures #343 +* Consider number of redirections instead of executions for cluster commands #344 (Thanks to @Spikhalskiy) +* Ensure unique reconnect scheduling #346 +* Guard ConnectionWatchdog against NPE from missing CommandHandler #358 +* Fix RedisAdvancedClusterAsyncCommandsImpl.msetnx return value #376 (Thanks to @mjaow) +* Allow hostnames in MasterSlaveTopologyProvider when parsing in master_host #377 (Thanks to @szabowexler) +* Allow empty values in BITFIELD using the reactive API #378 +* Support integer width multiplied offsets in BITFIELD #379 (Thanks to @christophstrobl) +* Propagate array sizes in MultiOutput #380 (Thanks to @christophstrobl) Other ------ -* Switch remaining tests to AssertJ #13 -* Promote 4.x branch to main branch #155 -* Add Wiki documentation for disconnectedBehavior option in ClientOptions #188 -* Switch travis-ci to container build #203 -* Refactor Makefile #207 -* Code cleanups #215 -* Reduce Google Guava usage #217 -* Improve contribution assets #219 -* Ensure OSGi compatibility #232 -* Upgrade netty to 4.0.36.Final #238 +* Improve test synchronization #216 +* Upgrade to stunnel 5.33 #290 +* Upgrade logging to log4j2 for tests #316 +* Upgrade to AssertJ 3.5.2 #352 +* Add test to verify behavior of GEODIST if a geoset is unknown #362 +* Update license/author headers #387 +* Upgrade to netty 4.0.42.Final/4.1.6.Final 390 + lettuce requires a minimum of Java 8 to build and run. It is tested continuously against the latest Redis source-build. @@ -287,4 +433,4 @@ If you need any support, meet lettuce at or lettuce-redis-client-users@googlegroups.com * Join the chat at https://gitter.im/mp911de/lettuce * Github Issues: https://github.com/mp911de/lettuce/issues -* Wiki: https://github.com/mp911de/lettuce/wiki \ No newline at end of file +* Wiki: https://github.com/mp911de/lettuce/wiki From 80668f970482e8ee7d9936a94a815063645b8a90 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Fri, 28 Oct 2016 10:49:48 +0200 Subject: [PATCH 061/808] Add Commands interface #371 --- .../lambdaworks/redis/dynamic/Commands.java | 26 +++++++++++++++++++ .../redis/dynamic/RedisCommandFactory.java | 2 +- .../lambdaworks/redis/ScoredValueTest.java | 2 +- .../redis/dynamic/RedisCommandsTest.java | 6 ++--- 4 files changed, 31 insertions(+), 5 deletions(-) create mode 100644 src/main/java/com/lambdaworks/redis/dynamic/Commands.java diff --git a/src/main/java/com/lambdaworks/redis/dynamic/Commands.java b/src/main/java/com/lambdaworks/redis/dynamic/Commands.java new file mode 100644 index 0000000000..69548b7262 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/dynamic/Commands.java @@ -0,0 +1,26 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.lambdaworks.redis.dynamic; + +/** + * Marker interface for dynamic Redis commands. Typically used by Redis Command Interfaces as extension point to discover + * interface declarations. + * + * @author Mark Paluch + * @since 5.0 + */ +public interface Commands { +} diff --git a/src/main/java/com/lambdaworks/redis/dynamic/RedisCommandFactory.java b/src/main/java/com/lambdaworks/redis/dynamic/RedisCommandFactory.java index eb83ac3dab..f068012101 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/RedisCommandFactory.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/RedisCommandFactory.java @@ -179,7 +179,7 @@ public void setVerifyCommandMethods(boolean verifyCommandMethods) { * @param commandInterface must not be {@literal null}. * @return the implemented Redis Commands interface. */ - public T getCommands(Class commandInterface) { + public T getCommands(Class commandInterface) { LettuceAssert.notNull(commandInterface, "Redis Command Interface must not be null"); diff --git a/src/test/java/com/lambdaworks/redis/ScoredValueTest.java b/src/test/java/com/lambdaworks/redis/ScoredValueTest.java index 438e831809..aec53eed3a 100644 --- a/src/test/java/com/lambdaworks/redis/ScoredValueTest.java +++ b/src/test/java/com/lambdaworks/redis/ScoredValueTest.java @@ -41,7 +41,7 @@ public void shouldCreateEmptyScoredValueFromOptional() { public void shouldCreateEmptyValue() { ScoredValue value = ScoredValue.empty(); - + assertThat(value.hasValue()).isFalse(); } diff --git a/src/test/java/com/lambdaworks/redis/dynamic/RedisCommandsTest.java b/src/test/java/com/lambdaworks/redis/dynamic/RedisCommandsTest.java index 51dba6236e..225e6ca1ed 100644 --- a/src/test/java/com/lambdaworks/redis/dynamic/RedisCommandsTest.java +++ b/src/test/java/com/lambdaworks/redis/dynamic/RedisCommandsTest.java @@ -91,7 +91,7 @@ public void verifierShouldCatchBuggyDeclarations() throws Exception { } - static interface TestInterface { + static interface TestInterface extends Commands { String get(String key); @@ -107,13 +107,13 @@ static interface TestInterface { Mono setReactive(String key, String value); } - static interface TooFewParameters { + static interface TooFewParameters extends Commands { String get(); } - static interface WithTypo { + static interface WithTypo extends Commands { String gat(String key); From 5f873e8d56e343a963baca5e7d7bc68078360d91 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Fri, 28 Oct 2016 14:58:08 +0200 Subject: [PATCH 062/808] Upgrade to Project Reactor 3.0.3 #395 --- RELEASE-NOTES.md | 1 + pom.xml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md index b2a51a4e72..d00a103eaa 100644 --- a/RELEASE-NOTES.md +++ b/RELEASE-NOTES.md @@ -422,6 +422,7 @@ Other * Add test to verify behavior of GEODIST if a geoset is unknown #362 * Update license/author headers #387 * Upgrade to netty 4.0.42.Final/4.1.6.Final 390 +* Upgrade to Project Reactor 3.0.3 #395 lettuce requires a minimum of Java 8 to build and run. It is tested continuously diff --git a/pom.xml b/pom.xml index 26e868e16a..fe05748647 100644 --- a/pom.xml +++ b/pom.xml @@ -76,7 +76,7 @@ io.projectreactor reactor-core - 3.0.1.BUILD-SNAPSHOT + 3.0.3.RELEASE From 844cd6dde156d3ed4996d37cbd311293fc68e031 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Fri, 28 Oct 2016 15:03:08 +0200 Subject: [PATCH 063/808] Disable shaded jar #396 --- RELEASE-NOTES.md | 1 + pom.xml | 51 +------------------------------------------- src/assembly/bin.xml | 5 ++--- 3 files changed, 4 insertions(+), 53 deletions(-) diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md index d00a103eaa..24efea1a71 100644 --- a/RELEASE-NOTES.md +++ b/RELEASE-NOTES.md @@ -423,6 +423,7 @@ Other * Update license/author headers #387 * Upgrade to netty 4.0.42.Final/4.1.6.Final 390 * Upgrade to Project Reactor 3.0.3 #395 +* Disable shaded jar #396 lettuce requires a minimum of Java 8 to build and run. It is tested continuously diff --git a/pom.xml b/pom.xml index fe05748647..e5f328684a 100644 --- a/pom.xml +++ b/pom.xml @@ -436,7 +436,7 @@ test -classpath - + org.openjdk.jmh.Main .* @@ -622,55 +622,6 @@ apidocs/** - - - org.apache.maven.plugins - maven-shade-plugin - 2.3 - - - package - - shade - - - - - rx - com.lambdaworks.rx - - - - com.google - com.lambdaworks.com.google - - - - org.HdrHistogram - com.lambdaworks.org.HdrHistogram - - - - org.LatencyUtils - com.lambdaworks.org.LatencyUtils - - - - org.apache.commons.pool2 - com.lambdaworks.org.apache.commons.pool2 - - - - io - com.lambdaworks.io - - - false - true - - - - diff --git a/src/assembly/bin.xml b/src/assembly/bin.xml index a65ed2ad90..0dfa47f183 100644 --- a/src/assembly/bin.xml +++ b/src/assembly/bin.xml @@ -13,7 +13,6 @@ biz.paluch.redis:lettuce:jar:${project.version} - biz.paluch.redis:lettuce:jar:shaded:${project.version} false @@ -30,9 +29,9 @@ - io.reactivex:* io.netty:* - com.google.guava:* + io.projectreactor:* + org.reactivestreams:reactive-streams:* org.apache.commons:* org.latencyutils:* org.hdrhistogram:* From 7161a36c2f571d0971775a419754398c87fae9c4 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Fri, 28 Oct 2016 15:08:51 +0200 Subject: [PATCH 064/808] [maven-release-plugin] prepare release 5.0.0.Beta1 --- pom.xml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index e5f328684a..32961d61c9 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ biz.paluch.redis lettuce - 5.0.0-SNAPSHOT + 5.0.0.Beta1 jar lettuce @@ -64,7 +64,8 @@ scm:git:https://github.com/mp911de/lettuce.git scm:git:https://github.com/mp911de/lettuce.git http://github.com/mp911de/lettuce - + 5.0.0.Beta1 + 3.0 From b764373ca79dc946477a5bd627bcfc4ab05c6403 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Fri, 28 Oct 2016 15:12:44 +0200 Subject: [PATCH 065/808] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 32961d61c9..914e9cf1fe 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ biz.paluch.redis lettuce - 5.0.0.Beta1 + 5.0.0-SNAPSHOT jar lettuce @@ -64,7 +64,7 @@ scm:git:https://github.com/mp911de/lettuce.git scm:git:https://github.com/mp911de/lettuce.git http://github.com/mp911de/lettuce - 5.0.0.Beta1 + HEAD From be257314d7c9b491f254b03f0525595137ed97eb Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Sun, 6 Nov 2016 11:56:53 +0100 Subject: [PATCH 066/808] Extend RedisClusterClient and RedisClusterFactoryBean to take multiple hosts #401 RedisClusterClient and RedisClusterFactoryBean can now be initialized by taking multiple hosts within one URI. RedisClusterClient.create("redis+tls://password@host1:6379,host2:6380") --- .../java/com/lambdaworks/redis/RedisURI.java | 35 ++++-- .../redis/cluster/RedisClusterClient.java | 30 ++--- .../redis/cluster/RedisClusterURIUtil.java | 81 +++++++++++++ .../RedisClusterClientFactoryBean.java | 61 +++++++--- .../com/lambdaworks/redis/RedisURITest.java | 39 +++--- .../cluster/RedisClusterURIUtilTest.java | 112 ++++++++++++++++++ .../RedisClusterClientFactoryBeanTest.java | 69 +++++++++-- 7 files changed, 353 insertions(+), 74 deletions(-) create mode 100644 src/main/java/com/lambdaworks/redis/cluster/RedisClusterURIUtil.java create mode 100644 src/test/java/com/lambdaworks/redis/cluster/RedisClusterURIUtilTest.java diff --git a/src/main/java/com/lambdaworks/redis/RedisURI.java b/src/main/java/com/lambdaworks/redis/RedisURI.java index 7461c0ffa3..74852f8c02 100644 --- a/src/main/java/com/lambdaworks/redis/RedisURI.java +++ b/src/main/java/com/lambdaworks/redis/RedisURI.java @@ -535,16 +535,20 @@ private static RedisURI buildRedisUriFromUri(URI uri) { private String getAuthority(final String scheme) { String authority = null; + if (host != null) { - authority = urlEncode(host) + getPortPart(port, scheme); + if (host.contains(",")) { + authority = host; + } else { + authority = urlEncode(host) + getPortPart(port, scheme); + } } if (sentinels.size() != 0) { - String joinedSentinels = sentinels.stream() + + authority = sentinels.stream() .map(redisURI -> urlEncode(redisURI.getHost()) + getPortPart(redisURI.getPort(), scheme)) .collect(Collectors.joining(",")); - - authority = joinedSentinels; } if (socket != null) { @@ -772,7 +776,8 @@ private static void parseSentinelMasterId(Builder builder, String queryParam) { } private static Builder configureStandalone(URI uri) { - Builder builder; + + Builder builder = null; Set allowedSchemes = LettuceSets.unmodifiableSet(URI_SCHEME_REDIS, URI_SCHEME_REDIS_SECURE, URI_SCHEME_REDIS_SOCKET, URI_SCHEME_REDIS_SOCKET_ALT, URI_SCHEME_REDIS_SECURE_ALT, URI_SCHEME_REDIS_TLS_ALT); @@ -783,10 +788,24 @@ private static Builder configureStandalone(URI uri) { if (URI_SCHEME_REDIS_SOCKET.equals(uri.getScheme()) || URI_SCHEME_REDIS_SOCKET_ALT.equals(uri.getScheme())) { builder = Builder.socket(uri.getPath()); } else { - if (uri.getPort() > 0) { - builder = Builder.redis(uri.getHost(), uri.getPort()); + + if (isNotEmpty(uri.getHost())) { + + if (uri.getPort() > 0) { + builder = Builder.redis(uri.getHost(), uri.getPort()); + } else { + builder = Builder.redis(uri.getHost()); + } } else { - builder = Builder.redis(uri.getHost()); + + if (isNotEmpty(uri.getAuthority())) { + String authority = uri.getAuthority(); + if (authority.indexOf('@') > -1) { + authority = authority.substring(authority.indexOf('@') + 1); + } + + builder = Builder.redis(authority); + } } } diff --git a/src/main/java/com/lambdaworks/redis/cluster/RedisClusterClient.java b/src/main/java/com/lambdaworks/redis/cluster/RedisClusterClient.java index 90093296e0..fa2861ac0f 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/RedisClusterClient.java +++ b/src/main/java/com/lambdaworks/redis/cluster/RedisClusterClient.java @@ -17,6 +17,7 @@ import java.io.Closeable; import java.net.SocketAddress; +import java.net.URI; import java.util.*; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; @@ -219,7 +220,7 @@ public static RedisClusterClient create(RedisURI redisURI) { * Create a new client that connects to the supplied {@link RedisURI uri} with default {@link ClientResources}. You can * connect to different Redis servers but you must supply a {@link RedisURI} on connecting. * - * @param redisURIs one or more Redis URI, must not be {@literal null} and not empty + * @param redisURIs one or more Redis URI, must not be {@literal null} and not empty. * @return a new instance of {@link RedisClusterClient} */ public static RedisClusterClient create(Iterable redisURIs) { @@ -232,12 +233,12 @@ public static RedisClusterClient create(Iterable redisURIs) { * Create a new client that connects to the supplied uri with default {@link ClientResources}. You can connect to different * Redis servers but you must supply a {@link RedisURI} on connecting. * - * @param uri the Redis URI, must not be {@literal null} + * @param uri the Redis URI, must not be empty or {@literal null}. * @return a new instance of {@link RedisClusterClient} */ public static RedisClusterClient create(String uri) { - LettuceAssert.notNull(uri, "URI must not be null"); - return create(RedisURI.create(uri)); + LettuceAssert.notEmpty(uri, "URI must not be empty"); + return create(RedisClusterURIUtil.toRedisURIs(URI.create(uri))); } /** @@ -261,13 +262,13 @@ public static RedisClusterClient create(ClientResources clientResources, RedisUR * supply a {@link RedisURI} on connecting. * * @param clientResources the client resources, must not be {@literal null} - * @param uri the Redis URI, must not be {@literal null} + * @param uri the Redis URI, must not be empty or {@literal null}. * @return a new instance of {@link RedisClusterClient} */ public static RedisClusterClient create(ClientResources clientResources, String uri) { assertNotNull(clientResources); - LettuceAssert.notNull(uri, "URI must not be null"); - return create(clientResources, RedisURI.create(uri)); + LettuceAssert.notEmpty(uri, "URI must not be empty"); + return create(clientResources, RedisClusterURIUtil.toRedisURIs(URI.create(uri))); } /** @@ -678,7 +679,7 @@ protected Partitions loadPartitions() { for (RedisClusterNode partition : loadedPartitions) { if (viewedBy != null) { RedisURI uri = partition.getUri(); - applyUriConnectionSettings(viewedBy, uri); + RedisClusterURIUtil.applyUriConnectionSettings(viewedBy, uri); } } @@ -841,19 +842,6 @@ boolean expireStaleConnections() { return getClusterClientOptions() == null || getClusterClientOptions().isCloseStaleConnections(); } - static void applyUriConnectionSettings(RedisURI from, RedisURI to) { - - if (from.getPassword() != null && from.getPassword().length != 0) { - to.setPassword(new String(from.getPassword())); - } - - to.setTimeout(from.getTimeout()); - to.setUnit(from.getUnit()); - to.setSsl(from.isSsl()); - to.setStartTls(from.isStartTls()); - to.setVerifyPeer(from.isVerifyPeer()); - } - private static void assertNotNull(RedisCodec codec) { LettuceAssert.notNull(codec, "RedisCodec must not be null"); } diff --git a/src/main/java/com/lambdaworks/redis/cluster/RedisClusterURIUtil.java b/src/main/java/com/lambdaworks/redis/cluster/RedisClusterURIUtil.java new file mode 100644 index 0000000000..fcdd7ca2c9 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/cluster/RedisClusterURIUtil.java @@ -0,0 +1,81 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.lambdaworks.redis.cluster; + +import java.net.URI; +import java.util.ArrayList; +import java.util.List; + +import com.lambdaworks.redis.RedisURI; +import com.lambdaworks.redis.internal.HostAndPort; + +/** + * {@link RedisClusterURIUtil} is a collection of {@link RedisURI}-based utility methods for {@link RedisClusterClient} use. + * + * @author Mark Paluch + * @since 4.4 + */ +public class RedisClusterURIUtil { + + /** + * Parse a Redis Cluster URI with potentially multiple hosts into a {@link List} of {@link RedisURI}. + * + * An URI follows the syntax: {@code redis://[password@]host[:port][,host2[:port2]]} + * + * @param uri must not be empty or {@literal null}. + * @return {@link List} of {@link RedisURI}. + */ + public static List toRedisURIs(URI uri) { + + RedisURI redisURI = RedisURI.create(uri); + + String[] parts = redisURI.getHost().split("\\,"); + + List redisURIs = new ArrayList<>(parts.length); + + for (String part : parts) { + HostAndPort hostAndPort = HostAndPort.parse(part); + + RedisURI nodeUri = RedisURI.create(hostAndPort.getHostText(), + hostAndPort.hasPort() ? hostAndPort.getPort() : redisURI.getPort()); + + applyUriConnectionSettings(redisURI, nodeUri); + + redisURIs.add(nodeUri); + } + + return redisURIs; + } + + /** + * Apply {@link RedisURI} settings such as SSL/Timeout/password. + * + * @param from from {@link RedisURI}. + * @param to from {@link RedisURI}. + */ + static void applyUriConnectionSettings(RedisURI from, RedisURI to) { + + if (from.getPassword() != null && from.getPassword().length != 0) { + to.setPassword(new String(from.getPassword())); + } + + to.setTimeout(from.getTimeout()); + to.setUnit(from.getUnit()); + to.setSsl(from.isSsl()); + to.setStartTls(from.isStartTls()); + to.setVerifyPeer(from.isVerifyPeer()); + } +} diff --git a/src/main/java/com/lambdaworks/redis/support/RedisClusterClientFactoryBean.java b/src/main/java/com/lambdaworks/redis/support/RedisClusterClientFactoryBean.java index 07b0fb9b9e..66a68bd158 100644 --- a/src/main/java/com/lambdaworks/redis/support/RedisClusterClientFactoryBean.java +++ b/src/main/java/com/lambdaworks/redis/support/RedisClusterClientFactoryBean.java @@ -18,19 +18,23 @@ import static com.lambdaworks.redis.LettuceStrings.isNotEmpty; import java.net.URI; +import java.util.Collection; +import java.util.Collections; +import java.util.List; import com.lambdaworks.redis.RedisURI; import com.lambdaworks.redis.cluster.RedisClusterClient; +import com.lambdaworks.redis.cluster.RedisClusterURIUtil; import com.lambdaworks.redis.internal.LettuceAssert; /** * Factory Bean for {@link RedisClusterClient} instances. Needs either a {@link URI} or a {@link RedisURI} as input and allows * to reuse {@link com.lambdaworks.redis.resource.ClientResources}. URI Format: {@code - * redis://[password@]host[:port] + * redis://[password@]host[:port][,host2[:port2]] * } * * {@code - * rediss://[password@]host[:port] + * rediss://[password@]host[:port][,host2[:port2]] * } * * @see RedisURI @@ -41,32 +45,52 @@ public class RedisClusterClientFactoryBean extends LettuceFactoryBeanSupport { private boolean verifyPeer = false; + private Collection redisURIs; @Override public void afterPropertiesSet() throws Exception { - if (getRedisURI() == null) { - URI uri = getUri(); + if (redisURIs == null) { - LettuceAssert.isTrue(!uri.getScheme().equals(RedisURI.URI_SCHEME_REDIS_SENTINEL), - "Sentinel mode not supported when using RedisClusterClient"); + if (getUri() != null) { + URI uri = getUri(); - RedisURI redisURI = RedisURI.create(uri); - if (isNotEmpty(getPassword())) { - redisURI.setPassword(getPassword()); - } + LettuceAssert.isTrue(!uri.getScheme().equals(RedisURI.URI_SCHEME_REDIS_SENTINEL), + "Sentinel mode not supported when using RedisClusterClient"); - if (RedisURI.URI_SCHEME_REDIS_SECURE.equals(uri.getScheme()) - || RedisURI.URI_SCHEME_REDIS_SECURE_ALT.equals(uri.getScheme()) - || RedisURI.URI_SCHEME_REDIS_TLS_ALT.equals(uri.getScheme())) { - redisURI.setVerifyPeer(verifyPeer); - } + List redisURIs = RedisClusterURIUtil.toRedisURIs(uri); + + for (RedisURI redisURI : redisURIs) { + applyProperties(uri.getScheme(), redisURI); + } + + this.redisURIs = redisURIs; + } else { - setRedisURI(redisURI); + URI uri = getRedisURI().toURI(); + RedisURI redisURI = RedisURI.create(uri); + applyProperties(uri.getScheme(), redisURI); + this.redisURIs = Collections.singleton(redisURI); + } } super.afterPropertiesSet(); + } + + private void applyProperties(String scheme, RedisURI redisURI) { + if (isNotEmpty(getPassword())) { + redisURI.setPassword(getPassword()); + } + + if (RedisURI.URI_SCHEME_REDIS_SECURE.equals(scheme) || RedisURI.URI_SCHEME_REDIS_SECURE_ALT.equals(scheme) + || RedisURI.URI_SCHEME_REDIS_TLS_ALT.equals(scheme)) { + redisURI.setVerifyPeer(verifyPeer); + } + } + + protected Collection getRedisURIs() { + return redisURIs; } @Override @@ -83,9 +107,10 @@ public Class getObjectType() { protected RedisClusterClient createInstance() throws Exception { if (getClientResources() != null) { - return RedisClusterClient.create(getClientResources(), getRedisURI()); + return RedisClusterClient.create(getClientResources(), redisURIs); } - return RedisClusterClient.create(getRedisURI()); + + return RedisClusterClient.create(redisURIs); } public boolean isVerifyPeer() { diff --git a/src/test/java/com/lambdaworks/redis/RedisURITest.java b/src/test/java/com/lambdaworks/redis/RedisURITest.java index 7174f20879..6335f6e23b 100644 --- a/src/test/java/com/lambdaworks/redis/RedisURITest.java +++ b/src/test/java/com/lambdaworks/redis/RedisURITest.java @@ -31,7 +31,7 @@ public class RedisURITest { @Test - public void equalsTest() throws Exception { + public void equalsTest() { RedisURI redisURI1 = RedisURI.create("redis://auth@localhost:1234/5"); RedisURI redisURI2 = RedisURI.create("redis://auth@localhost:1234/5"); @@ -46,7 +46,7 @@ public void equalsTest() throws Exception { } @Test - public void setUsage() throws Exception { + public void setUsage() { RedisURI redisURI1 = RedisURI.create("redis://auth@localhost:1234/5"); RedisURI redisURI2 = RedisURI.create("redis://auth@localhost:1234/5"); @@ -58,7 +58,7 @@ public void setUsage() throws Exception { } @Test - public void mapUsage() throws Exception { + public void mapUsage() { RedisURI redisURI1 = RedisURI.create("redis://auth@localhost:1234/5"); RedisURI redisURI2 = RedisURI.create("redis://auth@localhost:1234/5"); @@ -70,25 +70,31 @@ public void mapUsage() throws Exception { } @Test - public void simpleUriTest() throws Exception { + public void simpleUriTest() { RedisURI redisURI = RedisURI.create("redis://localhost:6379"); assertThat(redisURI.toURI().toString()).isEqualTo("redis://localhost"); } @Test - public void sslUriTest() throws Exception { + public void sslUriTest() { RedisURI redisURI = RedisURI.create("redis+ssl://localhost:6379"); assertThat(redisURI.toURI().toString()).isEqualTo("rediss://localhost:6379"); } @Test - public void tlsUriTest() throws Exception { + public void tlsUriTest() { RedisURI redisURI = RedisURI.create("redis+tls://localhost:6379"); assertThat(redisURI.toURI().toString()).isEqualTo("redis+tls://localhost:6379"); } @Test - public void sentinelEqualsTest() throws Exception { + public void multipleClusterNodesTest() { + RedisURI redisURI = RedisURI.create("redis+ssl://password@host1:6379,host2:6380"); + assertThat(redisURI.toURI().toString()).isEqualTo("rediss://password@host1:6379,host2:6380"); + } + + @Test + public void sentinelEqualsTest() { RedisURI redisURI1 = RedisURI.create("redis-sentinel://auth@h1:222,h2,h3:1234/5?sentinelMasterId=masterId"); RedisURI redisURI2 = RedisURI.create("redis-sentinel://auth@h1:222,h2,h3:1234/5#masterId"); @@ -103,7 +109,7 @@ public void sentinelEqualsTest() throws Exception { } @Test - public void sentinelUriTest() throws Exception { + public void sentinelUriTest() { RedisURI redisURI = RedisURI.create("redis-sentinel://auth@h1:222,h2,h3:1234/5?sentinelMasterId=masterId"); assertThat(redisURI.getSentinelMasterId()).isEqualTo("masterId"); @@ -117,7 +123,7 @@ public void sentinelUriTest() throws Exception { } @Test - public void socketEqualsTest() throws Exception { + public void socketEqualsTest() { RedisURI redisURI1 = RedisURI.create("redis-socket:///var/tmp/socket"); RedisURI redisURI2 = RedisURI.create("redis-socket:///var/tmp/socket"); @@ -132,7 +138,7 @@ public void socketEqualsTest() throws Exception { } @Test - public void socketUriTest() throws Exception { + public void socketUriTest() { RedisURI redisURI = RedisURI.create("redis-socket:///var/tmp/other-socket?db=2"); @@ -142,7 +148,7 @@ public void socketUriTest() throws Exception { } @Test - public void socketAltUriTest() throws Exception { + public void socketAltUriTest() { RedisURI redisURI = RedisURI.create("redis+socket:///var/tmp/other-socket?db=2"); @@ -152,7 +158,7 @@ public void socketAltUriTest() throws Exception { } @Test - public void timeoutParsingTest() throws Exception { + public void timeoutParsingTest() { checkUriTimeout("redis://auth@localhost:1234/5?timeout=5000", 5000, TimeUnit.MILLISECONDS); checkUriTimeout("redis://auth@localhost:1234/5?timeout=5000ms", 5000, TimeUnit.MILLISECONDS); checkUriTimeout("redis://auth@localhost:1234/5?timeout=5s", 5, TimeUnit.SECONDS); @@ -172,7 +178,7 @@ public void timeoutParsingTest() throws Exception { } @Test - public void queryStringDecodingTest() throws Exception { + public void queryStringDecodingTest() { String timeout = "%74%69%6D%65%6F%75%74"; String eq = "%3d"; String s = "%73"; @@ -180,7 +186,7 @@ public void queryStringDecodingTest() throws Exception { } @Test - public void timeoutParsingWithJunkParamTest() throws Exception { + public void timeoutParsingWithJunkParamTest() { RedisURI redisURI1 = RedisURI.create("redis-sentinel://auth@localhost:1234/5?timeout=5s;junkparam=#master-instance"); assertThat(redisURI1.getTimeout()).isEqualTo(5); assertThat(redisURI1.getUnit()).isEqualTo(TimeUnit.SECONDS); @@ -195,7 +201,7 @@ private RedisURI checkUriTimeout(String uri, long expectedTimeout, TimeUnit expe } @Test - public void databaseParsingTest() throws Exception { + public void databaseParsingTest() { RedisURI redisURI = RedisURI.create("redis://auth@localhost:1234/?database=5"); assertThat(redisURI.getDatabase()).isEqualTo(5); @@ -203,7 +209,7 @@ public void databaseParsingTest() throws Exception { } @Test - public void parsingWithInvalidValuesTest() throws Exception { + public void parsingWithInvalidValuesTest() { RedisURI redisURI = RedisURI .create("redis://@host:1234/?database=AAA&database=&timeout=&timeout=XYZ&sentinelMasterId="); assertThat(redisURI.getDatabase()).isEqualTo(0); @@ -211,5 +217,4 @@ public void parsingWithInvalidValuesTest() throws Exception { assertThat(redisURI.toURI().toString()).isEqualTo("redis://host:1234"); } - } diff --git a/src/test/java/com/lambdaworks/redis/cluster/RedisClusterURIUtilTest.java b/src/test/java/com/lambdaworks/redis/cluster/RedisClusterURIUtilTest.java new file mode 100644 index 0000000000..334c67e4b1 --- /dev/null +++ b/src/test/java/com/lambdaworks/redis/cluster/RedisClusterURIUtilTest.java @@ -0,0 +1,112 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.lambdaworks.redis.cluster; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.net.URI; +import java.util.List; + +import org.junit.Test; + +import com.lambdaworks.redis.RedisURI; + +/** + * @author Mark Paluch + */ +public class RedisClusterURIUtilTest { + + @Test + public void testSimpleUri() { + + List redisURIs = RedisClusterURIUtil.toRedisURIs(URI.create("redis://host:7479")); + + assertThat(redisURIs).hasSize(1); + + RedisURI host1 = redisURIs.get(0); + assertThat(host1.getHost()).isEqualTo("host"); + assertThat(host1.getPort()).isEqualTo(7479); + } + + @Test + public void testMultipleHosts() { + + List redisURIs = RedisClusterURIUtil.toRedisURIs(URI.create("redis://host1,host2")); + + assertThat(redisURIs).hasSize(2); + + RedisURI host1 = redisURIs.get(0); + assertThat(host1.getHost()).isEqualTo("host1"); + assertThat(host1.getPort()).isEqualTo(6379); + + RedisURI host2 = redisURIs.get(1); + assertThat(host2.getHost()).isEqualTo("host2"); + assertThat(host2.getPort()).isEqualTo(6379); + } + + @Test + public void testMultipleHostsWithPorts() { + + List redisURIs = RedisClusterURIUtil.toRedisURIs(URI.create("redis://host1:6379,host2:6380")); + + assertThat(redisURIs).hasSize(2); + + RedisURI host1 = redisURIs.get(0); + assertThat(host1.getHost()).isEqualTo("host1"); + assertThat(host1.getPort()).isEqualTo(6379); + + RedisURI host2 = redisURIs.get(1); + assertThat(host2.getHost()).isEqualTo("host2"); + assertThat(host2.getPort()).isEqualTo(6380); + } + + @Test + public void testSslWithPasswordSingleHost() { + + List redisURIs = RedisClusterURIUtil.toRedisURIs(URI.create("redis+tls://password@host1")); + + assertThat(redisURIs).hasSize(1); + + RedisURI host1 = redisURIs.get(0); + assertThat(host1.isSsl()).isTrue(); + assertThat(host1.isStartTls()).isTrue(); + assertThat(new String(host1.getPassword())).isEqualTo("password"); + assertThat(host1.getHost()).isEqualTo("host1"); + assertThat(host1.getPort()).isEqualTo(6379); + } + + @Test + public void testSslWithPasswordMultipleHosts() { + + List redisURIs = RedisClusterURIUtil.toRedisURIs(URI.create("redis+tls://password@host1:6379,host2:6380")); + + assertThat(redisURIs).hasSize(2); + + RedisURI host1 = redisURIs.get(0); + assertThat(host1.isSsl()).isTrue(); + assertThat(host1.isStartTls()).isTrue(); + assertThat(new String(host1.getPassword())).isEqualTo("password"); + assertThat(host1.getHost()).isEqualTo("host1"); + assertThat(host1.getPort()).isEqualTo(6379); + + RedisURI host2 = redisURIs.get(1); + assertThat(host2.isSsl()).isTrue(); + assertThat(host2.isStartTls()).isTrue(); + assertThat(new String(host2.getPassword())).isEqualTo("password"); + assertThat(host2.getHost()).isEqualTo("host2"); + assertThat(host2.getPort()).isEqualTo(6380); + } +} \ No newline at end of file diff --git a/src/test/java/com/lambdaworks/redis/support/RedisClusterClientFactoryBeanTest.java b/src/test/java/com/lambdaworks/redis/support/RedisClusterClientFactoryBeanTest.java index fdcde9f968..9399a92b45 100644 --- a/src/test/java/com/lambdaworks/redis/support/RedisClusterClientFactoryBeanTest.java +++ b/src/test/java/com/lambdaworks/redis/support/RedisClusterClientFactoryBeanTest.java @@ -15,9 +15,11 @@ */ package com.lambdaworks.redis.support; -import static org.assertj.core.api.Assertions.*; +import static org.assertj.core.api.Assertions.assertThat; import java.net.URI; +import java.util.Collection; +import java.util.Iterator; import org.junit.Test; @@ -49,8 +51,8 @@ public void validUri() throws Exception { sut.setUri(URI.create(RedisURI.URI_SCHEME_REDIS + "://password@host")); sut.afterPropertiesSet(); - assertThat(sut.getRedisURI().getHost()).isEqualTo("host"); - assertThat(sut.getRedisURI().getPassword()).isEqualTo("password".toCharArray()); + assertThat(getRedisURI().getHost()).isEqualTo("host"); + assertThat(getRedisURI().getPassword()).isEqualTo("password".toCharArray()); } @Test @@ -60,18 +62,65 @@ public void validUriPasswordOverride() throws Exception { sut.setPassword("thepassword"); sut.afterPropertiesSet(); - assertThat(sut.getRedisURI().getHost()).isEqualTo("host"); - assertThat(sut.getRedisURI().getPassword()).isEqualTo("thepassword".toCharArray()); + assertThat(getRedisURI().getHost()).isEqualTo("host"); + assertThat(getRedisURI().getPassword()).isEqualTo("thepassword".toCharArray()); } - + + @Test + public void multiNodeUri() throws Exception { + + sut.setUri(URI.create(RedisURI.URI_SCHEME_REDIS + "://password@host1,host2")); + sut.afterPropertiesSet(); + + Collection redisUris = sut.getRedisURIs(); + assertThat(redisUris).hasSize(2); + + Iterator iterator = redisUris.iterator(); + RedisURI host1 = iterator.next(); + RedisURI host2 = iterator.next(); + + assertThat(host1.getHost()).isEqualTo("host1"); + assertThat(host1.getPassword()).isEqualTo("password".toCharArray()); + + assertThat(host2.getHost()).isEqualTo("host2"); + assertThat(host2.getPassword()).isEqualTo("password".toCharArray()); + } + + @Test + public void multiNodeUriPasswordOverride() throws Exception { + + sut.setUri(URI.create(RedisURI.URI_SCHEME_REDIS + "://password@host1,host2")); + sut.setPassword("thepassword"); + + sut.afterPropertiesSet(); + + Collection redisUris = sut.getRedisURIs(); + assertThat(redisUris).hasSize(2); + + Iterator iterator = redisUris.iterator(); + RedisURI host1 = iterator.next(); + RedisURI host2 = iterator.next(); + + assertThat(host1.getHost()).isEqualTo("host1"); + assertThat(host1.getPassword()).isEqualTo("thepassword".toCharArray()); + + assertThat(host2.getHost()).isEqualTo("host2"); + assertThat(host2.getPassword()).isEqualTo("thepassword".toCharArray()); + } + @Test public void supportsSsl() throws Exception { sut.setUri(URI.create(RedisURI.URI_SCHEME_REDIS_SECURE + "://password@host")); sut.afterPropertiesSet(); - assertThat(sut.getRedisURI().getHost()).isEqualTo("host"); - assertThat(sut.getRedisURI().getPassword()).isEqualTo("password".toCharArray()); - assertThat(sut.getRedisURI().isVerifyPeer()).isFalse(); - assertThat(sut.getRedisURI().isSsl()).isTrue(); + + assertThat(getRedisURI().getHost()).isEqualTo("host"); + assertThat(getRedisURI().getPassword()).isEqualTo("password".toCharArray()); + assertThat(getRedisURI().isVerifyPeer()).isFalse(); + assertThat(getRedisURI().isSsl()).isTrue(); + } + + private RedisURI getRedisURI() { + return sut.getRedisURIs().iterator().next(); } } From 0fd589089889bfed78485d0814c90807375920de Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Sun, 6 Nov 2016 12:11:07 +0100 Subject: [PATCH 067/808] Use StringCodec from Utf8StringCodec #393 StringCodec now benefits from streamlined UTF-8 encoding/decoding. --- .../redis/codec/Utf8StringCodec.java | 64 ++----------------- .../redis/codec/CompressionCodecTest.java | 13 ++-- 2 files changed, 9 insertions(+), 68 deletions(-) diff --git a/src/main/java/com/lambdaworks/redis/codec/Utf8StringCodec.java b/src/main/java/com/lambdaworks/redis/codec/Utf8StringCodec.java index 3b84c36dec..5996608824 100644 --- a/src/main/java/com/lambdaworks/redis/codec/Utf8StringCodec.java +++ b/src/main/java/com/lambdaworks/redis/codec/Utf8StringCodec.java @@ -15,76 +15,22 @@ */ package com.lambdaworks.redis.codec; -import static java.nio.charset.CoderResult.OVERFLOW; - -import java.nio.ByteBuffer; -import java.nio.CharBuffer; -import java.nio.charset.Charset; -import java.nio.charset.CharsetDecoder; - import com.lambdaworks.redis.protocol.LettuceCharsets; /** * A {@link RedisCodec} that handles UTF-8 encoded keys and values. * * @author Will Glozer + * @author Mark Paluch + * @see StringCodec + * @see LettuceCharsets#UTF8 */ -public class Utf8StringCodec implements RedisCodec { - - private static final byte[] EMPTY = new byte[0]; - - private Charset charset; - private CharsetDecoder decoder; - private CharBuffer chars; - +public class Utf8StringCodec extends StringCodec implements RedisCodec { /** * Initialize a new instance that encodes and decodes strings using the UTF-8 charset; */ public Utf8StringCodec() { - charset = LettuceCharsets.UTF8; - decoder = charset.newDecoder(); - chars = CharBuffer.allocate(1024); - } - - @Override - public String decodeKey(ByteBuffer bytes) { - return decode(bytes); - } - - @Override - public String decodeValue(ByteBuffer bytes) { - return decode(bytes); - } - - @Override - public ByteBuffer encodeKey(String key) { - return encode(key); - } - - @Override - public ByteBuffer encodeValue(String value) { - return encode(value); - } - - private synchronized String decode(ByteBuffer bytes) { - chars.clear(); - bytes.mark(); - - decoder.reset(); - while (decoder.decode(bytes, chars, true) == OVERFLOW || decoder.flush(chars) == OVERFLOW) { - chars = CharBuffer.allocate(chars.capacity() * 2); - bytes.reset(); - } - - return chars.flip().toString(); - } - - private ByteBuffer encode(String string) { - if (string == null) { - return ByteBuffer.wrap(EMPTY); - } - - return charset.encode(string); + super(LettuceCharsets.UTF8); } } diff --git a/src/test/java/com/lambdaworks/redis/codec/CompressionCodecTest.java b/src/test/java/com/lambdaworks/redis/codec/CompressionCodecTest.java index e1198aef64..82201b36b2 100644 --- a/src/test/java/com/lambdaworks/redis/codec/CompressionCodecTest.java +++ b/src/test/java/com/lambdaworks/redis/codec/CompressionCodecTest.java @@ -28,8 +28,8 @@ public class CompressionCodecTest { private String key = "key"; - private byte[] keyGzipBytes = new byte[] { 31, -117, 8, 0, 0, 0, 0, 0, 0, 0, -53, 78, -83, 4, 0, -87, -85, -112, -118, 3, - 0, 0, 0 }; + private byte[] keyGzipBytes = new byte[] { 31, -117, 8, 0, 0, 0, 0, 0, 0, 0, -53, 78, -83, 4, 0, -87, -85, -112, -118, 3, 0, + 0, 0 }; private byte[] keyDeflateBytes = new byte[] { 120, -100, -53, 78, -83, 4, 0, 2, -121, 1, 74 }; private String value = "value"; @@ -80,13 +80,8 @@ private String toString(ByteBuffer buffer) throws IOException { } private byte[] toBytes(ByteBuffer buffer) { - byte[] bytes; - if (buffer.hasArray()) { - bytes = buffer.array(); - } else { - bytes = new byte[buffer.remaining()]; - buffer.get(bytes); - } + byte[] bytes = new byte[buffer.remaining()]; + buffer.get(bytes); return bytes; } } From 1cb86d068879f55ae33a6a62bfb4be4ef9a1c983 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Thu, 10 Nov 2016 09:45:44 +0100 Subject: [PATCH 068/808] Add reactive wrapper converters for RxJava1 and 2 #383 --- pom.xml | 23 + .../redis/dynamic/CommandMethod.java | 4 +- .../redis/dynamic/ConversionService.java | 138 +++++ .../redis/dynamic/ReactiveTypeAdapters.java | 576 ++++++++++++++++++ .../redis/dynamic/ReactiveTypes.java | 252 ++++++++ .../redis/dynamic/ReactiveWrappers.java | 84 --- .../redis/dynamic/RedisCommandFactory.java | 29 +- .../redis/dynamic/ConversionServiceTest.java | 87 +++ .../dynamic/ReactiveTypeAdaptersTest.java | 160 +++++ .../dynamic/ReactiveTypeAdaptionTest.java | 97 +++ .../redis/dynamic/RedisCommandsTest.java | 12 +- 11 files changed, 1361 insertions(+), 101 deletions(-) create mode 100644 src/main/java/com/lambdaworks/redis/dynamic/ConversionService.java create mode 100644 src/main/java/com/lambdaworks/redis/dynamic/ReactiveTypeAdapters.java create mode 100644 src/main/java/com/lambdaworks/redis/dynamic/ReactiveTypes.java delete mode 100644 src/main/java/com/lambdaworks/redis/dynamic/ReactiveWrappers.java create mode 100644 src/test/java/com/lambdaworks/redis/dynamic/ConversionServiceTest.java create mode 100644 src/test/java/com/lambdaworks/redis/dynamic/ReactiveTypeAdaptersTest.java create mode 100644 src/test/java/com/lambdaworks/redis/dynamic/ReactiveTypeAdaptionTest.java diff --git a/pom.xml b/pom.xml index 914e9cf1fe..37f350fe91 100644 --- a/pom.xml +++ b/pom.xml @@ -133,6 +133,29 @@ + + + + io.reactivex + rxjava + 1.2.1 + true + + + + io.reactivex + rxjava-reactive-streams + 1.2.0 + true + + + + io.reactivex.rxjava2 + rxjava + 2.0.0 + true + + diff --git a/src/main/java/com/lambdaworks/redis/dynamic/CommandMethod.java b/src/main/java/com/lambdaworks/redis/dynamic/CommandMethod.java index b7a357648d..f2585aa281 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/CommandMethod.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/CommandMethod.java @@ -74,7 +74,7 @@ public CommandMethod(Method method, Parameters parameters) { TypeInformation actualReturnType = this.returnType; while (Future.class.isAssignableFrom(actualReturnType.getType()) - || Publisher.class.isAssignableFrom(actualReturnType.getType())) { + || ReactiveTypes.supports(actualReturnType.getType())) { actualReturnType = actualReturnType.getComponentType(); } @@ -153,7 +153,7 @@ public boolean isFutureExecution() { * @return {@literal true} if the method uses reactive execution declaring {@link Publisher} as result type. */ public boolean isReactiveExecution() { - return ReactiveWrappers.supports(getReturnType().getType()); + return ReactiveTypes.supports(getReturnType().getType()); } @Override diff --git a/src/main/java/com/lambdaworks/redis/dynamic/ConversionService.java b/src/main/java/com/lambdaworks/redis/dynamic/ConversionService.java new file mode 100644 index 0000000000..efff7cdb02 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/dynamic/ConversionService.java @@ -0,0 +1,138 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.lambdaworks.redis.dynamic; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.function.Function; + +import com.lambdaworks.redis.dynamic.support.ClassTypeInformation; +import com.lambdaworks.redis.dynamic.support.TypeInformation; +import com.lambdaworks.redis.internal.LettuceAssert; + +/** + * @author Mark Paluch + */ +class ConversionService { + + private Map> converterMap = new HashMap<>(10); + + /** + * Register a converter {@link Function}. + * + * @param converter the converter. + */ + public void addConverter(Function converter) { + + LettuceAssert.notNull(converter, "Converter must not be null"); + + ClassTypeInformation classTypeInformation = ClassTypeInformation.from(converter.getClass()); + + TypeInformation typeInformation = classTypeInformation.getSuperTypeInformation(Function.class); + + List> typeArguments = typeInformation.getTypeArguments(); + + ConvertiblePair pair = new ConvertiblePair(typeArguments.get(0).getType(), typeArguments.get(1).getType()); + converterMap.put(pair, converter); + } + + @SuppressWarnings("unchecked") + public T convert(S source, Class targetType) { + + LettuceAssert.notNull(source, "Source must not be null"); + + return (T) getConverter(source.getClass(), targetType).apply(source); + } + + public boolean canConvert(Class sourceType, Class targetType) { + return findConverter(sourceType, targetType).isPresent(); + } + + @SuppressWarnings("unchecked") + Function getConverter(Class source, Class target) { + return findConverter(source, target).orElseThrow(() -> new IllegalArgumentException( + String.format("No converter found for %s to %s conversion", source.getName(), target.getName()))); + } + + private Optional> findConverter(Class source, Class target) { + LettuceAssert.notNull(source, "Source type must not be null"); + LettuceAssert.notNull(target, "Target type must not be null"); + + for (ConvertiblePair pair : converterMap.keySet()) { + + if (pair.getSourceType().isAssignableFrom(source) && target.isAssignableFrom(pair.getTargetType())) { + return Optional.of((Function) converterMap.get(pair)); + } + } + return Optional.empty(); + } + + /** + * Holder for a source-to-target class pair. + */ + final class ConvertiblePair { + + private final Class sourceType; + + private final Class targetType; + + /** + * Create a new source-to-target pair. + * + * @param sourceType the source type + * @param targetType the target type + */ + public ConvertiblePair(Class sourceType, Class targetType) { + + LettuceAssert.notNull(sourceType, "Source type must not be null"); + LettuceAssert.notNull(targetType, "Target type must not be null"); + this.sourceType = sourceType; + this.targetType = targetType; + } + + public Class getSourceType() { + return this.sourceType; + } + + public Class getTargetType() { + return this.targetType; + } + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + if (other == null || other.getClass() != ConvertiblePair.class) { + return false; + } + ConvertiblePair otherPair = (ConvertiblePair) other; + return (this.sourceType == otherPair.sourceType && this.targetType == otherPair.targetType); + } + + @Override + public int hashCode() { + return (this.sourceType.hashCode() * 31 + this.targetType.hashCode()); + } + + @Override + public String toString() { + return (this.sourceType.getName() + " -> " + this.targetType.getName()); + } + } +} diff --git a/src/main/java/com/lambdaworks/redis/dynamic/ReactiveTypeAdapters.java b/src/main/java/com/lambdaworks/redis/dynamic/ReactiveTypeAdapters.java new file mode 100644 index 0000000000..759ae80f7b --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/dynamic/ReactiveTypeAdapters.java @@ -0,0 +1,576 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.lambdaworks.redis.dynamic; + +import java.util.function.Function; + +import org.reactivestreams.Publisher; + +import com.lambdaworks.redis.dynamic.ReactiveTypes.ReactiveLibrary; +import com.lambdaworks.redis.internal.LettuceAssert; + +import io.reactivex.BackpressureStrategy; +import io.reactivex.Flowable; +import io.reactivex.Maybe; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import rx.Completable; +import rx.Observable; +import rx.RxReactiveStreams; +import rx.Single; +import rx.internal.reactivestreams.PublisherAdapter; + +/** + * @author Mark Paluch + */ +class ReactiveTypeAdapters { + + /** + * Register adapters in the conversion service. + * + * @param conversionService + */ + static void registerIn(ConversionService conversionService) { + + LettuceAssert.notNull(conversionService, "ConversionService must not be null!"); + + if (ReactiveTypes.isAvailable(ReactiveLibrary.PROJECT_REACTOR)) { + + if (ReactiveTypes.isAvailable(ReactiveLibrary.RXJAVA1)) { + + conversionService.addConverter(PublisherToRxJava1CompletableAdapter.INSTANCE); + conversionService.addConverter(RxJava1CompletableToPublisherAdapter.INSTANCE); + conversionService.addConverter(RxJava1CompletableToMonoAdapter.INSTANCE); + + conversionService.addConverter(PublisherToRxJava1SingleAdapter.INSTANCE); + conversionService.addConverter(RxJava1SingleToPublisherAdapter.INSTANCE); + conversionService.addConverter(RxJava1SingleToMonoAdapter.INSTANCE); + conversionService.addConverter(RxJava1SingleToFluxAdapter.INSTANCE); + + conversionService.addConverter(PublisherToRxJava1ObservableAdapter.INSTANCE); + conversionService.addConverter(RxJava1ObservableToPublisherAdapter.INSTANCE); + conversionService.addConverter(RxJava1ObservableToMonoAdapter.INSTANCE); + conversionService.addConverter(RxJava1ObservableToFluxAdapter.INSTANCE); + } + + if (ReactiveTypes.isAvailable(ReactiveLibrary.RXJAVA2)) { + + conversionService.addConverter(PublisherToRxJava2CompletableAdapter.INSTANCE); + conversionService.addConverter(RxJava2CompletableToPublisherAdapter.INSTANCE); + conversionService.addConverter(RxJava2CompletableToMonoAdapter.INSTANCE); + + conversionService.addConverter(PublisherToRxJava2SingleAdapter.INSTANCE); + conversionService.addConverter(RxJava2SingleToPublisherAdapter.INSTANCE); + conversionService.addConverter(RxJava2SingleToMonoAdapter.INSTANCE); + conversionService.addConverter(RxJava2SingleToFluxAdapter.INSTANCE); + + conversionService.addConverter(PublisherToRxJava2ObservableAdapter.INSTANCE); + conversionService.addConverter(RxJava2ObservableToPublisherAdapter.INSTANCE); + conversionService.addConverter(RxJava2ObservableToMonoAdapter.INSTANCE); + conversionService.addConverter(RxJava2ObservableToFluxAdapter.INSTANCE); + + conversionService.addConverter(PublisherToRxJava2FlowableAdapter.INSTANCE); + conversionService.addConverter(RxJava2FlowableToPublisherAdapter.INSTANCE); + + conversionService.addConverter(PublisherToRxJava2MaybeAdapter.INSTANCE); + conversionService.addConverter(RxJava2MaybeToPublisherAdapter.INSTANCE); + conversionService.addConverter(RxJava2MaybeToMonoAdapter.INSTANCE); + conversionService.addConverter(RxJava2MaybeToFluxAdapter.INSTANCE); + } + + conversionService.addConverter(PublisherToMonoAdapter.INSTANCE); + conversionService.addConverter(PublisherToFluxAdapter.INSTANCE); + + if (ReactiveTypes.isAvailable(ReactiveLibrary.RXJAVA1)) { + conversionService.addConverter(RxJava1SingleToObservableAdapter.INSTANCE); + conversionService.addConverter(RxJava1ObservableToSingleAdapter.INSTANCE); + } + + if (ReactiveTypes.isAvailable(ReactiveLibrary.RXJAVA2)) { + conversionService.addConverter(RxJava2SingleToObservableAdapter.INSTANCE); + conversionService.addConverter(RxJava2ObservableToSingleAdapter.INSTANCE); + conversionService.addConverter(RxJava2ObservableToMaybeAdapter.INSTANCE); + } + } + } + + // ------------------------------------------------------------------------- + // ReactiveStreams adapters + // ------------------------------------------------------------------------- + + /** + * An adapter {@link Function} to adopt a {@link Publisher} to {@link Flux}. + */ + public enum PublisherToFluxAdapter implements Function, Flux> { + + INSTANCE; + + @Override + public Flux apply(Publisher source) { + return Flux.from(source); + } + } + + /** + * An adapter {@link Function} to adopt a {@link Publisher} to {@link Mono}. + */ + public enum PublisherToMonoAdapter implements Function, Mono> { + + INSTANCE; + + @Override + public Mono apply(Publisher source) { + return Mono.from(source); + } + } + + // ------------------------------------------------------------------------- + // RxJava 1 adapters + // ------------------------------------------------------------------------- + + /** + * An adapter {@link Function} to adopt a {@link Publisher} to {@link Single}. + */ + public enum PublisherToRxJava1SingleAdapter implements Function, Single> { + + INSTANCE; + + @Override + public Single apply(Publisher source) { + return RxReactiveStreams.toSingle(source); + } + } + + /** + * An adapter {@link Function} to adopt a {@link Publisher} to {@link Completable}. + */ + public enum PublisherToRxJava1CompletableAdapter implements Function, Completable> { + + INSTANCE; + + @Override + public Completable apply(Publisher source) { + return RxReactiveStreams.toCompletable(source); + } + } + + /** + * An adapter {@link Function} to adopt a {@link Publisher} to {@link Observable}. + */ + public enum PublisherToRxJava1ObservableAdapter implements Function, Observable> { + + INSTANCE; + + @Override + public Observable apply(Publisher source) { + return RxReactiveStreams.toObservable(source); + } + } + + /** + * An adapter {@link Function} to adopt a {@link Single} to {@link Publisher}. + */ + public enum RxJava1SingleToPublisherAdapter implements Function, Publisher> { + + INSTANCE; + + @Override + public Publisher apply(Single source) { + return Flux.defer(() -> RxReactiveStreams.toPublisher(source)); + } + } + + /** + * An adapter {@link Function} to adopt a {@link Single} to {@link Mono}. + */ + public enum RxJava1SingleToMonoAdapter implements Function, Mono> { + + INSTANCE; + + @Override + public Mono apply(Single source) { + return Mono.defer(() -> Mono.from(RxReactiveStreams.toPublisher(source))); + } + } + + /** + * An adapter {@link Function} to adopt a {@link Single} to {@link Publisher}. + */ + public enum RxJava1SingleToFluxAdapter implements Function, Flux> { + + INSTANCE; + + @Override + public Flux apply(Single source) { + return Flux.defer(() -> RxReactiveStreams.toPublisher(source)); + } + } + + /** + * An adapter {@link Function} to adopt a {@link Completable} to {@link Publisher}. + */ + public enum RxJava1CompletableToPublisherAdapter implements Function> { + + INSTANCE; + + @Override + public Publisher apply(Completable source) { + return Flux.defer(() -> RxReactiveStreams.toPublisher(source)); + } + } + + /** + * An adapter {@link Function} to adopt a {@link Completable} to {@link Mono}. + */ + public enum RxJava1CompletableToMonoAdapter implements Function> { + + INSTANCE; + + @Override + public Mono apply(Completable source) { + return Mono.from(RxJava1CompletableToPublisherAdapter.INSTANCE.apply(source)); + } + } + + /** + * An adapter {@link Function} to adopt an {@link Observable} to {@link Publisher}. + */ + public enum RxJava1ObservableToPublisherAdapter implements Function, Publisher> { + + INSTANCE; + + @Override + public Publisher apply(Observable source) { + return Flux.defer(() -> new PublisherAdapter<>(source)); + } + } + + /** + * An adapter {@link Function} to adopt a {@link Observable} to {@link Mono}. + */ + public enum RxJava1ObservableToMonoAdapter implements Function, Mono> { + + INSTANCE; + + @Override + public Mono apply(Observable source) { + return Mono.defer(() -> Mono.from(RxReactiveStreams.toPublisher(source))); + } + } + + /** + * An adapter {@link Function} to adopt a {@link Observable} to {@link Flux}. + */ + public enum RxJava1ObservableToFluxAdapter implements Function, Flux> { + + INSTANCE; + + @Override + public Flux apply(Observable source) { + return Flux.defer(() -> Flux.from(RxReactiveStreams.toPublisher(source))); + } + } + + /** + * An adapter {@link Function} to adopt a {@link Observable} to {@link Single}. + */ + public enum RxJava1ObservableToSingleAdapter implements Function, Single> { + + INSTANCE; + + @Override + public Single apply(Observable source) { + return source.toSingle(); + } + } + + /** + * An adapter {@link Function} to adopt a {@link Single} to {@link Single}. + */ + public enum RxJava1SingleToObservableAdapter implements Function, Observable> { + + INSTANCE; + + @Override + public Observable apply(Single source) { + return source.toObservable(); + } + } + + // ------------------------------------------------------------------------- + // RxJava 2 adapters + // ------------------------------------------------------------------------- + + /** + * An adapter {@link Function} to adopt a {@link Publisher} to {@link io.reactivex.Single}. + */ + public enum PublisherToRxJava2SingleAdapter implements Function, io.reactivex.Single> { + + INSTANCE; + + @Override + public io.reactivex.Single apply(Publisher source) { + return io.reactivex.Single.fromPublisher(source); + } + } + + /** + * An adapter {@link Function} to adopt a {@link Publisher} to {@link io.reactivex.Completable}. + */ + public enum PublisherToRxJava2CompletableAdapter implements Function, io.reactivex.Completable> { + + INSTANCE; + + @Override + public io.reactivex.Completable apply(Publisher source) { + return io.reactivex.Completable.fromPublisher(source); + } + } + + /** + * An adapter {@link Function} to adopt a {@link Publisher} to {@link io.reactivex.Observable}. + */ + public enum PublisherToRxJava2ObservableAdapter implements Function, io.reactivex.Observable> { + + INSTANCE; + + @Override + public io.reactivex.Observable apply(Publisher source) { + return io.reactivex.Observable.fromPublisher(source); + } + } + + /** + * An adapter {@link Function} to adopt a {@link io.reactivex.Single} to {@link Publisher}. + */ + public enum RxJava2SingleToPublisherAdapter implements Function, Publisher> { + + INSTANCE; + + @Override + public Publisher apply(io.reactivex.Single source) { + return source.toFlowable(); + } + } + + /** + * An adapter {@link Function} to adopt a {@link io.reactivex.Single} to {@link Mono}. + */ + public enum RxJava2SingleToMonoAdapter implements Function, Mono> { + + INSTANCE; + + @Override + public Mono apply(io.reactivex.Single source) { + return Mono.from(source.toFlowable()); + } + } + + /** + * An adapter {@link Function} to adopt a {@link io.reactivex.Single} to {@link Publisher}. + */ + public enum RxJava2SingleToFluxAdapter implements Function, Flux> { + + INSTANCE; + + @Override + public Flux apply(io.reactivex.Single source) { + return Flux.from(source.toFlowable()); + } + } + + /** + * An adapter {@link Function} to adopt a {@link io.reactivex.Completable} to {@link Publisher}. + */ + public enum RxJava2CompletableToPublisherAdapter implements Function> { + + INSTANCE; + + @Override + public Publisher apply(io.reactivex.Completable source) { + return source.toFlowable(); + } + } + + /** + * An adapter {@link Function} to adopt a {@link io.reactivex.Completable} to {@link Mono}. + */ + public enum RxJava2CompletableToMonoAdapter implements Function> { + + INSTANCE; + + @Override + public Mono apply(io.reactivex.Completable source) { + return Mono.from(RxJava2CompletableToPublisherAdapter.INSTANCE.apply(source)); + } + } + + /** + * An adapter {@link Function} to adopt an {@link io.reactivex.Observable} to {@link Publisher}. + */ + public enum RxJava2ObservableToPublisherAdapter implements Function, Publisher> { + + INSTANCE; + + @Override + public Publisher apply(io.reactivex.Observable source) { + return source.toFlowable(BackpressureStrategy.BUFFER); + } + } + + /** + * An adapter {@link Function} to adopt a {@link io.reactivex.Observable} to {@link Mono}. + */ + public enum RxJava2ObservableToMonoAdapter implements Function, Mono> { + + INSTANCE; + + @Override + public Mono apply(io.reactivex.Observable source) { + return Mono.from(source.toFlowable(BackpressureStrategy.BUFFER)); + } + } + + /** + * An adapter {@link Function} to adopt a {@link io.reactivex.Observable} to {@link Flux}. + */ + public enum RxJava2ObservableToFluxAdapter implements Function, Flux> { + + INSTANCE; + + @Override + public Flux apply(io.reactivex.Observable source) { + return Flux.from(source.toFlowable(BackpressureStrategy.BUFFER)); + } + } + + /** + * An adapter {@link Function} to adopt a {@link Publisher} to {@link io.reactivex.Flowable}. + */ + public enum PublisherToRxJava2FlowableAdapter implements Function, io.reactivex.Flowable> { + + INSTANCE; + + @Override + public io.reactivex.Flowable apply(Publisher source) { + return Flowable.fromPublisher(source); + } + } + + /** + * An adapter {@link Function} to adopt a {@link io.reactivex.Flowable} to {@link Publisher}. + */ + public enum RxJava2FlowableToPublisherAdapter implements Function, Publisher> { + + INSTANCE; + + @Override + public Publisher apply(io.reactivex.Flowable source) { + return source; + } + } + + /** + * An adapter {@link Function} to adopt a {@link Publisher} to {@link io.reactivex.Flowable}. + */ + public enum PublisherToRxJava2MaybeAdapter implements Function, io.reactivex.Maybe> { + + INSTANCE; + + @Override + public io.reactivex.Maybe apply(Publisher source) { + return Flowable.fromPublisher(source).singleElement(); + } + } + + /** + * An adapter {@link Function} to adopt a {@link io.reactivex.Maybe} to {@link Publisher}. + */ + public enum RxJava2MaybeToPublisherAdapter implements Function, Publisher> { + + INSTANCE; + + @Override + public Publisher apply(io.reactivex.Maybe source) { + return source.toFlowable(); + } + } + + /** + * An adapter {@link Function} to adopt a {@link io.reactivex.Maybe} to {@link Mono}. + */ + public enum RxJava2MaybeToMonoAdapter implements Function, Mono> { + + INSTANCE; + + @Override + public Mono apply(io.reactivex.Maybe source) { + return Mono.from(source.toFlowable()); + } + } + + /** + * An adapter {@link Function} to adopt a {@link io.reactivex.Maybe} to {@link Flux}. + */ + public enum RxJava2MaybeToFluxAdapter implements Function, Flux> { + + INSTANCE; + + @Override + public Flux apply(io.reactivex.Maybe source) { + return Flux.from(source.toFlowable()); + } + } + + /** + * An adapter {@link Function} to adopt a {@link Observable} to {@link Single}. + */ + public enum RxJava2ObservableToSingleAdapter implements Function, io.reactivex.Single> { + + INSTANCE; + + @Override + public io.reactivex.Single apply(io.reactivex.Observable source) { + return source.singleOrError(); + } + } + + /** + * An adapter {@link Function} to adopt a {@link Observable} to {@link Maybe}. + */ + public enum RxJava2ObservableToMaybeAdapter implements Function, io.reactivex.Maybe> { + + INSTANCE; + + @Override + public io.reactivex.Maybe apply(io.reactivex.Observable source) { + return source.singleElement(); + } + } + + /** + * An adapter {@link Function} to adopt a {@link Single} to {@link Single}. + */ + public enum RxJava2SingleToObservableAdapter implements Function, io.reactivex.Observable> { + + INSTANCE; + + @Override + public io.reactivex.Observable apply(io.reactivex.Single source) { + return source.toObservable(); + } + } +} diff --git a/src/main/java/com/lambdaworks/redis/dynamic/ReactiveTypes.java b/src/main/java/com/lambdaworks/redis/dynamic/ReactiveTypes.java new file mode 100644 index 0000000000..7066cebf95 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/dynamic/ReactiveTypes.java @@ -0,0 +1,252 @@ +/* + * Copyright 2011-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.lambdaworks.redis.dynamic; + +import java.util.*; +import java.util.Map.Entry; +import java.util.stream.Collectors; + +import org.reactivestreams.Publisher; + +import com.lambdaworks.redis.internal.LettuceAssert; +import com.lambdaworks.redis.internal.LettuceClassUtils; + +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import rx.Completable; +import rx.Observable; +import rx.Single; + +/** + * Utility class to expose details about reactive wrapper types. This class exposes whether a reactive wrapper is supported in + * general and whether a particular type is suitable for no-value/single-value/multi-value usage. + *

    + * Supported types are discovered by their availability on the class path. This class is typically used to determine + * multiplicity and whether a reactive wrapper type is acceptable for a specific operation. + * + * @author Mark Paluch + * @since 5.0 + * @see org.reactivestreams.Publisher + * @see rx.Single + * @see rx.Observable + * @see rx.Completable + * @see io.reactivex.Single + * @see io.reactivex.Maybe + * @see io.reactivex.Observable + * @see io.reactivex.Completable + * @see io.reactivex.Flowable + * @see Mono + * @see Flux + */ +class ReactiveTypes { + + private static final boolean PROJECT_REACTOR_PRESENT = LettuceClassUtils.isPresent("reactor.core.publisher.Mono"); + private static final boolean RXJAVA1_PRESENT = LettuceClassUtils.isPresent("rx.Completable"); + private static final boolean RXJAVA2_PRESENT = LettuceClassUtils.isPresent("io.reactivex.Flowable"); + + private static final Map, Descriptor> REACTIVE_WRAPPERS; + + static { + + Map, Descriptor> reactiveWrappers = new LinkedHashMap<>(3); + + if (RXJAVA1_PRESENT) { + + reactiveWrappers.put(Single.class, new Descriptor(false, true, false)); + reactiveWrappers.put(Completable.class, new Descriptor(false, true, true)); + reactiveWrappers.put(Observable.class, new Descriptor(true, true, false)); + } + + if (RXJAVA2_PRESENT) { + + reactiveWrappers.put(io.reactivex.Single.class, new Descriptor(false, true, false)); + reactiveWrappers.put(io.reactivex.Maybe.class, new Descriptor(false, true, false)); + reactiveWrappers.put(io.reactivex.Completable.class, new Descriptor(false, true, true)); + reactiveWrappers.put(io.reactivex.Flowable.class, new Descriptor(true, true, false)); + reactiveWrappers.put(io.reactivex.Observable.class, new Descriptor(true, true, false)); + } + + if (PROJECT_REACTOR_PRESENT) { + + reactiveWrappers.put(Mono.class, new Descriptor(false, true, false)); + reactiveWrappers.put(Flux.class, new Descriptor(true, true, true)); + reactiveWrappers.put(Publisher.class, new Descriptor(true, true, true)); + } + + REACTIVE_WRAPPERS = Collections.unmodifiableMap(reactiveWrappers); + } + + /** + * Returns {@literal true} if reactive support is available. More specifically, whether RxJava1/2 or Project Reactor + * libraries are on the class path. + * + * @return {@literal true} if reactive support is available. + */ + public static boolean isAvailable() { + return isAvailable(ReactiveLibrary.PROJECT_REACTOR) || isAvailable(ReactiveLibrary.RXJAVA1) + || isAvailable(ReactiveLibrary.RXJAVA2); + } + + /** + * Returns {@literal true} if the {@link ReactiveLibrary} is available. + * + * @param reactiveLibrary must not be {@literal null}. + * @return {@literal true} if the {@link ReactiveLibrary} is available. + */ + public static boolean isAvailable(ReactiveLibrary reactiveLibrary) { + + LettuceAssert.notNull(reactiveLibrary, "ReactiveLibrary must not be null!"); + + switch (reactiveLibrary) { + case PROJECT_REACTOR: + return PROJECT_REACTOR_PRESENT; + case RXJAVA1: + return RXJAVA1_PRESENT; + case RXJAVA2: + return RXJAVA2_PRESENT; + } + + throw new IllegalArgumentException(String.format("ReactiveLibrary %s not supported", reactiveLibrary)); + } + + /** + * Returns {@literal true} if the {@code type} is a supported reactive wrapper type. + * + * @param type must not be {@literal null}. + * @return {@literal true} if the {@code type} is a supported reactive wrapper type. + */ + public static boolean supports(Class type) { + return isNoValueType(type) || isSingleValueType(type) || isMultiValueType(type); + } + + /** + * Returns {@literal true} if {@code type} is a reactive wrapper type that contains no value. + * + * @param type must not be {@literal null}. + * @return {@literal true} if {@code type} is a reactive wrapper type that contains no value. + */ + public static boolean isNoValueType(Class type) { + + LettuceAssert.notNull(type, "Class must not be null!"); + + return findDescriptor(type).map(Descriptor::isNoValue).orElse(false); + } + + /** + * Returns {@literal true} if {@code type} is a reactive wrapper type for a single value. + * + * @param type must not be {@literal null}. + * @return {@literal true} if {@code type} is a reactive wrapper type for a single value. + */ + public static boolean isSingleValueType(Class type) { + + LettuceAssert.notNull(type, "Class must not be null!"); + + return findDescriptor(type).map((descriptor) -> !descriptor.isMultiValue() && !descriptor.isNoValue()).orElse(false); + } + + /** + * Returns {@literal true} if {@code type} is a reactive wrapper type supporting multiple values ({@code 0..N} elements). + * + * @param type must not be {@literal null}. + * @return {@literal true} if {@code type} is a reactive wrapper type supporting multiple values ({@code 0..N} elements). + */ + public static boolean isMultiValueType(Class type) { + + LettuceAssert.notNull(type, "Class must not be null!"); + + // Prevent single-types with a multi-hierarchy supertype to be reported as multi type + // See Mono implements Publisher + if (isSingleValueType(type)) { + return false; + } + + return findDescriptor(type).map(Descriptor::isMultiValue).orElse(false); + } + + /** + * Returns a collection of No-Value wrapper types. + * + * @return a collection of No-Value wrapper types. + */ + public static Collection> getNoValueTypes() { + return REACTIVE_WRAPPERS.entrySet().stream().filter(entry -> entry.getValue().isNoValue()).map(Entry::getKey) + .collect(Collectors.toList()); + } + + /** + * Returns a collection of Single-Value wrapper types. + * + * @return a collection of Single-Value wrapper types. + */ + public static Collection> getSingleValueTypes() { + return REACTIVE_WRAPPERS.entrySet().stream().filter(entry -> !entry.getValue().isMultiValue()).map(Entry::getKey) + .collect(Collectors.toList()); + } + + /** + * Returns a collection of Multi-Value wrapper types. + * + * @return a collection of Multi-Value wrapper types. + */ + public static Collection> getMultiValueTypes() { + return REACTIVE_WRAPPERS.entrySet().stream().filter(entry -> entry.getValue().isMultiValue()).map(Entry::getKey) + .collect(Collectors.toList()); + } + + private static Optional findDescriptor(Class rhsType) { + + for (Class type : REACTIVE_WRAPPERS.keySet()) { + if (LettuceClassUtils.isAssignable(type, rhsType)) { + return Optional.ofNullable(REACTIVE_WRAPPERS.get(type)); + } + } + return Optional.empty(); + } + + /** + * Enumeration of supported reactive libraries. + * + * @author Mark Paluch + */ + enum ReactiveLibrary { + PROJECT_REACTOR, RXJAVA1, RXJAVA2; + } + + public static class Descriptor { + private final boolean isMultiValue; + private final boolean supportsEmpty; + private final boolean isNoValue; + + public Descriptor(boolean isMultiValue, boolean canBeEmpty, boolean isNoValue) { + this.isMultiValue = isMultiValue; + this.supportsEmpty = canBeEmpty; + this.isNoValue = isNoValue; + } + + public boolean isMultiValue() { + return this.isMultiValue; + } + + public boolean supportsEmpty() { + return this.supportsEmpty; + } + + public boolean isNoValue() { + return this.isNoValue; + } + } +} \ No newline at end of file diff --git a/src/main/java/com/lambdaworks/redis/dynamic/ReactiveWrappers.java b/src/main/java/com/lambdaworks/redis/dynamic/ReactiveWrappers.java deleted file mode 100644 index 32abe54f4d..0000000000 --- a/src/main/java/com/lambdaworks/redis/dynamic/ReactiveWrappers.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2011-2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.lambdaworks.redis.dynamic; - -import java.util.HashSet; -import java.util.Set; - -import com.lambdaworks.redis.internal.LettuceAssert; -import com.lambdaworks.redis.internal.LettuceClassUtils; - -/** - * Converters to potentially convert the execution of a command method into a variety of wrapper types potentially being - * available on the classpath. Currently supported: - *

      - *
    • {@link reactor.core.publisher.Mono}
    • - *
    • {@link reactor.core.publisher.Flux}
    • - *
    • {@link org.reactivestreams.Publisher}
    • - *
    - * - * @author Mark Paluch - * @since 5.0 - */ -abstract class ReactiveWrappers { - - private static final Class MONO = LettuceClassUtils.findClass("reactor.core.publisher.Mono"); - private static final Class FLUX = LettuceClassUtils.findClass("reactor.core.publisher.Flux"); - private static final Class PUBLISHER = LettuceClassUtils.findClass("org.reactivestreams.Publisher"); - - private static final Set> REACTIVE_WRAPPERS = new HashSet<>(); - private static final Set> SINGLE_WRAPPERS = new HashSet<>(); - private static final Set> MULTI_WRAPPERS = new HashSet<>(); - - static { - - if (MONO != null) { - REACTIVE_WRAPPERS.add(MONO); - SINGLE_WRAPPERS.add(MONO); - } - - if (FLUX != null) { - REACTIVE_WRAPPERS.add(FLUX); - MULTI_WRAPPERS.add(FLUX); - } - - if (PUBLISHER != null) { - REACTIVE_WRAPPERS.add(PUBLISHER); - MULTI_WRAPPERS.add(PUBLISHER); - } - } - - public static boolean supports(Class wrapperType) { - - LettuceAssert.notNull(wrapperType, "Wrapper type must not be null"); - - return REACTIVE_WRAPPERS.contains(wrapperType); - } - - public static boolean isSingle(Class wrapperType) { - - LettuceAssert.notNull(wrapperType, "Wrapper type must not be null"); - - return SINGLE_WRAPPERS.contains(wrapperType) && !isMulti(wrapperType); - } - - public static boolean isMulti(Class wrapperType) { - - LettuceAssert.notNull(wrapperType, "Wrapper type must not be null"); - - return MULTI_WRAPPERS.contains(wrapperType); - } -} diff --git a/src/main/java/com/lambdaworks/redis/dynamic/RedisCommandFactory.java b/src/main/java/com/lambdaworks/redis/dynamic/RedisCommandFactory.java index f068012101..4c61cac856 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/RedisCommandFactory.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/RedisCommandFactory.java @@ -219,7 +219,7 @@ public CommandFactoryExecutorMethodInterceptor(RedisCommandsMetadata redisComman for (Method method : redisCommandsMetadata.getMethods()) { - if (ReactiveWrappers.supports(method.getReturnType())) { + if (ReactiveTypes.supports(method.getReturnType())) { continue; } @@ -289,15 +289,17 @@ class ReactiveCommandFactoryExecutorMethodInterceptor implements MethodIntercept private final Map commandFactories = new ConcurrentHashMap<>(); private final AbstractRedisReactiveCommands redisReactiveCommands; + private final ConversionService conversionService = new ConversionService(); public ReactiveCommandFactoryExecutorMethodInterceptor(RedisCommandsMetadata redisCommandsMetadata, BaseRedisReactiveCommands redisReactiveCommands) { + ReactiveTypeAdapters.registerIn(this.conversionService); ReactiveRedisCommandFactoryResolver lookupStrategy = new ReactiveRedisCommandFactoryResolver(redisCodecs); for (Method method : redisCommandsMetadata.getMethods()) { - if (ReactiveWrappers.supports(method.getReturnType())) { + if (ReactiveTypes.supports(method.getReturnType())) { ReactiveCommandSegmentCommandFactory commandFactory = lookupStrategy.resolveRedisCommandFactory(method, redisCommandsMetadata); @@ -318,21 +320,30 @@ public Object invoke(MethodInvocation invocation) throws Throwable { ReactiveCommandSegmentCommandFactory commandFactory = commandFactories.get(method); - if (ReactiveWrappers.isSingle(method.getReturnType())) { - return redisReactiveCommands.createMono(() -> commandFactory.createCommand(arguments)); - } - - if (commandFactory.isStreamingExecution()) { + Object result = dispatch(method, arguments, commandFactory); - return redisReactiveCommands.createDissolvingFlux(() -> commandFactory.createCommand(arguments)); + if (method.getReturnType().isAssignableFrom(result.getClass())) { + return result; } - return redisReactiveCommands.createFlux(() -> commandFactory.createCommand(arguments)); + return conversionService.convert(result, method.getReturnType()); } return invocation.proceed(); } + protected Object dispatch(Method method, Object[] arguments, ReactiveCommandSegmentCommandFactory commandFactory) { + if (ReactiveTypes.isSingleValueType(method.getReturnType())) { + return redisReactiveCommands.createMono(() -> commandFactory.createCommand(arguments)); + } + + if (commandFactory.isStreamingExecution()) { + return redisReactiveCommands.createDissolvingFlux(() -> commandFactory.createCommand(arguments)); + } + + return redisReactiveCommands.createFlux(() -> commandFactory.createCommand(arguments)); + } + private boolean hasFactoryFor(Method method) { return commandFactories.containsKey(method); } diff --git a/src/test/java/com/lambdaworks/redis/dynamic/ConversionServiceTest.java b/src/test/java/com/lambdaworks/redis/dynamic/ConversionServiceTest.java new file mode 100644 index 0000000000..2e520306fd --- /dev/null +++ b/src/test/java/com/lambdaworks/redis/dynamic/ConversionServiceTest.java @@ -0,0 +1,87 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.lambdaworks.redis.dynamic; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.fail; + +import java.util.function.Function; + +import org.junit.Test; + +import io.reactivex.Observable; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +/** + * @author Mark Paluch + */ +public class ConversionServiceTest { + + ConversionService sut = new ConversionService(); + + @Test + public void getConverter() { + + sut.addConverter(new FluxToObservableConverter()); + sut.addConverter(new MonoToObservableConverter()); + + assertThat(sut.getConverter(Flux.just("").getClass(), Observable.class)).isNotNull() + .isInstanceOf(FluxToObservableConverter.class); + + try { + sut.getConverter(Flux.just("").getClass(), String.class); + fail("Missing IllegalArgumentException"); + } catch (IllegalArgumentException e) { + assertThat(e).hasMessageContaining("No converter found for reactor.core.publisher.FluxJust to java.lang.String"); + } + } + + @Test + public void canConvert() { + + sut.addConverter(new FluxToObservableConverter()); + sut.addConverter(new MonoToObservableConverter()); + + assertThat(sut.canConvert(Flux.class, Observable.class)).isTrue(); + assertThat(sut.canConvert(Observable.class, Flux.class)).isFalse(); + } + + @Test + public void convert() { + + sut.addConverter(new FluxToObservableConverter()); + sut.addConverter(new MonoToObservableConverter()); + + Observable observable = sut.convert(Mono.just("hello"), Observable.class); + assertThat(observable.blockingFirst()).isEqualTo("world"); + } + + private class FluxToObservableConverter implements Function, Observable> { + @Override + public Observable apply(Flux source) { + return null; + } + } + + private class MonoToObservableConverter implements Function, Observable> { + @Override + public Observable apply(Mono source) { + return Observable.just("world"); + } + } + +} \ No newline at end of file diff --git a/src/test/java/com/lambdaworks/redis/dynamic/ReactiveTypeAdaptersTest.java b/src/test/java/com/lambdaworks/redis/dynamic/ReactiveTypeAdaptersTest.java new file mode 100644 index 0000000000..f5761c903f --- /dev/null +++ b/src/test/java/com/lambdaworks/redis/dynamic/ReactiveTypeAdaptersTest.java @@ -0,0 +1,160 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.lambdaworks.redis.dynamic; + +import static org.assertj.core.api.Assertions.assertThat; + +import io.reactivex.Flowable; +import org.junit.Before; +import org.junit.Test; +import org.reactivestreams.Publisher; + +import io.reactivex.Maybe; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import rx.Single; + +/** + * @author Mark Paluch + */ +public class ReactiveTypeAdaptersTest { + + ConversionService conversionService = new ConversionService(); + + @Before + public void before() throws Exception { + ReactiveTypeAdapters.registerIn(conversionService); + } + + @Test + public void toWrapperShouldCastMonoToMono() { + + Mono foo = Mono.just("foo"); + assertThat(conversionService.convert(foo, Mono.class)).isSameAs(foo); + } + + @Test + public void toWrapperShouldConvertMonoToRxJava1Single() { + + Mono foo = Mono.just("foo"); + assertThat(conversionService.convert(foo, Single.class)).isInstanceOf(Single.class); + } + + @Test + public void toWrapperShouldConvertMonoToRxJava2Single() { + + Mono foo = Mono.just("foo"); + assertThat(conversionService.convert(foo, io.reactivex.Single.class)).isInstanceOf(io.reactivex.Single.class); + } + + @Test + public void toWrapperShouldConvertRxJava2SingleToMono() { + + io.reactivex.Single foo = io.reactivex.Single.just("foo"); + assertThat(conversionService.convert(foo, Mono.class)).isInstanceOf(Mono.class); + } + + @Test + public void toWrapperShouldConvertRxJava2SingleToPublisher() { + + io.reactivex.Single foo = io.reactivex.Single.just("foo"); + assertThat(conversionService.convert(foo, Publisher.class)).isInstanceOf(Publisher.class); + } + + @Test + public void toWrapperShouldConvertRxJava2MaybeToMono() { + + io.reactivex.Maybe foo = io.reactivex.Maybe.just("foo"); + assertThat(conversionService.convert(foo, Mono.class)).isInstanceOf(Mono.class); + } + + @Test + public void toWrapperShouldConvertRxJava2MaybeToFlux() { + + io.reactivex.Maybe foo = io.reactivex.Maybe.just("foo"); + assertThat(conversionService.convert(foo, Flux.class)).isInstanceOf(Flux.class); + } + + @Test + public void toWrapperShouldConvertRxJava2MaybeToPublisher() { + + io.reactivex.Maybe foo = io.reactivex.Maybe.just("foo"); + assertThat(conversionService.convert(foo, Publisher.class)).isInstanceOf(Publisher.class); + } + + @Test + public void toWrapperShouldConvertRxJava2FlowableToMono() { + + io.reactivex.Flowable foo = io.reactivex.Flowable.just("foo"); + assertThat(conversionService.convert(foo, Mono.class)).isInstanceOf(Mono.class); + } + + @Test + public void toWrapperShouldConvertRxJava2FlowableToFlux() { + + io.reactivex.Flowable foo = io.reactivex.Flowable.just("foo"); + assertThat(conversionService.convert(foo, Flux.class)).isInstanceOf(Flux.class); + } + + @Test + public void toWrapperShouldCastRxJava2FlowableToPublisher() { + + io.reactivex.Flowable foo = io.reactivex.Flowable.just("foo"); + assertThat(conversionService.convert(foo, Publisher.class)).isInstanceOf(Flux.class); + } + + @Test + public void toWrapperShouldConvertRxJava2ObservableToMono() { + + io.reactivex.Observable foo = io.reactivex.Observable.just("foo"); + assertThat(conversionService.convert(foo, Mono.class)).isInstanceOf(Mono.class); + } + + @Test + public void toWrapperShouldConvertRxJava2ObservableToFlux() { + + io.reactivex.Observable foo = io.reactivex.Observable.just("foo"); + assertThat(conversionService.convert(foo, Flux.class)).isInstanceOf(Flux.class); + } + + @Test + public void toWrapperShouldConvertRxJava2ObservableToSingle() { + + io.reactivex.Observable foo = io.reactivex.Observable.just("foo"); + assertThat(conversionService.convert(foo, io.reactivex.Single.class)).isInstanceOf(io.reactivex.Single.class); + } + + @Test + public void toWrapperShouldConvertRxJava2ObservableToMaybe() { + + io.reactivex.Observable foo = io.reactivex.Observable.empty(); + assertThat(conversionService.convert(foo, Maybe.class)).isInstanceOf(Maybe.class); + } + + @Test + public void toWrapperShouldConvertRxJava2ObservableToPublisher() { + + io.reactivex.Observable foo = io.reactivex.Observable.just("foo"); + assertThat(conversionService.convert(foo, Publisher.class)).isInstanceOf(Publisher.class); + } + + @Test + public void toWrapperShouldConvertMonoToFlux() { + + Mono foo = Mono.just("foo"); + assertThat(conversionService.convert(foo, Flux.class)).isInstanceOf(Flux.class); + } +} \ No newline at end of file diff --git a/src/test/java/com/lambdaworks/redis/dynamic/ReactiveTypeAdaptionTest.java b/src/test/java/com/lambdaworks/redis/dynamic/ReactiveTypeAdaptionTest.java new file mode 100644 index 0000000000..cc1f36c24c --- /dev/null +++ b/src/test/java/com/lambdaworks/redis/dynamic/ReactiveTypeAdaptionTest.java @@ -0,0 +1,97 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.lambdaworks.redis.dynamic; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.Before; +import org.junit.Test; + +import com.lambdaworks.redis.AbstractRedisClientTest; +import com.lambdaworks.redis.dynamic.annotation.Command; + +import rx.Observable; +import rx.Single; + +/** + * @author Mark Paluch + */ +public class ReactiveTypeAdaptionTest extends AbstractRedisClientTest { + + private TestInterface api; + + @Before + public void before() throws Exception { + + redis.set(key, value); + + RedisCommandFactory factory = new RedisCommandFactory(redis.getStatefulConnection()); + this.api = factory.getCommands(TestInterface.class); + } + + @Test + public void rxJava1Single() throws Exception { + + Single single = api.getRxJava1Single(key); + assertThat(single.toBlocking().value()).isEqualTo(value); + } + + @Test + public void rxJava1Observable() throws Exception { + + Observable observable = api.getRxJava1Observable(key); + assertThat(observable.toBlocking().last()).isEqualTo(value); + } + + @Test + public void rxJava2Single() throws Exception { + + io.reactivex.Single single = api.getRxJava2Single(key); + assertThat(single.blockingGet()).isEqualTo(value); + } + + @Test + public void rxJava2Maybe() throws Exception { + + io.reactivex.Maybe maybe = api.getRxJava2Maybe(key); + assertThat(maybe.blockingGet()).isEqualTo(value); + } + + @Test + public void rxJava2Observable() throws Exception { + + io.reactivex.Observable observable = api.getRxJava2Observable(key); + assertThat(observable.blockingFirst()).isEqualTo(value); + } + + static interface TestInterface extends Commands { + + @Command("GET") + Single getRxJava1Single(String key); + + @Command("GET") + Observable getRxJava1Observable(String key); + + @Command("GET") + io.reactivex.Single getRxJava2Single(String key); + + @Command("GET") + io.reactivex.Maybe getRxJava2Maybe(String key); + + @Command("GET") + io.reactivex.Observable getRxJava2Observable(String key); + } +} diff --git a/src/test/java/com/lambdaworks/redis/dynamic/RedisCommandsTest.java b/src/test/java/com/lambdaworks/redis/dynamic/RedisCommandsTest.java index 225e6ca1ed..426b22eb1c 100644 --- a/src/test/java/com/lambdaworks/redis/dynamic/RedisCommandsTest.java +++ b/src/test/java/com/lambdaworks/redis/dynamic/RedisCommandsTest.java @@ -42,7 +42,7 @@ public void sync() throws Exception { TestInterface api = factory.getCommands(TestInterface.class); - api.setSync("key", "value", Timeout.create(10, TimeUnit.SECONDS)); + api.setSync(key, value, Timeout.create(10, TimeUnit.SECONDS)); assertThat(api.get("key")).isEqualTo("value"); assertThat(api.getAsBytes("key")).isEqualTo("value".getBytes()); } @@ -54,9 +54,9 @@ public void async() throws Exception { TestInterface api = factory.getCommands(TestInterface.class); - Future key = api.set("key", "value"); - assertThat(key).isInstanceOf(CompletableFuture.class); - key.get(); + Future set = api.set(key, value); + assertThat(set).isInstanceOf(CompletableFuture.class); + set.get(); } @Test @@ -66,8 +66,8 @@ public void reactive() throws Exception { TestInterface api = factory.getCommands(TestInterface.class); - Mono key = api.setReactive("key", "value"); - assertThat(key.block()).isEqualTo("OK"); + Mono set = api.setReactive(key, value); + assertThat(set.block()).isEqualTo("OK"); } @Test From 7ff76fa20295f30ff0e7a450870aa583ee886aa9 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Sat, 12 Nov 2016 16:02:16 +0100 Subject: [PATCH 069/808] Provide synchronous ScanIterator API #397 Lettuce now provides ScanIterator to iterate over keys, hashes, sets and sorted sets using Iterator and Stream. ScanIterator is synchronous and implements Iterator. ScanIterator scan = ScanIterator.scan(connection.sync()); List keys = scan.stream().collect(Collectors.toList()); --- .../com/lambdaworks/redis/ScanIterator.java | 306 ++++++++++++++++++ .../lambdaworks/redis/ScanIteratorTest.java | 235 ++++++++++++++ .../redis/cluster/ScanIteratorTest.java | 253 +++++++++++++++ 3 files changed, 794 insertions(+) create mode 100644 src/main/java/com/lambdaworks/redis/ScanIterator.java create mode 100644 src/test/java/com/lambdaworks/redis/ScanIteratorTest.java create mode 100644 src/test/java/com/lambdaworks/redis/cluster/ScanIteratorTest.java diff --git a/src/main/java/com/lambdaworks/redis/ScanIterator.java b/src/main/java/com/lambdaworks/redis/ScanIterator.java new file mode 100644 index 0000000000..4b59f2f327 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/ScanIterator.java @@ -0,0 +1,306 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.lambdaworks.redis; + +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.Optional; +import java.util.Spliterators; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; + +import com.lambdaworks.redis.api.sync.RedisHashCommands; +import com.lambdaworks.redis.api.sync.RedisKeyCommands; +import com.lambdaworks.redis.api.sync.RedisSetCommands; +import com.lambdaworks.redis.api.sync.RedisSortedSetCommands; +import com.lambdaworks.redis.internal.LettuceAssert; + +/** + * Scan command support exposed through {@link Iterator}. + *

    + * {@link ScanIterator} uses synchronous command interfaces to scan over keys ({@code SCAN}), sets ({@code SSCAN}), sorted sets + * ({@code ZSCAN}), and hashes ({@code HSCAN}). A {@link ScanIterator} is stateful and not thread-safe. Instances can be used + * only once to iterate over results. + * + * @author Mark Paluch + * @since 4.4 + */ +abstract public class ScanIterator implements Iterator { + + /** + * Sequentially iterate over keys in the keyspace. This method uses {@code SCAN} to perform an iterative scan. + * + * @param commands the commands interface, must not be {@literal null}. + * @return a new {@link ScanIterator}. + */ + public static ScanIterator scan(RedisKeyCommands commands) { + return scan(commands, Optional.empty()); + } + + /** + * Sequentially iterate over keys in the keyspace. This method uses {@code SCAN} to perform an iterative scan. + * + * @param commands the commands interface, must not be {@literal null}. + * @param scanArgs the scan arguments, must not be {@literal null}. + * @return a new {@link ScanIterator}. + */ + public static ScanIterator scan(RedisKeyCommands commands, ScanArgs scanArgs) { + + LettuceAssert.notNull(scanArgs, "ScanArgs must not be null"); + + return scan(commands, Optional.of(scanArgs)); + } + + private static ScanIterator scan(RedisKeyCommands commands, Optional scanArgs) { + + LettuceAssert.notNull(commands, "RedisKeyCommands must not be null"); + + return new SyncScanIterator() { + + @Override + protected ScanCursor nextScanCursor(ScanCursor scanCursor) { + + KeyScanCursor cursor = getNextScanCursor(scanCursor); + chunk = cursor.getKeys().iterator(); + return cursor; + } + + private KeyScanCursor getNextScanCursor(ScanCursor scanCursor) { + + if (scanCursor == null) { + return scanArgs.map(commands::scan).orElseGet(commands::scan); + } + + return scanArgs.map((scanArgs) -> commands.scan(scanCursor, scanArgs)) + .orElseGet(() -> commands.scan(scanCursor)); + } + }; + } + + /** + * Sequentially iterate over entries in a hash identified by {@code key}. This method uses {@code HSCAN} to perform an + * iterative scan. + * + * @param commands the commands interface, must not be {@literal null}. + * @return a new {@link ScanIterator}. + */ + public static ScanIterator> hscan(RedisHashCommands commands, K key) { + return hscan(commands, key, Optional.empty()); + } + + /** + * Sequentially iterate over entries in a hash identified by {@code key}. This method uses {@code HSCAN} to perform an + * iterative scan. + * + * @param commands the commands interface, must not be {@literal null}. + * @param scanArgs the scan arguments, must not be {@literal null}. + * @return a new {@link ScanIterator}. + */ + public static ScanIterator> hscan(RedisHashCommands commands, K key, ScanArgs scanArgs) { + + LettuceAssert.notNull(scanArgs, "ScanArgs must not be null"); + + return hscan(commands, key, Optional.of(scanArgs)); + } + + private static ScanIterator> hscan(RedisHashCommands commands, K key, + Optional scanArgs) { + + LettuceAssert.notNull(commands, "RedisKeyCommands must not be null"); + LettuceAssert.notNull(key, "Key must not be null"); + + return new SyncScanIterator>() { + + @Override + protected ScanCursor nextScanCursor(ScanCursor scanCursor) { + + MapScanCursor cursor = getNextScanCursor(scanCursor); + chunk = cursor.getMap().keySet().stream().map(k -> KeyValue.fromNullable(k, cursor.getMap().get(k))).iterator(); + return cursor; + } + + private MapScanCursor getNextScanCursor(ScanCursor scanCursor) { + + if (scanCursor == null) { + return scanArgs.map(scanArgs -> commands.hscan(key, scanArgs)).orElseGet(() -> commands.hscan(key)); + } + + return scanArgs.map((scanArgs) -> commands.hscan(key, scanCursor, scanArgs)) + .orElseGet(() -> commands.hscan(key, scanCursor)); + } + }; + } + + /** + * Sequentially iterate over elements in a set identified by {@code key}. This method uses {@code SSCAN} to perform an + * iterative scan. + * + * @param commands the commands interface, must not be {@literal null}. + * @return a new {@link ScanIterator}. + */ + public static ScanIterator sscan(RedisSetCommands commands, K key) { + return sscan(commands, key, Optional.empty()); + } + + /** + * Sequentially iterate over elements in a set identified by {@code key}. This method uses {@code SSCAN} to perform an + * iterative scan. + * + * @param commands the commands interface, must not be {@literal null}. + * @param scanArgs the scan arguments, must not be {@literal null}. + * @return a new {@link ScanIterator}. + */ + public static ScanIterator sscan(RedisSetCommands commands, K key, ScanArgs scanArgs) { + + LettuceAssert.notNull(scanArgs, "ScanArgs must not be null"); + + return sscan(commands, key, Optional.of(scanArgs)); + } + + private static ScanIterator sscan(RedisSetCommands commands, K key, Optional scanArgs) { + + LettuceAssert.notNull(commands, "RedisKeyCommands must not be null"); + LettuceAssert.notNull(key, "Key must not be null"); + + return new SyncScanIterator() { + + @Override + protected ScanCursor nextScanCursor(ScanCursor scanCursor) { + + ValueScanCursor cursor = getNextScanCursor(scanCursor); + chunk = cursor.getValues().iterator(); + return cursor; + } + + private ValueScanCursor getNextScanCursor(ScanCursor scanCursor) { + + if (scanCursor == null) { + return scanArgs.map(scanArgs -> commands.sscan(key, scanArgs)).orElseGet(() -> commands.sscan(key)); + } + + return scanArgs.map((scanArgs) -> commands.sscan(key, scanCursor, scanArgs)) + .orElseGet(() -> commands.sscan(key, scanCursor)); + } + }; + } + + /** + * Sequentially iterate over scored values in a sorted set identified by {@code key}. This method uses {@code ZSCAN} to + * perform an iterative scan. + * + * @param commands the commands interface, must not be {@literal null}. + * @return a new {@link ScanIterator}. + */ + public static ScanIterator> zscan(RedisSortedSetCommands commands, K key) { + return zscan(commands, key, Optional.empty()); + } + + /** + * Sequentially iterate over scored values in a sorted set identified by {@code key}. This method uses {@code ZSCAN} to + * perform an iterative scan. + * + * @param commands the commands interface, must not be {@literal null}. + * @param scanArgs the scan arguments, must not be {@literal null}. + * @return a new {@link ScanIterator}. + */ + public static ScanIterator> zscan(RedisSortedSetCommands commands, K key, ScanArgs scanArgs) { + + LettuceAssert.notNull(scanArgs, "ScanArgs must not be null"); + + return zscan(commands, key, Optional.of(scanArgs)); + } + + private static ScanIterator> zscan(RedisSortedSetCommands commands, K key, + Optional scanArgs) { + + LettuceAssert.notNull(commands, "RedisKeyCommands must not be null"); + LettuceAssert.notNull(key, "Key must not be null"); + + return new SyncScanIterator>() { + + @Override + protected ScanCursor nextScanCursor(ScanCursor scanCursor) { + + ScoredValueScanCursor cursor = getNextScanCursor(scanCursor); + chunk = cursor.getValues().iterator(); + return cursor; + } + + private ScoredValueScanCursor getNextScanCursor(ScanCursor scanCursor) { + + if (scanCursor == null) { + return scanArgs.map(scanArgs -> commands.zscan(key, scanArgs)).orElseGet(() -> commands.zscan(key)); + } + + return scanArgs.map((scanArgs) -> commands.zscan(key, scanCursor, scanArgs)) + .orElseGet(() -> commands.zscan(key, scanCursor)); + } + }; + } + + /** + * Returns a sequential {@code Stream} with this {@link ScanIterator} as its source. + * + * @return a {@link Stream} for this {@link ScanIterator}. + */ + public Stream stream() { + return StreamSupport.stream(Spliterators.spliterator(this, 0, 0), false); + } + + /** + * Synchronous {@link ScanIterator} implementation. + * + * @param + */ + private static abstract class SyncScanIterator extends ScanIterator { + + private ScanCursor scanCursor; + protected Iterator chunk = null; + + @Override + public boolean hasNext() { + + while (scanCursor == null || !scanCursor.isFinished()) { + + if (scanCursor == null || !hasChunkElements()) { + scanCursor = nextScanCursor(scanCursor); + } + + if (hasChunkElements()) { + return true; + } + } + + return hasChunkElements(); + } + + private boolean hasChunkElements() { + return chunk.hasNext(); + } + + @Override + public T next() { + + if (!hasNext()) { + throw new NoSuchElementException(); + } + + return chunk.next(); + } + + protected abstract ScanCursor nextScanCursor(ScanCursor scanCursor); + } +} diff --git a/src/test/java/com/lambdaworks/redis/ScanIteratorTest.java b/src/test/java/com/lambdaworks/redis/ScanIteratorTest.java new file mode 100644 index 0000000000..911bc8462b --- /dev/null +++ b/src/test/java/com/lambdaworks/redis/ScanIteratorTest.java @@ -0,0 +1,235 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.lambdaworks.redis; + +import static org.assertj.core.api.AssertionsForClassTypes.fail; +import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; + +import java.util.ArrayList; +import java.util.List; +import java.util.NoSuchElementException; +import java.util.stream.Collectors; + +import org.junit.Test; + +import com.lambdaworks.KeysAndValues; + +/** + * @author Mark Paluch + */ +public class ScanIteratorTest extends AbstractRedisClientTest { + + @Test + public void scanShouldThrowNoSuchElementExceptionOnEmpty() throws Exception { + + redis.mset(KeysAndValues.MAP); + + ScanIterator scan = ScanIterator.scan(redis, ScanArgs.Builder.limit(50).match("key-foo")); + + assertThat(scan.hasNext()).isFalse(); + try { + scan.next(); + fail("Missing NoSuchElementException"); + } catch (NoSuchElementException e) { + assertThat(e).isInstanceOf(NoSuchElementException.class); + } + } + + @Test + public void keysSinglePass() throws Exception { + + redis.mset(KeysAndValues.MAP); + + ScanIterator scan = ScanIterator.scan(redis, ScanArgs.Builder.limit(50).match("key-11*")); + + assertThat(scan.hasNext()).isTrue(); + assertThat(scan.hasNext()).isTrue(); + + for (int i = 0; i < 11; i++) { + assertThat(scan.hasNext()).isTrue(); + assertThat(scan.next()).isNotNull(); + } + + assertThat(scan.hasNext()).isFalse(); + } + + @Test + public void keysMultiPass() throws Exception { + + redis.mset(KeysAndValues.MAP); + + ScanIterator scan = ScanIterator.scan(redis); + + List keys = scan.stream().collect(Collectors.toList()); + + assertThat(keys).containsAll(KeysAndValues.KEYS); + } + + @Test + public void hscanShouldThrowNoSuchElementExceptionOnEmpty() throws Exception { + + redis.mset(KeysAndValues.MAP); + + ScanIterator> scan = ScanIterator.hscan(redis, "none", + ScanArgs.Builder.limit(50).match("key-foo")); + + assertThat(scan.hasNext()).isFalse(); + try { + scan.next(); + fail("Missing NoSuchElementException"); + } catch (NoSuchElementException e) { + assertThat(e).isInstanceOf(NoSuchElementException.class); + } + } + + @Test + public void hashSinglePass() throws Exception { + + redis.hmset(key, KeysAndValues.MAP); + + ScanIterator> scan = ScanIterator.hscan(redis, key, + ScanArgs.Builder.limit(50).match("key-11*")); + + assertThat(scan.hasNext()).isTrue(); + assertThat(scan.hasNext()).isTrue(); + + for (int i = 0; i < 11; i++) { + assertThat(scan.hasNext()).isTrue(); + assertThat(scan.next()).isNotNull(); + } + + assertThat(scan.hasNext()).isFalse(); + } + + @Test + public void hashMultiPass() throws Exception { + + redis.hmset(key, KeysAndValues.MAP); + + ScanIterator> scan = ScanIterator.hscan(redis, key); + + List> keys = scan.stream().collect(Collectors.toList()); + + assertThat(keys).containsAll( + KeysAndValues.KEYS.stream().map(s -> KeyValue.fromNullable(s, KeysAndValues.MAP.get(s))).collect(Collectors.toList())); + } + + @Test + public void sscanShouldThrowNoSuchElementExceptionOnEmpty() throws Exception { + + redis.sadd(key, KeysAndValues.VALUES.toArray(new String[0])); + + ScanIterator scan = ScanIterator.sscan(redis, "none", + ScanArgs.Builder.limit(50).match("key-foo")); + + assertThat(scan.hasNext()).isFalse(); + try { + scan.next(); + fail("Missing NoSuchElementException"); + } catch (NoSuchElementException e) { + assertThat(e).isInstanceOf(NoSuchElementException.class); + } + } + + @Test + public void setSinglePass() throws Exception { + + redis.sadd(key, KeysAndValues.KEYS.toArray(new String[0])); + + ScanIterator scan = ScanIterator.sscan(redis, key, + ScanArgs.Builder.limit(50).match("key-11*")); + + assertThat(scan.hasNext()).isTrue(); + assertThat(scan.hasNext()).isTrue(); + + for (int i = 0; i < 11; i++) { + assertThat(scan.hasNext()).isTrue(); + assertThat(scan.next()).isNotNull(); + } + + assertThat(scan.hasNext()).isFalse(); + } + + @Test + public void setMultiPass() throws Exception { + + redis.sadd(key, KeysAndValues.KEYS.toArray(new String[0])); + + ScanIterator scan = ScanIterator.sscan(redis, key); + + List values = scan.stream().collect(Collectors.toList()); + + assertThat(values).containsAll(values); + } + + @Test + public void zscanShouldThrowNoSuchElementExceptionOnEmpty() throws Exception { + + for (int i = 0; i < KeysAndValues.COUNT; i++) { + redis.zadd(key, ScoredValue.just(i, KeysAndValues.KEYS.get(i))); + } + + + ScanIterator> scan = ScanIterator.zscan(redis, "none", + ScanArgs.Builder.limit(50).match("key-foo")); + + assertThat(scan.hasNext()).isFalse(); + try { + scan.next(); + fail("Missing NoSuchElementException"); + } catch (NoSuchElementException e) { + assertThat(e).isInstanceOf(NoSuchElementException.class); + } + } + + @Test + public void zsetSinglePass() throws Exception { + + for (int i = 0; i < KeysAndValues.COUNT; i++) { + redis.zadd(key, ScoredValue.just(i, KeysAndValues.KEYS.get(i))); + } + + ScanIterator> scan = ScanIterator.zscan(redis, key, + ScanArgs.Builder.limit(50).match("key-11*")); + + assertThat(scan.hasNext()).isTrue(); + assertThat(scan.hasNext()).isTrue(); + + for (int i = 0; i < 11; i++) { + assertThat(scan.hasNext()).isTrue(); + assertThat(scan.next()).isNotNull(); + } + + assertThat(scan.hasNext()).isFalse(); + } + + @Test + public void zsetMultiPass() throws Exception { + + List> expected = new ArrayList<>(); + for (int i = 0; i < KeysAndValues.COUNT; i++) { + ScoredValue scoredValue = ScoredValue.just(i, KeysAndValues.KEYS.get(i)); + expected.add(scoredValue); + redis.zadd(key, scoredValue); + } + + ScanIterator> scan = ScanIterator.zscan(redis, key); + + List> values = scan.stream().collect(Collectors.toList()); + + assertThat(values).containsAll(values); + } +} \ No newline at end of file diff --git a/src/test/java/com/lambdaworks/redis/cluster/ScanIteratorTest.java b/src/test/java/com/lambdaworks/redis/cluster/ScanIteratorTest.java new file mode 100644 index 0000000000..964a3963ff --- /dev/null +++ b/src/test/java/com/lambdaworks/redis/cluster/ScanIteratorTest.java @@ -0,0 +1,253 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.lambdaworks.redis.cluster; + +import static org.assertj.core.api.AssertionsForClassTypes.fail; +import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; + +import java.util.ArrayList; +import java.util.List; +import java.util.NoSuchElementException; +import java.util.stream.Collectors; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import com.lambdaworks.KeysAndValues; +import com.lambdaworks.redis.KeyValue; +import com.lambdaworks.redis.ScanArgs; +import com.lambdaworks.redis.ScanIterator; +import com.lambdaworks.redis.ScoredValue; +import com.lambdaworks.redis.cluster.api.StatefulRedisClusterConnection; +import com.lambdaworks.redis.cluster.api.sync.RedisAdvancedClusterCommands; + +/** + * @author Mark Paluch + */ +public class ScanIteratorTest extends AbstractClusterTest { + + private StatefulRedisClusterConnection connection; + private RedisAdvancedClusterCommands redis; + + @Before + public void before() throws Exception { + + this.connection = clusterClient.connect(); + this.redis = this.connection.sync(); + } + + @After + public void tearDown() throws Exception { + this.connection.close(); + } + + @Test + public void scanShouldThrowNoSuchElementExceptionOnEmpty() throws Exception { + + redis.mset(KeysAndValues.MAP); + + ScanIterator scan = ScanIterator.scan(redis, ScanArgs.Builder.limit(50).match("key-foo")); + + assertThat(scan.hasNext()).isFalse(); + try { + scan.next(); + fail("Missing NoSuchElementException"); + } catch (NoSuchElementException e) { + assertThat(e).isInstanceOf(NoSuchElementException.class); + } + } + + @Test + public void keysSinglePass() throws Exception { + + redis.mset(KeysAndValues.MAP); + + ScanIterator scan = ScanIterator.scan(redis, ScanArgs.Builder.limit(50).match("key-11*")); + + assertThat(scan.hasNext()).isTrue(); + assertThat(scan.hasNext()).isTrue(); + + for (int i = 0; i < 11; i++) { + assertThat(scan.hasNext()).isTrue(); + assertThat(scan.next()).isNotNull(); + } + + assertThat(scan.hasNext()).isFalse(); + } + + @Test + public void keysMultiPass() throws Exception { + + redis.mset(KeysAndValues.MAP); + + ScanIterator scan = ScanIterator.scan(redis); + + List keys = scan.stream().collect(Collectors.toList()); + + assertThat(keys).containsAll(KeysAndValues.KEYS); + } + + @Test + public void hscanShouldThrowNoSuchElementExceptionOnEmpty() throws Exception { + + redis.mset(KeysAndValues.MAP); + + ScanIterator> scan = ScanIterator.hscan(redis, "none", + ScanArgs.Builder.limit(50).match("key-foo")); + + assertThat(scan.hasNext()).isFalse(); + try { + scan.next(); + fail("Missing NoSuchElementException"); + } catch (NoSuchElementException e) { + assertThat(e).isInstanceOf(NoSuchElementException.class); + } + } + + @Test + public void hashSinglePass() throws Exception { + + redis.hmset(key, KeysAndValues.MAP); + + ScanIterator> scan = ScanIterator.hscan(redis, key, + ScanArgs.Builder.limit(50).match("key-11*")); + + assertThat(scan.hasNext()).isTrue(); + assertThat(scan.hasNext()).isTrue(); + + for (int i = 0; i < 11; i++) { + assertThat(scan.hasNext()).isTrue(); + assertThat(scan.next()).isNotNull(); + } + + assertThat(scan.hasNext()).isFalse(); + } + + @Test + public void hashMultiPass() throws Exception { + + redis.hmset(key, KeysAndValues.MAP); + + ScanIterator> scan = ScanIterator.hscan(redis, key); + + List> keys = scan.stream().collect(Collectors.toList()); + + assertThat(keys).containsAll(KeysAndValues.KEYS.stream().map(s -> KeyValue.fromNullable(s, KeysAndValues.MAP.get(s))) + .collect(Collectors.toList())); + } + + @Test + public void sscanShouldThrowNoSuchElementExceptionOnEmpty() throws Exception { + + redis.sadd(key, KeysAndValues.VALUES.toArray(new String[0])); + + ScanIterator scan = ScanIterator.sscan(redis, "none", ScanArgs.Builder.limit(50).match("key-foo")); + + assertThat(scan.hasNext()).isFalse(); + try { + scan.next(); + fail("Missing NoSuchElementException"); + } catch (NoSuchElementException e) { + assertThat(e).isInstanceOf(NoSuchElementException.class); + } + } + + @Test + public void setSinglePass() throws Exception { + + redis.sadd(key, KeysAndValues.KEYS.toArray(new String[0])); + + ScanIterator scan = ScanIterator.sscan(redis, key, ScanArgs.Builder.limit(50).match("key-11*")); + + assertThat(scan.hasNext()).isTrue(); + assertThat(scan.hasNext()).isTrue(); + + for (int i = 0; i < 11; i++) { + assertThat(scan.hasNext()).isTrue(); + assertThat(scan.next()).isNotNull(); + } + + assertThat(scan.hasNext()).isFalse(); + } + + @Test + public void setMultiPass() throws Exception { + + redis.sadd(key, KeysAndValues.KEYS.toArray(new String[0])); + + ScanIterator scan = ScanIterator.sscan(redis, key); + + List values = scan.stream().collect(Collectors.toList()); + + assertThat(values).containsAll(values); + } + + @Test + public void zscanShouldThrowNoSuchElementExceptionOnEmpty() throws Exception { + + for (int i = 0; i < KeysAndValues.COUNT; i++) { + redis.zadd(key, ScoredValue.just(i, KeysAndValues.KEYS.get(i))); + } + + ScanIterator> scan = ScanIterator.zscan(redis, "none", ScanArgs.Builder.limit(50).match("key-foo")); + + assertThat(scan.hasNext()).isFalse(); + try { + scan.next(); + fail("Missing NoSuchElementException"); + } catch (NoSuchElementException e) { + assertThat(e).isInstanceOf(NoSuchElementException.class); + } + } + + @Test + public void zsetSinglePass() throws Exception { + + for (int i = 0; i < KeysAndValues.COUNT; i++) { + redis.zadd(key, ScoredValue.just(i, KeysAndValues.KEYS.get(i))); + } + + ScanIterator> scan = ScanIterator.zscan(redis, key, ScanArgs.Builder.limit(50).match("key-11*")); + + assertThat(scan.hasNext()).isTrue(); + assertThat(scan.hasNext()).isTrue(); + + for (int i = 0; i < 11; i++) { + assertThat(scan.hasNext()).isTrue(); + assertThat(scan.next()).isNotNull(); + } + + assertThat(scan.hasNext()).isFalse(); + } + + @Test + public void zsetMultiPass() throws Exception { + + List> expected = new ArrayList<>(); + for (int i = 0; i < KeysAndValues.COUNT; i++) { + ScoredValue scoredValue = ScoredValue.just(i, KeysAndValues.KEYS.get(i)); + expected.add(scoredValue); + redis.zadd(key, scoredValue); + } + + ScanIterator> scan = ScanIterator.zscan(redis, key); + + List> values = scan.stream().collect(Collectors.toList()); + + assertThat(values).containsAll(values); + } +} \ No newline at end of file From ee70da3d1f970b4591752e302375a819feea89cf Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Sun, 13 Nov 2016 19:48:48 +0100 Subject: [PATCH 070/808] Fix compiler ambiguities on JDK 8u31 --- .../com/lambdaworks/redis/dynamic/ReactiveTypeAdapters.java | 6 +++--- .../lambdaworks/redis/dynamic/ReactiveTypeAdaptersTest.java | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/lambdaworks/redis/dynamic/ReactiveTypeAdapters.java b/src/main/java/com/lambdaworks/redis/dynamic/ReactiveTypeAdapters.java index 759ae80f7b..48e0b7f539 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/ReactiveTypeAdapters.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/ReactiveTypeAdapters.java @@ -202,7 +202,7 @@ public enum RxJava1SingleToMonoAdapter implements Function, Mono> { @Override public Mono apply(Single source) { - return Mono.defer(() -> Mono.from(RxReactiveStreams.toPublisher(source))); + return Mono.defer(() -> Mono.from((Publisher) RxReactiveStreams.toPublisher(source))); } } @@ -267,7 +267,7 @@ public enum RxJava1ObservableToMonoAdapter implements Function, Mo @Override public Mono apply(Observable source) { - return Mono.defer(() -> Mono.from(RxReactiveStreams.toPublisher(source))); + return Mono.defer(() -> Mono.from((Publisher) RxReactiveStreams.toPublisher(source))); } } @@ -280,7 +280,7 @@ public enum RxJava1ObservableToFluxAdapter implements Function, Fl @Override public Flux apply(Observable source) { - return Flux.defer(() -> Flux.from(RxReactiveStreams.toPublisher(source))); + return Flux.defer(() -> Flux.from((Publisher) RxReactiveStreams.toPublisher(source))); } } diff --git a/src/test/java/com/lambdaworks/redis/dynamic/ReactiveTypeAdaptersTest.java b/src/test/java/com/lambdaworks/redis/dynamic/ReactiveTypeAdaptersTest.java index f5761c903f..5e8cf8c0bc 100644 --- a/src/test/java/com/lambdaworks/redis/dynamic/ReactiveTypeAdaptersTest.java +++ b/src/test/java/com/lambdaworks/redis/dynamic/ReactiveTypeAdaptersTest.java @@ -113,7 +113,7 @@ public void toWrapperShouldConvertRxJava2FlowableToFlux() { public void toWrapperShouldCastRxJava2FlowableToPublisher() { io.reactivex.Flowable foo = io.reactivex.Flowable.just("foo"); - assertThat(conversionService.convert(foo, Publisher.class)).isInstanceOf(Flux.class); + assertThat(conversionService.convert(foo, Publisher.class)).isInstanceOf(Flowable.class); } @Test From 724e8f8f885f6ad3f9d406ad901847b509f56b0c Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Sun, 13 Nov 2016 19:56:17 +0100 Subject: [PATCH 071/808] Test fix --- .../com/lambdaworks/redis/dynamic/ReactiveTypeAdaptersTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/lambdaworks/redis/dynamic/ReactiveTypeAdaptersTest.java b/src/test/java/com/lambdaworks/redis/dynamic/ReactiveTypeAdaptersTest.java index 5e8cf8c0bc..3c99cd8a44 100644 --- a/src/test/java/com/lambdaworks/redis/dynamic/ReactiveTypeAdaptersTest.java +++ b/src/test/java/com/lambdaworks/redis/dynamic/ReactiveTypeAdaptersTest.java @@ -113,7 +113,7 @@ public void toWrapperShouldConvertRxJava2FlowableToFlux() { public void toWrapperShouldCastRxJava2FlowableToPublisher() { io.reactivex.Flowable foo = io.reactivex.Flowable.just("foo"); - assertThat(conversionService.convert(foo, Publisher.class)).isInstanceOf(Flowable.class); + assertThat(conversionService.convert(foo, Publisher.class)).isInstanceOf(Publisher.class); } @Test From d3800903c60d82fe5a26b66155bac8d50125b0aa Mon Sep 17 00:00:00 2001 From: Takashi Takebayashi Date: Thu, 24 Nov 2016 13:49:18 +0900 Subject: [PATCH 072/808] Update code samples in readme to Lettuce 4.0 #410 Fixes #409 --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 0a10f778bf..d4ceedb753 100644 --- a/README.md +++ b/README.md @@ -111,9 +111,10 @@ Basic Usage ----------- ```java -RedisClient client = RedisClient.create("redis://localhost") -RedisStringsConnection connection = client.connect() -String value = connection.get("key") +RedisClient client = RedisClient.create("redis://localhost"); +StatefulRedisConnection connection = client.connect(); +RedisStringCommands sync = connection.sync(); +String value = sync.get("key"); ``` Each Redis command is implemented by one or more methods with names identical From 90b886487b03d4ba3254648b6cd484d1ca076762 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Wed, 23 Nov 2016 13:01:53 +0100 Subject: [PATCH 073/808] Simplify NodeSelection implementation #408 Improve reuse of AbstractNodeSelection by providing template methods. Remove (Static|Dynamic)(Sync|Async)NodeSelection and replace methods with extractor functions. Extract ClusterFutureSyncInvocationHandler for reuse. --- .../redis/cluster/AbstractNodeSelection.java | 70 ++++-- .../ClusterDistributionChannelWriter.java | 8 + .../ClusterFutureSyncInvocationHandler.java | 205 ++++++++++++++++++ .../cluster/DynamicAsyncNodeSelection.java | 68 ------ .../redis/cluster/DynamicNodeSelection.java | 32 ++- .../cluster/DynamicSyncNodeSelection.java | 68 ------ .../NodeSelectionInvocationHandler.java | 69 ++++-- .../redis/cluster/ReactiveExecutionsImpl.java | 51 +++++ ...RedisAdvancedClusterAsyncCommandsImpl.java | 28 ++- .../StatefulRedisClusterConnectionImpl.java | 164 +------------- .../cluster/StaticAsyncNodeSelection.java | 68 ------ .../redis/cluster/StaticNodeSelection.java | 33 ++- .../cluster/StaticSyncNodeSelection.java | 68 ------ .../redis/cluster/SyncExecutionsImpl.java | 1 + .../cluster/api/NodeSelectionSupport.java | 4 - .../api/StatefulRedisClusterConnection.java | 2 +- .../api/reactive/ReactiveExecutions.java | 44 ++++ 17 files changed, 477 insertions(+), 506 deletions(-) create mode 100644 src/main/java/com/lambdaworks/redis/cluster/ClusterFutureSyncInvocationHandler.java delete mode 100644 src/main/java/com/lambdaworks/redis/cluster/DynamicAsyncNodeSelection.java delete mode 100644 src/main/java/com/lambdaworks/redis/cluster/DynamicSyncNodeSelection.java create mode 100644 src/main/java/com/lambdaworks/redis/cluster/ReactiveExecutionsImpl.java delete mode 100644 src/main/java/com/lambdaworks/redis/cluster/StaticAsyncNodeSelection.java delete mode 100644 src/main/java/com/lambdaworks/redis/cluster/StaticSyncNodeSelection.java create mode 100644 src/main/java/com/lambdaworks/redis/cluster/api/reactive/ReactiveExecutions.java diff --git a/src/main/java/com/lambdaworks/redis/cluster/AbstractNodeSelection.java b/src/main/java/com/lambdaworks/redis/cluster/AbstractNodeSelection.java index cbe789b428..be1e8f2cdd 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/AbstractNodeSelection.java +++ b/src/main/java/com/lambdaworks/redis/cluster/AbstractNodeSelection.java @@ -15,14 +15,13 @@ */ package com.lambdaworks.redis.cluster; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; -import com.lambdaworks.redis.RedisURI; import com.lambdaworks.redis.api.StatefulRedisConnection; import com.lambdaworks.redis.cluster.api.NodeSelectionSupport; -import com.lambdaworks.redis.cluster.api.StatefulRedisClusterConnection; import com.lambdaworks.redis.cluster.models.partitions.RedisClusterNode; /** @@ -33,44 +32,69 @@ * @param Command command interface type to invoke multi-node operations. * @param Key type. * @param Value type. + * @since 4.1 * @author Mark Paluch */ abstract class AbstractNodeSelection implements NodeSelectionSupport { - protected ClusterDistributionChannelWriter writer; - protected StatefulRedisClusterConnection globalConnection; + @Override + public Map asMap() { - private ClusterConnectionProvider.Intent intent; + List list = nodes().stream().collect(Collectors.toList()); + Map map = new HashMap<>(); - public AbstractNodeSelection(StatefulRedisClusterConnection globalConnection, ClusterConnectionProvider.Intent intent) { - this.globalConnection = globalConnection; - this.intent = intent; - writer = ((StatefulRedisClusterConnectionImpl) globalConnection).getClusterDistributionChannelWriter(); - } + list.forEach((key) -> map.put(key, getApi(key))); - protected StatefulRedisConnection getConnection(RedisClusterNode redisClusterNode) { - RedisURI uri = redisClusterNode.getUri(); - return writer.getClusterConnectionProvider().getConnection(intent, uri.getHost(), uri.getPort()); + return map; } - /** - * @return List of involved nodes - */ - protected abstract List nodes(); - @Override public int size() { return nodes().size(); } - public Map> statefulMap() { - return nodes().stream().collect( - Collectors.toMap(redisClusterNode -> redisClusterNode, redisClusterNode1 -> getConnection(redisClusterNode1))); - } - @Override public RedisClusterNode node(int index) { return nodes().get(index); } + // This method is never called, the value is supplied by AOP magic. + @Override + public CMD commands() { + return null; + } + + @Override + public API commands(int index) { + return getApi(node(index)); + } + + /** + * + * @return {@link Map} between a {@link RedisClusterNode} to its actual {@link StatefulRedisConnection}. + */ + protected Map> statefulMap() { + return nodes().stream().collect(Collectors.toMap(redisClusterNode -> redisClusterNode, this::getConnection)); + } + + /** + * Template method to be implemented by implementing classes to obtain a {@link StatefulRedisConnection}. + * + * @param redisClusterNode must not be {@literal null}. + * @return + */ + protected abstract StatefulRedisConnection getConnection(RedisClusterNode redisClusterNode); + + /** + * Template method to be implemented by implementing classes to obtain a the API object given a {@link RedisClusterNode}. + * + * @param redisClusterNode must not be {@literal null}. + * @return + */ + protected abstract API getApi(RedisClusterNode redisClusterNode); + + /** + * @return List of involved nodes + */ + protected abstract List nodes(); } diff --git a/src/main/java/com/lambdaworks/redis/cluster/ClusterDistributionChannelWriter.java b/src/main/java/com/lambdaworks/redis/cluster/ClusterDistributionChannelWriter.java index 9513d69529..b6fd201ae5 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/ClusterDistributionChannelWriter.java +++ b/src/main/java/com/lambdaworks/redis/cluster/ClusterDistributionChannelWriter.java @@ -41,6 +41,7 @@ class ClusterDistributionChannelWriter implements RedisChannelWriter { private ClusterConnectionProvider clusterConnectionProvider; private boolean closed = false; + private volatile Partitions partitions; ClusterDistributionChannelWriter(ClientOptions clientOptions, RedisChannelWriter defaultWriter, ClusterEventListener clusterEventListener, EventExecutorGroup eventExecutors) { @@ -226,11 +227,18 @@ public void setClusterConnectionProvider(ClusterConnectionProvider clusterConnec } public void setPartitions(Partitions partitions) { + + this.partitions = partitions; + if (clusterConnectionProvider != null) { clusterConnectionProvider.setPartitions(partitions); } } + public Partitions getPartitions(){ + return partitions; + } + /** * Set from which nodes data is read. The setting is used as default for read operations on this connection. See the * documentation for {@link ReadFrom} for more information. diff --git a/src/main/java/com/lambdaworks/redis/cluster/ClusterFutureSyncInvocationHandler.java b/src/main/java/com/lambdaworks/redis/cluster/ClusterFutureSyncInvocationHandler.java new file mode 100644 index 0000000000..0a249e7695 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/cluster/ClusterFutureSyncInvocationHandler.java @@ -0,0 +1,205 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.lambdaworks.redis.cluster; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Predicate; + +import com.lambdaworks.redis.LettuceFutures; +import com.lambdaworks.redis.RedisFuture; +import com.lambdaworks.redis.api.StatefulConnection; +import com.lambdaworks.redis.api.StatefulRedisConnection; +import com.lambdaworks.redis.api.sync.RedisCommands; +import com.lambdaworks.redis.cluster.api.NodeSelectionSupport; +import com.lambdaworks.redis.cluster.api.StatefulRedisClusterConnection; +import com.lambdaworks.redis.cluster.api.sync.RedisClusterCommands; +import com.lambdaworks.redis.cluster.models.partitions.RedisClusterNode; +import com.lambdaworks.redis.internal.AbstractInvocationHandler; + +/** + * Invocation-handler to synchronize API calls which use Futures as backend. This class leverages the need to implement a full + * sync class which just delegates every request. + * + * @param Key type. + * @param Value type. + * @author Mark Paluch + * @since 3.0 + */ +@SuppressWarnings("unchecked") +class ClusterFutureSyncInvocationHandler extends AbstractInvocationHandler { + + private final StatefulConnection connection; + private final Class asyncCommandsInterface; + private final Class nodeSelectionInterface; + private final Class nodeSelectionCommandsInterface; + private final Object asyncApi; + + private final Map apiMethodCache = new ConcurrentHashMap<>(RedisClusterCommands.class.getMethods().length, + 1); + private final Map connectionMethodCache = new ConcurrentHashMap<>(5, 1); + + private static final Constructor LOOKUP_CONSTRUCTOR; + + static { + try { + LOOKUP_CONSTRUCTOR = MethodHandles.Lookup.class.getDeclaredConstructor(Class.class, int.class); + if (!LOOKUP_CONSTRUCTOR.isAccessible()) { + LOOKUP_CONSTRUCTOR.setAccessible(true); + } + } catch (NoSuchMethodException exp) { + // should be impossible, but... + throw new IllegalStateException(exp); + } + } + + ClusterFutureSyncInvocationHandler(StatefulConnection connection, Class asyncCommandsInterface, + Class nodeSelectionInterface, Class nodeSelectionCommandsInterface, Object asyncApi) { + this.connection = connection; + this.asyncCommandsInterface = asyncCommandsInterface; + this.nodeSelectionInterface = nodeSelectionInterface; + this.nodeSelectionCommandsInterface = nodeSelectionCommandsInterface; + this.asyncApi = asyncApi; + } + + /** + * + * @see AbstractInvocationHandler#handleInvocation(Object, Method, Object[]) + */ + @Override + protected Object handleInvocation(Object proxy, Method method, Object[] args) throws Throwable { + + try { + + if (method.isDefault()) { + return getDefaultMethodHandle(method).bindTo(proxy).invokeWithArguments(args); + } + + if (method.getName().equals("getConnection") && args.length > 0) { + Method targetMethod = connectionMethodCache.computeIfAbsent(method, key -> { + try { + return connection.getClass().getMethod(key.getName(), key.getParameterTypes()); + } catch (NoSuchMethodException e) { + throw new IllegalStateException(e); + } + }); + + Object result = targetMethod.invoke(connection, args); + if (result instanceof StatefulRedisClusterConnection) { + StatefulRedisClusterConnection connection = (StatefulRedisClusterConnection) result; + return connection.sync(); + } + + if (result instanceof StatefulRedisConnection) { + StatefulRedisConnection connection = (StatefulRedisConnection) result; + return connection.sync(); + } + } + + if (method.getName().equals("readonly") && args.length == 1) { + return nodes((Predicate) args[0], ClusterConnectionProvider.Intent.READ, false); + } + + if (method.getName().equals("nodes") && args.length == 1) { + return nodes((Predicate) args[0], ClusterConnectionProvider.Intent.WRITE, false); + } + + if (method.getName().equals("nodes") && args.length == 2) { + return nodes((Predicate) args[0], ClusterConnectionProvider.Intent.WRITE, (Boolean) args[1]); + } + + Method targetMethod = apiMethodCache.computeIfAbsent(method, key -> { + + try { + return asyncApi.getClass().getMethod(key.getName(), key.getParameterTypes()); + } catch (NoSuchMethodException e) { + throw new IllegalStateException(e); + } + }); + + Object result = targetMethod.invoke(asyncApi, args); + + if (result instanceof RedisFuture) { + RedisFuture command = (RedisFuture) result; + if (!method.getName().equals("exec") && !method.getName().equals("multi")) { + if (connection instanceof StatefulRedisConnection && ((StatefulRedisConnection) connection).isMulti()) { + return null; + } + } + return LettuceFutures.awaitOrCancel(command, connection.getTimeout(), connection.getTimeoutUnit()); + } + + return result; + + } catch (InvocationTargetException e) { + throw e.getTargetException(); + } + } + + protected Object nodes(Predicate predicate, ClusterConnectionProvider.Intent intent, boolean dynamic) { + + NodeSelectionSupport, ?> selection = null; + + if (connection instanceof StatefulRedisClusterConnectionImpl) { + + StatefulRedisClusterConnectionImpl impl = (StatefulRedisClusterConnectionImpl) connection; + + if (dynamic) { + selection = new DynamicNodeSelection, Object, K, V>( + impl.getClusterDistributionChannelWriter(), predicate, intent, StatefulRedisConnection::sync); + } else { + + selection = new StaticNodeSelection, Object, K, V>( + impl.getClusterDistributionChannelWriter(), predicate, intent, StatefulRedisConnection::sync); + } + } + + if (connection instanceof StatefulRedisClusterPubSubConnectionImpl) { + + StatefulRedisClusterPubSubConnectionImpl impl = (StatefulRedisClusterPubSubConnectionImpl) connection; + selection = new StaticNodeSelection, Object, K, V>(impl.getClusterDistributionChannelWriter(), + predicate, intent, StatefulRedisConnection::sync); + } + + NodeSelectionInvocationHandler h = new NodeSelectionInvocationHandler((AbstractNodeSelection) selection, + asyncCommandsInterface, connection.getTimeout(), connection.getTimeoutUnit()); + return Proxy.newProxyInstance(NodeSelectionSupport.class.getClassLoader(), + new Class[] { nodeSelectionCommandsInterface, nodeSelectionInterface }, h); + } + + private static MethodHandles.Lookup privateMethodHandleLookup(Class declaringClass) { + try { + return LOOKUP_CONSTRUCTOR.newInstance(declaringClass, MethodHandles.Lookup.PRIVATE); + } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { + throw new IllegalStateException(e); + } + } + + private static MethodHandle getDefaultMethodHandle(Method method) { + Class declaringClass = method.getDeclaringClass(); + try { + return privateMethodHandleLookup(declaringClass).unreflectSpecial(method, declaringClass); + } catch (IllegalAccessException e) { + throw new IllegalArgumentException("Did not pass in an interface method: " + method); + } + } +} diff --git a/src/main/java/com/lambdaworks/redis/cluster/DynamicAsyncNodeSelection.java b/src/main/java/com/lambdaworks/redis/cluster/DynamicAsyncNodeSelection.java deleted file mode 100644 index 9952c45420..0000000000 --- a/src/main/java/com/lambdaworks/redis/cluster/DynamicAsyncNodeSelection.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2011-2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.lambdaworks.redis.cluster; - -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.function.Predicate; -import java.util.stream.Collectors; - -import com.lambdaworks.redis.api.async.RedisAsyncCommands; -import com.lambdaworks.redis.cluster.api.StatefulRedisClusterConnection; -import com.lambdaworks.redis.cluster.models.partitions.RedisClusterNode; - -/** - * @param Command command interface type to invoke multi-node operations. - * @param Key type. - * @param Value type. - * @author Mark Paluch - */ -class DynamicAsyncNodeSelection extends DynamicNodeSelection, CMD, K, V> { - - public DynamicAsyncNodeSelection(StatefulRedisClusterConnection globalConnection, - Predicate selector, ClusterConnectionProvider.Intent intent) { - super(globalConnection, selector, intent); - } - - public Iterator> iterator() { - List list = nodes().stream().collect(Collectors.toList()); - return list.stream().map(node -> getConnection(node).async()).iterator(); - } - - @Override - public RedisAsyncCommands commands(int index) { - return statefulMap().get(nodes().get(index)).async(); - } - - @Override - public Map> asMap() { - - List list = nodes().stream().collect(Collectors.toList()); - Map> map = new HashMap<>(); - - list.forEach((key) -> map.put(key, getConnection(key).async())); - - return map; - } - - // This method is never called, the value is supplied by AOP magic. - @Override - public CMD commands() { - return null; - } -} diff --git a/src/main/java/com/lambdaworks/redis/cluster/DynamicNodeSelection.java b/src/main/java/com/lambdaworks/redis/cluster/DynamicNodeSelection.java index a290dade50..518d10b68e 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/DynamicNodeSelection.java +++ b/src/main/java/com/lambdaworks/redis/cluster/DynamicNodeSelection.java @@ -16,10 +16,12 @@ package com.lambdaworks.redis.cluster; import java.util.List; +import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Collectors; -import com.lambdaworks.redis.cluster.api.StatefulRedisClusterConnection; +import com.lambdaworks.redis.RedisURI; +import com.lambdaworks.redis.api.StatefulRedisConnection; import com.lambdaworks.redis.cluster.models.partitions.RedisClusterNode; /** @@ -31,18 +33,36 @@ * @param Value type. * @author Mark Paluch */ -abstract class DynamicNodeSelection extends AbstractNodeSelection { +class DynamicNodeSelection extends AbstractNodeSelection { + private final ClusterDistributionChannelWriter writer; private final Predicate selector; + private final ClusterConnectionProvider.Intent intent; + private final Function, API> apiExtractor; + + public DynamicNodeSelection(ClusterDistributionChannelWriter writer, Predicate selector, + ClusterConnectionProvider.Intent intent, Function, API> apiExtractor) { - public DynamicNodeSelection(StatefulRedisClusterConnection globalConnection, Predicate selector, - ClusterConnectionProvider.Intent intent) { - super(globalConnection, intent); this.selector = selector; + this.intent = intent; + this.writer = writer; + this.apiExtractor = apiExtractor; + } + + @Override + protected StatefulRedisConnection getConnection(RedisClusterNode redisClusterNode) { + + RedisURI uri = redisClusterNode.getUri(); + return writer.getClusterConnectionProvider().getConnection(intent, uri.getHost(), uri.getPort()); + } + + @Override + protected API getApi(RedisClusterNode redisClusterNode) { + return apiExtractor.apply(getConnection(redisClusterNode)); } @Override protected List nodes() { - return globalConnection.getPartitions().getPartitions().stream().filter(selector).collect(Collectors.toList()); + return writer.getPartitions().getPartitions().stream().filter(selector).collect(Collectors.toList()); } } diff --git a/src/main/java/com/lambdaworks/redis/cluster/DynamicSyncNodeSelection.java b/src/main/java/com/lambdaworks/redis/cluster/DynamicSyncNodeSelection.java deleted file mode 100644 index f8d7a5f783..0000000000 --- a/src/main/java/com/lambdaworks/redis/cluster/DynamicSyncNodeSelection.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2011-2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.lambdaworks.redis.cluster; - -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.function.Predicate; -import java.util.stream.Collectors; - -import com.lambdaworks.redis.api.sync.RedisCommands; -import com.lambdaworks.redis.cluster.api.StatefulRedisClusterConnection; -import com.lambdaworks.redis.cluster.models.partitions.RedisClusterNode; - -/** - * @param Command command interface type to invoke multi-node operations. - * @param Key type. - * @param Value type. - * @author Mark Paluch - */ -class DynamicSyncNodeSelection extends DynamicNodeSelection, CMD, K, V> { - - public DynamicSyncNodeSelection(StatefulRedisClusterConnection globalConnection, - Predicate selector, ClusterConnectionProvider.Intent intent) { - super(globalConnection, selector, intent); - } - - public Iterator> iterator() { - List list = nodes().stream().collect(Collectors.toList()); - return list.stream().map(node -> getConnection(node).sync()).iterator(); - } - - @Override - public RedisCommands commands(int index) { - return statefulMap().get(nodes().get(index)).sync(); - } - - @Override - public Map> asMap() { - - List list = nodes().stream().collect(Collectors.toList()); - Map> map = new HashMap<>(); - - list.forEach((key) -> map.put(key, getConnection(key).sync())); - - return map; - } - - // This method is never called, the value is supplied by AOP magic. - @Override - public CMD commands() { - return null; - } -} diff --git a/src/main/java/com/lambdaworks/redis/cluster/NodeSelectionInvocationHandler.java b/src/main/java/com/lambdaworks/redis/cluster/NodeSelectionInvocationHandler.java index ca70b110c4..a9077ae8f3 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/NodeSelectionInvocationHandler.java +++ b/src/main/java/com/lambdaworks/redis/cluster/NodeSelectionInvocationHandler.java @@ -26,15 +26,15 @@ import com.lambdaworks.redis.RedisCommandTimeoutException; import com.lambdaworks.redis.api.StatefulRedisConnection; import com.lambdaworks.redis.cluster.api.NodeSelectionSupport; -import com.lambdaworks.redis.cluster.api.async.RedisClusterAsyncCommands; import com.lambdaworks.redis.cluster.models.partitions.RedisClusterNode; import com.lambdaworks.redis.internal.AbstractInvocationHandler; import com.lambdaworks.redis.internal.LettuceAssert; /** * Invocation handler to trigger commands on multiple connections and return a holder for the values. - * + * * @author Mark Paluch + * @since 4.4 */ class NodeSelectionInvocationHandler extends AbstractInvocationHandler { @@ -42,9 +42,10 @@ class NodeSelectionInvocationHandler extends AbstractInvocationHandler { private final Map nodeSelectionMethods = new ConcurrentHashMap<>(); private final Map connectionMethod = new ConcurrentHashMap<>(); + private final Class commandsInterface; private AbstractNodeSelection selection; - private boolean sync; + private ExecutionModel executionModel; private long timeout; private TimeUnit unit; @@ -57,55 +58,75 @@ class NodeSelectionInvocationHandler extends AbstractInvocationHandler { } } - public NodeSelectionInvocationHandler(AbstractNodeSelection selection) { - this(selection, false, 0, null); + NodeSelectionInvocationHandler(AbstractNodeSelection selection, Class commandsInterface, + ExecutionModel executionModel) { + this(selection, commandsInterface, 0, null, executionModel); } - public NodeSelectionInvocationHandler(AbstractNodeSelection selection, boolean sync, long timeout, + NodeSelectionInvocationHandler(AbstractNodeSelection selection, Class commandsInterface, long timeout, TimeUnit unit) { - if (sync) { + this(selection, commandsInterface, timeout, unit, ExecutionModel.SYNC); + } + + private NodeSelectionInvocationHandler(AbstractNodeSelection selection, Class commandsInterface, + long timeout, TimeUnit unit, ExecutionModel executionModel) { + + if (executionModel == ExecutionModel.SYNC) { LettuceAssert.isTrue(timeout > 0, "Timeout must be greater 0 when using sync mode"); LettuceAssert.notNull(unit, "Unit must not be null when using sync mode"); } + LettuceAssert.notNull(executionModel, "ExecutionModel must not be null"); + this.selection = selection; - this.sync = sync; + this.commandsInterface = commandsInterface; this.unit = unit; this.timeout = timeout; + this.executionModel = executionModel; } @Override - @SuppressWarnings("rawtypes") + @SuppressWarnings({ "rawtypes", "unchecked" }) protected Object handleInvocation(Object proxy, Method method, Object[] args) throws Throwable { try { - Method targetMethod = findMethod(RedisClusterAsyncCommands.class, method, connectionMethod); + Method targetMethod = findMethod(commandsInterface, method, connectionMethod); Map> connections = new HashMap<>(selection.size(), 1); connections.putAll(selection.statefulMap()); if (targetMethod != null) { - Map> executions = new HashMap<>(); + Map executions = new HashMap<>(); + for (Map.Entry> entry : connections.entrySet()) { - CompletionStage result = (CompletionStage) targetMethod.invoke(entry.getValue().async(), args); + StatefulRedisConnection connection = entry.getValue(); + Object result = targetMethod.invoke( + executionModel == ExecutionModel.REACTIVE ? connection.reactive() : connection.async(), args); + executions.put(entry.getKey(), result); } - if (sync) { - if (!awaitAll(timeout, unit, executions.values())) { - throw createTimeoutException(executions); + if (executionModel == ExecutionModel.SYNC) { + + Map> asyncExecutions = (Map) executions; + if (!awaitAll(timeout, unit, asyncExecutions.values())) { + throw createTimeoutException(asyncExecutions); } - if (atLeastOneFailed(executions)) { - throw createExecutionException(executions); + if (atLeastOneFailed(asyncExecutions)) { + throw createExecutionException(asyncExecutions); } - return new SyncExecutionsImpl(executions); + return new SyncExecutionsImpl(asyncExecutions); + } + + if (executionModel == ExecutionModel.REACTIVE) { + return new ReactiveExecutionsImpl(executions); } - return new AsyncExecutionsImpl<>((Map) executions); + return new AsyncExecutionsImpl(executions); } if (method.getName().equals("commands") && args.length == 0) { @@ -152,8 +173,7 @@ public static boolean awaitAll(long timeout, TimeUnit unit, Collection> executions) { return executions.values().stream() - .filter(completionStage -> completionStage.toCompletableFuture().isCompletedExceptionally()).findFirst() - .isPresent(); + .anyMatch(completionStage -> completionStage.toCompletableFuture().isCompletedExceptionally()); } private RedisCommandTimeoutException createTimeoutException(Map> executions) { @@ -197,8 +217,7 @@ private RedisCommandExecutionException createExecutionException(Map notFinished) { - return String.join(", ", - notFinished.stream().map(redisClusterNode -> getDescriptor(redisClusterNode)).collect(Collectors.toList())); + return String.join(", ", notFinished.stream().map(this::getDescriptor).collect(Collectors.toList())); } private String getDescriptor(RedisClusterNode redisClusterNode) { @@ -234,4 +253,8 @@ private Method findMethod(Class type, Method method, Map cach cache.put(method, NULL_MARKER_METHOD); return null; } + + enum ExecutionModel { + SYNC, ASYNC, REACTIVE; + } } diff --git a/src/main/java/com/lambdaworks/redis/cluster/ReactiveExecutionsImpl.java b/src/main/java/com/lambdaworks/redis/cluster/ReactiveExecutionsImpl.java new file mode 100644 index 0000000000..9860f69b3b --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/cluster/ReactiveExecutionsImpl.java @@ -0,0 +1,51 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.lambdaworks.redis.cluster; + +import java.util.Collection; +import java.util.Map; + +import com.lambdaworks.redis.cluster.api.reactive.ReactiveExecutions; +import com.lambdaworks.redis.cluster.models.partitions.RedisClusterNode; + +import org.reactivestreams.Publisher; +import reactor.core.publisher.Flux; +import rx.Observable; + +/** + * Default implementation of {@link ReactiveExecutions}. + * + * @author Mark Paluch + * @since 4.4 + */ +class ReactiveExecutionsImpl implements ReactiveExecutions { + + private Map> executions; + + public ReactiveExecutionsImpl(Map> executions) { + this.executions = executions; + } + + @Override + public Flux flux() { + return Flux.merge(executions.values()); + } + + @Override + public Collection nodes() { + return executions.keySet(); + } +} diff --git a/src/main/java/com/lambdaworks/redis/cluster/RedisAdvancedClusterAsyncCommandsImpl.java b/src/main/java/com/lambdaworks/redis/cluster/RedisAdvancedClusterAsyncCommandsImpl.java index cb0867bd86..c059510d34 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/RedisAdvancedClusterAsyncCommandsImpl.java +++ b/src/main/java/com/lambdaworks/redis/cluster/RedisAdvancedClusterAsyncCommandsImpl.java @@ -17,6 +17,7 @@ import static com.lambdaworks.redis.cluster.ClusterScanSupport.asyncClusterKeyScanCursorMapper; import static com.lambdaworks.redis.cluster.ClusterScanSupport.asyncClusterStreamScanCursorMapper; +import static com.lambdaworks.redis.cluster.NodeSelectionInvocationHandler.ExecutionModel.ASYNC; import static com.lambdaworks.redis.cluster.models.partitions.RedisClusterNode.NodeFlag.MASTER; import java.lang.reflect.Proxy; @@ -240,10 +241,10 @@ public RedisFuture msetnx(Map map) { } return new PipelinedRedisFuture<>(executions, objectPipelinedRedisFuture -> { - + for (RedisFuture listRedisFuture : executions.values()) { Boolean b = MultiNodeExecution.execute(() -> listRedisFuture.get()); - if (b == null || !b) { + if (b == null || !b) { return false; } } @@ -343,7 +344,7 @@ public RedisFuture> keys(K pattern) { return new PipelinedRedisFuture<>(executions, objectPipelinedRedisFuture -> { List result = new ArrayList<>(); for (RedisFuture> future : executions.values()) { - result.addAll(MultiNodeExecution.execute(() -> future.get())); + result.addAll(MultiNodeExecution.execute(future::get)); } return result; }); @@ -410,8 +411,8 @@ protected Map> executeOnMasters( * @param result type * @return map of a key (counter) and commands. */ - protected Map> executeOnNodes( - Function, RedisFuture> function, Function filter) { + protected Map> executeOnNodes(Function, RedisFuture> function, + Function filter) { Map> executions = new HashMap<>(); for (RedisClusterNode redisClusterNode : getStatefulConnection().getPartitions()) { @@ -474,15 +475,19 @@ protected AsyncNodeSelection nodes(Predicate predicate, NodeSelectionSupport, ?> selection; + StatefulRedisClusterConnectionImpl impl = (StatefulRedisClusterConnectionImpl) connection; if (dynamic) { - selection = new DynamicAsyncNodeSelection<>(getStatefulConnection(), predicate, intent); + selection = new DynamicNodeSelection, Object, K, V>( + impl.getClusterDistributionChannelWriter(), predicate, intent, StatefulRedisConnection::async); } else { - selection = new StaticAsyncNodeSelection<>(getStatefulConnection(), predicate, intent); + selection = new StaticNodeSelection, Object, K, V>( + impl.getClusterDistributionChannelWriter(), predicate, intent, StatefulRedisConnection::async); } - NodeSelectionInvocationHandler h = new NodeSelectionInvocationHandler((AbstractNodeSelection) selection); - return (AsyncNodeSelection) Proxy.newProxyInstance(NodeSelectionSupport.class.getClassLoader(), new Class[] { - NodeSelectionAsyncCommands.class, AsyncNodeSelection.class }, h); + NodeSelectionInvocationHandler h = new NodeSelectionInvocationHandler((AbstractNodeSelection) selection, + RedisClusterAsyncCommands.class, ASYNC); + return (AsyncNodeSelection) Proxy.newProxyInstance(NodeSelectionSupport.class.getClassLoader(), + new Class[] { NodeSelectionAsyncCommands.class, AsyncNodeSelection.class }, h); } @Override @@ -504,7 +509,7 @@ public RedisFuture> scan(ScanCursor scanCursor, ScanArgs scanAr @Override public RedisFuture> scan(ScanCursor scanCursor) { - return clusterScan(scanCursor, (connection, cursor) -> connection.scan(cursor), asyncClusterKeyScanCursorMapper()); + return clusterScan(scanCursor, RedisKeyAsyncCommands::scan, asyncClusterKeyScanCursorMapper()); } @Override @@ -553,5 +558,4 @@ static RedisFuture clusterScan(StatefulRedisClus RedisFuture scanCursor = scanFunction.apply(connection.getConnection(currentNodeId).async(), continuationCursor); return mapper.map(nodeIds, currentNodeId, scanCursor); } - } diff --git a/src/main/java/com/lambdaworks/redis/cluster/StatefulRedisClusterConnectionImpl.java b/src/main/java/com/lambdaworks/redis/cluster/StatefulRedisClusterConnectionImpl.java index ce123aaf02..4a2ca950af 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/StatefulRedisClusterConnectionImpl.java +++ b/src/main/java/com/lambdaworks/redis/cluster/StatefulRedisClusterConnectionImpl.java @@ -19,30 +19,23 @@ import static com.lambdaworks.redis.protocol.CommandType.READONLY; import static com.lambdaworks.redis.protocol.CommandType.READWRITE; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.reflect.*; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Proxy; import java.util.concurrent.TimeUnit; import java.util.function.Consumer; -import java.util.function.Predicate; import com.lambdaworks.redis.*; import com.lambdaworks.redis.api.StatefulRedisConnection; -import com.lambdaworks.redis.api.sync.RedisCommands; -import com.lambdaworks.redis.cluster.api.NodeSelectionSupport; import com.lambdaworks.redis.cluster.api.StatefulRedisClusterConnection; import com.lambdaworks.redis.cluster.api.async.RedisAdvancedClusterAsyncCommands; +import com.lambdaworks.redis.cluster.api.async.RedisClusterAsyncCommands; import com.lambdaworks.redis.cluster.api.reactive.RedisAdvancedClusterReactiveCommands; import com.lambdaworks.redis.cluster.api.sync.NodeSelection; import com.lambdaworks.redis.cluster.api.sync.NodeSelectionCommands; import com.lambdaworks.redis.cluster.api.sync.RedisAdvancedClusterCommands; -import com.lambdaworks.redis.cluster.api.sync.RedisClusterCommands; import com.lambdaworks.redis.cluster.models.partitions.Partitions; import com.lambdaworks.redis.cluster.models.partitions.RedisClusterNode; import com.lambdaworks.redis.codec.RedisCodec; -import com.lambdaworks.redis.internal.AbstractInvocationHandler; import com.lambdaworks.redis.internal.LettuceAssert; import com.lambdaworks.redis.protocol.CompleteableCommand; import com.lambdaworks.redis.protocol.ConnectionWatchdog; @@ -96,8 +89,9 @@ public RedisAdvancedClusterCommands sync() { return sync; } - public InvocationHandler syncInvocationHandler() { - return new ClusterFutureSyncInvocationHandler<>(this, async()); + protected InvocationHandler syncInvocationHandler() { + return new ClusterFutureSyncInvocationHandler<>(this, RedisClusterAsyncCommands.class, NodeSelection.class, + NodeSelectionCommands.class, async()); } @Override @@ -218,150 +212,4 @@ public void setReadFrom(ReadFrom readFrom) { public ReadFrom getReadFrom() { return getClusterDistributionChannelWriter().getReadFrom(); } - - /** - * Invocation-handler to synchronize API calls which use Futures as backend. This class leverages the need to implement a - * full sync class which just delegates every request. - * - * @param Key type. - * @param Value type. - * @author Mark Paluch - * @since 3.0 - */ - @SuppressWarnings("unchecked") - private static class ClusterFutureSyncInvocationHandler extends AbstractInvocationHandler { - - private final StatefulRedisClusterConnection connection; - private final Object asyncApi; - private final Map apiMethodCache = new ConcurrentHashMap<>(RedisClusterCommands.class.getMethods().length, 1); - private final Map connectionMethodCache = new ConcurrentHashMap<>(5, 1); - - private static final Constructor LOOKUP_CONSTRUCTOR; - - static { - try { - LOOKUP_CONSTRUCTOR = MethodHandles.Lookup.class.getDeclaredConstructor(Class.class, int.class); - if (!LOOKUP_CONSTRUCTOR.isAccessible()) { - LOOKUP_CONSTRUCTOR.setAccessible(true); - } - } catch (NoSuchMethodException exp) { - // should be impossible, but... - throw new IllegalStateException(exp); - } - } - - ClusterFutureSyncInvocationHandler(StatefulRedisClusterConnection connection, Object asyncApi) { - this.connection = connection; - this.asyncApi = asyncApi; - } - - static MethodHandles.Lookup privateMethodHandleLookup(Class declaringClass) { - try { - return LOOKUP_CONSTRUCTOR.newInstance(declaringClass, MethodHandles.Lookup.PRIVATE); - } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { - throw new IllegalStateException(e); - } - } - - static MethodHandle getDefaultMethodHandle(Method method) { - Class declaringClass = method.getDeclaringClass(); - try { - return privateMethodHandleLookup(declaringClass).unreflectSpecial(method, declaringClass); - } catch (IllegalAccessException e) { - throw new IllegalArgumentException("Did not pass in an interface method: " + method); - } - } - - /** - * - * @see AbstractInvocationHandler#handleInvocation(Object, Method, Object[]) - */ - @Override - protected Object handleInvocation(Object proxy, Method method, Object[] args) throws Throwable { - - try { - - if (method.isDefault()) { - return getDefaultMethodHandle(method).bindTo(proxy).invokeWithArguments(args); - } - - if (method.getName().equals("getConnection") && args.length > 0) { - Method targetMethod = connectionMethodCache.computeIfAbsent(method, key -> { - try { - return connection.getClass().getMethod(key.getName(), key.getParameterTypes()); - } catch (NoSuchMethodException e) { - throw new IllegalStateException(e); - } - }); - - Object result = targetMethod.invoke(connection, args); - if (result instanceof StatefulRedisClusterConnection) { - StatefulRedisClusterConnection connection = (StatefulRedisClusterConnection) result; - return connection.sync(); - } - - if (result instanceof StatefulRedisConnection) { - StatefulRedisConnection connection = (StatefulRedisConnection) result; - return connection.sync(); - } - } - - if (method.getName().equals("readonly") && args.length == 1) { - return nodes((Predicate) args[0], ClusterConnectionProvider.Intent.READ, false); - } - - if (method.getName().equals("nodes") && args.length == 1) { - return nodes((Predicate) args[0], ClusterConnectionProvider.Intent.WRITE, false); - } - - if (method.getName().equals("nodes") && args.length == 2) { - return nodes((Predicate) args[0], ClusterConnectionProvider.Intent.WRITE, - (Boolean) args[1]); - } - - Method targetMethod = apiMethodCache.computeIfAbsent(method, key -> { - - try { - return asyncApi.getClass().getMethod(key.getName(), key.getParameterTypes()); - } catch (NoSuchMethodException e) { - throw new IllegalStateException(e); - } - }); - - Object result = targetMethod.invoke(asyncApi, args); - - if (result instanceof RedisFuture) { - RedisFuture command = (RedisFuture) result; - if (!method.getName().equals("exec") && !method.getName().equals("multi")) { - if (connection instanceof StatefulRedisConnection && ((StatefulRedisConnection) connection).isMulti()) { - return null; - } - } - return LettuceFutures.awaitOrCancel(command, connection.getTimeout(), connection.getTimeoutUnit()); - } - - return result; - - } catch (InvocationTargetException e) { - throw e.getTargetException(); - } - } - - protected NodeSelection nodes(Predicate predicate, ClusterConnectionProvider.Intent intent, - boolean dynamic) { - - NodeSelectionSupport, ?> selection; - - if (dynamic) { - selection = new DynamicSyncNodeSelection<>(connection, predicate, intent); - } else { - selection = new StaticSyncNodeSelection<>(connection, predicate, intent); - } - - NodeSelectionInvocationHandler h = new NodeSelectionInvocationHandler((AbstractNodeSelection) selection, - true, connection.getTimeout(), connection.getTimeoutUnit()); - return (NodeSelection) Proxy.newProxyInstance(NodeSelectionSupport.class.getClassLoader(), - new Class[] { NodeSelectionCommands.class, NodeSelection.class }, h); - } - } } diff --git a/src/main/java/com/lambdaworks/redis/cluster/StaticAsyncNodeSelection.java b/src/main/java/com/lambdaworks/redis/cluster/StaticAsyncNodeSelection.java deleted file mode 100644 index 4c398ad759..0000000000 --- a/src/main/java/com/lambdaworks/redis/cluster/StaticAsyncNodeSelection.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2011-2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.lambdaworks.redis.cluster; - -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.function.Predicate; -import java.util.stream.Collectors; - -import com.lambdaworks.redis.api.async.RedisAsyncCommands; -import com.lambdaworks.redis.cluster.api.StatefulRedisClusterConnection; -import com.lambdaworks.redis.cluster.models.partitions.RedisClusterNode; - -/** - * @param Command command interface type to invoke multi-node operations. - * @param Key type. - * @param Value type. - * @author Mark Paluch - */ -class StaticAsyncNodeSelection extends StaticNodeSelection, CMD, K, V> { - - public StaticAsyncNodeSelection(StatefulRedisClusterConnection globalConnection, - Predicate selector, ClusterConnectionProvider.Intent intent) { - super(globalConnection, selector, intent); - } - - public Iterator> iterator() { - List list = nodes().stream().collect(Collectors.toList()); - return list.stream().map(node -> getConnection(node).async()).iterator(); - } - - @Override - public RedisAsyncCommands commands(int index) { - return statefulMap().get(nodes().get(index)).async(); - } - - @Override - public Map> asMap() { - - List list = nodes().stream().collect(Collectors.toList()); - Map> map = new HashMap<>(); - - list.forEach((key) -> map.put(key, getConnection(key).async())); - - return map; - } - - // This method is never called, the value is supplied by AOP magic. - @Override - public CMD commands() { - return null; - } -} diff --git a/src/main/java/com/lambdaworks/redis/cluster/StaticNodeSelection.java b/src/main/java/com/lambdaworks/redis/cluster/StaticNodeSelection.java index 0136524b16..a6c228102d 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/StaticNodeSelection.java +++ b/src/main/java/com/lambdaworks/redis/cluster/StaticNodeSelection.java @@ -16,10 +16,12 @@ package com.lambdaworks.redis.cluster; import java.util.List; +import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Collectors; -import com.lambdaworks.redis.cluster.api.StatefulRedisClusterConnection; +import com.lambdaworks.redis.RedisURI; +import com.lambdaworks.redis.api.StatefulRedisConnection; import com.lambdaworks.redis.cluster.models.partitions.RedisClusterNode; /** @@ -31,16 +33,33 @@ * @param Value type. * @author Mark Paluch */ -abstract class StaticNodeSelection extends AbstractNodeSelection { +class StaticNodeSelection extends AbstractNodeSelection { + private final ClusterDistributionChannelWriter writer; + private final ClusterConnectionProvider.Intent intent; private final List redisClusterNodes; + private final Function, API> apiExtractor; - public StaticNodeSelection(StatefulRedisClusterConnection globalConnection, Predicate selector, - ClusterConnectionProvider.Intent intent) { - super(globalConnection, intent); + public StaticNodeSelection(ClusterDistributionChannelWriter writer, Predicate selector, + ClusterConnectionProvider.Intent intent, Function, API> apiExtractor) { - this.redisClusterNodes = globalConnection.getPartitions().getPartitions().stream().filter(selector) - .collect(Collectors.toList()); + this.writer = writer; + this.intent = intent; + this.apiExtractor = apiExtractor; + + this.redisClusterNodes = writer.getPartitions().getPartitions().stream().filter(selector).collect(Collectors.toList()); + } + + @Override + protected StatefulRedisConnection getConnection(RedisClusterNode redisClusterNode) { + + RedisURI uri = redisClusterNode.getUri(); + return writer.getClusterConnectionProvider().getConnection(intent, uri.getHost(), uri.getPort()); + } + + @Override + protected API getApi(RedisClusterNode redisClusterNode) { + return apiExtractor.apply(getConnection(redisClusterNode)); } @Override diff --git a/src/main/java/com/lambdaworks/redis/cluster/StaticSyncNodeSelection.java b/src/main/java/com/lambdaworks/redis/cluster/StaticSyncNodeSelection.java deleted file mode 100644 index 0eed23e42a..0000000000 --- a/src/main/java/com/lambdaworks/redis/cluster/StaticSyncNodeSelection.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2011-2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.lambdaworks.redis.cluster; - -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.function.Predicate; -import java.util.stream.Collectors; - -import com.lambdaworks.redis.api.sync.RedisCommands; -import com.lambdaworks.redis.cluster.api.StatefulRedisClusterConnection; -import com.lambdaworks.redis.cluster.models.partitions.RedisClusterNode; - -/** - * @param Command command interface type to invoke multi-node operations. - * @param Key type. - * @param Value type. - * @author Mark Paluch - */ -class StaticSyncNodeSelection extends StaticNodeSelection, CMD, K, V> { - - public StaticSyncNodeSelection(StatefulRedisClusterConnection globalConnection, Predicate selector, - ClusterConnectionProvider.Intent intent) { - super(globalConnection, selector, intent); - } - - public Iterator> iterator() { - List list = nodes().stream().collect(Collectors.toList()); - return list.stream().map(node -> getConnection(node).sync()).iterator(); - } - - @Override - public RedisCommands commands(int index) { - return statefulMap().get(nodes().get(index)).sync(); - } - - @Override - public Map> asMap() { - - List list = nodes().stream().collect(Collectors.toList()); - Map> map = new HashMap<>(); - - list.forEach((key) -> map.put(key, getConnection(key).sync())); - - return map; - } - - // This method is never called, the value is supplied by AOP magic. - @Override - public CMD commands() { - return null; - } -} diff --git a/src/main/java/com/lambdaworks/redis/cluster/SyncExecutionsImpl.java b/src/main/java/com/lambdaworks/redis/cluster/SyncExecutionsImpl.java index 6359874730..ded848df87 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/SyncExecutionsImpl.java +++ b/src/main/java/com/lambdaworks/redis/cluster/SyncExecutionsImpl.java @@ -26,6 +26,7 @@ /** * @author Mark Paluch + * TODO: Add timeout handling */ class SyncExecutionsImpl implements Executions { diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/NodeSelectionSupport.java b/src/main/java/com/lambdaworks/redis/cluster/api/NodeSelectionSupport.java index 0429463909..46682a0ade 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/NodeSelectionSupport.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/NodeSelectionSupport.java @@ -31,13 +31,11 @@ public interface NodeSelectionSupport { /** - * * @return number of nodes. */ int size(); /** - * * @return commands API to run on this node selection. */ CMD commands(); @@ -59,9 +57,7 @@ public interface NodeSelectionSupport { RedisClusterNode node(int index); /** - * * @return map of {@link RedisClusterNode} and the connection/commands objects */ Map asMap(); - } diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/StatefulRedisClusterConnection.java b/src/main/java/com/lambdaworks/redis/cluster/api/StatefulRedisClusterConnection.java index 30baedea74..f2a7b15060 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/StatefulRedisClusterConnection.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/StatefulRedisClusterConnection.java @@ -26,7 +26,7 @@ import com.lambdaworks.redis.cluster.models.partitions.Partitions; /** - * A stateful cluster connection providing. Advanced cluster connections provide transparent command routing based on the first + * A stateful cluster connection. Advanced cluster connections provide transparent command routing based on the first * command key. * * @param Key type. diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/reactive/ReactiveExecutions.java b/src/main/java/com/lambdaworks/redis/cluster/api/reactive/ReactiveExecutions.java new file mode 100644 index 0000000000..9c8203191b --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/cluster/api/reactive/ReactiveExecutions.java @@ -0,0 +1,44 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.lambdaworks.redis.cluster.api.reactive; + +import java.util.Collection; + +import com.lambdaworks.redis.cluster.models.partitions.RedisClusterNode; + +import reactor.core.publisher.Flux; +import rx.Observable; + +/** + * Execution holder for a reactive command to be executed on multiple nodes. + * + * @author Mark Paluch + * @since 4.4 + */ +public interface ReactiveExecutions { + + /** + * Return an {@link Observable} that contains a combined stream of the multi-node execution. + * + * @return + */ + Flux flux(); + + /** + * @return collection of nodes on which the command was executed. + */ + Collection nodes(); +} From a26c2290b90bbd55bfb6236d8240c17934447949 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Fri, 25 Nov 2016 09:44:37 +0100 Subject: [PATCH 074/808] Allow Pub/Sub subscriptions on a node selection within Redis Cluster #385 Lettuce now supports Pub/Sub subscriptions on particular nodes with Redis Cluster. Subscriptions to one or a selection of nodes is useful especially when working with keyspace notifications. Keyspace notifications with Redis Cluster are published only to the node where the event originates and these notifications are not broadcasted across the cluster. This change introduces StatefulRedisClusterPubSubConnection that exposes node-selection APIs for synchronous, asynchronous and reactive subscription operations. --- .../ClusterPubSubConnectionProvider.java | 147 +++++++++++++ .../PooledClusterConnectionProvider.java | 102 ++++++--- .../redis/cluster/PubSubClusterEndpoint.java | 200 +++++++++++++++++ .../redis/cluster/RedisClusterClient.java | 83 +++++-- .../RedisClusterPubSubAsyncCommandsImpl.java | 104 +++++++++ ...edisClusterPubSubReactiveCommandsImpl.java | 104 +++++++++ ...tefulRedisClusterPubSubConnectionImpl.java | 182 ++++++++++++++++ .../api/reactive/ReactiveExecutions.java | 3 +- .../pubsub/RedisClusterPubSubAdapter.java | 59 +++++ .../pubsub/RedisClusterPubSubListener.java | 78 +++++++ .../StatefulRedisClusterPubSubConnection.java | 159 ++++++++++++++ .../NodeSelectionPubSubAsyncCommands.java | 59 +++++ .../api/async/PubSubAsyncNodeSelection.java | 36 ++++ .../RedisClusterPubSubAsyncCommands.java | 85 ++++++++ .../NodeSelectionPubSubReactiveCommands.java | 59 +++++ .../reactive/PubSubReactiveNodeSelection.java | 31 +++ .../RedisClusterPubSubReactiveCommands.java | 85 ++++++++ .../api/sync/NodeSelectionPubSubCommands.java | 59 +++++ .../pubsub/api/sync/PubSubNodeSelection.java | 30 +++ .../api/sync/RedisClusterPubSubCommands.java | 85 ++++++++ .../redis/pubsub/PubSubEndpoint.java | 14 +- .../pubsub/StatefulRedisPubSubConnection.java | 11 +- .../StatefulRedisPubSubConnectionImpl.java | 2 +- .../pubsub/api/sync/RedisPubSubCommands.java | 1 - .../cluster/pubsub/PubSubClusterTest.java | 204 +++++++++--------- .../cluster/pubsub/PubSubConnectionTest.java | 142 ++++++++++++ .../redis/support/PubSubTestListener.java | 87 ++++++++ 27 files changed, 2048 insertions(+), 163 deletions(-) create mode 100644 src/main/java/com/lambdaworks/redis/cluster/ClusterPubSubConnectionProvider.java create mode 100644 src/main/java/com/lambdaworks/redis/cluster/PubSubClusterEndpoint.java create mode 100644 src/main/java/com/lambdaworks/redis/cluster/RedisClusterPubSubAsyncCommandsImpl.java create mode 100644 src/main/java/com/lambdaworks/redis/cluster/RedisClusterPubSubReactiveCommandsImpl.java create mode 100644 src/main/java/com/lambdaworks/redis/cluster/StatefulRedisClusterPubSubConnectionImpl.java create mode 100644 src/main/java/com/lambdaworks/redis/cluster/pubsub/RedisClusterPubSubAdapter.java create mode 100644 src/main/java/com/lambdaworks/redis/cluster/pubsub/RedisClusterPubSubListener.java create mode 100644 src/main/java/com/lambdaworks/redis/cluster/pubsub/StatefulRedisClusterPubSubConnection.java create mode 100644 src/main/java/com/lambdaworks/redis/cluster/pubsub/api/async/NodeSelectionPubSubAsyncCommands.java create mode 100644 src/main/java/com/lambdaworks/redis/cluster/pubsub/api/async/PubSubAsyncNodeSelection.java create mode 100644 src/main/java/com/lambdaworks/redis/cluster/pubsub/api/async/RedisClusterPubSubAsyncCommands.java create mode 100644 src/main/java/com/lambdaworks/redis/cluster/pubsub/api/reactive/NodeSelectionPubSubReactiveCommands.java create mode 100644 src/main/java/com/lambdaworks/redis/cluster/pubsub/api/reactive/PubSubReactiveNodeSelection.java create mode 100644 src/main/java/com/lambdaworks/redis/cluster/pubsub/api/reactive/RedisClusterPubSubReactiveCommands.java create mode 100644 src/main/java/com/lambdaworks/redis/cluster/pubsub/api/sync/NodeSelectionPubSubCommands.java create mode 100644 src/main/java/com/lambdaworks/redis/cluster/pubsub/api/sync/PubSubNodeSelection.java create mode 100644 src/main/java/com/lambdaworks/redis/cluster/pubsub/api/sync/RedisClusterPubSubCommands.java create mode 100644 src/test/java/com/lambdaworks/redis/cluster/pubsub/PubSubConnectionTest.java create mode 100644 src/test/java/com/lambdaworks/redis/support/PubSubTestListener.java diff --git a/src/main/java/com/lambdaworks/redis/cluster/ClusterPubSubConnectionProvider.java b/src/main/java/com/lambdaworks/redis/cluster/ClusterPubSubConnectionProvider.java new file mode 100644 index 0000000000..e43beca31a --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/cluster/ClusterPubSubConnectionProvider.java @@ -0,0 +1,147 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.lambdaworks.redis.cluster; + +import com.lambdaworks.redis.cluster.models.partitions.RedisClusterNode; +import com.lambdaworks.redis.cluster.pubsub.RedisClusterPubSubListener; +import com.lambdaworks.redis.codec.RedisCodec; +import com.lambdaworks.redis.pubsub.RedisPubSubAdapter; +import com.lambdaworks.redis.pubsub.RedisPubSubListener; +import com.lambdaworks.redis.pubsub.StatefulRedisPubSubConnection; + +/** + * {@link ClusterConnectionProvider} to provide {@link StatefulRedisPubSubConnection}s for Redis Cluster use. + *

    + * {@link StatefulRedisPubSubConnection}s provided by this {@link ClusterConnectionProvider} get a {@link RedisPubSubListener} + * registered that propagates received events to an upstream {@link RedisClusterPubSubListener} to provide message propagation. + * Message propagation performs a {@link RedisClusterNode} lookup to distinguish notifications between cluster nodes. + * + * @author Mark Paluch + * @since 4.4 + */ +class ClusterPubSubConnectionProvider extends PooledClusterConnectionProvider { + + private final RedisClusterClient redisClusterClient; + private final RedisCodec redisCodec; + private final RedisClusterPubSubListener notifications; + + /** + * Creates a new {@link ClusterPubSubConnectionProvider}. + * + * @param redisClusterClient must not be {@literal null}. + * @param clusterWriter must not be {@literal null}. + * @param redisCodec must not be {@literal null}. + * @param notificationTarget must not be {@literal null}. + */ + public ClusterPubSubConnectionProvider(RedisClusterClient redisClusterClient, + ClusterDistributionChannelWriter clusterWriter, RedisCodec redisCodec, + RedisClusterPubSubListener notificationTarget) { + + super(redisClusterClient, clusterWriter, redisCodec); + + this.redisClusterClient = redisClusterClient; + this.redisCodec = redisCodec; + this.notifications = notificationTarget; + } + + @Override + protected ClusterNodeConnectionFactory getConnectionFactory() { + return new PubSubConnectionFactory(); + } + + private class PubSubConnectionFactory implements ClusterNodeConnectionFactory { + + @Override + public StatefulRedisPubSubConnection apply(ConnectionKey key) { + + StatefulRedisPubSubConnection connection = null; + + if (key.nodeId != null) { + + // NodeId connections do not provide command recovery due to cluster reconfiguration + connection = redisClusterClient.connectPubSubToNode(redisCodec, key.nodeId, getSocketAddressSupplier(key)); + + connection.addListener(new DelegatingRedisClusterPubSubListener(key.nodeId)); + } + + if (key.host != null) { + + // Host and port connections do provide command recovery due to cluster reconfiguration + connection = redisClusterClient.connectPubSubToNode(redisCodec, key.host + ":" + key.port, + getSocketAddressSupplier(key)); + + connection.addListener(new DelegatingRedisClusterPubSubListener(key.host, key.port)); + } + + return connection; + } + } + + private class DelegatingRedisClusterPubSubListener extends RedisPubSubAdapter { + + private final String nodeId; + private final String host; + private final int port; + + public DelegatingRedisClusterPubSubListener(String nodeId) { + + this.nodeId = nodeId; + this.host = null; + this.port = 0; + } + + public DelegatingRedisClusterPubSubListener(String host, int port) { + + this.nodeId = null; + this.host = host; + this.port = port; + } + + @Override + public void message(K channel, V message) { + notifications.message(getNode(), channel, message); + } + + @Override + public void message(K pattern, K channel, V message) { + notifications.message(getNode(), pattern, channel, message); + } + + @Override + public void subscribed(K channel, long count) { + notifications.subscribed(getNode(), channel, count); + } + + @Override + public void psubscribed(K pattern, long count) { + notifications.psubscribed(getNode(), pattern, count); + } + + @Override + public void unsubscribed(K channel, long count) { + notifications.unsubscribed(getNode(), channel, count); + } + + @Override + public void punsubscribed(K pattern, long count) { + notifications.punsubscribed(getNode(), pattern, count); + } + + private RedisClusterNode getNode() { + return nodeId != null ? getPartitions().getPartitionByNodeId(nodeId) : getPartition(host, port); + } + } +} diff --git a/src/main/java/com/lambdaworks/redis/cluster/PooledClusterConnectionProvider.java b/src/main/java/com/lambdaworks/redis/cluster/PooledClusterConnectionProvider.java index 22b6887406..9705677c4c 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/PooledClusterConnectionProvider.java +++ b/src/main/java/com/lambdaworks/redis/cluster/PooledClusterConnectionProvider.java @@ -59,7 +59,9 @@ class PooledClusterConnectionProvider implements ClusterConnectionProvider private final StatefulRedisConnection writers[] = new StatefulRedisConnection[SlotHash.SLOT_COUNT]; private final StatefulRedisConnection readers[][] = new StatefulRedisConnection[SlotHash.SLOT_COUNT][]; private final RedisClusterClient redisClusterClient; - private final ConnectionFactory connectionFactory; + private final ClusterNodeConnectionFactory connectionFactory; + private final RedisChannelWriter clusterWriter; + private final RedisCodec redisCodec; private Partitions partitions; private boolean autoFlushCommands = true; @@ -68,8 +70,10 @@ class PooledClusterConnectionProvider implements ClusterConnectionProvider public PooledClusterConnectionProvider(RedisClusterClient redisClusterClient, RedisChannelWriter clusterWriter, RedisCodec redisCodec) { + this.redisCodec = redisCodec; this.redisClusterClient = redisClusterClient; - this.connectionFactory = new ConnectionFactory(redisClusterClient, redisCodec, clusterWriter); + this.clusterWriter = clusterWriter; + this.connectionFactory = new ConnectionPostProcessor(getConnectionFactory()); } @Override @@ -228,7 +232,8 @@ public StatefulRedisConnection getConnection(Intent intent, String host, i } } - private RedisClusterNode getPartition(String host, int port) { + protected RedisClusterNode getPartition(String host, int port) { + for (RedisClusterNode partition : partitions) { RedisURI uri = partition.getUri(); if (port == uri.getPort() && host.equals(uri.getHost())) { @@ -276,6 +281,10 @@ public void setPartitions(Partitions partitions) { } } + protected Partitions getPartitions() { + return partitions; + } + private void reconfigurePartitions() { if (!redisClusterClient.expireStaleConnections()) { @@ -402,12 +411,12 @@ private void resetFastConnectionCache() { } } - private RuntimeException invalidConnectionPoint(String message) { + private static RuntimeException invalidConnectionPoint(String message) { return new IllegalArgumentException( "Connection to " + message + " not allowed. This connection point is not known in the cluster view"); } - private Supplier getSocketAddressSupplier(final ConnectionKey connectionKey) { + Supplier getSocketAddressSupplier(final ConnectionKey connectionKey) { return () -> { if (connectionKey.nodeId != null) { SocketAddress socketAddress = getSocketAddress(connectionKey.nodeId); @@ -433,11 +442,12 @@ private SocketAddress getSocketAddress(String nodeId) { /** * Connection to identify a connection either by nodeId or host/port. */ - private static class ConnectionKey { - private final ClusterConnectionProvider.Intent intent; - private final String nodeId; - private final String host; - private final int port; + static class ConnectionKey { + + final ClusterConnectionProvider.Intent intent; + final String nodeId; + final String host; + final int port; public ConnectionKey(Intent intent, String nodeId) { this.intent = intent; @@ -481,7 +491,7 @@ public int hashCode() { } } - private boolean validateClusterNodeMembership() { + boolean validateClusterNodeMembership() { return redisClusterClient.getClusterClientOptions() == null || redisClusterClient.getClusterClientOptions().isValidateClusterNodeMembership(); } @@ -490,31 +500,28 @@ private StatefulRedisConnection getOrCreateConnection(ConnectionKey key) { return connections.computeIfAbsent(key, connectionFactory); } - private class ConnectionFactory implements Function> { + /** + * @return a factory {@link Function} + */ + protected ClusterNodeConnectionFactory getConnectionFactory() { + return new NodeConnectionFactoryImpl(redisClusterClient, redisCodec, clusterWriter); + } - private final RedisClusterClient redisClusterClient; - private final RedisCodec redisCodec; - private final RedisChannelWriter clusterWriter; + private class ConnectionPostProcessor implements ClusterNodeConnectionFactory { - public ConnectionFactory(RedisClusterClient redisClusterClient, RedisCodec redisCodec, - RedisChannelWriter clusterWriter) { - this.redisClusterClient = redisClusterClient; - this.redisCodec = redisCodec; - this.clusterWriter = clusterWriter; + private final Function> delegate; + + public ConnectionPostProcessor(Function> delegate) { + this.delegate = delegate; } @Override public StatefulRedisConnection apply(ConnectionKey key) { - StatefulRedisConnection connection = null; - if (key.nodeId != null) { - if (partitions.getPartitionByNodeId(key.nodeId) == null) { + if (getPartitions().getPartitionByNodeId(key.nodeId) == null) { throw invalidConnectionPoint("node id " + key.nodeId); } - - // NodeId connections do not provide command recovery due to cluster reconfiguration - connection = redisClusterClient.connectToNode(redisCodec, key.nodeId, null, getSocketAddressSupplier(key)); } if (key.host != null) { @@ -524,12 +531,10 @@ public StatefulRedisConnection apply(ConnectionKey key) { throw invalidConnectionPoint(key.host + ":" + key.port); } } - - // Host and port connections do provide command recovery due to cluster reconfiguration - connection = redisClusterClient.connectToNode(redisCodec, key.host + ":" + key.port, clusterWriter, - getSocketAddressSupplier(key)); } + StatefulRedisConnection connection = delegate.apply(key); + LettuceAssert.notNull(connection, "Connection is null. Check ConnectionKey because host and nodeId are null"); try { @@ -548,4 +553,41 @@ public StatefulRedisConnection apply(ConnectionKey key) { return connection; } } + + private class NodeConnectionFactoryImpl implements ClusterNodeConnectionFactory { + + private final RedisClusterClient redisClusterClient; + private final RedisCodec redisCodec; + private final RedisChannelWriter clusterWriter; + + public NodeConnectionFactoryImpl(RedisClusterClient redisClusterClient, RedisCodec redisCodec, + RedisChannelWriter clusterWriter) { + this.redisClusterClient = redisClusterClient; + this.redisCodec = redisCodec; + this.clusterWriter = clusterWriter; + } + + @Override + public StatefulRedisConnection apply(ConnectionKey key) { + + StatefulRedisConnection connection = null; + + if (key.nodeId != null) { + // NodeId connections do not provide command recovery due to cluster reconfiguration + connection = redisClusterClient.connectToNode(redisCodec, key.nodeId, null, getSocketAddressSupplier(key)); + } + + if (key.host != null) { + // Host and port connections do provide command recovery due to cluster reconfiguration + connection = redisClusterClient.connectToNode(redisCodec, key.host + ":" + key.port, clusterWriter, + getSocketAddressSupplier(key)); + } + + return connection; + } + } + + interface ClusterNodeConnectionFactory extends Function> { + + } } diff --git a/src/main/java/com/lambdaworks/redis/cluster/PubSubClusterEndpoint.java b/src/main/java/com/lambdaworks/redis/cluster/PubSubClusterEndpoint.java new file mode 100644 index 0000000000..f4286e1326 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/cluster/PubSubClusterEndpoint.java @@ -0,0 +1,200 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.lambdaworks.redis.cluster; + +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; + +import com.lambdaworks.redis.ClientOptions; +import com.lambdaworks.redis.cluster.models.partitions.RedisClusterNode; +import com.lambdaworks.redis.cluster.pubsub.RedisClusterPubSubAdapter; +import com.lambdaworks.redis.cluster.pubsub.RedisClusterPubSubListener; +import com.lambdaworks.redis.pubsub.PubSubEndpoint; +import com.lambdaworks.redis.pubsub.PubSubOutput; + +/** + * @author Mark Paluch + */ +public class PubSubClusterEndpoint extends PubSubEndpoint { + + private final List> clusterListeners = new CopyOnWriteArrayList<>(); + private final NotifyingMessageListener multicast = new NotifyingMessageListener(); + private final UpstreamMessageListener upstream = new UpstreamMessageListener(); + + private volatile boolean nodeMessagePropagation = false; + private volatile RedisClusterNode clusterNode; + + /** + * Initialize a new instance that handles commands from the supplied queue. + * + * @param clientOptions client options for this connection, must not be {@literal null} + */ + public PubSubClusterEndpoint(ClientOptions clientOptions) { + super(clientOptions); + } + + /** + * Add a new {@link RedisClusterPubSubListener listener}. + * + * @param listener the listener, must not be {@literal null}. + */ + public void addListener(RedisClusterPubSubListener listener) { + clusterListeners.add(listener); + } + + public RedisClusterPubSubListener getUpstreamListener() { + return upstream; + } + + /** + * Remove an existing {@link RedisClusterPubSubListener listener}. + * + * @param listener the listener, must not be {@literal null}. + */ + public void removeListener(RedisClusterPubSubListener listener) { + clusterListeners.remove(listener); + } + + public void setNodeMessagePropagation(boolean nodeMessagePropagation) { + this.nodeMessagePropagation = nodeMessagePropagation; + } + + void setClusterNode(RedisClusterNode clusterNode) { + this.clusterNode = clusterNode; + } + + protected void notifyListeners(PubSubOutput output) { + // update listeners + switch (output.type()) { + case message: + multicast.message(clusterNode, output.channel(), output.get()); + break; + case pmessage: + multicast.message(clusterNode, output.pattern(), output.channel(), output.get()); + break; + case psubscribe: + multicast.psubscribed(clusterNode, output.pattern(), output.count()); + break; + case punsubscribe: + multicast.punsubscribed(clusterNode, output.pattern(), output.count()); + break; + case subscribe: + multicast.subscribed(clusterNode, output.channel(), output.count()); + break; + case unsubscribe: + multicast.unsubscribed(clusterNode, output.channel(), output.count()); + break; + default: + throw new UnsupportedOperationException("Operation " + output.type() + " not supported"); + } + } + + private class UpstreamMessageListener extends NotifyingMessageListener { + + @Override + public void message(RedisClusterNode node, K channel, V message) { + + if (nodeMessagePropagation) { + super.message(node, channel, message); + } + } + + @Override + public void message(RedisClusterNode node, K pattern, K channel, V message) { + + if (nodeMessagePropagation) { + super.message(node, pattern, channel, message); + } + } + + @Override + public void subscribed(RedisClusterNode node, K channel, long count) { + + if (nodeMessagePropagation) { + super.subscribed(node, channel, count); + } + } + + @Override + public void psubscribed(RedisClusterNode node, K pattern, long count) { + + if (nodeMessagePropagation) { + super.psubscribed(node, pattern, count); + } + } + + @Override + public void unsubscribed(RedisClusterNode node, K channel, long count) { + + if (nodeMessagePropagation) { + super.unsubscribed(node, channel, count); + } + } + + @Override + public void punsubscribed(RedisClusterNode node, K pattern, long count) { + + if (nodeMessagePropagation) { + super.punsubscribed(node, pattern, count); + } + } + } + + private class NotifyingMessageListener extends RedisClusterPubSubAdapter { + + @Override + public void message(RedisClusterNode node, K channel, V message) { + + getListeners().forEach(listener -> listener.message(channel, message)); + clusterListeners.forEach(listener -> listener.message(node, channel, message)); + } + + @Override + public void message(RedisClusterNode node, K pattern, K channel, V message) { + + getListeners().forEach(listener -> listener.message(pattern, channel, message)); + clusterListeners.forEach(listener -> listener.message(node, pattern, channel, message)); + } + + @Override + public void subscribed(RedisClusterNode node, K channel, long count) { + + getListeners().forEach(listener -> listener.subscribed(channel, count)); + clusterListeners.forEach(listener -> listener.subscribed(node, channel, count)); + } + + @Override + public void psubscribed(RedisClusterNode node, K pattern, long count) { + + getListeners().forEach(listener -> listener.psubscribed(pattern, count)); + clusterListeners.forEach(listener -> listener.psubscribed(node, pattern, count)); + } + + @Override + public void unsubscribed(RedisClusterNode node, K channel, long count) { + + getListeners().forEach(listener -> listener.unsubscribed(channel, count)); + clusterListeners.forEach(listener -> listener.unsubscribed(node, channel, count)); + } + + @Override + public void punsubscribed(RedisClusterNode node, K pattern, long count) { + + getListeners().forEach(listener -> listener.punsubscribed(pattern, count)); + clusterListeners.forEach(listener -> listener.punsubscribed(node, pattern, count)); + } + } +} diff --git a/src/main/java/com/lambdaworks/redis/cluster/RedisClusterClient.java b/src/main/java/com/lambdaworks/redis/cluster/RedisClusterClient.java index fa2861ac0f..0cfedb6788 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/RedisClusterClient.java +++ b/src/main/java/com/lambdaworks/redis/cluster/RedisClusterClient.java @@ -36,6 +36,7 @@ import com.lambdaworks.redis.cluster.event.ClusterTopologyChangedEvent; import com.lambdaworks.redis.cluster.models.partitions.Partitions; import com.lambdaworks.redis.cluster.models.partitions.RedisClusterNode; +import com.lambdaworks.redis.cluster.pubsub.StatefulRedisClusterPubSubConnection; import com.lambdaworks.redis.cluster.topology.ClusterTopologyRefresh; import com.lambdaworks.redis.cluster.topology.NodeConnectionFactory; import com.lambdaworks.redis.cluster.topology.TopologyComparators; @@ -44,9 +45,8 @@ import com.lambdaworks.redis.internal.LettuceAssert; import com.lambdaworks.redis.internal.LettuceLists; import com.lambdaworks.redis.output.KeyValueStreamingChannel; -import com.lambdaworks.redis.output.ValueStreamingChannel; -import com.lambdaworks.redis.protocol.DefaultEndpoint; import com.lambdaworks.redis.protocol.CommandHandler; +import com.lambdaworks.redis.protocol.DefaultEndpoint; import com.lambdaworks.redis.pubsub.PubSubCommandHandler; import com.lambdaworks.redis.pubsub.PubSubEndpoint; import com.lambdaworks.redis.pubsub.StatefulRedisPubSubConnection; @@ -344,7 +344,7 @@ public StatefulRedisClusterConnection connect(RedisCodec code * * @return A new stateful Redis Cluster connection */ - public StatefulRedisPubSubConnection connectPubSub() { + public StatefulRedisClusterPubSubConnection connectPubSub() { return connectPubSub(newStringStringCodec()); } @@ -368,11 +368,10 @@ public StatefulRedisPubSubConnection connectPubSub() { * @return A new stateful Redis Cluster connection */ @SuppressWarnings("unchecked") - public StatefulRedisPubSubConnection connectPubSub(RedisCodec codec) { + public StatefulRedisClusterPubSubConnection connectPubSub(RedisCodec codec) { return connectClusterPubSubImpl(codec); } - protected StatefulRedisConnection connectToNode(final SocketAddress socketAddress) { return connectToNode(newStringStringCodec(), socketAddress.toString(), null, new Supplier() { @Override @@ -419,6 +418,43 @@ StatefulRedisConnection connectToNode(RedisCodec codec, Strin return connection; } + /** + * Create a pub/sub connection to a redis socket address. + * + * @param codec Use this codec to encode/decode keys and values, must not be {@literal null} + * @param nodeId the nodeId + * @param socketAddressSupplier supplier for the socket address + * @param Key type + * @param Value type + * @return A new connection + */ + StatefulRedisPubSubConnection connectPubSubToNode(RedisCodec codec, String nodeId, + final Supplier socketAddressSupplier) { + + assertNotNull(codec); + assertNotEmpty(initialUris); + + LettuceAssert.notNull(socketAddressSupplier, "SocketAddressSupplier must not be null"); + + logger.debug("connectPubSubToNode(" + nodeId + ")"); + + PubSubEndpoint endpoint = new PubSubEndpoint(clientOptions); + StatefulRedisPubSubConnectionImpl connection = new StatefulRedisPubSubConnectionImpl<>(endpoint, endpoint, codec, + timeout, unit); + + try { + connectStateful(connection, endpoint, getFirstUri(), socketAddressSupplier, + () -> new PubSubCommandHandler(clientResources, codec, endpoint)); + + connection.registerCloseables(closeableResources, connection); + } catch (RedisException e) { + connection.close(); + throw e; + } + return connection; + + } + /** * Create a clustered pub/sub connection with command distributor. * @@ -441,8 +477,8 @@ StatefulRedisClusterConnectionImpl connectClusterImpl(RedisCodec pooledClusterConnectionProvider = new PooledClusterConnectionProvider(this, clusterWriter, codec); @@ -490,7 +526,7 @@ StatefulRedisClusterConnectionImpl connectClusterImpl(RedisCodec Value type * @return a new connection */ - StatefulRedisPubSubConnectionImpl connectClusterPubSubImpl(RedisCodec codec) { + StatefulRedisClusterPubSubConnection connectClusterPubSubImpl(RedisCodec codec) { if (partitions == null) { initializePartitions(); @@ -502,19 +538,20 @@ StatefulRedisPubSubConnectionImpl connectClusterPubSubImpl(RedisCod Supplier socketAddressSupplier = getSocketAddressSupplier(TopologyComparators::sortByClientCount); - PubSubEndpoint endpoint = new PubSubEndpoint(clientOptions); + PubSubClusterEndpoint endpoint = new PubSubClusterEndpoint(clientOptions); ClusterDistributionChannelWriter clusterWriter = new ClusterDistributionChannelWriter(clientOptions, endpoint, clusterTopologyRefreshScheduler, getResources().eventExecutorGroup()); - PooledClusterConnectionProvider pooledClusterConnectionProvider = new PooledClusterConnectionProvider(this, - clusterWriter, codec); - clusterWriter.setClusterConnectionProvider(pooledClusterConnectionProvider); + StatefulRedisClusterPubSubConnectionImpl connection = new StatefulRedisClusterPubSubConnectionImpl<>(endpoint, + clusterWriter, codec, timeout, unit); - StatefulRedisPubSubConnectionImpl connection = new StatefulRedisPubSubConnectionImpl<>(endpoint, clusterWriter, - codec, timeout, unit); + ClusterPubSubConnectionProvider pooledClusterConnectionProvider = new ClusterPubSubConnectionProvider<>(this, + clusterWriter, codec, connection.getUpstreamListener()); - clusterWriter.setPartitions(partitions); + clusterWriter.setClusterConnectionProvider(pooledClusterConnectionProvider); + + connection.setPartitions(partitions); boolean connected = false; RedisException causingException = null; @@ -534,7 +571,9 @@ StatefulRedisPubSubConnectionImpl connectClusterPubSubImpl(RedisCod if (!connected) { connection.close(); - throw causingException; + if (causingException != null) { + throw causingException; + } } connection.registerCloseables(closeableResources, connection, clusterWriter, pooledClusterConnectionProvider); @@ -568,8 +607,8 @@ private void connectStateful(StatefulRedisConnectionImpl connection * */ private void connectStateful(DefaultEndpoint endpoint, StatefulRedisClusterConnectionImpl connection, - RedisURI connectionSettings, Supplier socketAddressSupplier, - Supplier commandHandlerSupplier) { + RedisURI connectionSettings, Supplier socketAddressSupplier, + Supplier commandHandlerSupplier) { connectStateful0(connection, endpoint, connectionSettings, socketAddressSupplier, commandHandlerSupplier); @@ -639,6 +678,10 @@ protected void updatePartitionsInConnections() { forEachClusterConnection(input -> { input.setPartitions(partitions); }); + + forEachClusterPubSubConnection(input -> { + input.setPartitions(partitions); + }); } protected void initializePartitions() { @@ -805,6 +848,10 @@ protected void forEachClusterConnection(Consumer input instanceof StatefulRedisClusterConnectionImpl, function); } + protected void forEachClusterPubSubConnection(Consumer> function) { + forEachCloseable(input -> input instanceof StatefulRedisClusterPubSubConnectionImpl, function); + } + protected void forEachCloseable(Predicate selector, Consumer function) { for (Closeable c : closeableResources) { if (selector.test(c)) { diff --git a/src/main/java/com/lambdaworks/redis/cluster/RedisClusterPubSubAsyncCommandsImpl.java b/src/main/java/com/lambdaworks/redis/cluster/RedisClusterPubSubAsyncCommandsImpl.java new file mode 100644 index 0000000000..9d1deadcb8 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/cluster/RedisClusterPubSubAsyncCommandsImpl.java @@ -0,0 +1,104 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.lambdaworks.redis.cluster; + +import static com.lambdaworks.redis.cluster.NodeSelectionInvocationHandler.ExecutionModel.ASYNC; + +import java.lang.reflect.Proxy; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +import com.lambdaworks.redis.RedisURI; +import com.lambdaworks.redis.cluster.api.NodeSelectionSupport; +import com.lambdaworks.redis.cluster.models.partitions.RedisClusterNode; +import com.lambdaworks.redis.cluster.pubsub.StatefulRedisClusterPubSubConnection; +import com.lambdaworks.redis.cluster.pubsub.api.async.NodeSelectionPubSubAsyncCommands; +import com.lambdaworks.redis.cluster.pubsub.api.async.PubSubAsyncNodeSelection; +import com.lambdaworks.redis.cluster.pubsub.api.async.RedisClusterPubSubAsyncCommands; +import com.lambdaworks.redis.codec.RedisCodec; +import com.lambdaworks.redis.pubsub.RedisPubSubAsyncCommandsImpl; +import com.lambdaworks.redis.pubsub.StatefulRedisPubSubConnection; +import com.lambdaworks.redis.pubsub.api.async.RedisPubSubAsyncCommands; + +/** + * @author Mark Paluch + */ +class RedisClusterPubSubAsyncCommandsImpl extends RedisPubSubAsyncCommandsImpl + implements RedisClusterPubSubAsyncCommands { + + /** + * Initialize a new connection. + * + * @param connection the connection . + * @param codec Codec used to encode/decode keys and values. + */ + public RedisClusterPubSubAsyncCommandsImpl(StatefulRedisClusterPubSubConnection connection, RedisCodec codec) { + super(connection, codec); + } + + @Override + public StatefulRedisClusterPubSubConnection getStatefulConnection() { + return (StatefulRedisClusterPubSubConnection) super.getStatefulConnection(); + } + + @SuppressWarnings("unchecked") + @Override + public PubSubAsyncNodeSelection nodes(Predicate predicate) { + + PubSubAsyncNodeSelection selection = new StaticPubSubAsyncNodeSelection<>(getStatefulConnection(), predicate); + + NodeSelectionInvocationHandler h = new NodeSelectionInvocationHandler((AbstractNodeSelection) selection, + RedisPubSubAsyncCommands.class, ASYNC); + return (PubSubAsyncNodeSelection) Proxy.newProxyInstance(NodeSelectionSupport.class.getClassLoader(), + new Class[] { NodeSelectionPubSubAsyncCommands.class, PubSubAsyncNodeSelection.class }, h); + } + + private static class StaticPubSubAsyncNodeSelection + extends AbstractNodeSelection, NodeSelectionPubSubAsyncCommands, K, V> + implements PubSubAsyncNodeSelection { + + private final List redisClusterNodes; + private final ClusterDistributionChannelWriter writer; + + @SuppressWarnings("unchecked") + public StaticPubSubAsyncNodeSelection(StatefulRedisClusterPubSubConnection globalConnection, + Predicate selector) { + + this.redisClusterNodes = globalConnection.getPartitions().getPartitions().stream().filter(selector) + .collect(Collectors.toList()); + writer = ((StatefulRedisClusterPubSubConnectionImpl) globalConnection).getClusterDistributionChannelWriter(); + } + + @Override + protected RedisPubSubAsyncCommands getApi(RedisClusterNode redisClusterNode) { + return getConnection(redisClusterNode).async(); + } + + protected List nodes() { + return redisClusterNodes; + } + + @SuppressWarnings("unchecked") + protected StatefulRedisPubSubConnection getConnection(RedisClusterNode redisClusterNode) { + RedisURI uri = redisClusterNode.getUri(); + return (StatefulRedisPubSubConnection) writer.getClusterConnectionProvider() + .getConnection(ClusterConnectionProvider.Intent.WRITE, uri.getHost(), uri.getPort()); + } + } +} diff --git a/src/main/java/com/lambdaworks/redis/cluster/RedisClusterPubSubReactiveCommandsImpl.java b/src/main/java/com/lambdaworks/redis/cluster/RedisClusterPubSubReactiveCommandsImpl.java new file mode 100644 index 0000000000..46bc3f1592 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/cluster/RedisClusterPubSubReactiveCommandsImpl.java @@ -0,0 +1,104 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.lambdaworks.redis.cluster; + +import static com.lambdaworks.redis.cluster.NodeSelectionInvocationHandler.ExecutionModel.REACTIVE; + +import java.lang.reflect.Proxy; +import java.util.List; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +import com.lambdaworks.redis.RedisURI; +import com.lambdaworks.redis.cluster.api.NodeSelectionSupport; +import com.lambdaworks.redis.cluster.models.partitions.RedisClusterNode; +import com.lambdaworks.redis.cluster.pubsub.StatefulRedisClusterPubSubConnection; +import com.lambdaworks.redis.cluster.pubsub.api.reactive.NodeSelectionPubSubReactiveCommands; +import com.lambdaworks.redis.cluster.pubsub.api.reactive.PubSubReactiveNodeSelection; +import com.lambdaworks.redis.cluster.pubsub.api.reactive.RedisClusterPubSubReactiveCommands; +import com.lambdaworks.redis.codec.RedisCodec; +import com.lambdaworks.redis.pubsub.RedisPubSubReactiveCommandsImpl; +import com.lambdaworks.redis.pubsub.StatefulRedisPubSubConnection; +import com.lambdaworks.redis.pubsub.api.reactive.RedisPubSubReactiveCommands; + +/** + * @author Mark Paluch + */ +class RedisClusterPubSubReactiveCommandsImpl extends RedisPubSubReactiveCommandsImpl + implements RedisClusterPubSubReactiveCommands { + + /** + * Initialize a new connection. + * + * @param connection the connection . + * @param codec Codec used to encode/decode keys and values. + */ + public RedisClusterPubSubReactiveCommandsImpl(StatefulRedisClusterPubSubConnection connection, + RedisCodec codec) { + super(connection, codec); + } + + @Override + public StatefulRedisClusterPubSubConnection getStatefulConnection() { + return (StatefulRedisClusterPubSubConnection) super.getStatefulConnection(); + } + + @SuppressWarnings("unchecked") + @Override + public PubSubReactiveNodeSelection nodes(Predicate predicate) { + + PubSubReactiveNodeSelection selection = new StaticPubSubReactiveNodeSelection(getStatefulConnection(), + predicate); + + NodeSelectionInvocationHandler h = new NodeSelectionInvocationHandler((AbstractNodeSelection) selection, + RedisPubSubReactiveCommands.class, REACTIVE); + return (PubSubReactiveNodeSelection) Proxy.newProxyInstance(NodeSelectionSupport.class.getClassLoader(), + new Class[] { NodeSelectionPubSubReactiveCommands.class, PubSubReactiveNodeSelection.class }, h); + } + + private static class StaticPubSubReactiveNodeSelection + extends AbstractNodeSelection, NodeSelectionPubSubReactiveCommands, K, V> + implements PubSubReactiveNodeSelection { + + private final List redisClusterNodes; + private final ClusterDistributionChannelWriter writer; + + @SuppressWarnings("unchecked") + public StaticPubSubReactiveNodeSelection(StatefulRedisClusterPubSubConnection globalConnection, + Predicate selector) { + + this.redisClusterNodes = globalConnection.getPartitions().getPartitions().stream().filter(selector) + .collect(Collectors.toList()); + writer = ((StatefulRedisClusterPubSubConnectionImpl) globalConnection).getClusterDistributionChannelWriter(); + } + + @Override + protected RedisPubSubReactiveCommands getApi(RedisClusterNode redisClusterNode) { + return getConnection(redisClusterNode).reactive(); + } + + protected List nodes() { + return redisClusterNodes; + } + + @SuppressWarnings("unchecked") + protected StatefulRedisPubSubConnection getConnection(RedisClusterNode redisClusterNode) { + RedisURI uri = redisClusterNode.getUri(); + return (StatefulRedisPubSubConnection) writer.getClusterConnectionProvider() + .getConnection(ClusterConnectionProvider.Intent.WRITE, uri.getHost(), uri.getPort()); + } + } +} diff --git a/src/main/java/com/lambdaworks/redis/cluster/StatefulRedisClusterPubSubConnectionImpl.java b/src/main/java/com/lambdaworks/redis/cluster/StatefulRedisClusterPubSubConnectionImpl.java new file mode 100644 index 0000000000..4f6e3f2656 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/cluster/StatefulRedisClusterPubSubConnectionImpl.java @@ -0,0 +1,182 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.lambdaworks.redis.cluster; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Proxy; +import java.util.concurrent.TimeUnit; + +import com.lambdaworks.redis.AbstractRedisClient; +import com.lambdaworks.redis.RedisChannelWriter; +import com.lambdaworks.redis.RedisException; +import com.lambdaworks.redis.RedisURI; +import com.lambdaworks.redis.cluster.models.partitions.Partitions; +import com.lambdaworks.redis.cluster.models.partitions.RedisClusterNode; +import com.lambdaworks.redis.cluster.pubsub.RedisClusterPubSubListener; +import com.lambdaworks.redis.cluster.pubsub.StatefulRedisClusterPubSubConnection; +import com.lambdaworks.redis.cluster.pubsub.api.async.RedisClusterPubSubAsyncCommands; +import com.lambdaworks.redis.cluster.pubsub.api.reactive.RedisClusterPubSubReactiveCommands; +import com.lambdaworks.redis.cluster.pubsub.api.sync.NodeSelectionPubSubCommands; +import com.lambdaworks.redis.cluster.pubsub.api.sync.PubSubNodeSelection; +import com.lambdaworks.redis.cluster.pubsub.api.sync.RedisClusterPubSubCommands; +import com.lambdaworks.redis.codec.RedisCodec; +import com.lambdaworks.redis.pubsub.RedisPubSubAsyncCommandsImpl; +import com.lambdaworks.redis.pubsub.RedisPubSubReactiveCommandsImpl; +import com.lambdaworks.redis.pubsub.StatefulRedisPubSubConnection; +import com.lambdaworks.redis.pubsub.StatefulRedisPubSubConnectionImpl; +import com.lambdaworks.redis.pubsub.api.async.RedisPubSubAsyncCommands; +import com.lambdaworks.redis.pubsub.api.sync.RedisPubSubCommands; + +/** + * @author Mark Paluch + */ +class StatefulRedisClusterPubSubConnectionImpl extends StatefulRedisPubSubConnectionImpl + implements StatefulRedisClusterPubSubConnection { + + private final PubSubClusterEndpoint endpoint; + private volatile Partitions partitions; + + /** + * Initialize a new connection. + * + * @param writer the channel writer + * @param codec Codec used to encode/decode keys and values. + * @param timeout Maximum time to wait for a response. + * @param unit Unit of time for the timeout. + */ + public StatefulRedisClusterPubSubConnectionImpl(PubSubClusterEndpoint endpoint, RedisChannelWriter writer, + RedisCodec codec, long timeout, TimeUnit unit) { + + super(endpoint, writer, codec, timeout, unit); + this.endpoint = endpoint; + } + + @Override + public RedisClusterPubSubAsyncCommands async() { + return (RedisClusterPubSubAsyncCommands) super.async(); + } + + @Override + protected RedisPubSubAsyncCommandsImpl newRedisAsyncCommandsImpl() { + return new RedisClusterPubSubAsyncCommandsImpl<>(this, codec); + } + + @Override + public RedisClusterPubSubCommands sync() { + return (RedisClusterPubSubCommands) super.sync(); + } + + @SuppressWarnings("unchecked") + @Override + protected RedisPubSubCommands newRedisSyncCommandsImpl() { + + return (RedisPubSubCommands) Proxy.newProxyInstance(AbstractRedisClient.class.getClassLoader(), + new Class[] { RedisClusterPubSubCommands.class, RedisPubSubCommands.class }, syncInvocationHandler()); + } + + private InvocationHandler syncInvocationHandler() { + return new ClusterFutureSyncInvocationHandler(this, RedisPubSubAsyncCommands.class, PubSubNodeSelection.class, + NodeSelectionPubSubCommands.class, async()); + } + + @Override + public RedisClusterPubSubReactiveCommands reactive() { + return (RedisClusterPubSubReactiveCommands) super.reactive(); + } + + @Override + protected RedisPubSubReactiveCommandsImpl newRedisReactiveCommandsImpl() { + return new RedisClusterPubSubReactiveCommandsImpl(this, codec); + } + + @Override + public void activated() { + super.activated(); + async().clusterMyId().thenAccept(nodeId -> endpoint.setClusterNode(partitions.getPartitionByNodeId(nodeId))); + } + + @Override + public StatefulRedisPubSubConnection getConnection(String nodeId) { + + RedisURI redisURI = lookup(nodeId); + + if (redisURI == null) { + throw new RedisException("NodeId " + nodeId + " does not belong to the cluster"); + } + + return (StatefulRedisPubSubConnection) getClusterDistributionChannelWriter().getClusterConnectionProvider() + .getConnection(ClusterConnectionProvider.Intent.WRITE, nodeId); + } + + @Override + public StatefulRedisPubSubConnection getConnection(String host, int port) { + + return (StatefulRedisPubSubConnection) getClusterDistributionChannelWriter().getClusterConnectionProvider() + .getConnection(ClusterConnectionProvider.Intent.WRITE, host, port); + } + + public void setPartitions(Partitions partitions) { + this.partitions = partitions; + getClusterDistributionChannelWriter().setPartitions(partitions); + } + + public Partitions getPartitions() { + return partitions; + } + + @Override + public void setNodeMessagePropagation(boolean enabled) { + this.endpoint.setNodeMessagePropagation(enabled); + } + + /** + * Add a new {@link RedisClusterPubSubListener listener}. + * + * @param listener the listener, must not be {@literal null}. + */ + @Override + public void addListener(RedisClusterPubSubListener listener) { + endpoint.addListener(listener); + } + + /** + * Remove an existing {@link RedisClusterPubSubListener listener}. + * + * @param listener the listener, must not be {@literal null}. + */ + @Override + public void removeListener(RedisClusterPubSubListener listener) { + endpoint.removeListener(listener); + } + + RedisClusterPubSubListener getUpstreamListener() { + return endpoint.getUpstreamListener(); + } + + protected ClusterDistributionChannelWriter getClusterDistributionChannelWriter() { + return (ClusterDistributionChannelWriter) super.getChannelWriter(); + } + + private RedisURI lookup(String nodeId) { + + for (RedisClusterNode partition : partitions) { + if (partition.getNodeId().equals(nodeId)) { + return partition.getUri(); + } + } + return null; + } +} diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/reactive/ReactiveExecutions.java b/src/main/java/com/lambdaworks/redis/cluster/api/reactive/ReactiveExecutions.java index 9c8203191b..264b234d4a 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/reactive/ReactiveExecutions.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/reactive/ReactiveExecutions.java @@ -20,7 +20,6 @@ import com.lambdaworks.redis.cluster.models.partitions.RedisClusterNode; import reactor.core.publisher.Flux; -import rx.Observable; /** * Execution holder for a reactive command to be executed on multiple nodes. @@ -31,7 +30,7 @@ public interface ReactiveExecutions { /** - * Return an {@link Observable} that contains a combined stream of the multi-node execution. + * Return a {@link Flux} that contains a combined stream of the multi-node execution. * * @return */ diff --git a/src/main/java/com/lambdaworks/redis/cluster/pubsub/RedisClusterPubSubAdapter.java b/src/main/java/com/lambdaworks/redis/cluster/pubsub/RedisClusterPubSubAdapter.java new file mode 100644 index 0000000000..4b279848de --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/cluster/pubsub/RedisClusterPubSubAdapter.java @@ -0,0 +1,59 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.lambdaworks.redis.cluster.pubsub; + +import com.lambdaworks.redis.cluster.models.partitions.RedisClusterNode; + +/** + * Convenience adapter with an empty implementation of all {@link RedisClusterPubSubListener} callback methods. + * + * @param Key type. + * @param Value type. + * @author Mark Paluch + * @since 4.4 + */ +public class RedisClusterPubSubAdapter implements RedisClusterPubSubListener { + + @Override + public void message(RedisClusterNode node, K channel, V message) { + // empty adapter method + } + + @Override + public void message(RedisClusterNode node, K pattern, K channel, V message) { + // empty adapter method + } + + @Override + public void subscribed(RedisClusterNode node, K channel, long count) { + // empty adapter method + } + + @Override + public void psubscribed(RedisClusterNode node, K pattern, long count) { + // empty adapter method + } + + @Override + public void unsubscribed(RedisClusterNode node, K channel, long count) { + // empty adapter method + } + + @Override + public void punsubscribed(RedisClusterNode node, K pattern, long count) { + // empty adapter method + } +} diff --git a/src/main/java/com/lambdaworks/redis/cluster/pubsub/RedisClusterPubSubListener.java b/src/main/java/com/lambdaworks/redis/cluster/pubsub/RedisClusterPubSubListener.java new file mode 100644 index 0000000000..b3ab77f8c8 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/cluster/pubsub/RedisClusterPubSubListener.java @@ -0,0 +1,78 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.lambdaworks.redis.cluster.pubsub; + +import com.lambdaworks.redis.cluster.models.partitions.RedisClusterNode; + +/** + * Interface for Redis Cluster Pub/Sub listeners. + * + * @param Key type. + * @param Value type. + * @author Mark Paluch + * @since 4.4 + */ +public interface RedisClusterPubSubListener { + + /** + * Message received from a channel subscription. + * + * @param channel Channel. + * @param message Message. + */ + void message(RedisClusterNode node, K channel, V message); + + /** + * Message received from a pattern subscription. + * + * @param pattern Pattern + * @param channel Channel + * @param message Message + */ + void message(RedisClusterNode node, K pattern, K channel, V message); + + /** + * Subscribed to a channel. + * + * @param channel Channel + * @param count Subscription count. + */ + void subscribed(RedisClusterNode node, K channel, long count); + + /** + * Subscribed to a pattern. + * + * @param pattern Pattern. + * @param count Subscription count. + */ + void psubscribed(RedisClusterNode node, K pattern, long count); + + /** + * Unsubscribed from a channel. + * + * @param channel Channel + * @param count Subscription count. + */ + void unsubscribed(RedisClusterNode node, K channel, long count); + + /** + * Unsubscribed from a pattern. + * + * @param pattern Channel + * @param count Subscription count. + */ + void punsubscribed(RedisClusterNode node, K pattern, long count); +} diff --git a/src/main/java/com/lambdaworks/redis/cluster/pubsub/StatefulRedisClusterPubSubConnection.java b/src/main/java/com/lambdaworks/redis/cluster/pubsub/StatefulRedisClusterPubSubConnection.java new file mode 100644 index 0000000000..a0e9358256 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/cluster/pubsub/StatefulRedisClusterPubSubConnection.java @@ -0,0 +1,159 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.lambdaworks.redis.cluster.pubsub; + +import java.util.function.Predicate; + +import com.lambdaworks.redis.RedisException; +import com.lambdaworks.redis.cluster.ClusterClientOptions; +import com.lambdaworks.redis.cluster.api.sync.NodeSelection; +import com.lambdaworks.redis.cluster.models.partitions.Partitions; +import com.lambdaworks.redis.cluster.pubsub.api.async.RedisClusterPubSubAsyncCommands; +import com.lambdaworks.redis.cluster.pubsub.api.reactive.RedisClusterPubSubReactiveCommands; +import com.lambdaworks.redis.cluster.pubsub.api.sync.RedisClusterPubSubCommands; +import com.lambdaworks.redis.pubsub.RedisPubSubListener; +import com.lambdaworks.redis.pubsub.StatefulRedisPubSubConnection; + +/** + * A stateful Pub/Sub connection for Redis Cluster use. This connection type is intended for Pub/Sub messaging with Redis + * Cluster. The connection provides transparent command routing based on the first command key. + *

    + * This connection allows publishing and subscription to Pub/Sub messages within a Redis Cluster. Due to Redis Cluster's nature, + * messages are broadcasted across the cluster and a client can connect to any arbitrary node to participate with a + * subscription. + * + *

    + *     
    + *  StatefulRedisClusterPubSubConnection connection = clusterClient.connectPubSub();
    + *  connection.addListener(…);
    + *
    + *  RedisClusterPubSubCommands sync = connection.sync();
    + *  sync.subscribe("channel");
    + *  sync.publish("channel", "message");
    + *     
    + * 
    + * + *

    Keyspace notifications

    Redis clients can subscribe to user-space Pub/Sub messages and Redis keyspace notifications. + * Other than user-space Pub/Sub messages are Keyspace notifications not broadcasted to the whole cluster. They stay node-local. + * Subscription to keyspace notifications requires subscription to the nodes which publish the keyspace notifications. + * + *

    + * {@link StatefulRedisClusterPubSubConnection} allows node-specific subscriptions and {@link #setNodeMessagePropagation message + * propagation}. {@link #setNodeMessagePropagation} can notify a {@link RedisPubSubListener} that requires a single registration + * with {@link #addListener(RedisPubSubListener) this connection}. Node-subscriptions are supported on + * {@link #getConnection(String, int) connection} and {@link NodeSelection} levels through + * {@link RedisClusterPubSubAsyncCommands#nodes(Predicate) asynchronous}, {@link RedisClusterPubSubCommands#nodes(Predicate) + * synchronous}, and {@link RedisClusterPubSubReactiveCommands#nodes(Predicate) reactive} APIs. + * + *

    + *     
    + *  StatefulRedisClusterPubSubConnection connection = clusterClient.connectPubSub();
    + *  connection.addListener(…);
    + *
    + *  RedisClusterPubSubCommands sync = connection.sync();
    + *  sync.slaves().commands().psubscribe("__key*__:*");
    + *     
    + * 
    + * + * @author Mark Paluch + * @since 4.4 + */ +public interface StatefulRedisClusterPubSubConnection extends StatefulRedisPubSubConnection { + + /** + * Returns the {@link RedisClusterPubSubCommands} API for the current connection. Does not create a new connection. + * + * @return the synchronous API for the underlying connection. + */ + RedisClusterPubSubCommands sync(); + + /** + * Returns the {@link RedisClusterPubSubAsyncCommands} API for the current connection. Does not create a new connection. + * + * @return the asynchronous API for the underlying connection. + */ + RedisClusterPubSubAsyncCommands async(); + + /** + * Returns the {@link RedisClusterPubSubReactiveCommands} API for the current connection. Does not create a new connection. + * + * @return the reactive API for the underlying connection. + */ + RedisClusterPubSubReactiveCommands reactive(); + + /** + * Retrieve a connection to the specified cluster node using the nodeId. Host and port are looked up in the node list. This + * connection is bound to the node id. Once the cluster topology view is updated, the connection will try to reconnect the + * to the node with the specified {@code nodeId}, that behavior can also lead to a closed connection once the node with the + * specified {@code nodeId} is no longer part of the cluster. + * + * Do not close the connections. Otherwise, unpredictable behavior will occur. The nodeId must be part of the cluster and is + * validated against the current topology view in {@link com.lambdaworks.redis.cluster.models.partitions.Partitions}. + * + * @param nodeId the node Id + * @return a connection to the requested cluster node + * @throws RedisException if the requested node identified by {@code nodeId} is not part of the cluster + */ + StatefulRedisPubSubConnection getConnection(String nodeId); + + /** + * Retrieve a connection to the specified cluster node using host and port. This connection is bound to a host and port. + * Updates to the cluster topology view can close the connection once the host, identified by {@code host} and {@code port}, + * are no longer part of the cluster. + * + * Do not close the connections. Otherwise, unpredictable behavior will occur. Host and port connections are verified by + * default for cluster membership, see {@link ClusterClientOptions#isValidateClusterNodeMembership()}. + * + * @param host the host + * @param port the port + * @return a connection to the requested cluster node + * @throws RedisException if the requested node identified by {@code host} and {@code port} is not part of the cluster + */ + StatefulRedisPubSubConnection getConnection(String host, int port); + + /** + * @return Known partitions for this connection. + */ + Partitions getPartitions(); + + /** + * Enables/disables node message propagation to {@code this} {@link StatefulRedisClusterPubSubConnection connections} + * {@link RedisPubSubListener listeners}. + *

    + * If {@code enabled} is {@literal true}, then Pub/Sub messages received on node-specific connections are propagated to this + * connection facade. Registered {@link RedisPubSubListener} will receive messages from individual node subscriptions. + *

    + * Node event propagation is disabled by default. + * + * @param enabled {@literal true} to enable node message propagation; {@literal false} (default) to disable message + * propagation. + */ + void setNodeMessagePropagation(boolean enabled); + + /** + * Add a new {@link RedisClusterPubSubListener listener}. + * + * @param listener the listener, must not be {@literal null}. + */ + void addListener(RedisClusterPubSubListener listener); + + /** + * Remove an existing {@link RedisClusterPubSubListener listener}. + * + * @param listener the listener, must not be {@literal null}. + */ + void removeListener(RedisClusterPubSubListener listener); +} diff --git a/src/main/java/com/lambdaworks/redis/cluster/pubsub/api/async/NodeSelectionPubSubAsyncCommands.java b/src/main/java/com/lambdaworks/redis/cluster/pubsub/api/async/NodeSelectionPubSubAsyncCommands.java new file mode 100644 index 0000000000..10e367ae1b --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/cluster/pubsub/api/async/NodeSelectionPubSubAsyncCommands.java @@ -0,0 +1,59 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.lambdaworks.redis.cluster.pubsub.api.async; + +import com.lambdaworks.redis.cluster.api.async.AsyncExecutions; + +/** + * Asynchronous executed commands on a node selection for Pub/Sub. + * + * @author Mark Paluch + * @since 4.4 + */ +public interface NodeSelectionPubSubAsyncCommands { + + /** + * Listen for messages published to channels matching the given patterns. + * + * @param patterns the patterns + * @return RedisFuture<Void> Future to synchronize {@code psubscribe} completion + */ + AsyncExecutions psubscribe(K... patterns); + + /** + * Stop listening for messages posted to channels matching the given patterns. + * + * @param patterns the patterns + * @return RedisFuture<Void> Future to synchronize {@code punsubscribe} completion + */ + AsyncExecutions punsubscribe(K... patterns); + + /** + * Listen for messages published to the given channels. + * + * @param channels the channels + * @return RedisFuture<Void> Future to synchronize {@code subscribe} completion + */ + AsyncExecutions subscribe(K... channels); + + /** + * Stop listening for messages posted to the given channels. + * + * @param channels the channels + * @return RedisFuture<Void> Future to synchronize {@code unsubscribe} completion. + */ + AsyncExecutions unsubscribe(K... channels); +} diff --git a/src/main/java/com/lambdaworks/redis/cluster/pubsub/api/async/PubSubAsyncNodeSelection.java b/src/main/java/com/lambdaworks/redis/cluster/pubsub/api/async/PubSubAsyncNodeSelection.java new file mode 100644 index 0000000000..cb08366da9 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/cluster/pubsub/api/async/PubSubAsyncNodeSelection.java @@ -0,0 +1,36 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.lambdaworks.redis.cluster.pubsub.api.async; + +import com.lambdaworks.redis.api.async.RedisAsyncCommands; +import com.lambdaworks.redis.cluster.api.NodeSelectionSupport; +import com.lambdaworks.redis.cluster.api.async.NodeSelectionAsyncCommands; +import com.lambdaworks.redis.pubsub.api.async.RedisPubSubAsyncCommands; + +/** + * Node selection with access to asynchronous executed commands on the set. This API is subject to incompatible changes in a + * future release. The API is exempt from any compatibility guarantees made by lettuce. The current state implies nothing about + * the quality or performance of the API in question, only the fact that it is not "API-frozen." + * + * The NodeSelection command API and its result types are a base for discussions. + * + * @author Mark Paluch + * @since 4.4 + */ +public interface PubSubAsyncNodeSelection extends + NodeSelectionSupport, NodeSelectionPubSubAsyncCommands> { + +} diff --git a/src/main/java/com/lambdaworks/redis/cluster/pubsub/api/async/RedisClusterPubSubAsyncCommands.java b/src/main/java/com/lambdaworks/redis/cluster/pubsub/api/async/RedisClusterPubSubAsyncCommands.java new file mode 100644 index 0000000000..39d6826233 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/cluster/pubsub/api/async/RedisClusterPubSubAsyncCommands.java @@ -0,0 +1,85 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.lambdaworks.redis.cluster.pubsub.api.async; + +import java.util.function.Predicate; + +import com.lambdaworks.redis.cluster.models.partitions.RedisClusterNode; +import com.lambdaworks.redis.cluster.pubsub.StatefulRedisClusterPubSubConnection; +import com.lambdaworks.redis.pubsub.api.async.RedisPubSubAsyncCommands; + +/** + * Asynchronous and thread-safe Redis Cluster PubSub API. Operations are executed either on the main connection or a + * {@link PubSubAsyncNodeSelection}. + * + * @param Key type. + * @param Value type. + * @author Mark Paluch + * @since 4.4 + */ +public interface RedisClusterPubSubAsyncCommands extends RedisPubSubAsyncCommands { + + /** + * @return the underlying connection. + */ + StatefulRedisClusterPubSubConnection getStatefulConnection(); + + /** + * Select all masters. + * + * @return API with asynchronous executed commands on a selection of master cluster nodes. + */ + default PubSubAsyncNodeSelection masters() { + return nodes(redisClusterNode -> redisClusterNode.is(RedisClusterNode.NodeFlag.MASTER)); + } + + /** + * Select all slaves. + * + * @return API with asynchronous executed commands on a selection of slave cluster nodes. + */ + default PubSubAsyncNodeSelection slaves() { + return nodes(redisClusterNode -> redisClusterNode.is(RedisClusterNode.NodeFlag.SLAVE)); + } + + /** + * Select all slaves. + * + * @param predicate Predicate to filter nodes + * @return API with asynchronous executed commands on a selection of slave cluster nodes. + */ + default PubSubAsyncNodeSelection slaves(Predicate predicate) { + return nodes( + redisClusterNode -> predicate.test(redisClusterNode) && redisClusterNode.is(RedisClusterNode.NodeFlag.SLAVE)); + } + + /** + * Select all known cluster nodes. + * + * @return API with asynchronous executed commands on a selection of all cluster nodes. + */ + default PubSubAsyncNodeSelection all() { + return nodes(redisClusterNode -> true); + } + + /** + * Select nodes by a predicate. + * + * @param predicate Predicate to filter nodes + * @return API with asynchronous executed commands on a selection of cluster nodes matching {@code predicate} + */ + PubSubAsyncNodeSelection nodes(Predicate predicate); +} diff --git a/src/main/java/com/lambdaworks/redis/cluster/pubsub/api/reactive/NodeSelectionPubSubReactiveCommands.java b/src/main/java/com/lambdaworks/redis/cluster/pubsub/api/reactive/NodeSelectionPubSubReactiveCommands.java new file mode 100644 index 0000000000..24dddfe903 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/cluster/pubsub/api/reactive/NodeSelectionPubSubReactiveCommands.java @@ -0,0 +1,59 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.lambdaworks.redis.cluster.pubsub.api.reactive; + +import com.lambdaworks.redis.cluster.api.reactive.ReactiveExecutions; + +/** + * Reactive executed commands on a node selection for Pub/Sub. + * + * @author Mark Paluch + * @since 4.4 + */ +public interface NodeSelectionPubSubReactiveCommands { + + /** + * Listen for messages published to channels matching the given patterns. + * + * @param patterns the patterns + * @return RedisFuture<Void> Future to synchronize {@code psubscribe} completion + */ + ReactiveExecutions psubscribe(K... patterns); + + /** + * Stop listening for messages posted to channels matching the given patterns. + * + * @param patterns the patterns + * @return RedisFuture<Void> Future to synchronize {@code punsubscribe} completion + */ + ReactiveExecutions punsubscribe(K... patterns); + + /** + * Listen for messages published to the given channels. + * + * @param channels the channels + * @return RedisFuture<Void> Future to synchronize {@code subscribe} completion + */ + ReactiveExecutions subscribe(K... channels); + + /** + * Stop listening for messages posted to the given channels. + * + * @param channels the channels + * @return RedisFuture<Void> Future to synchronize {@code unsubscribe} completion. + */ + ReactiveExecutions unsubscribe(K... channels); +} diff --git a/src/main/java/com/lambdaworks/redis/cluster/pubsub/api/reactive/PubSubReactiveNodeSelection.java b/src/main/java/com/lambdaworks/redis/cluster/pubsub/api/reactive/PubSubReactiveNodeSelection.java new file mode 100644 index 0000000000..1125a6abe9 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/cluster/pubsub/api/reactive/PubSubReactiveNodeSelection.java @@ -0,0 +1,31 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.lambdaworks.redis.cluster.pubsub.api.reactive; + +import com.lambdaworks.redis.cluster.api.NodeSelectionSupport; +import com.lambdaworks.redis.pubsub.api.reactive.RedisPubSubReactiveCommands; +import com.lambdaworks.redis.pubsub.api.sync.RedisPubSubCommands; + +/** + * Node selection with access to {@link RedisPubSubCommands}. + * + * @author Mark Paluch + * @since 4.4 + */ +public interface PubSubReactiveNodeSelection + extends NodeSelectionSupport, NodeSelectionPubSubReactiveCommands> { + +} diff --git a/src/main/java/com/lambdaworks/redis/cluster/pubsub/api/reactive/RedisClusterPubSubReactiveCommands.java b/src/main/java/com/lambdaworks/redis/cluster/pubsub/api/reactive/RedisClusterPubSubReactiveCommands.java new file mode 100644 index 0000000000..0f15a30a31 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/cluster/pubsub/api/reactive/RedisClusterPubSubReactiveCommands.java @@ -0,0 +1,85 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.lambdaworks.redis.cluster.pubsub.api.reactive; + +import java.util.function.Predicate; + +import com.lambdaworks.redis.cluster.models.partitions.RedisClusterNode; +import com.lambdaworks.redis.cluster.pubsub.StatefulRedisClusterPubSubConnection; +import com.lambdaworks.redis.pubsub.api.reactive.RedisPubSubReactiveCommands; + +/** + * Reactive and thread-safe Redis Cluster PubSub API. Operations are executed either on the main connection or a + * {@link PubSubReactiveNodeSelection}. + * + * @param Key type. + * @param Value type. + * @author Mark Paluch + * @since 4.4 + */ +public interface RedisClusterPubSubReactiveCommands extends RedisPubSubReactiveCommands { + + /** + * @return the underlying connection. + */ + StatefulRedisClusterPubSubConnection getStatefulConnection(); + + /** + * Select all masters. + * + * @return API with asynchronous executed commands on a selection of master cluster nodes. + */ + default PubSubReactiveNodeSelection masters() { + return nodes(redisClusterNode -> redisClusterNode.is(RedisClusterNode.NodeFlag.MASTER)); + } + + /** + * Select all slaves. + * + * @return API with asynchronous executed commands on a selection of slave cluster nodes. + */ + default PubSubReactiveNodeSelection slaves() { + return nodes(redisClusterNode -> redisClusterNode.is(RedisClusterNode.NodeFlag.SLAVE)); + } + + /** + * Select all slaves. + * + * @param predicate Predicate to filter nodes + * @return API with asynchronous executed commands on a selection of slave cluster nodes. + */ + default PubSubReactiveNodeSelection slaves(Predicate predicate) { + return nodes( + redisClusterNode -> predicate.test(redisClusterNode) && redisClusterNode.is(RedisClusterNode.NodeFlag.SLAVE)); + } + + /** + * Select all known cluster nodes. + * + * @return API with asynchronous executed commands on a selection of all cluster nodes. + */ + default PubSubReactiveNodeSelection all() { + return nodes(redisClusterNode -> true); + } + + /** + * Select nodes by a predicate. + * + * @param predicate Predicate to filter nodes + * @return API with asynchronous executed commands on a selection of cluster nodes matching {@code predicate} + */ + PubSubReactiveNodeSelection nodes(Predicate predicate); +} diff --git a/src/main/java/com/lambdaworks/redis/cluster/pubsub/api/sync/NodeSelectionPubSubCommands.java b/src/main/java/com/lambdaworks/redis/cluster/pubsub/api/sync/NodeSelectionPubSubCommands.java new file mode 100644 index 0000000000..87984dfdb1 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/cluster/pubsub/api/sync/NodeSelectionPubSubCommands.java @@ -0,0 +1,59 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.lambdaworks.redis.cluster.pubsub.api.sync; + +import com.lambdaworks.redis.cluster.api.sync.Executions; + +/** + * Synchronous executed commands on a node selection for Pub/Sub. + * + * @author Mark Paluch + * @since 4.4 + */ +public interface NodeSelectionPubSubCommands { + + /** + * Listen for messages published to channels matching the given patterns. + * + * @param patterns the patterns + * @return Executions to synchronize {@code psubscribe} completion + */ + Executions psubscribe(K... patterns); + + /** + * Stop listening for messages posted to channels matching the given patterns. + * + * @param patterns the patterns + * @return Executions Future to synchronize {@code punsubscribe} completion + */ + Executions punsubscribe(K... patterns); + + /** + * Listen for messages published to the given channels. + * + * @param channels the channels + * @return Executions Future to synchronize {@code subscribe} completion + */ + Executions subscribe(K... channels); + + /** + * Stop listening for messages posted to the given channels. + * + * @param channels the channels + * @return Executions Future to synchronize {@code unsubscribe} completion. + */ + Executions unsubscribe(K... channels); +} diff --git a/src/main/java/com/lambdaworks/redis/cluster/pubsub/api/sync/PubSubNodeSelection.java b/src/main/java/com/lambdaworks/redis/cluster/pubsub/api/sync/PubSubNodeSelection.java new file mode 100644 index 0000000000..4362952d4b --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/cluster/pubsub/api/sync/PubSubNodeSelection.java @@ -0,0 +1,30 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.lambdaworks.redis.cluster.pubsub.api.sync; + +import com.lambdaworks.redis.cluster.api.NodeSelectionSupport; +import com.lambdaworks.redis.pubsub.api.sync.RedisPubSubCommands; + +/** + * Node selection with access to {@link RedisPubSubCommands}. + * + * @author Mark Paluch + * @since 4.4 + */ +public interface PubSubNodeSelection + extends NodeSelectionSupport, NodeSelectionPubSubCommands> { + +} diff --git a/src/main/java/com/lambdaworks/redis/cluster/pubsub/api/sync/RedisClusterPubSubCommands.java b/src/main/java/com/lambdaworks/redis/cluster/pubsub/api/sync/RedisClusterPubSubCommands.java new file mode 100644 index 0000000000..4bd2df92d3 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/cluster/pubsub/api/sync/RedisClusterPubSubCommands.java @@ -0,0 +1,85 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.lambdaworks.redis.cluster.pubsub.api.sync; + +import java.util.function.Predicate; + +import com.lambdaworks.redis.cluster.models.partitions.RedisClusterNode; +import com.lambdaworks.redis.cluster.pubsub.StatefulRedisClusterPubSubConnection; +import com.lambdaworks.redis.pubsub.api.sync.RedisPubSubCommands; + +/** + * Synchronous and thread-safe Redis Cluster PubSub API. Operations are executed either on the main connection or a + * {@link PubSubNodeSelection}. + * + * @param Key type. + * @param Value type. + * @author Mark Paluch + * @since 4.4 + */ +public interface RedisClusterPubSubCommands extends RedisPubSubCommands { + + /** + * @return the underlying connection. + */ + StatefulRedisClusterPubSubConnection getStatefulConnection(); + + /** + * Select all masters. + * + * @return API with asynchronous executed commands on a selection of master cluster nodes. + */ + default PubSubNodeSelection masters() { + return nodes(redisClusterNode -> redisClusterNode.is(RedisClusterNode.NodeFlag.MASTER)); + } + + /** + * Select all slaves. + * + * @return API with asynchronous executed commands on a selection of slave cluster nodes. + */ + default PubSubNodeSelection slaves() { + return nodes(redisClusterNode -> redisClusterNode.is(RedisClusterNode.NodeFlag.SLAVE)); + } + + /** + * Select all slaves. + * + * @param predicate Predicate to filter nodes + * @return API with asynchronous executed commands on a selection of slave cluster nodes. + */ + default PubSubNodeSelection slaves(Predicate predicate) { + return nodes( + redisClusterNode -> predicate.test(redisClusterNode) && redisClusterNode.is(RedisClusterNode.NodeFlag.SLAVE)); + } + + /** + * Select all known cluster nodes. + * + * @return API with asynchronous executed commands on a selection of all cluster nodes. + */ + default PubSubNodeSelection all() { + return nodes(redisClusterNode -> true); + } + + /** + * Select nodes by a predicate. + * + * @param predicate Predicate to filter nodes + * @return API with asynchronous executed commands on a selection of cluster nodes matching {@code predicate} + */ + PubSubNodeSelection nodes(Predicate predicate); +} diff --git a/src/main/java/com/lambdaworks/redis/pubsub/PubSubEndpoint.java b/src/main/java/com/lambdaworks/redis/pubsub/PubSubEndpoint.java index ffc3682013..fe1817613d 100644 --- a/src/main/java/com/lambdaworks/redis/pubsub/PubSubEndpoint.java +++ b/src/main/java/com/lambdaworks/redis/pubsub/PubSubEndpoint.java @@ -46,23 +46,27 @@ public PubSubEndpoint(ClientOptions clientOptions) { } /** - * Add a new listener. + * Add a new {@link RedisPubSubListener listener}. * - * @param listener Listener. + * @param listener the listener, must not be {@literal null}. */ public void addListener(RedisPubSubListener listener) { listeners.add(listener); } /** - * Remove an existing listener. + * Remove an existing {@link RedisPubSubListener listener}.. * - * @param listener Listener. + * @param listener the listener, must not be {@literal null}. */ public void removeListener(RedisPubSubListener listener) { listeners.remove(listener); } + protected List> getListeners() { + return listeners; + } + public Set getChannels() { return channels; } @@ -82,7 +86,7 @@ public void notifyMessage(PubSubOutput output) { notifyListeners(output); } - private void notifyListeners(PubSubOutput output) { + protected void notifyListeners(PubSubOutput output) { // update listeners for (RedisPubSubListener listener : listeners) { switch (output.type()) { diff --git a/src/main/java/com/lambdaworks/redis/pubsub/StatefulRedisPubSubConnection.java b/src/main/java/com/lambdaworks/redis/pubsub/StatefulRedisPubSubConnection.java index 3a0729cd80..e5d8cbd78e 100644 --- a/src/main/java/com/lambdaworks/redis/pubsub/StatefulRedisPubSubConnection.java +++ b/src/main/java/com/lambdaworks/redis/pubsub/StatefulRedisPubSubConnection.java @@ -59,17 +59,16 @@ public interface StatefulRedisPubSubConnection extends StatefulRedisConnec RedisPubSubReactiveCommands reactive(); /** - * Add a new listener. - * - * @param listener Listener. + * Add a new {@link RedisPubSubListener listener}. + * + * @param listener the listener, must not be {@literal null}. */ void addListener(RedisPubSubListener listener); /** - * Remove an existing listener. + * Remove an existing {@link RedisPubSubListener listener}.. * - * @param listener Listener. + * @param listener the listener, must not be {@literal null}. */ void removeListener(RedisPubSubListener listener); - } diff --git a/src/main/java/com/lambdaworks/redis/pubsub/StatefulRedisPubSubConnectionImpl.java b/src/main/java/com/lambdaworks/redis/pubsub/StatefulRedisPubSubConnectionImpl.java index b7a0c06a06..e0e4b4251b 100644 --- a/src/main/java/com/lambdaworks/redis/pubsub/StatefulRedisPubSubConnectionImpl.java +++ b/src/main/java/com/lambdaworks/redis/pubsub/StatefulRedisPubSubConnectionImpl.java @@ -118,7 +118,7 @@ protected RedisPubSubReactiveCommandsImpl newRedisReactiveCommandsImpl() { /** * Re-subscribe to all previously subscribed channels and patterns. - * + * * @return list of the futures of the {@literal subscribe} and {@literal psubscribe} commands. */ protected List> resubscribe() { diff --git a/src/main/java/com/lambdaworks/redis/pubsub/api/sync/RedisPubSubCommands.java b/src/main/java/com/lambdaworks/redis/pubsub/api/sync/RedisPubSubCommands.java index 77b6b0aed1..3649c08c6e 100644 --- a/src/main/java/com/lambdaworks/redis/pubsub/api/sync/RedisPubSubCommands.java +++ b/src/main/java/com/lambdaworks/redis/pubsub/api/sync/RedisPubSubCommands.java @@ -20,7 +20,6 @@ import com.lambdaworks.redis.pubsub.StatefulRedisPubSubConnection; /** - * * Synchronous and thread-safe Redis PubSub API. * * @param Key type. diff --git a/src/test/java/com/lambdaworks/redis/cluster/pubsub/PubSubClusterTest.java b/src/test/java/com/lambdaworks/redis/cluster/pubsub/PubSubClusterTest.java index 96b4ffc0e3..b52cf8aedb 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/pubsub/PubSubClusterTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/pubsub/PubSubClusterTest.java @@ -17,174 +17,178 @@ import static org.assertj.core.api.Assertions.assertThat; -import java.util.List; import java.util.concurrent.BlockingQueue; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.LinkedBlockingQueue; import org.junit.After; import org.junit.Before; import org.junit.Test; -import com.lambdaworks.redis.api.sync.RedisCommands; +import com.lambdaworks.redis.RedisURI; import com.lambdaworks.redis.cluster.AbstractClusterTest; -import com.lambdaworks.redis.cluster.api.StatefulRedisClusterConnection; import com.lambdaworks.redis.cluster.models.partitions.RedisClusterNode; -import com.lambdaworks.redis.internal.LettuceFactories; -import com.lambdaworks.redis.pubsub.RedisPubSubListener; +import com.lambdaworks.redis.cluster.pubsub.api.async.NodeSelectionPubSubAsyncCommands; +import com.lambdaworks.redis.cluster.pubsub.api.async.PubSubAsyncNodeSelection; +import com.lambdaworks.redis.cluster.pubsub.api.reactive.NodeSelectionPubSubReactiveCommands; +import com.lambdaworks.redis.cluster.pubsub.api.reactive.PubSubReactiveNodeSelection; +import com.lambdaworks.redis.cluster.pubsub.api.sync.NodeSelectionPubSubCommands; +import com.lambdaworks.redis.cluster.pubsub.api.sync.PubSubNodeSelection; import com.lambdaworks.redis.pubsub.StatefulRedisPubSubConnection; +import com.lambdaworks.redis.support.PubSubTestListener; /** * @author Mark Paluch */ -public class PubSubClusterTest extends AbstractClusterTest implements RedisPubSubListener { +public class PubSubClusterTest extends AbstractClusterTest { - private BlockingQueue channels; - private BlockingQueue patterns; - private BlockingQueue messages; - private BlockingQueue counts; + private PubSubTestListener connectionListener = new PubSubTestListener(); + private PubSubTestListener nodeListener = new PubSubTestListener(); - private StatefulRedisClusterConnection connection; - private StatefulRedisPubSubConnection pubSubConnection; + private StatefulRedisClusterPubSubConnection pubSubConnection; private StatefulRedisPubSubConnection pubSubConnection2; @Before public void openPubSubConnection() throws Exception { - connection = clusterClient.connect(); + pubSubConnection = clusterClient.connectPubSub(); pubSubConnection2 = clusterClient.connectPubSub(); - channels = LettuceFactories.newBlockingQueue(); - patterns = LettuceFactories.newBlockingQueue(); - messages = LettuceFactories.newBlockingQueue(); - counts = LettuceFactories.newBlockingQueue(); + + pubSubConnection.addListener(connectionListener); } @After public void closePubSubConnection() throws Exception { - connection.close(); pubSubConnection.close(); pubSubConnection2.close(); } @Test - public void testRegularClientPubSubChannels() throws Exception { + public void testNodeIdSubscription() throws Exception { + + RedisClusterNode partition = pubSubConnection.getPartitions().getPartition(0); + + StatefulRedisPubSubConnection node = pubSubConnection.getConnection(partition.getNodeId()); + node.addListener(nodeListener); - String nodeId = pubSubConnection.sync().clusterMyId(); - RedisClusterNode otherNode = getOtherThan(nodeId); - pubSubConnection.sync().subscribe(key); + node.sync().subscribe("channel"); - List channelsOnSubscribedNode = connection.getConnection(nodeId).sync().pubsubChannels(); - assertThat(channelsOnSubscribedNode).hasSize(1); + pubSubConnection2.sync().publish("channel", "message"); - List channelsOnOtherNode = connection.getConnection(otherNode.getNodeId()).sync().pubsubChannels(); - assertThat(channelsOnOtherNode).isEmpty(); + assertThat(nodeListener.getMessages().take()).isEqualTo("message"); + assertThat(connectionListener.getMessages().poll()).isNull(); } @Test - public void testRegularClientPublish() throws Exception { + public void testNodeMessagePropagationSubscription() throws Exception { - String nodeId = pubSubConnection.sync().clusterMyId(); - RedisClusterNode otherNode = getOtherThan(nodeId); - pubSubConnection.sync().subscribe(key); - pubSubConnection.addListener(this); + RedisClusterNode partition = pubSubConnection.getPartitions().getPartition(0); + pubSubConnection.setNodeMessagePropagation(true); - connection.getConnection(nodeId).sync().publish(key, value); - assertThat(messages.take()).isEqualTo(value); + StatefulRedisPubSubConnection node = pubSubConnection.getConnection(partition.getNodeId()); + node.sync().subscribe("channel"); - connection.getConnection(otherNode.getNodeId()).sync().publish(key, value); - assertThat(messages.take()).isEqualTo(value); - } + pubSubConnection2.sync().publish("channel", "message"); + assertThat(connectionListener.getMessages().take()).isEqualTo("message"); + } @Test - public void testPubSubClientPublish() throws Exception { + public void testNodeHostAndPortMessagePropagationSubscription() throws Exception { + + RedisClusterNode partition = pubSubConnection.getPartitions().getPartition(0); + pubSubConnection.setNodeMessagePropagation(true); - String nodeId = pubSubConnection.sync().clusterMyId(); - pubSubConnection.sync().subscribe(key); - pubSubConnection.addListener(this); + RedisURI uri = partition.getUri(); + StatefulRedisPubSubConnection node = pubSubConnection.getConnection(uri.getHost(), uri.getPort()); + node.sync().subscribe("channel"); - assertThat(pubSubConnection2.sync().clusterMyId()).isEqualTo(nodeId); + pubSubConnection2.sync().publish("channel", "message"); - pubSubConnection2.sync().publish(key, value); - assertThat(messages.take()).isEqualTo(value); + assertThat(connectionListener.getMessages().take()).isEqualTo("message"); } @Test - public void testConnectToLeastClientsNode() throws Exception { + public void testAsyncSubscription() throws Exception { - clusterClient.reloadPartitions(); - String nodeId = pubSubConnection.sync().clusterMyId(); + pubSubConnection.setNodeMessagePropagation(true); - StatefulRedisPubSubConnection connectionAfterPartitionReload = clusterClient.connectPubSub(); - String newConnectionNodeId = connectionAfterPartitionReload.sync().clusterMyId(); - connectionAfterPartitionReload.close(); + PubSubAsyncNodeSelection masters = pubSubConnection.async().masters(); + NodeSelectionPubSubAsyncCommands commands = masters.commands(); - assertThat(nodeId).isNotEqualTo(newConnectionNodeId); + CompletableFuture.allOf(commands.psubscribe("chann*").futures()).get(); + + pubSubConnection2.sync().publish("channel", "message"); + + assertThat(masters.size()).isEqualTo(2); + assertThat(connectionListener.getMessages().take()).isEqualTo("message"); + assertThat(connectionListener.getMessages().take()).isEqualTo("message"); + assertThat(connectionListener.getMessages().poll()).isNull(); } @Test - public void testRegularClientPubSubPublish() throws Exception { + public void testSyncSubscription() throws Exception { + + pubSubConnection.setNodeMessagePropagation(true); - String nodeId = pubSubConnection.sync().clusterMyId(); - RedisClusterNode otherNode = getOtherThan(nodeId); - pubSubConnection.sync().subscribe(key); - pubSubConnection.addListener(this); + PubSubNodeSelection masters = pubSubConnection.sync().masters(); + NodeSelectionPubSubCommands commands = masters.commands(); - List channelsOnSubscribedNode = connection.getConnection(nodeId).sync().pubsubChannels(); - assertThat(channelsOnSubscribedNode).hasSize(1); + commands.psubscribe("chann*"); - RedisCommands otherNodeConnection = connection.getConnection(otherNode.getNodeId()).sync(); - otherNodeConnection.publish(key, value); - assertThat(channels.take()).isEqualTo(key); + pubSubConnection2.sync().publish("channel", "message"); + assertThat(masters.size()).isEqualTo(2); + assertThat(connectionListener.getMessages().take()).isEqualTo("message"); + assertThat(connectionListener.getMessages().take()).isEqualTo("message"); + assertThat(connectionListener.getMessages().poll()).isNull(); } - private RedisClusterNode getOtherThan(String nodeId) { - for (RedisClusterNode redisClusterNode : clusterClient.getPartitions()) { - if (redisClusterNode.getNodeId().equals(nodeId)) { - continue; - } - return redisClusterNode; - } + @Test + public void testReactiveSubscription() throws Exception { - throw new IllegalStateException("No other nodes than " + nodeId + " available"); - } + pubSubConnection.setNodeMessagePropagation(true); - // RedisPubSubListener implementation + PubSubReactiveNodeSelection masters = pubSubConnection.reactive().masters(); + NodeSelectionPubSubReactiveCommands commands = masters.commands(); - @Override - public void message(String channel, String message) { - channels.add(channel); - messages.add(message); - } + commands.psubscribe("chann*").flux().then().block(); - @Override - public void message(String pattern, String channel, String message) { - patterns.add(pattern); - channels.add(channel); - messages.add(message); - } + pubSubConnection2.sync().publish("channel", "message"); - @Override - public void subscribed(String channel, long count) { - channels.add(channel); - counts.add(count); + assertThat(masters.size()).isEqualTo(2); + assertThat(connectionListener.getMessages().take()).isEqualTo("message"); + assertThat(connectionListener.getMessages().take()).isEqualTo("message"); + assertThat(connectionListener.getMessages().poll()).isNull(); } - @Override - public void psubscribed(String pattern, long count) { - patterns.add(pattern); - counts.add(count); - } + @Test + public void testClusterListener() throws Exception { - @Override - public void unsubscribed(String channel, long count) { - channels.add(channel); - counts.add(count); - } + BlockingQueue nodes = new LinkedBlockingQueue<>(); + pubSubConnection.setNodeMessagePropagation(true); + pubSubConnection.addListener(new RedisClusterPubSubAdapter() { - @Override - public void punsubscribed(String pattern, long count) { - patterns.add(pattern); - counts.add(count); - } + @Override + public void message(RedisClusterNode node, String pattern, String channel, String message) { + nodes.add(node); + } + }); + + PubSubNodeSelection masters = pubSubConnection.sync().masters(); + NodeSelectionPubSubCommands commands = masters.commands(); + + commands.psubscribe("chann*"); + pubSubConnection2.sync().publish("channel", "message"); + + assertThat(masters.size()).isEqualTo(2); + assertThat(connectionListener.getMessages().take()).isEqualTo("message"); + assertThat(connectionListener.getMessages().take()).isEqualTo("message"); + assertThat(connectionListener.getMessages().poll()).isNull(); + + assertThat(nodes.take()).isNotNull(); + assertThat(nodes.take()).isNotNull(); + assertThat(nodes.poll()).isNull(); + } } diff --git a/src/test/java/com/lambdaworks/redis/cluster/pubsub/PubSubConnectionTest.java b/src/test/java/com/lambdaworks/redis/cluster/pubsub/PubSubConnectionTest.java new file mode 100644 index 0000000000..d3ef4ebcdf --- /dev/null +++ b/src/test/java/com/lambdaworks/redis/cluster/pubsub/PubSubConnectionTest.java @@ -0,0 +1,142 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.lambdaworks.redis.cluster.pubsub; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.List; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import com.lambdaworks.redis.api.sync.RedisCommands; +import com.lambdaworks.redis.cluster.AbstractClusterTest; +import com.lambdaworks.redis.cluster.api.StatefulRedisClusterConnection; +import com.lambdaworks.redis.cluster.models.partitions.RedisClusterNode; +import com.lambdaworks.redis.pubsub.StatefulRedisPubSubConnection; +import com.lambdaworks.redis.support.PubSubTestListener; + +/** + * @author Mark Paluch + */ +public class PubSubConnectionTest extends AbstractClusterTest { + + private PubSubTestListener listener = new PubSubTestListener(); + + private StatefulRedisClusterConnection connection; + private StatefulRedisPubSubConnection pubSubConnection; + private StatefulRedisPubSubConnection pubSubConnection2; + + @Before + public void openPubSubConnection() throws Exception { + connection = clusterClient.connect(); + pubSubConnection = clusterClient.connectPubSub(); + pubSubConnection2 = clusterClient.connectPubSub(); + + } + + @After + public void closePubSubConnection() throws Exception { + connection.close(); + pubSubConnection.close(); + pubSubConnection2.close(); + } + + @Test + public void testRegularClientPubSubChannels() throws Exception { + + String nodeId = pubSubConnection.sync().clusterMyId(); + RedisClusterNode otherNode = getOtherThan(nodeId); + pubSubConnection.sync().subscribe(key); + + List channelsOnSubscribedNode = connection.getConnection(nodeId).sync().pubsubChannels(); + assertThat(channelsOnSubscribedNode).hasSize(1); + + List channelsOnOtherNode = connection.getConnection(otherNode.getNodeId()).sync().pubsubChannels(); + assertThat(channelsOnOtherNode).isEmpty(); + } + + @Test + public void testRegularClientPublish() throws Exception { + + String nodeId = pubSubConnection.sync().clusterMyId(); + RedisClusterNode otherNode = getOtherThan(nodeId); + pubSubConnection.sync().subscribe(key); + pubSubConnection.addListener(listener); + + connection.getConnection(nodeId).sync().publish(key, value); + assertThat(listener.getMessages().take()).isEqualTo(value); + + connection.getConnection(otherNode.getNodeId()).sync().publish(key, value); + assertThat(listener.getMessages().take()).isEqualTo(value); + } + + @Test + public void testPubSubClientPublish() throws Exception { + + String nodeId = pubSubConnection.sync().clusterMyId(); + pubSubConnection.sync().subscribe(key); + pubSubConnection.addListener(listener); + + assertThat(pubSubConnection2.sync().clusterMyId()).isEqualTo(nodeId); + + pubSubConnection2.sync().publish(key, value); + assertThat(listener.getMessages().take()).isEqualTo(value); + } + + @Test + public void testConnectToLeastClientsNode() throws Exception { + + clusterClient.reloadPartitions(); + String nodeId = pubSubConnection.sync().clusterMyId(); + + StatefulRedisPubSubConnection connectionAfterPartitionReload = clusterClient.connectPubSub(); + String newConnectionNodeId = connectionAfterPartitionReload.sync().clusterMyId(); + connectionAfterPartitionReload.close(); + + assertThat(nodeId).isNotEqualTo(newConnectionNodeId); + } + + @Test + public void testRegularClientPubSubPublish() throws Exception { + + String nodeId = pubSubConnection.sync().clusterMyId(); + RedisClusterNode otherNode = getOtherThan(nodeId); + pubSubConnection.sync().subscribe(key); + pubSubConnection.addListener(listener); + + List channelsOnSubscribedNode = connection.getConnection(nodeId).sync().pubsubChannels(); + assertThat(channelsOnSubscribedNode).hasSize(1); + + RedisCommands otherNodeConnection = connection.getConnection(otherNode.getNodeId()).sync(); + otherNodeConnection.publish(key, value); + assertThat(listener.getChannels().take()).isEqualTo(key); + + } + + private RedisClusterNode getOtherThan(String nodeId) { + for (RedisClusterNode redisClusterNode : clusterClient.getPartitions()) { + if (redisClusterNode.getNodeId().equals(nodeId)) { + continue; + } + return redisClusterNode; + } + + throw new IllegalStateException("No other nodes than " + nodeId + " available"); + } + +} diff --git a/src/test/java/com/lambdaworks/redis/support/PubSubTestListener.java b/src/test/java/com/lambdaworks/redis/support/PubSubTestListener.java new file mode 100644 index 0000000000..c4c2ac753c --- /dev/null +++ b/src/test/java/com/lambdaworks/redis/support/PubSubTestListener.java @@ -0,0 +1,87 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.lambdaworks.redis.support; + +import java.util.concurrent.BlockingQueue; + +import com.lambdaworks.redis.internal.LettuceFactories; +import com.lambdaworks.redis.pubsub.RedisPubSubListener; + +/** + * @author Mark Paluch + */ +public class PubSubTestListener implements RedisPubSubListener { + + private BlockingQueue channels = LettuceFactories.newBlockingQueue(); + private BlockingQueue patterns = LettuceFactories.newBlockingQueue(); + private BlockingQueue messages = LettuceFactories.newBlockingQueue(); + private BlockingQueue counts = LettuceFactories.newBlockingQueue(); + + // RedisPubSubListener implementation + + @Override + public void message(String channel, String message) { + channels.add(channel); + messages.add(message); + } + + @Override + public void message(String pattern, String channel, String message) { + patterns.add(pattern); + channels.add(channel); + messages.add(message); + } + + @Override + public void subscribed(String channel, long count) { + channels.add(channel); + counts.add(count); + } + + @Override + public void psubscribed(String pattern, long count) { + patterns.add(pattern); + counts.add(count); + } + + @Override + public void unsubscribed(String channel, long count) { + channels.add(channel); + counts.add(count); + } + + @Override + public void punsubscribed(String pattern, long count) { + patterns.add(pattern); + counts.add(count); + } + + public BlockingQueue getChannels() { + return channels; + } + + public BlockingQueue getPatterns() { + return patterns; + } + + public BlockingQueue getMessages() { + return messages; + } + + public BlockingQueue getCounts() { + return counts; + } +} From bdf37aea55cf157cf692f7da0014db9f0efdd8af Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Fri, 25 Nov 2016 20:40:08 +0100 Subject: [PATCH 075/808] Remove addListener/removeListener methods from execution-specific Pub/Sub interfaces #412 Remove addListener/removeListener methods to remove API ambiguity. --- .../pubsub/RedisPubSubAsyncCommandsImpl.java | 20 ------------ .../RedisPubSubReactiveCommandsImpl.java | 32 +++++-------------- .../api/async/RedisPubSubAsyncCommands.java | 14 -------- .../reactive/RedisPubSubReactiveCommands.java | 15 --------- .../pubsub/api/sync/RedisPubSubCommands.java | 15 --------- .../redis/pubsub/PubSubCommandTest.java | 10 +++--- .../redis/pubsub/PubSubReactiveTest.java | 6 ++-- 7 files changed, 16 insertions(+), 96 deletions(-) diff --git a/src/main/java/com/lambdaworks/redis/pubsub/RedisPubSubAsyncCommandsImpl.java b/src/main/java/com/lambdaworks/redis/pubsub/RedisPubSubAsyncCommandsImpl.java index 81f0897173..9aac82b3b8 100644 --- a/src/main/java/com/lambdaworks/redis/pubsub/RedisPubSubAsyncCommandsImpl.java +++ b/src/main/java/com/lambdaworks/redis/pubsub/RedisPubSubAsyncCommandsImpl.java @@ -46,26 +46,6 @@ public RedisPubSubAsyncCommandsImpl(StatefulRedisPubSubConnection connecti this.commandBuilder = new PubSubCommandBuilder<>(codec); } - /** - * Add a new listener. - * - * @param listener Listener. - */ - @Override - public void addListener(RedisPubSubListener listener) { - getStatefulConnection().addListener(listener); - } - - /** - * Remove an existing listener. - * - * @param listener Listener. - */ - @Override - public void removeListener(RedisPubSubListener listener) { - getStatefulConnection().removeListener(listener); - } - @Override @SuppressWarnings("unchecked") public RedisFuture psubscribe(K... patterns) { diff --git a/src/main/java/com/lambdaworks/redis/pubsub/RedisPubSubReactiveCommandsImpl.java b/src/main/java/com/lambdaworks/redis/pubsub/RedisPubSubReactiveCommandsImpl.java index 53d76d2d23..6a9a2cb362 100644 --- a/src/main/java/com/lambdaworks/redis/pubsub/RedisPubSubReactiveCommandsImpl.java +++ b/src/main/java/com/lambdaworks/redis/pubsub/RedisPubSubReactiveCommandsImpl.java @@ -51,16 +51,6 @@ public RedisPubSubReactiveCommandsImpl(StatefulRedisPubSubConnection conne this.commandBuilder = new PubSubCommandBuilder<>(codec); } - /** - * Add a new listener. - * - * @param listener Listener. - */ - @Override - public void addListener(RedisPubSubListener listener) { - getStatefulConnection().addListener(listener); - } - @Override public Flux> observePatterns() { return observePatterns(FluxSink.OverflowStrategy.BUFFER); @@ -68,6 +58,7 @@ public Flux> observePatterns() { @Override public Flux> observePatterns(FluxSink.OverflowStrategy overflowStrategy) { + return Flux.create(sink -> { RedisPubSubAdapter listener = new RedisPubSubAdapter() { @@ -78,9 +69,11 @@ public void message(K pattern, K channel, V message) { } }; - addListener(listener); + StatefulRedisPubSubConnection statefulConnection = getStatefulConnection(); + statefulConnection.addListener(listener); + sink.setCancellation(() -> { - removeListener(listener); + statefulConnection.removeListener(listener); }); }, overflowStrategy); @@ -104,25 +97,16 @@ public void message(K channel, V message) { } }; - addListener(listener); + StatefulRedisPubSubConnection statefulConnection = getStatefulConnection(); + statefulConnection.addListener(listener); sink.setCancellation(() -> { - removeListener(listener); + statefulConnection.removeListener(listener); }); }, overflowStrategy); } - /** - * Remove an existing listener. - * - * @param listener Listener. - */ - @Override - public void removeListener(RedisPubSubListener listener) { - getStatefulConnection().removeListener(listener); - } - @Override public Mono psubscribe(K... patterns) { return createMono(() -> commandBuilder.psubscribe(patterns)).then(); diff --git a/src/main/java/com/lambdaworks/redis/pubsub/api/async/RedisPubSubAsyncCommands.java b/src/main/java/com/lambdaworks/redis/pubsub/api/async/RedisPubSubAsyncCommands.java index 0d5b35a31d..6e98e33186 100644 --- a/src/main/java/com/lambdaworks/redis/pubsub/api/async/RedisPubSubAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/pubsub/api/async/RedisPubSubAsyncCommands.java @@ -30,20 +30,6 @@ */ public interface RedisPubSubAsyncCommands extends RedisAsyncCommands { - /** - * Add a new listener. - * - * @param listener Listener. - */ - void addListener(RedisPubSubListener listener); - - /** - * Remove an existing listener. - * - * @param listener Listener. - */ - void removeListener(RedisPubSubListener listener); - /** * Listen for messages published to channels matching the given patterns. * diff --git a/src/main/java/com/lambdaworks/redis/pubsub/api/reactive/RedisPubSubReactiveCommands.java b/src/main/java/com/lambdaworks/redis/pubsub/api/reactive/RedisPubSubReactiveCommands.java index 4fb69e964c..8e2d6d00d7 100644 --- a/src/main/java/com/lambdaworks/redis/pubsub/api/reactive/RedisPubSubReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/pubsub/api/reactive/RedisPubSubReactiveCommands.java @@ -16,7 +16,6 @@ package com.lambdaworks.redis.pubsub.api.reactive; import com.lambdaworks.redis.api.reactive.RedisReactiveCommands; -import com.lambdaworks.redis.pubsub.RedisPubSubListener; import com.lambdaworks.redis.pubsub.StatefulRedisPubSubConnection; import reactor.core.publisher.Flux; @@ -33,20 +32,6 @@ */ public interface RedisPubSubReactiveCommands extends RedisReactiveCommands { - /** - * Add a new listener. - * - * @param listener Listener. - */ - void addListener(RedisPubSubListener listener); - - /** - * Remove an existing listener. - * - * @param listener Listener. - */ - void removeListener(RedisPubSubListener listener); - /** * Flux for messages ({@literal pmessage}) received though pattern subscriptions. The connection needs to be subscribed to * one or more patterns using {@link #psubscribe(Object[])}. diff --git a/src/main/java/com/lambdaworks/redis/pubsub/api/sync/RedisPubSubCommands.java b/src/main/java/com/lambdaworks/redis/pubsub/api/sync/RedisPubSubCommands.java index 3649c08c6e..55ddaf7d56 100644 --- a/src/main/java/com/lambdaworks/redis/pubsub/api/sync/RedisPubSubCommands.java +++ b/src/main/java/com/lambdaworks/redis/pubsub/api/sync/RedisPubSubCommands.java @@ -16,7 +16,6 @@ package com.lambdaworks.redis.pubsub.api.sync; import com.lambdaworks.redis.api.sync.RedisCommands; -import com.lambdaworks.redis.pubsub.RedisPubSubListener; import com.lambdaworks.redis.pubsub.StatefulRedisPubSubConnection; /** @@ -29,20 +28,6 @@ */ public interface RedisPubSubCommands extends RedisCommands { - /** - * Add a new listener. - * - * @param listener Listener. - */ - void addListener(RedisPubSubListener listener); - - /** - * Remove an existing listener. - * - * @param listener Listener. - */ - void removeListener(RedisPubSubListener listener); - /** * Listen for messages published to channels matching the given patterns. * diff --git a/src/test/java/com/lambdaworks/redis/pubsub/PubSubCommandTest.java b/src/test/java/com/lambdaworks/redis/pubsub/PubSubCommandTest.java index 9cf8ffd16a..60d8fd7c8d 100644 --- a/src/test/java/com/lambdaworks/redis/pubsub/PubSubCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/pubsub/PubSubCommandTest.java @@ -56,7 +56,7 @@ public class PubSubCommandTest extends AbstractRedisClientTest implements RedisP @Before public void openPubSubConnection() throws Exception { pubsub = client.connectPubSub().async(); - pubsub.addListener(this); + pubsub.getStatefulConnection().addListener(this); channels = LettuceFactories.newBlockingQueue(); patterns = LettuceFactories.newBlockingQueue(); messages = LettuceFactories.newBlockingQueue(); @@ -74,7 +74,7 @@ public void auth() throws Exception { @Override protected void run(RedisClient client) throws Exception { RedisPubSubAsyncCommands connection = client.connectPubSub().async(); - connection.addListener(PubSubCommandTest.this); + connection.getStatefulConnection().addListener(PubSubCommandTest.this); connection.auth(passwd); connection.subscribe(channel); @@ -89,7 +89,7 @@ public void authWithReconnect() throws Exception { @Override protected void run(RedisClient client) throws Exception { RedisPubSubAsyncCommands connection = client.connectPubSub().async(); - connection.addListener(PubSubCommandTest.this); + connection.getStatefulConnection().addListener(PubSubCommandTest.this); connection.auth(passwd); connection.quit(); Wait.untilTrue(() -> { @@ -351,7 +351,7 @@ public void unsubscribed(String channel, long count) { } }; - pubsub.addListener(adapter); + pubsub.getStatefulConnection().addListener(adapter); pubsub.subscribe(channel); pubsub.psubscribe(pattern); @@ -373,7 +373,7 @@ public void removeListener() throws Exception { assertThat(channels.take()).isEqualTo(channel); assertThat(messages.take()).isEqualTo(message); - pubsub.removeListener(this); + pubsub.getStatefulConnection().removeListener(this); redis.publish(channel, message); assertThat(channels.poll(10, TimeUnit.MILLISECONDS)).isNull(); diff --git a/src/test/java/com/lambdaworks/redis/pubsub/PubSubReactiveTest.java b/src/test/java/com/lambdaworks/redis/pubsub/PubSubReactiveTest.java index 124249fd1a..a57c9414e4 100644 --- a/src/test/java/com/lambdaworks/redis/pubsub/PubSubReactiveTest.java +++ b/src/test/java/com/lambdaworks/redis/pubsub/PubSubReactiveTest.java @@ -68,7 +68,7 @@ public void openPubSubConnection() throws Exception { pubsub = client.connectPubSub().reactive(); pubsub2 = client.connectPubSub().reactive(); - pubsub.addListener(this); + pubsub.getStatefulConnection().addListener(this); channels = LettuceFactories.newBlockingQueue(); patterns = LettuceFactories.newBlockingQueue(); messages = LettuceFactories.newBlockingQueue(); @@ -379,7 +379,7 @@ public void unsubscribed(String channel, long count) { } }; - pubsub.addListener(adapter); + pubsub.getStatefulConnection().addListener(adapter); pubsub.subscribe(channel).subscribe(); pubsub.psubscribe(pattern).subscribe(); @@ -402,7 +402,7 @@ public void removeListener() throws Exception { assertThat(channels.take()).isEqualTo(channel); assertThat(messages.take()).isEqualTo(message); - pubsub.removeListener(this); + pubsub.getStatefulConnection().removeListener(this); pubsub2.publish(channel, message).subscribe(); assertThat(channels.poll(10, TimeUnit.MILLISECONDS)).isNull(); From 7259a0bedc69dad257b810b1f21c35a74973b295 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Fri, 25 Nov 2016 20:46:01 +0100 Subject: [PATCH 076/808] Remove deprecated LettuceFutures.await method #388 Removed in favor of LettuceFutures.awaitOrCancel. --- .../com/lambdaworks/redis/LettuceFutures.java | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/src/main/java/com/lambdaworks/redis/LettuceFutures.java b/src/main/java/com/lambdaworks/redis/LettuceFutures.java index 93280ad30c..2aae3610c3 100644 --- a/src/main/java/com/lambdaworks/redis/LettuceFutures.java +++ b/src/main/java/com/lambdaworks/redis/LettuceFutures.java @@ -89,24 +89,7 @@ public static boolean awaitAll(long timeout, TimeUnit unit, Future... futures * @return Result of the command. */ public static T awaitOrCancel(RedisFuture cmd, long timeout, TimeUnit unit) { - return await(timeout, unit, cmd); - } - /** - * Wait until futures are complete or the supplied timeout is reached. Commands are canceled if the timeout is reached but - * the command is not finished. - * - * @param cmd Command to wait for - * @param timeout Maximum time to wait for futures to complete - * @param unit Unit of time for the timeout - * @param Result type - * @deprecated The method name does not reflect what the method is doing, therefore it is deprecated. Use - * {@link #awaitOrCancel(RedisFuture, long, TimeUnit)} instead. The semantics did not change and - * {@link #awaitOrCancel(RedisFuture, long, TimeUnit)} simply calls this method. - * @return True if all futures complete in time. - */ - @Deprecated - public static T await(long timeout, TimeUnit unit, RedisFuture cmd) { try { if (!cmd.await(timeout, unit)) { cmd.cancel(true); From 3c52541138aa4ee0ee4d6a091349ac7924759d64 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Fri, 25 Nov 2016 22:27:24 +0100 Subject: [PATCH 077/808] Default to epoll transport if available #402 Use epoll for socket transport (TCP) if epoll library is available and running on a linux operating system. Epoll usage can be disabled with setting -Dbiz.paluch.redis.lettuce.epoll=false --- .../redis/AbstractRedisClient.java | 41 +++--- .../com/lambdaworks/redis/EpollProvider.java | 128 +++++++++++++----- .../com/lambdaworks/redis/Transports.java | 89 ++++++++++++ .../DefaultEventLoopGroupProvider.java | 4 +- 4 files changed, 210 insertions(+), 52 deletions(-) create mode 100644 src/main/java/com/lambdaworks/redis/Transports.java diff --git a/src/main/java/com/lambdaworks/redis/AbstractRedisClient.java b/src/main/java/com/lambdaworks/redis/AbstractRedisClient.java index 3d7ac014c7..f8d6eb0715 100644 --- a/src/main/java/com/lambdaworks/redis/AbstractRedisClient.java +++ b/src/main/java/com/lambdaworks/redis/AbstractRedisClient.java @@ -27,6 +27,7 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Supplier; +import com.lambdaworks.redis.Transports.NativeTransports; import com.lambdaworks.redis.internal.LettuceAssert; import com.lambdaworks.redis.protocol.ConnectionWatchdog; import com.lambdaworks.redis.resource.ClientResources; @@ -38,7 +39,6 @@ import io.netty.channel.group.ChannelGroup; import io.netty.channel.group.DefaultChannelGroup; import io.netty.channel.nio.NioEventLoopGroup; -import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.util.HashedWheelTimer; import io.netty.util.concurrent.EventExecutorGroup; import io.netty.util.concurrent.Future; @@ -104,8 +104,8 @@ protected AbstractRedisClient(ClientResources clientResources) { } /** - * Set the default timeout for connections created by this client. The timeout - * applies to connection attempts and non-blocking commands. + * Set the default timeout for connections created by this client. The timeout applies to connection attempts and + * non-blocking commands. * * @param timeout Default connection timeout. * @param unit Unit of time for the timeout. @@ -151,39 +151,44 @@ protected void connectionBuilder(Supplier socketAddressSupplier, protected void channelType(ConnectionBuilder connectionBuilder, ConnectionPoint connectionPoint) { + LettuceAssert.notNull(connectionPoint, "ConnectionPoint must not be null"); + connectionBuilder.bootstrap().group(getEventLoopGroup(connectionPoint)); - if (connectionPoint != null && connectionPoint.getSocket() != null) { + if (connectionPoint.getSocket() != null) { checkForEpollLibrary(); - connectionBuilder.bootstrap().channel(EpollProvider.epollDomainSocketChannelClass); + connectionBuilder.bootstrap().channel(NativeTransports.domainSocketChannelClass()); } else { - connectionBuilder.bootstrap().channel(NioSocketChannel.class); + connectionBuilder.bootstrap().channel(Transports.socketChannelClass()); } } private synchronized EventLoopGroup getEventLoopGroup(ConnectionPoint connectionPoint) { - if ((connectionPoint == null || connectionPoint.getSocket() == null) - && !eventLoopGroups.containsKey(NioEventLoopGroup.class)) { - eventLoopGroups.put(NioEventLoopGroup.class, clientResources.eventLoopGroupProvider().allocate(NioEventLoopGroup.class)); + if (connectionPoint.getSocket() == null && !eventLoopGroups.containsKey(Transports.eventLoopGroupClass())) { + eventLoopGroups.put(Transports.eventLoopGroupClass(), + clientResources.eventLoopGroupProvider().allocate(Transports.eventLoopGroupClass())); } - if (connectionPoint != null && connectionPoint.getSocket() != null) { + if (connectionPoint.getSocket() != null) { + checkForEpollLibrary(); - if (!eventLoopGroups.containsKey(EpollProvider.epollEventLoopGroupClass)) { - EventLoopGroup epl = clientResources.eventLoopGroupProvider().allocate(EpollProvider.epollEventLoopGroupClass); - eventLoopGroups.put(EpollProvider.epollEventLoopGroupClass, epl); + Class eventLoopGroupClass = NativeTransports.eventLoopGroupClass(); + + if (!eventLoopGroups.containsKey(NativeTransports.eventLoopGroupClass())) { + eventLoopGroups.put(eventLoopGroupClass, + clientResources.eventLoopGroupProvider().allocate(eventLoopGroupClass)); } } - if (connectionPoint == null || connectionPoint.getSocket() == null) { - return eventLoopGroups.get(NioEventLoopGroup.class); + if (connectionPoint.getSocket() == null) { + return eventLoopGroups.get(Transports.eventLoopGroupClass()); } - if (connectionPoint != null && connectionPoint.getSocket() != null) { + if (connectionPoint.getSocket() != null) { checkForEpollLibrary(); - return eventLoopGroups.get(EpollProvider.epollEventLoopGroupClass); + return eventLoopGroups.get(NativeTransports.eventLoopGroupClass()); } throw new IllegalStateException("This should not have happened in a binary decision. Please file a bug."); @@ -199,7 +204,7 @@ protected > T initializeChannel(Connec RedisChannelHandler connection = connectionBuilder.connection(); SocketAddress redisAddress = connectionBuilder.socketAddress(); - if(clientResources.eventExecutorGroup().isShuttingDown()){ + if (clientResources.eventExecutorGroup().isShuttingDown()) { throw new IllegalStateException("Cannot connect. Worker pool not running"); } diff --git a/src/main/java/com/lambdaworks/redis/EpollProvider.java b/src/main/java/com/lambdaworks/redis/EpollProvider.java index 53a4609e3a..297bae9e76 100644 --- a/src/main/java/com/lambdaworks/redis/EpollProvider.java +++ b/src/main/java/com/lambdaworks/redis/EpollProvider.java @@ -17,14 +17,16 @@ import java.lang.reflect.Constructor; import java.net.SocketAddress; -import java.util.concurrent.Callable; +import java.util.Locale; import java.util.concurrent.ThreadFactory; import com.lambdaworks.redis.internal.LettuceAssert; - import com.lambdaworks.redis.internal.LettuceClassUtils; + import io.netty.channel.Channel; import io.netty.channel.EventLoopGroup; +import io.netty.util.concurrent.EventExecutorGroup; +import io.netty.util.internal.SystemPropertyUtil; import io.netty.util.internal.logging.InternalLogger; import io.netty.util.internal.logging.InternalLoggerFactory; @@ -36,73 +38,133 @@ */ public class EpollProvider { - protected static final InternalLogger logger = InternalLoggerFactory.getInstance(EpollProvider.class); + private static final InternalLogger logger = InternalLoggerFactory.getInstance(EpollProvider.class); - public static final Class epollEventLoopGroupClass; - public static final Class epollDomainSocketChannelClass; - public static final Class domainSocketAddressClass; + private static final String EPOLL_ENABLED_KEY = "biz.paluch.lettuce.redis.epoll"; + private static final boolean EPOLL_ENABLED = Boolean.parseBoolean(SystemPropertyUtil.get(EPOLL_ENABLED_KEY, "true")); + private static final boolean EPOLL_COMPATIBLE = SystemPropertyUtil.get("os.name").toLowerCase(Locale.UK).trim() + .startsWith("linux"); + private static final Class epollEventLoopGroupClass; + private static final Class epollDomainSocketChannelClass; + private static final Class epollSocketChannelClass; + private static final Class domainSocketAddressClass; static { epollEventLoopGroupClass = getClass("io.netty.channel.epoll.EpollEventLoopGroup"); epollDomainSocketChannelClass = getClass("io.netty.channel.epoll.EpollDomainSocketChannel"); + epollSocketChannelClass = getClass("io.netty.channel.epoll.EpollSocketChannel"); domainSocketAddressClass = getClass("io.netty.channel.unix.DomainSocketAddress"); - if (epollDomainSocketChannelClass == null || epollEventLoopGroupClass == null) { + + if (epollDomainSocketChannelClass == null || epollEventLoopGroupClass == null || epollSocketChannelClass == null) { logger.debug("Starting without optional Epoll library"); + } else { + + logger.debug("Starting with Epoll library"); + + if (!EPOLL_COMPATIBLE) { + logger.debug(String.format("Epoll not compatible with %s", SystemPropertyUtil.get("os.name"))); + } } } /** - * Try to load class {@literal className}. + * @param type must not be {@literal null}. + * @return {@literal true} if {@code type} is a {@link io.netty.channel.epoll.EpollEventLoopGroup}. + */ + public static boolean isEventLoopGroup(Class type) { + + LettuceAssert.notNull(type, "EventLoopGroup type must not be null"); + + return type.equals(epollEventLoopGroupClass); + } + + /** + * Create a new {@link io.netty.channel.epoll.EpollEventLoopGroup}. * - * @param className - * @param Expected return type for casting. - * @return instance of {@literal className} or null + * @param nThreads + * @param threadFactory + * @return the {@link EventLoopGroup}. */ - private static Class getClass(String className) { + public static EventLoopGroup newEventLoopGroup(int nThreads, ThreadFactory threadFactory) { + try { - return (Class) LettuceClassUtils.forName(className); - } catch (ClassNotFoundException e) { - logger.debug("Cannot load class " + className, e); + Constructor constructor = epollEventLoopGroupClass.getConstructor(Integer.TYPE, + ThreadFactory.class); + return constructor.newInstance(nThreads, threadFactory); + } catch (Exception e) { + throw new IllegalStateException(e); } - return null; + } + + /** + * @return {@literal true} if epoll is available. + */ + public static boolean isAvailable() { + return domainSocketAddressClass != null && epollDomainSocketChannelClass != null && EPOLL_ENABLED && EPOLL_COMPATIBLE; + } + + /** + * + * @return the {@link io.netty.channel.epoll.EpollDomainSocketChannel} class. + */ + static Class domainSocketChannelClass() { + return epollDomainSocketChannelClass; + } + + /** + * + * @return the {@link io.netty.channel.epoll.EpollSocketChannel} class. + */ + static Class socketChannelClass() { + return epollSocketChannelClass; + } + + /** + * + * @return the {@link io.netty.channel.epoll.EpollEventLoopGroup} class. + */ + static Class eventLoopGroupClass() { + return epollEventLoopGroupClass; } /** * Check whether the Epoll library is available on the class path. - * + * * @throws IllegalStateException if the {@literal netty-transport-native-epoll} library is not available - * + * */ static void checkForEpollLibrary() { - LettuceAssert.assertState(domainSocketAddressClass != null && epollDomainSocketChannelClass != null, + LettuceAssert.assertState(EPOLL_ENABLED && EPOLL_COMPATIBLE, + String.format("epoll use is disabled via System properties (%s)", EPOLL_ENABLED_KEY)); + LettuceAssert.assertState(isAvailable(), "Cannot connect using sockets without the optional netty-transport-native-epoll library on the class path"); } static SocketAddress newSocketAddress(String socketPath) { - return get(() -> { - Constructor constructor = domainSocketAddressClass.getConstructor(String.class); - return constructor.newInstance(socketPath); - }); - } - - public static EventLoopGroup newEventLoopGroup(int nThreads, ThreadFactory threadFactory) { try { - Constructor constructor = epollEventLoopGroupClass - .getConstructor(Integer.TYPE, ThreadFactory.class); - return constructor.newInstance(nThreads, threadFactory); + Constructor constructor = domainSocketAddressClass.getConstructor(String.class); + return constructor.newInstance(socketPath); } catch (Exception e) { throw new IllegalStateException(e); } } - private static V get(Callable supplier) { + /** + * Try to load class {@literal className}. + * + * @param className + * @param Expected return type for casting. + * @return instance of {@literal className} or null + */ + private static Class getClass(String className) { try { - return supplier.call(); - } catch (Exception e) { - throw new IllegalStateException(e); + return (Class) LettuceClassUtils.forName(className); + } catch (ClassNotFoundException e) { + logger.debug("Cannot load class " + className, e); } + return null; } } diff --git a/src/main/java/com/lambdaworks/redis/Transports.java b/src/main/java/com/lambdaworks/redis/Transports.java new file mode 100644 index 0000000000..330cb8d14b --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/Transports.java @@ -0,0 +1,89 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.lambdaworks.redis; + +import io.netty.channel.Channel; +import io.netty.channel.EventLoopGroup; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.nio.NioSocketChannel; + +/** + * Transport infrastructure utility class. This class provides {@link EventLoopGroup} and {@link Channel} classes for socket and + * native socket transports. + * + * @author Mark Paluch + * @since 4.4 + */ +class Transports { + + /** + * @return the default {@link EventLoopGroup} for socket transport that is compatible with {@link #socketChannelClass()}. + */ + static Class eventLoopGroupClass() { + + if (NativeTransports.isSocketSupport()) { + return NativeTransports.eventLoopGroupClass(); + } + + return NioEventLoopGroup.class; + } + + /** + * @return the default {@link Channel} for socket (network/TCP) transport. + */ + static Class socketChannelClass() { + + if (NativeTransports.isSocketSupport()) { + return NativeTransports.socketChannelClass(); + } + + return NioSocketChannel.class; + } + + /** + * Native transport support. + */ + static class NativeTransports { + + /** + * @return {@literal true} if a native transport is available. + */ + static boolean isSocketSupport() { + return EpollProvider.isAvailable(); + } + + /** + * @return the native transport socket {@link Channel} class. + */ + static Class socketChannelClass() { + return EpollProvider.socketChannelClass(); + } + + /** + * @return the native transport domain socket {@link Channel} class. + */ + static Class domainSocketChannelClass() { + return EpollProvider.domainSocketChannelClass(); + } + + /** + * @return the native transport {@link EventLoopGroup} class. + */ + static Class eventLoopGroupClass() { + return EpollProvider.eventLoopGroupClass(); + } + } +} diff --git a/src/main/java/com/lambdaworks/redis/resource/DefaultEventLoopGroupProvider.java b/src/main/java/com/lambdaworks/redis/resource/DefaultEventLoopGroupProvider.java index 1059262c3a..5cac9a7172 100644 --- a/src/main/java/com/lambdaworks/redis/resource/DefaultEventLoopGroupProvider.java +++ b/src/main/java/com/lambdaworks/redis/resource/DefaultEventLoopGroupProvider.java @@ -132,6 +132,7 @@ private T getOrCreate(Class type) { * @throws IllegalArgumentException if the {@code type} is not supported. */ public static EventExecutorGroup createEventLoopGroup(Class type, int numberOfThreads) { + if (DefaultEventExecutorGroup.class.equals(type)) { return new DefaultEventExecutorGroup(numberOfThreads, new DefaultThreadFactory("lettuce-eventExecutorLoop", true)); } @@ -140,9 +141,10 @@ public static EventExecutorGroup createEventLoopG return new NioEventLoopGroup(numberOfThreads, new DefaultThreadFactory("lettuce-nioEventLoop", true)); } - if (EpollProvider.epollEventLoopGroupClass != null && EpollProvider.epollEventLoopGroupClass.equals(type)) { + if (EpollProvider.isAvailable() && EpollProvider.isEventLoopGroup(type)) { return EpollProvider.newEventLoopGroup(numberOfThreads, new DefaultThreadFactory("lettuce-epollEventLoop", true)); } + throw new IllegalArgumentException("Type " + type.getName() + " not supported"); } From b2878e377f3d9ab159408dfdb266b728372ff798 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Fri, 25 Nov 2016 22:28:18 +0100 Subject: [PATCH 078/808] Guard OpenSSL tests if OpenSSL is not available --- src/test/java/com/lambdaworks/SslTest.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/test/java/com/lambdaworks/SslTest.java b/src/test/java/com/lambdaworks/SslTest.java index be52145474..3a4e00f3fc 100644 --- a/src/test/java/com/lambdaworks/SslTest.java +++ b/src/test/java/com/lambdaworks/SslTest.java @@ -27,6 +27,7 @@ import java.util.List; import java.util.concurrent.ExecutionException; +import io.netty.handler.ssl.OpenSsl; import org.junit.AfterClass; import org.junit.Before; import org.junit.Test; @@ -127,6 +128,8 @@ public void standaloneWithJdkSslFailsWithWrongTruststore() throws Exception { @Test public void standaloneWithOpenSsl() throws Exception { + assumeTrue(OpenSsl.isAvailable()); + SslOptions sslOptions = SslOptions.builder() // .openSslProvider() // .truststore(new File(LOCALHOST_KEYSTORE)) // @@ -139,6 +142,8 @@ public void standaloneWithOpenSsl() throws Exception { @Test(expected = RedisConnectionException.class) public void standaloneWithOpenSslFailsWithWrongTruststore() throws Exception { + assumeTrue(OpenSsl.isAvailable()); + SslOptions sslOptions = SslOptions.builder() // .openSslProvider() // .build(); From 9dd11e7869764dd5198ec887823aadf0ffcaccda Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Tue, 29 Nov 2016 18:15:10 +0100 Subject: [PATCH 079/808] Apply proxy wrapper to obtained pooled connections #411 Connection pooling no longer pools proxies but wraps objects returned by the object pool. The proxy state is still invalidated which makes references to the proxy unusable once the connection is released back to the pool but the proxy instance it self is not pooled. Retrieval of the same connection will create a fresh proxy instance. --- .../redis/support/ConnectionPoolSupport.java | 82 +++++++---- .../support/ConnectionPoolSupportTest.java | 134 +++++++++++++++++- 2 files changed, 187 insertions(+), 29 deletions(-) diff --git a/src/main/java/com/lambdaworks/redis/support/ConnectionPoolSupport.java b/src/main/java/com/lambdaworks/redis/support/ConnectionPoolSupport.java index f7c68b4dba..1a9b880aff 100644 --- a/src/main/java/com/lambdaworks/redis/support/ConnectionPoolSupport.java +++ b/src/main/java/com/lambdaworks/redis/support/ConnectionPoolSupport.java @@ -23,11 +23,6 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.function.Supplier; -import com.lambdaworks.redis.RedisClient; -import com.lambdaworks.redis.RedisURI; -import com.lambdaworks.redis.api.StatefulRedisConnection; -import com.lambdaworks.redis.cluster.RedisClusterClient; -import com.lambdaworks.redis.cluster.api.StatefulRedisClusterConnection; import org.apache.commons.pool2.BasePooledObjectFactory; import org.apache.commons.pool2.ObjectPool; import org.apache.commons.pool2.PooledObject; @@ -113,6 +108,7 @@ private ConnectionPoolSupport() { * @param connection type. * @return the connection pool. */ + @SuppressWarnings("unchecked") public static > GenericObjectPool createGenericObjectPool( Supplier connectionSupplier, GenericObjectPoolConfig config, boolean wrapConnections) { @@ -120,10 +116,24 @@ private ConnectionPoolSupport() { LettuceAssert.notNull(config, "GenericObjectPoolConfig must not be null"); AtomicReference> poolRef = new AtomicReference<>(); - Supplier providerToUse = wrapConnections ? wrappedConnectionSupplier(connectionSupplier, poolRef) - : connectionSupplier; - GenericObjectPool pool = new GenericObjectPool<>(new RedisPooledObjectFactory(providerToUse), config); + GenericObjectPool pool = new GenericObjectPool(new RedisPooledObjectFactory(connectionSupplier), config) { + + @Override + public synchronized T borrowObject() throws Exception { + return wrapConnections ? wrapConnection(super.borrowObject(), this) : super.borrowObject(); + } + + @Override + public synchronized void returnObject(T obj) { + + if (wrapConnections && obj instanceof HasTargetConnection) { + super.returnObject((T) ((HasTargetConnection) obj).getTargetConnection()); + return; + } + super.returnObject(obj); + } + }; poolRef.set(pool); @@ -153,41 +163,49 @@ private ConnectionPoolSupport() { * @param connection type. * @return the connection pool. */ + @SuppressWarnings("unchecked") public static > SoftReferenceObjectPool createSoftReferenceObjectPool( Supplier connectionSupplier, boolean wrapConnections) { LettuceAssert.notNull(connectionSupplier, "Connection supplier must not be null"); AtomicReference> poolRef = new AtomicReference<>(); - Supplier providerToUse = wrapConnections ? wrappedConnectionSupplier(connectionSupplier, poolRef) - : connectionSupplier; - SoftReferenceObjectPool pool = new SoftReferenceObjectPool<>(new RedisPooledObjectFactory<>(providerToUse)); + SoftReferenceObjectPool pool = new SoftReferenceObjectPool(new RedisPooledObjectFactory<>(connectionSupplier)) { + @Override + public synchronized T borrowObject() throws Exception { + return wrapConnections ? wrapConnection(super.borrowObject(), this) : super.borrowObject(); + } + + @Override + public synchronized void returnObject(T obj) throws Exception { + + if (wrapConnections && obj instanceof HasTargetConnection) { + super.returnObject((T) ((HasTargetConnection) obj).getTargetConnection()); + return; + } + super.returnObject(obj); + } + }; poolRef.set(pool); return pool; } @SuppressWarnings("unchecked") - private static Supplier wrappedConnectionSupplier(Supplier connectionSupplier, - AtomicReference> poolRef) { - - return new Supplier() { + private static T wrapConnection(T connection, ObjectPool pool) { - @Override - public T get() { + ReturnObjectOnCloseInvocationHandler handler = new ReturnObjectOnCloseInvocationHandler(connection, pool); - T connection = connectionSupplier.get(); - ReturnObjectOnCloseInvocationHandler handler = new ReturnObjectOnCloseInvocationHandler<>(connection, - poolRef.get()); + Class[] implementedInterfaces = connection.getClass().getInterfaces(); + Class[] interfaces = new Class[implementedInterfaces.length + 1]; + interfaces[0] = HasTargetConnection.class; + System.arraycopy(implementedInterfaces, 0, interfaces, 1, implementedInterfaces.length); - T proxiedConnection = (T) Proxy.newProxyInstance(getClass().getClassLoader(), - connection.getClass().getInterfaces(), handler); - handler.setProxiedConnection(proxiedConnection); + T proxiedConnection = (T) Proxy.newProxyInstance(connection.getClass().getClassLoader(), interfaces, handler); + handler.setProxiedConnection(proxiedConnection); - return proxiedConnection; - } - }; + return proxiedConnection; } /** @@ -242,7 +260,6 @@ void setProxiedConnection(T proxiedConnection) { this.proxiedConnection = proxiedConnection; } - @SuppressWarnings("unchecked") @Override protected Object handleInvocation(Object proxy, Method method, Object[] args) throws Throwable { @@ -250,6 +267,10 @@ protected Object handleInvocation(Object proxy, Method method, Object[] args) th return proxiedConnection; } + if (method.getName().equals("getTargetConnection")) { + return connection; + } + if (connection == null) { throw new RedisException("Connection is deallocated and cannot be used anymore."); } @@ -335,4 +356,11 @@ protected Object handleInvocation(Object proxy, Method method, Object[] args) th } } } + + /** + * Interface to retrieve an underlying target connection from a proxy. + */ + interface HasTargetConnection { + StatefulConnection getTargetConnection(); + } } diff --git a/src/test/java/com/lambdaworks/redis/support/ConnectionPoolSupportTest.java b/src/test/java/com/lambdaworks/redis/support/ConnectionPoolSupportTest.java index 09fe78f5cc..2112e789d2 100644 --- a/src/test/java/com/lambdaworks/redis/support/ConnectionPoolSupportTest.java +++ b/src/test/java/com/lambdaworks/redis/support/ConnectionPoolSupportTest.java @@ -20,6 +20,7 @@ import java.lang.reflect.Proxy; +import org.apache.commons.pool2.ObjectPool; import org.apache.commons.pool2.impl.GenericObjectPool; import org.apache.commons.pool2.impl.GenericObjectPoolConfig; import org.apache.commons.pool2.impl.SoftReferenceObjectPool; @@ -54,9 +55,58 @@ public void genericPoolShouldWorkWithWrappedConnections() throws Exception { GenericObjectPool> pool = ConnectionPoolSupport .createGenericObjectPool(() -> client.connect(), new GenericObjectPoolConfig()); + borrowAndReturn(pool); + borrowAndClose(pool); + borrowAndCloseTryWithResources(pool); + + pool.returnObject(pool.borrowObject().sync().getStatefulConnection()); + pool.returnObject(pool.borrowObject().async().getStatefulConnection()); + + pool.close(); + } + + @Test + public void softReferencePoolShouldWorkWithWrappedConnections() throws Exception { + + GenericObjectPool> pool = ConnectionPoolSupport + .createGenericObjectPool(() -> client.connect(), new GenericObjectPoolConfig()); + + borrowAndReturn(pool); + borrowAndClose(pool); + borrowAndCloseTryWithResources(pool); + + pool.returnObject(pool.borrowObject().sync().getStatefulConnection()); + pool.returnObject(pool.borrowObject().async().getStatefulConnection()); + + pool.close(); + } + + @Test + public void genericPoolShouldWorkWithPlainConnections() throws Exception { + + GenericObjectPool> pool = ConnectionPoolSupport + .createGenericObjectPool(() -> client.connect(), new GenericObjectPoolConfig(), false); + + borrowAndReturn(pool); + StatefulRedisConnection connection = pool.borrowObject(); - RedisCommands sync = connection.sync(); - sync.ping(); + assertThat(Proxy.isProxyClass(connection.getClass())).isFalse(); + pool.returnObject(connection); + + pool.close(); + } + + @Test + public void softReferencePoolShouldWorkWithPlainConnections() throws Exception { + + SoftReferenceObjectPool> pool = ConnectionPoolSupport + .createSoftReferenceObjectPool(() -> client.connect(), false); + + borrowAndReturn(pool); + + StatefulRedisConnection connection = pool.borrowObject(); + assertThat(Proxy.isProxyClass(connection.getClass())).isFalse(); + pool.returnObject(connection); connection.close(); pool.close(); @@ -220,4 +270,84 @@ public void wrappedObjectClosedAfterReturn() throws Exception { pool.close(); } + + @Test + public void tryWithResourcesReturnsConnectionToPool() throws Exception { + + GenericObjectPool> pool = ConnectionPoolSupport + .createGenericObjectPool(() -> client.connect(), new GenericObjectPoolConfig()); + + StatefulRedisConnection usedConnection = null; + try (StatefulRedisConnection connection = pool.borrowObject()) { + + RedisCommands sync = connection.sync(); + sync.ping(); + + usedConnection = connection; + } + + try { + usedConnection.isMulti(); + fail("Missing RedisException"); + } catch (RedisException e) { + assertThat(e).hasMessageContaining("deallocated"); + } + + pool.close(); + } + + @Test + public void tryWithResourcesReturnsSoftRefConnectionToPool() throws Exception { + + SoftReferenceObjectPool> pool = ConnectionPoolSupport + .createSoftReferenceObjectPool(() -> client.connect()); + + StatefulRedisConnection usedConnection = null; + try (StatefulRedisConnection connection = pool.borrowObject()) { + + RedisCommands sync = connection.sync(); + sync.ping(); + + usedConnection = connection; + } + + try { + usedConnection.isMulti(); + fail("Missing RedisException"); + } catch (RedisException e) { + assertThat(e).hasMessageContaining("deallocated"); + } + + pool.close(); + } + + private void borrowAndReturn(ObjectPool> pool) throws Exception { + + for (int i = 0; i < 10; i++) { + StatefulRedisConnection connection = pool.borrowObject(); + RedisCommands sync = connection.sync(); + sync.ping(); + pool.returnObject(connection); + } + } + + private void borrowAndCloseTryWithResources(ObjectPool> pool) throws Exception { + + for (int i = 0; i < 10; i++) { + try (StatefulRedisConnection connection = pool.borrowObject()) { + RedisCommands sync = connection.sync(); + sync.ping(); + } + } + } + + private void borrowAndClose(ObjectPool> pool) throws Exception { + + for (int i = 0; i < 10; i++) { + StatefulRedisConnection connection = pool.borrowObject(); + RedisCommands sync = connection.sync(); + sync.ping(); + connection.close(); + } + } } From a4dc321c743becb219a0fd096f2569be15fafe44 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Thu, 1 Dec 2016 10:07:12 +0100 Subject: [PATCH 080/808] Support CLIENT and INFO commands for Redis Sentinel #415 --- .../RedisSentinelAsyncCommandsImpl.java | 41 +++++++ .../RedisSentinelReactiveCommandsImpl.java | 45 ++++++- .../sentinel/SentinelCommandBuilder.java | 66 ++++++++-- .../api/async/RedisSentinelAsyncCommands.java | 63 ++++++++++ .../RedisSentinelReactiveCommands.java | 63 ++++++++++ .../api/sync/RedisSentinelCommands.java | 63 ++++++++++ .../redis/api/RedisSentinelCommands.java | 63 ++++++++++ .../redis/sentinel/AbstractSentinelTest.java | 3 + .../redis/sentinel/SentinelCommandTest.java | 3 + .../sentinel/SentinelConnectionTest.java | 3 + .../redis/sentinel/SentinelRule.java | 1 - .../sentinel/SentinelServerCommandTest.java | 115 ++++++++++++++++++ .../SentinelServerReactiveCommandTest.java | 48 ++++++++ 13 files changed, 562 insertions(+), 15 deletions(-) create mode 100644 src/test/java/com/lambdaworks/redis/sentinel/SentinelServerCommandTest.java create mode 100644 src/test/java/com/lambdaworks/redis/sentinel/reactive/SentinelServerReactiveCommandTest.java diff --git a/src/main/java/com/lambdaworks/redis/sentinel/RedisSentinelAsyncCommandsImpl.java b/src/main/java/com/lambdaworks/redis/sentinel/RedisSentinelAsyncCommandsImpl.java index 7eb0e135c2..ccabe0a9c4 100644 --- a/src/main/java/com/lambdaworks/redis/sentinel/RedisSentinelAsyncCommandsImpl.java +++ b/src/main/java/com/lambdaworks/redis/sentinel/RedisSentinelAsyncCommandsImpl.java @@ -22,6 +22,7 @@ import java.util.concurrent.CompletionStage; import java.util.concurrent.atomic.AtomicReference; +import com.lambdaworks.redis.KillArgs; import com.lambdaworks.redis.RedisFuture; import com.lambdaworks.redis.api.StatefulConnection; import com.lambdaworks.redis.codec.RedisCodec; @@ -136,6 +137,46 @@ public RedisFuture ping() { return dispatch(commandBuilder.ping()); } + @Override + public RedisFuture clientGetname() { + return dispatch(commandBuilder.clientGetname()); + } + + @Override + public RedisFuture clientSetname(K name) { + return dispatch(commandBuilder.clientSetname(name)); + } + + @Override + public RedisFuture clientKill(String addr) { + return dispatch(commandBuilder.clientKill(addr)); + } + + @Override + public RedisFuture clientKill(KillArgs killArgs) { + return dispatch(commandBuilder.clientKill(killArgs)); + } + + @Override + public RedisFuture clientPause(long timeout) { + return dispatch(commandBuilder.clientPause(timeout)); + } + + @Override + public RedisFuture clientList() { + return dispatch(commandBuilder.clientList()); + } + + @Override + public RedisFuture info() { + return dispatch(commandBuilder.info()); + } + + @Override + public RedisFuture info(String section) { + return dispatch(commandBuilder.info(section)); + } + public AsyncCommand dispatch(RedisCommand cmd) { return connection.dispatch(new AsyncCommand<>(cmd)); } diff --git a/src/main/java/com/lambdaworks/redis/sentinel/RedisSentinelReactiveCommandsImpl.java b/src/main/java/com/lambdaworks/redis/sentinel/RedisSentinelReactiveCommandsImpl.java index e0e5d426c5..f6c84fd2ed 100644 --- a/src/main/java/com/lambdaworks/redis/sentinel/RedisSentinelReactiveCommandsImpl.java +++ b/src/main/java/com/lambdaworks/redis/sentinel/RedisSentinelReactiveCommandsImpl.java @@ -19,6 +19,7 @@ import java.net.SocketAddress; import java.util.Map; +import com.lambdaworks.redis.KillArgs; import com.lambdaworks.redis.AbstractRedisReactiveCommands; import com.lambdaworks.redis.api.StatefulConnection; import com.lambdaworks.redis.codec.RedisCodec; @@ -112,12 +113,52 @@ public Mono ping() { return createMono(commandBuilder::ping); } - // @Override + @Override + public Mono clientGetname() { + return createMono(commandBuilder::clientGetname); + } + + @Override + public Mono clientSetname(K name) { + return createMono(() -> commandBuilder.clientSetname(name)); + } + + @Override + public Mono clientKill(String addr) { + return createMono(() -> commandBuilder.clientKill(addr)); + } + + @Override + public Mono clientKill(KillArgs killArgs) { + return createMono(() -> commandBuilder.clientKill(killArgs)); + } + + @Override + public Mono clientPause(long timeout) { + return createMono(() -> commandBuilder.clientPause(timeout)); + } + + @Override + public Mono clientList() { + return createMono(commandBuilder::clientList); + } + + @Override + public Mono info() { + return createMono(commandBuilder::info); + } + + @Override + public Mono info(String section) { + return createMono(() -> commandBuilder.info(section)); + } + + @Override public void close() { connection.close(); } - // @Override + @Override public boolean isOpen() { return connection.isOpen(); } diff --git a/src/main/java/com/lambdaworks/redis/sentinel/SentinelCommandBuilder.java b/src/main/java/com/lambdaworks/redis/sentinel/SentinelCommandBuilder.java index b26203c3d8..7381d7b334 100644 --- a/src/main/java/com/lambdaworks/redis/sentinel/SentinelCommandBuilder.java +++ b/src/main/java/com/lambdaworks/redis/sentinel/SentinelCommandBuilder.java @@ -15,23 +15,16 @@ */ package com.lambdaworks.redis.sentinel; -import static com.lambdaworks.redis.protocol.CommandKeyword.FAILOVER; -import static com.lambdaworks.redis.protocol.CommandKeyword.RESET; -import static com.lambdaworks.redis.protocol.CommandKeyword.SLAVES; -import static com.lambdaworks.redis.protocol.CommandType.MONITOR; -import static com.lambdaworks.redis.protocol.CommandType.PING; -import static com.lambdaworks.redis.protocol.CommandType.SENTINEL; -import static com.lambdaworks.redis.protocol.CommandType.SET; +import static com.lambdaworks.redis.protocol.CommandKeyword.*; +import static com.lambdaworks.redis.protocol.CommandType.*; import java.util.List; import java.util.Map; +import com.lambdaworks.redis.KillArgs; import com.lambdaworks.redis.codec.RedisCodec; -import com.lambdaworks.redis.output.IntegerOutput; -import com.lambdaworks.redis.output.ListOfMapsOutput; -import com.lambdaworks.redis.output.MapOutput; -import com.lambdaworks.redis.output.StatusOutput; -import com.lambdaworks.redis.output.ValueListOutput; +import com.lambdaworks.redis.internal.LettuceAssert; +import com.lambdaworks.redis.output.*; import com.lambdaworks.redis.protocol.BaseRedisCommandBuilder; import com.lambdaworks.redis.protocol.Command; import com.lambdaworks.redis.protocol.CommandArgs; @@ -87,6 +80,55 @@ public Command set(K key, String option, V value) { return createCommand(SENTINEL, new StatusOutput(codec), args); } + public Command clientGetname() { + CommandArgs args = new CommandArgs(codec).add(GETNAME); + return createCommand(CLIENT, new KeyOutput(codec), args); + } + + public Command clientSetname(K name) { + LettuceAssert.notNull(name, "Name must not be null"); + + CommandArgs args = new CommandArgs(codec).add(SETNAME).addKey(name); + return createCommand(CLIENT, new StatusOutput(codec), args); + } + + public Command clientKill(String addr) { + LettuceAssert.notNull(addr, "Addr must not be null"); + LettuceAssert.notEmpty(addr, "Addr must not be empty"); + + CommandArgs args = new CommandArgs(codec).add(KILL).add(addr); + return createCommand(CLIENT, new StatusOutput(codec), args); + } + + public Command clientKill(KillArgs killArgs) { + LettuceAssert.notNull(killArgs, "KillArgs must not be null"); + + CommandArgs args = new CommandArgs(codec).add(KILL); + killArgs.build(args); + return createCommand(CLIENT, new IntegerOutput(codec), args); + } + + public Command clientPause(long timeout) { + CommandArgs args = new CommandArgs(codec).add(PAUSE).add(timeout); + return createCommand(CLIENT, new StatusOutput(codec), args); + } + + public Command clientList() { + CommandArgs args = new CommandArgs(codec).add(LIST); + return createCommand(CLIENT, new StatusOutput(codec), args); + } + + public Command info() { + return createCommand(INFO, new StatusOutput(codec)); + } + + public Command info(String section) { + LettuceAssert.notNull(section, "Section must not be null"); + + CommandArgs args = new CommandArgs(codec).add(section); + return createCommand(INFO, new StatusOutput(codec), args); + } + public Command ping() { return createCommand(PING, new StatusOutput(codec)); } diff --git a/src/main/java/com/lambdaworks/redis/sentinel/api/async/RedisSentinelAsyncCommands.java b/src/main/java/com/lambdaworks/redis/sentinel/api/async/RedisSentinelAsyncCommands.java index 73fe33bc13..1e203d3f14 100644 --- a/src/main/java/com/lambdaworks/redis/sentinel/api/async/RedisSentinelAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/sentinel/api/async/RedisSentinelAsyncCommands.java @@ -18,6 +18,7 @@ import java.net.SocketAddress; import java.util.List; import java.util.Map; +import com.lambdaworks.redis.KillArgs; import com.lambdaworks.redis.sentinel.api.StatefulRedisSentinelConnection; import com.lambdaworks.redis.RedisFuture; @@ -109,6 +110,68 @@ public interface RedisSentinelAsyncCommands { */ RedisFuture remove(K key); + /** + * Get the current connection name. + * + * @return K bulk-string-reply The connection name, or a null bulk reply if no name is set. + */ + RedisFuture clientGetname(); + + /** + * Set the current connection name. + * + * @param name the client name + * @return simple-string-reply {@code OK} if the connection name was successfully set. + */ + RedisFuture clientSetname(K name); + + /** + * Kill the connection of a client identified by ip:port. + * + * @param addr ip:port + * @return String simple-string-reply {@code OK} if the connection exists and has been closed + */ + RedisFuture clientKill(String addr); + + /** + * Kill connections of clients which are filtered by {@code killArgs} + * + * @param killArgs args for the kill operation + * @return Long integer-reply number of killed connections + */ + RedisFuture clientKill(KillArgs killArgs); + + /** + * Stop processing commands from clients for some time. + * + * @param timeout the timeout value in milliseconds + * @return String simple-string-reply The command returns OK or an error if the timeout is invalid. + */ + RedisFuture clientPause(long timeout); + + /** + * Get the list of client connections. + * + * @return String bulk-string-reply a unique string, formatted as follows: One client connection per line (separated by LF), + * each line is composed of a succession of property=value fields separated by a space character. + */ + RedisFuture clientList(); + + /** + * Get information and statistics about the server. + * + * @return String bulk-string-reply as a collection of text lines. + */ + RedisFuture info(); + + /** + * Get information and statistics about the server. + * + * @param section the section type: string + * @return String bulk-string-reply as a collection of text lines. + */ + RedisFuture info(String section); + /** * Ping the server. * diff --git a/src/main/java/com/lambdaworks/redis/sentinel/api/reactive/RedisSentinelReactiveCommands.java b/src/main/java/com/lambdaworks/redis/sentinel/api/reactive/RedisSentinelReactiveCommands.java index c623cf36b3..daff5b8773 100644 --- a/src/main/java/com/lambdaworks/redis/sentinel/api/reactive/RedisSentinelReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/sentinel/api/reactive/RedisSentinelReactiveCommands.java @@ -18,6 +18,7 @@ import java.net.SocketAddress; import java.util.List; import java.util.Map; +import com.lambdaworks.redis.KillArgs; import com.lambdaworks.redis.sentinel.api.StatefulRedisSentinelConnection; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -110,6 +111,68 @@ public interface RedisSentinelReactiveCommands { */ Mono remove(K key); + /** + * Get the current connection name. + * + * @return K bulk-string-reply The connection name, or a null bulk reply if no name is set. + */ + Mono clientGetname(); + + /** + * Set the current connection name. + * + * @param name the client name + * @return simple-string-reply {@code OK} if the connection name was successfully set. + */ + Mono clientSetname(K name); + + /** + * Kill the connection of a client identified by ip:port. + * + * @param addr ip:port + * @return String simple-string-reply {@code OK} if the connection exists and has been closed + */ + Mono clientKill(String addr); + + /** + * Kill connections of clients which are filtered by {@code killArgs} + * + * @param killArgs args for the kill operation + * @return Long integer-reply number of killed connections + */ + Mono clientKill(KillArgs killArgs); + + /** + * Stop processing commands from clients for some time. + * + * @param timeout the timeout value in milliseconds + * @return String simple-string-reply The command returns OK or an error if the timeout is invalid. + */ + Mono clientPause(long timeout); + + /** + * Get the list of client connections. + * + * @return String bulk-string-reply a unique string, formatted as follows: One client connection per line (separated by LF), + * each line is composed of a succession of property=value fields separated by a space character. + */ + Mono clientList(); + + /** + * Get information and statistics about the server. + * + * @return String bulk-string-reply as a collection of text lines. + */ + Mono info(); + + /** + * Get information and statistics about the server. + * + * @param section the section type: string + * @return String bulk-string-reply as a collection of text lines. + */ + Mono info(String section); + /** * Ping the server. * diff --git a/src/main/java/com/lambdaworks/redis/sentinel/api/sync/RedisSentinelCommands.java b/src/main/java/com/lambdaworks/redis/sentinel/api/sync/RedisSentinelCommands.java index 249d320ad3..98f6e4b1cf 100644 --- a/src/main/java/com/lambdaworks/redis/sentinel/api/sync/RedisSentinelCommands.java +++ b/src/main/java/com/lambdaworks/redis/sentinel/api/sync/RedisSentinelCommands.java @@ -18,6 +18,7 @@ import java.net.SocketAddress; import java.util.List; import java.util.Map; +import com.lambdaworks.redis.KillArgs; import com.lambdaworks.redis.sentinel.api.StatefulRedisSentinelConnection; /** @@ -108,6 +109,68 @@ public interface RedisSentinelCommands { */ String remove(K key); + /** + * Get the current connection name. + * + * @return K bulk-string-reply The connection name, or a null bulk reply if no name is set. + */ + K clientGetname(); + + /** + * Set the current connection name. + * + * @param name the client name + * @return simple-string-reply {@code OK} if the connection name was successfully set. + */ + String clientSetname(K name); + + /** + * Kill the connection of a client identified by ip:port. + * + * @param addr ip:port + * @return String simple-string-reply {@code OK} if the connection exists and has been closed + */ + String clientKill(String addr); + + /** + * Kill connections of clients which are filtered by {@code killArgs} + * + * @param killArgs args for the kill operation + * @return Long integer-reply number of killed connections + */ + Long clientKill(KillArgs killArgs); + + /** + * Stop processing commands from clients for some time. + * + * @param timeout the timeout value in milliseconds + * @return String simple-string-reply The command returns OK or an error if the timeout is invalid. + */ + String clientPause(long timeout); + + /** + * Get the list of client connections. + * + * @return String bulk-string-reply a unique string, formatted as follows: One client connection per line (separated by LF), + * each line is composed of a succession of property=value fields separated by a space character. + */ + String clientList(); + + /** + * Get information and statistics about the server. + * + * @return String bulk-string-reply as a collection of text lines. + */ + String info(); + + /** + * Get information and statistics about the server. + * + * @param section the section type: string + * @return String bulk-string-reply as a collection of text lines. + */ + String info(String section); + /** * Ping the server. * diff --git a/src/main/templates/com/lambdaworks/redis/api/RedisSentinelCommands.java b/src/main/templates/com/lambdaworks/redis/api/RedisSentinelCommands.java index 255c2f0060..62d16303a3 100644 --- a/src/main/templates/com/lambdaworks/redis/api/RedisSentinelCommands.java +++ b/src/main/templates/com/lambdaworks/redis/api/RedisSentinelCommands.java @@ -19,6 +19,7 @@ import java.util.List; import java.util.Map; +import com.lambdaworks.redis.KillArgs; import com.lambdaworks.redis.sentinel.api.StatefulRedisSentinelConnection; /** @@ -108,6 +109,68 @@ public interface RedisSentinelCommands { */ String remove(K key); + /** + * Get the current connection name. + * + * @return K bulk-string-reply The connection name, or a null bulk reply if no name is set. + */ + K clientGetname(); + + /** + * Set the current connection name. + * + * @param name the client name + * @return simple-string-reply {@code OK} if the connection name was successfully set. + */ + String clientSetname(K name); + + /** + * Kill the connection of a client identified by ip:port. + * + * @param addr ip:port + * @return String simple-string-reply {@code OK} if the connection exists and has been closed + */ + String clientKill(String addr); + + /** + * Kill connections of clients which are filtered by {@code killArgs} + * + * @param killArgs args for the kill operation + * @return Long integer-reply number of killed connections + */ + Long clientKill(KillArgs killArgs); + + /** + * Stop processing commands from clients for some time. + * + * @param timeout the timeout value in milliseconds + * @return String simple-string-reply The command returns OK or an error if the timeout is invalid. + */ + String clientPause(long timeout); + + /** + * Get the list of client connections. + * + * @return String bulk-string-reply a unique string, formatted as follows: One client connection per line (separated by LF), + * each line is composed of a succession of property=value fields separated by a space character. + */ + String clientList(); + + /** + * Get information and statistics about the server. + * + * @return String bulk-string-reply as a collection of text lines. + */ + String info(); + + /** + * Get information and statistics about the server. + * + * @param section the section type: string + * @return String bulk-string-reply as a collection of text lines. + */ + String info(String section); + /** * Ping the server. * diff --git a/src/test/java/com/lambdaworks/redis/sentinel/AbstractSentinelTest.java b/src/test/java/com/lambdaworks/redis/sentinel/AbstractSentinelTest.java index 7018859b0c..db7f5f8088 100644 --- a/src/test/java/com/lambdaworks/redis/sentinel/AbstractSentinelTest.java +++ b/src/test/java/com/lambdaworks/redis/sentinel/AbstractSentinelTest.java @@ -24,6 +24,9 @@ import com.lambdaworks.redis.RedisClient; import com.lambdaworks.redis.sentinel.api.sync.RedisSentinelCommands; +/** + * @author Mark Paluch + */ public abstract class AbstractSentinelTest extends AbstractTest { public static final String MASTER_ID = "mymaster"; diff --git a/src/test/java/com/lambdaworks/redis/sentinel/SentinelCommandTest.java b/src/test/java/com/lambdaworks/redis/sentinel/SentinelCommandTest.java index 47c944a357..786cd6beed 100644 --- a/src/test/java/com/lambdaworks/redis/sentinel/SentinelCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/sentinel/SentinelCommandTest.java @@ -36,6 +36,9 @@ import com.lambdaworks.redis.api.sync.RedisCommands; import com.lambdaworks.redis.sentinel.api.sync.RedisSentinelCommands; +/** + * @author Mark Paluch + */ public class SentinelCommandTest extends AbstractSentinelTest { @Rule diff --git a/src/test/java/com/lambdaworks/redis/sentinel/SentinelConnectionTest.java b/src/test/java/com/lambdaworks/redis/sentinel/SentinelConnectionTest.java index e59e031d3b..130fab8b7a 100644 --- a/src/test/java/com/lambdaworks/redis/sentinel/SentinelConnectionTest.java +++ b/src/test/java/com/lambdaworks/redis/sentinel/SentinelConnectionTest.java @@ -37,6 +37,9 @@ import com.lambdaworks.redis.sentinel.api.async.RedisSentinelAsyncCommands; import com.lambdaworks.redis.sentinel.api.sync.RedisSentinelCommands; +/** + * @author Mark Paluch + */ public class SentinelConnectionTest extends AbstractSentinelTest { private StatefulRedisSentinelConnection connection; diff --git a/src/test/java/com/lambdaworks/redis/sentinel/SentinelRule.java b/src/test/java/com/lambdaworks/redis/sentinel/SentinelRule.java index 6dee9a1697..df5dc93ff3 100644 --- a/src/test/java/com/lambdaworks/redis/sentinel/SentinelRule.java +++ b/src/test/java/com/lambdaworks/redis/sentinel/SentinelRule.java @@ -50,7 +50,6 @@ *

  • Setup a master/slave combination
  • * * - * * @author Mark Paluch */ public class SentinelRule implements TestRule { diff --git a/src/test/java/com/lambdaworks/redis/sentinel/SentinelServerCommandTest.java b/src/test/java/com/lambdaworks/redis/sentinel/SentinelServerCommandTest.java new file mode 100644 index 0000000000..ece10ede8b --- /dev/null +++ b/src/test/java/com/lambdaworks/redis/sentinel/SentinelServerCommandTest.java @@ -0,0 +1,115 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.lambdaworks.redis.sentinel; + +import static com.lambdaworks.redis.TestSettings.hostAddr; +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; + +import com.lambdaworks.redis.KillArgs; +import com.lambdaworks.redis.RedisClient; +import com.lambdaworks.redis.RedisURI; +import com.lambdaworks.redis.TestSettings; +import com.lambdaworks.redis.sentinel.api.sync.RedisSentinelCommands; + +/** + * @author Mark Paluch + */ +public class SentinelServerCommandTest extends AbstractSentinelTest { + + @Rule + public SentinelRule sentinelRule = new SentinelRule(sentinelClient, false, 26379, 26380); + + @BeforeClass + public static void setupClient() { + sentinelClient = RedisClient.create(RedisURI.Builder.sentinel(TestSettings.host(), MASTER_ID).build()); + } + + @Before + public void openConnection() throws Exception { + super.openConnection(); + + try { + sentinel.master(MASTER_ID); + } catch (Exception e) { + sentinelRule.monitor(MASTER_ID, hostAddr(), TestSettings.port(3), 1, true); + } + } + + @Test + public void clientGetSetname() throws Exception { + assertThat(sentinel.clientGetname()).isNull(); + assertThat(sentinel.clientSetname("test")).isEqualTo("OK"); + assertThat(sentinel.clientGetname()).isEqualTo("test"); + assertThat(sentinel.clientSetname("")).isEqualTo("OK"); + assertThat(sentinel.clientGetname()).isNull(); + } + + @Test + public void clientPause() throws Exception { + assertThat(sentinel.clientPause(10)).isEqualTo("OK"); + } + + @Test + public void clientKill() throws Exception { + Pattern p = Pattern.compile(".*addr=([^ ]+).*"); + String clients = sentinel.clientList(); + Matcher m = p.matcher(clients); + + assertThat(m.lookingAt()).isTrue(); + assertThat(sentinel.clientKill(m.group(1))).isEqualTo("OK"); + } + + @Test + public void clientKillExtended() throws Exception { + + RedisSentinelCommands connection2 = sentinelClient.connectSentinel().sync(); + connection2.clientSetname("killme"); + + Pattern p = Pattern.compile("^.*addr=([^ ]+).*name=killme.*$", Pattern.MULTILINE | Pattern.DOTALL); + String clients = sentinel.clientList(); + Matcher m = p.matcher(clients); + + assertThat(m.matches()).isTrue(); + String addr = m.group(1); + assertThat(sentinel.clientKill(KillArgs.Builder.addr(addr).skipme())).isGreaterThan(0); + + assertThat(sentinel.clientKill(KillArgs.Builder.id(4234))).isEqualTo(0); + assertThat(sentinel.clientKill(KillArgs.Builder.typeSlave().id(4234))).isEqualTo(0); + assertThat(sentinel.clientKill(KillArgs.Builder.typeNormal().id(4234))).isEqualTo(0); + assertThat(sentinel.clientKill(KillArgs.Builder.typePubsub().id(4234))).isEqualTo(0); + + connection2.close(); + } + + @Test + public void clientList() throws Exception { + assertThat(sentinel.clientList().contains("addr=")).isTrue(); + } + + @Test + public void info() throws Exception { + assertThat(sentinel.info().contains("redis_version")).isTrue(); + assertThat(sentinel.info("server").contains("redis_version")).isTrue(); + } +} diff --git a/src/test/java/com/lambdaworks/redis/sentinel/reactive/SentinelServerReactiveCommandTest.java b/src/test/java/com/lambdaworks/redis/sentinel/reactive/SentinelServerReactiveCommandTest.java new file mode 100644 index 0000000000..6eaea17ac8 --- /dev/null +++ b/src/test/java/com/lambdaworks/redis/sentinel/reactive/SentinelServerReactiveCommandTest.java @@ -0,0 +1,48 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.lambdaworks.redis.sentinel.reactive; + +import static com.lambdaworks.redis.TestSettings.hostAddr; +import static org.assertj.core.api.Assertions.assertThat; + +import com.lambdaworks.redis.TestSettings; +import com.lambdaworks.redis.sentinel.SentinelServerCommandTest; +import com.lambdaworks.redis.sentinel.api.async.RedisSentinelAsyncCommands; +import com.lambdaworks.redis.sentinel.api.reactive.RedisSentinelReactiveCommands; +import com.lambdaworks.util.ReactiveSyncInvocationHandler; + +/** + * @author Mark Paluch + */ +public class SentinelServerReactiveCommandTest extends SentinelServerCommandTest { + + @Override + public void openConnection() throws Exception { + + RedisSentinelAsyncCommands async = sentinelClient.connectSentinel().async(); + RedisSentinelReactiveCommands reactive = async.getStatefulConnection().reactive(); + sentinel = ReactiveSyncInvocationHandler.sync(async.getStatefulConnection()); + + try { + sentinel.master(MASTER_ID); + } catch (Exception e) { + sentinelRule.monitor(MASTER_ID, hostAddr(), TestSettings.port(3), 1, true); + } + + assertThat(reactive.isOpen()).isTrue(); + assertThat(reactive.getStatefulConnection()).isSameAs(async.getStatefulConnection()); + } +} From 71c1131761ae1f58522083c7c68c179fa3903e75 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Thu, 1 Dec 2016 10:24:55 +0100 Subject: [PATCH 081/808] Remove close method from Redis Sentinel command interfaces #415 --- .../redis/sentinel/RedisSentinelAsyncCommandsImpl.java | 1 - .../sentinel/api/async/RedisSentinelAsyncCommands.java | 5 ----- .../api/reactive/RedisSentinelReactiveCommands.java | 5 ----- .../redis/sentinel/api/sync/RedisSentinelCommands.java | 5 ----- .../com/lambdaworks/redis/api/RedisSentinelCommands.java | 5 ----- src/test/java/com/lambdaworks/redis/AllTheAPIsTest.java | 2 +- .../lambdaworks/redis/sentinel/AbstractSentinelTest.java | 2 +- .../lambdaworks/redis/sentinel/SentinelCommandTest.java | 2 +- .../redis/sentinel/SentinelConnectionTest.java | 8 ++++---- .../java/com/lambdaworks/redis/sentinel/SentinelRule.java | 2 +- .../redis/sentinel/SentinelServerCommandTest.java | 2 +- .../util/ConnectionDecoratingInvocationHandler.java | 4 ++++ 12 files changed, 13 insertions(+), 30 deletions(-) diff --git a/src/main/java/com/lambdaworks/redis/sentinel/RedisSentinelAsyncCommandsImpl.java b/src/main/java/com/lambdaworks/redis/sentinel/RedisSentinelAsyncCommandsImpl.java index ccabe0a9c4..423c2cb550 100644 --- a/src/main/java/com/lambdaworks/redis/sentinel/RedisSentinelAsyncCommandsImpl.java +++ b/src/main/java/com/lambdaworks/redis/sentinel/RedisSentinelAsyncCommandsImpl.java @@ -181,7 +181,6 @@ public AsyncCommand dispatch(RedisCommand cmd) { return connection.dispatch(new AsyncCommand<>(cmd)); } - @Override public void close() { connection.close(); } diff --git a/src/main/java/com/lambdaworks/redis/sentinel/api/async/RedisSentinelAsyncCommands.java b/src/main/java/com/lambdaworks/redis/sentinel/api/async/RedisSentinelAsyncCommands.java index 1e203d3f14..6ce644bbd9 100644 --- a/src/main/java/com/lambdaworks/redis/sentinel/api/async/RedisSentinelAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/sentinel/api/async/RedisSentinelAsyncCommands.java @@ -179,11 +179,6 @@ public interface RedisSentinelAsyncCommands { */ RedisFuture ping(); - /** - * close the underlying connection. - */ - void close(); - /** * * @return true if the connection is open (connected and not closed). diff --git a/src/main/java/com/lambdaworks/redis/sentinel/api/reactive/RedisSentinelReactiveCommands.java b/src/main/java/com/lambdaworks/redis/sentinel/api/reactive/RedisSentinelReactiveCommands.java index daff5b8773..d784f09935 100644 --- a/src/main/java/com/lambdaworks/redis/sentinel/api/reactive/RedisSentinelReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/sentinel/api/reactive/RedisSentinelReactiveCommands.java @@ -180,11 +180,6 @@ public interface RedisSentinelReactiveCommands { */ Mono ping(); - /** - * close the underlying connection. - */ - void close(); - /** * * @return true if the connection is open (connected and not closed). diff --git a/src/main/java/com/lambdaworks/redis/sentinel/api/sync/RedisSentinelCommands.java b/src/main/java/com/lambdaworks/redis/sentinel/api/sync/RedisSentinelCommands.java index 98f6e4b1cf..52b5e76cea 100644 --- a/src/main/java/com/lambdaworks/redis/sentinel/api/sync/RedisSentinelCommands.java +++ b/src/main/java/com/lambdaworks/redis/sentinel/api/sync/RedisSentinelCommands.java @@ -178,11 +178,6 @@ public interface RedisSentinelCommands { */ String ping(); - /** - * close the underlying connection. - */ - void close(); - /** * * @return true if the connection is open (connected and not closed). diff --git a/src/main/templates/com/lambdaworks/redis/api/RedisSentinelCommands.java b/src/main/templates/com/lambdaworks/redis/api/RedisSentinelCommands.java index 62d16303a3..44c9d44f11 100644 --- a/src/main/templates/com/lambdaworks/redis/api/RedisSentinelCommands.java +++ b/src/main/templates/com/lambdaworks/redis/api/RedisSentinelCommands.java @@ -178,11 +178,6 @@ public interface RedisSentinelCommands { */ String ping(); - /** - * close the underlying connection. - */ - void close(); - /** * * @return true if the connection is open (connected and not closed). diff --git a/src/test/java/com/lambdaworks/redis/AllTheAPIsTest.java b/src/test/java/com/lambdaworks/redis/AllTheAPIsTest.java index f35c04559c..313807ae8b 100644 --- a/src/test/java/com/lambdaworks/redis/AllTheAPIsTest.java +++ b/src/test/java/com/lambdaworks/redis/AllTheAPIsTest.java @@ -91,7 +91,7 @@ public void pubsubStateful() throws Exception { // Sentinel @Test public void sentinelSync() throws Exception { - redisClient.connectSentinel().sync().close(); + redisClient.connectSentinel().sync().getStatefulConnection().close(); } @Test diff --git a/src/test/java/com/lambdaworks/redis/sentinel/AbstractSentinelTest.java b/src/test/java/com/lambdaworks/redis/sentinel/AbstractSentinelTest.java index db7f5f8088..855d451328 100644 --- a/src/test/java/com/lambdaworks/redis/sentinel/AbstractSentinelTest.java +++ b/src/test/java/com/lambdaworks/redis/sentinel/AbstractSentinelTest.java @@ -47,7 +47,7 @@ public void openConnection() throws Exception { @After public void closeConnection() throws Exception { if (sentinel != null) { - sentinel.close(); + sentinel.getStatefulConnection().close(); } } diff --git a/src/test/java/com/lambdaworks/redis/sentinel/SentinelCommandTest.java b/src/test/java/com/lambdaworks/redis/sentinel/SentinelCommandTest.java index 786cd6beed..b2e4b19351 100644 --- a/src/test/java/com/lambdaworks/redis/sentinel/SentinelCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/sentinel/SentinelCommandTest.java @@ -101,7 +101,7 @@ public void sentinelConnectWith() throws Exception { RedisSentinelCommands sentinelConnection = client.connectSentinel().sync(); assertThat(sentinelConnection.ping()).isEqualTo("PONG"); - sentinelConnection.close(); + sentinelConnection.getStatefulConnection().close(); RedisCommands connection2 = client.connect().sync(); assertThat(connection2.ping()).isEqualTo("PONG"); diff --git a/src/test/java/com/lambdaworks/redis/sentinel/SentinelConnectionTest.java b/src/test/java/com/lambdaworks/redis/sentinel/SentinelConnectionTest.java index 130fab8b7a..8f6decc055 100644 --- a/src/test/java/com/lambdaworks/redis/sentinel/SentinelConnectionTest.java +++ b/src/test/java/com/lambdaworks/redis/sentinel/SentinelConnectionTest.java @@ -114,7 +114,7 @@ public void testSyncAsyncConversion() throws Exception { public void testSyncClose() throws Exception { StatefulRedisSentinelConnection statefulConnection = sentinel.getStatefulConnection(); - statefulConnection.sync().close(); + statefulConnection.sync().getStatefulConnection().close(); Wait.untilTrue(() -> !sentinel.isOpen()).waitOrTimeout(); @@ -125,7 +125,7 @@ public void testSyncClose() throws Exception { @Test public void testAsyncClose() throws Exception { StatefulRedisSentinelConnection statefulConnection = sentinel.getStatefulConnection(); - statefulConnection.async().close(); + statefulConnection.async().getStatefulConnection().close(); Wait.untilTrue(() -> !sentinel.isOpen()).waitOrTimeout(); @@ -138,12 +138,12 @@ public void connectToOneNode() throws Exception { RedisSentinelCommands connection = sentinelClient .connectSentinel(RedisURI.Builder.sentinel(TestSettings.host(), MASTER_ID).build()).sync(); assertThat(connection.ping()).isEqualTo("PONG"); - connection.close(); + connection.getStatefulConnection().close(); } @Test public void connectWithByteCodec() throws Exception { RedisSentinelCommands connection = sentinelClient.connectSentinel(new ByteArrayCodec()).sync(); assertThat(connection.master(MASTER_ID.getBytes())).isNotNull(); - connection.close(); + connection.getStatefulConnection().close(); } } diff --git a/src/test/java/com/lambdaworks/redis/sentinel/SentinelRule.java b/src/test/java/com/lambdaworks/redis/sentinel/SentinelRule.java index df5dc93ff3..a5f8864fdf 100644 --- a/src/test/java/com/lambdaworks/redis/sentinel/SentinelRule.java +++ b/src/test/java/com/lambdaworks/redis/sentinel/SentinelRule.java @@ -96,7 +96,7 @@ public void evaluate() throws Throwable { base.evaluate(); for (RedisSentinelCommands commands : sentinelConnections.values()) { - commands.close(); + commands.getStatefulConnection().close(); } } }; diff --git a/src/test/java/com/lambdaworks/redis/sentinel/SentinelServerCommandTest.java b/src/test/java/com/lambdaworks/redis/sentinel/SentinelServerCommandTest.java index ece10ede8b..283041f5d6 100644 --- a/src/test/java/com/lambdaworks/redis/sentinel/SentinelServerCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/sentinel/SentinelServerCommandTest.java @@ -99,7 +99,7 @@ public void clientKillExtended() throws Exception { assertThat(sentinel.clientKill(KillArgs.Builder.typeNormal().id(4234))).isEqualTo(0); assertThat(sentinel.clientKill(KillArgs.Builder.typePubsub().id(4234))).isEqualTo(0); - connection2.close(); + connection2.getStatefulConnection().close(); } @Test diff --git a/src/test/java/com/lambdaworks/util/ConnectionDecoratingInvocationHandler.java b/src/test/java/com/lambdaworks/util/ConnectionDecoratingInvocationHandler.java index 745a07d325..d908754fd8 100644 --- a/src/test/java/com/lambdaworks/util/ConnectionDecoratingInvocationHandler.java +++ b/src/test/java/com/lambdaworks/util/ConnectionDecoratingInvocationHandler.java @@ -22,6 +22,7 @@ import com.lambdaworks.redis.api.StatefulRedisConnection; import com.lambdaworks.redis.cluster.api.StatefulRedisClusterConnection; import com.lambdaworks.redis.internal.AbstractInvocationHandler; +import com.lambdaworks.redis.sentinel.api.StatefulRedisSentinelConnection; /** * @author Mark Paluch @@ -48,6 +49,9 @@ protected Object handleInvocation(Object proxy, Method method, Object[] args) th if (result instanceof StatefulRedisClusterConnection && proxyMethod.getReturnType().isAssignableFrom(StatefulRedisClusterConnection.class)) { interfaces = new Class[] { StatefulConnection.class, StatefulRedisClusterConnection.class }; + } else if (result instanceof StatefulRedisSentinelConnection + && proxyMethod.getReturnType().isAssignableFrom(StatefulRedisSentinelConnection.class)) { + interfaces = new Class[] { StatefulConnection.class, StatefulRedisSentinelConnection.class }; } else { interfaces = new Class[] { StatefulConnection.class, StatefulRedisConnection.class }; } From 4753849228d90d44922741ad90e15bb8239991b0 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Thu, 1 Dec 2016 14:23:03 +0100 Subject: [PATCH 082/808] Allow setting client name with RedisURI #416 RedisURI now allows client name configuration to set the client name upon connection. The client name is applied to all connection types. Client name can be set via URI and API: redis://host:port?clientName=foo redisURI.setClientName("foo") RedisURI.Builder.redis("host").withClientName("foo") --- .../com/lambdaworks/redis/RedisClient.java | 30 +++--- .../java/com/lambdaworks/redis/RedisURI.java | 96 +++++++++++++++---- .../redis/StatefulRedisConnectionImpl.java | 21 +++- .../redis/cluster/RedisClusterClient.java | 8 ++ .../StatefulRedisClusterConnectionImpl.java | 21 +++- .../MasterSlaveConnectionProvider.java | 3 + .../masterslave/RedisMasterSlaveNode.java | 8 +- .../StatefulRedisSentinelConnectionImpl.java | 26 ++++- .../com/lambdaworks/redis/ClientTest.java | 33 +++++++ .../redis/RedisURIBuilderTest.java | 11 +++ .../com/lambdaworks/redis/RedisURITest.java | 8 ++ .../redis/cluster/RedisClusterClientTest.java | 40 +++++++- .../masterslave/MasterSlaveSentinelTest.java | 18 +++- .../redis/masterslave/MasterSlaveTest.java | 15 ++- .../masterslave/StaticMasterSlaveTest.java | 14 ++- .../sentinel/SentinelConnectionTest.java | 34 ++++++- 16 files changed, 336 insertions(+), 50 deletions(-) diff --git a/src/main/java/com/lambdaworks/redis/RedisClient.java b/src/main/java/com/lambdaworks/redis/RedisClient.java index 591fd723d5..d16aa8e2e1 100644 --- a/src/main/java/com/lambdaworks/redis/RedisClient.java +++ b/src/main/java/com/lambdaworks/redis/RedisClient.java @@ -17,7 +17,6 @@ import static com.lambdaworks.redis.LettuceStrings.isEmpty; import static com.lambdaworks.redis.LettuceStrings.isNotEmpty; -import static com.lambdaworks.redis.internal.LettuceClassUtils.isPresent; import java.net.ConnectException; import java.net.SocketAddress; @@ -31,8 +30,8 @@ import com.lambdaworks.redis.codec.RedisCodec; import com.lambdaworks.redis.codec.StringCodec; import com.lambdaworks.redis.internal.LettuceAssert; -import com.lambdaworks.redis.protocol.DefaultEndpoint; import com.lambdaworks.redis.protocol.CommandHandler; +import com.lambdaworks.redis.protocol.DefaultEndpoint; import com.lambdaworks.redis.pubsub.PubSubCommandHandler; import com.lambdaworks.redis.pubsub.PubSubEndpoint; import com.lambdaworks.redis.pubsub.StatefulRedisPubSubConnection; @@ -41,7 +40,6 @@ import com.lambdaworks.redis.resource.SocketAddressResolver; import com.lambdaworks.redis.sentinel.StatefulRedisSentinelConnectionImpl; import com.lambdaworks.redis.sentinel.api.StatefulRedisSentinelConnection; -import com.lambdaworks.redis.sentinel.api.async.RedisSentinelAsyncCommands; /** * A scalable thread-safe Redis client. Multiple threads may share one connection if they avoid @@ -200,7 +198,6 @@ public StatefulRedisConnection connect(RedisCodec codec, Redi return connectStandalone(codec, redisURI, Timeout.from(redisURI)); } - private StatefulRedisConnection connectStandalone(RedisCodec codec, RedisURI redisURI, Timeout timeout) { assertNotNull(codec); @@ -215,7 +212,7 @@ private StatefulRedisConnection connectStandalone(RedisCodec } private void connectStateful(StatefulRedisConnectionImpl connection, RedisURI redisURI, - DefaultEndpoint endpoint, Supplier commandHandlerSupplier) { + DefaultEndpoint endpoint, Supplier commandHandlerSupplier) { ConnectionBuilder connectionBuilder; if (redisURI.isSsl()) { @@ -239,10 +236,13 @@ private void connectStateful(StatefulRedisConnectionImpl connection connection.async().auth(new String(redisURI.getPassword())); } + if (LettuceStrings.isNotEmpty(redisURI.getClientName())) { + connection.setClientName(redisURI.getClientName()); + } + if (redisURI.getDatabase() != 0) { connection.async().select(redisURI.getDatabase()); } - } /** @@ -301,8 +301,8 @@ private StatefulRedisPubSubConnection connectPubSub(RedisCodec endpoint = new PubSubEndpoint(clientOptions); - StatefulRedisPubSubConnectionImpl connection = newStatefulRedisPubSubConnection(endpoint, - endpoint, codec, timeout.timeout, timeout.timeUnit); + StatefulRedisPubSubConnectionImpl connection = newStatefulRedisPubSubConnection(endpoint, endpoint, codec, + timeout.timeout, timeout.timeUnit); connectStateful(connection, redisURI, endpoint, () -> new PubSubCommandHandler<>(clientResources, codec, endpoint)); @@ -368,12 +368,13 @@ private StatefulRedisSentinelConnection connectSentinel(RedisCodec< DefaultEndpoint endpoint = new DefaultEndpoint(clientOptions); - StatefulRedisSentinelConnectionImpl connection = newStatefulRedisSentinelConnection(endpoint, - codec, timeout.timeout, timeout.timeUnit); + StatefulRedisSentinelConnectionImpl connection = newStatefulRedisSentinelConnection(endpoint, codec, + timeout.timeout, timeout.timeUnit); logger.debug("Trying to get a Sentinel connection for one of: " + redisURI.getSentinels()); - connectionBuilder.endpoint(endpoint).commandHandler(() -> new CommandHandler(clientResources, endpoint)).connection(connection); + connectionBuilder.endpoint(endpoint).commandHandler(() -> new CommandHandler(clientResources, endpoint)) + .connection(connection); connectionBuilder(getSocketAddressSupplier(redisURI), connectionBuilder, redisURI); if (redisURI.getSentinels().isEmpty() && (isNotEmpty(redisURI.getHost()) || !isEmpty(redisURI.getSocket()))) { @@ -413,6 +414,10 @@ private StatefulRedisSentinelConnection connectSentinel(RedisCodec< } } + if (LettuceStrings.isNotEmpty(redisURI.getClientName())) { + connection.setClientName(redisURI.getClientName()); + } + return connection; } @@ -527,8 +532,7 @@ private SocketAddress getSocketAddress(RedisURI redisURI) } private SocketAddress lookupRedis(RedisURI sentinelUri) throws InterruptedException, TimeoutException, ExecutionException { - StatefulRedisSentinelConnection connection = connectSentinel( - sentinelUri); + StatefulRedisSentinelConnection connection = connectSentinel(sentinelUri); try { return connection.async().getMasterAddrByName(sentinelUri.getSentinelMasterId()).get(timeout, unit); } finally { diff --git a/src/main/java/com/lambdaworks/redis/RedisURI.java b/src/main/java/com/lambdaworks/redis/RedisURI.java index 74852f8c02..fa74b34184 100644 --- a/src/main/java/com/lambdaworks/redis/RedisURI.java +++ b/src/main/java/com/lambdaworks/redis/RedisURI.java @@ -34,8 +34,8 @@ import com.lambdaworks.redis.protocol.LettuceCharsets; /** - * Redis URI. Contains connection details for the Redis/Sentinel connections. You can provide the database, password and - * timeouts within the RedisURI. + * Redis URI. Contains connection details for the Redis/Sentinel connections. You can provide the database, client name, + * password and timeouts within the RedisURI. * * You have following possibilities to create a {@link RedisURI}: * @@ -68,19 +68,20 @@ * * Redis Standalone
    redis{@code ://}[password@]host [{@code :} * port][{@code /}database][{@code ?} [timeout=timeout[d|h|m|s|ms|us|ns]] [ - * &database=database]]
    + * &database=database] [&clientName=clientName]] * * Redis Standalone (SSL)
    rediss{@code ://}[password@]host [{@code :} * port][{@code /}database][{@code ?} [timeout=timeout[d|h|m|s|ms|us|ns]] [ - * &database=database]]
    + * &database=database] [&clientName=clientName]] * * Redis Standalone (Unix Domain Sockets)
    redis-socket{@code ://} [password@]path[ - * {@code ?}[timeout=timeout[d|h|m|s|ms|us|ns]][&database=database]]
    + * {@code ?}[timeout=timeout[d|h|m|s|ms|us|ns]][&database=database] [&clientName=clientName]] + * * * Redis Sentinel
    redis-sentinel{@code ://}[password@]host1 [{@code :} * port1][, host2 [{@code :}port2]][, hostN [{@code :}portN]][{@code /} * database][{@code ?} [timeout=timeout[d|h|m|s|ms|us|ns]] [ - * &sentinelMasterId=sentinelMasterId] [&database=database]]
    + * &sentinelMasterId=sentinelMasterId] [&database=database] [&clientName=clientName]] * *

    * Schemes @@ -108,8 +109,7 @@ *

    * Hint: The database parameter within the query part has higher precedence than the database in the path. *

    - * - * + * * RedisURI supports Redis Standalone, Redis Sentinel and Redis Cluster with plain, SSL, TLS and unix domain socket connections. * * @author Mark Paluch @@ -129,6 +129,7 @@ public class RedisURI implements Serializable, ConnectionPoint { public static final String PARAMETER_NAME_DATABASE = "database"; public static final String PARAMETER_NAME_DATABASE_ALT = "db"; public static final String PARAMETER_NAME_SENTINEL_MASTER_ID = "sentinelMasterId"; + public static final String PARAMETER_NAME_CLIENT_NAME = "clientName"; public static final Map TIME_UNIT_MAP; @@ -165,6 +166,7 @@ public class RedisURI implements Serializable, ConnectionPoint { private String sentinelMasterId; private int port; private int database; + private String clientName; private char[] password; private boolean ssl = false; private boolean verifyPeer = true; @@ -387,6 +389,26 @@ public void setDatabase(int database) { this.database = database; } + /** + * Returns the client name. + * + * @return + * @since 4.4 + */ + public String getClientName() { + return clientName; + } + + /** + * Sets the client name to be applied on Redis connections. + * + * @param clientName the client name. + * @since 4.4 + */ + public void setClientName(String clientName) { + this.clientName = clientName; + } + /** * Returns {@literal true} if SSL mode is enabled. * @@ -519,6 +541,10 @@ private static RedisURI buildRedisUriFromUri(URI uri) { parseDatabase(builder, queryParam); } + if (forStartWith.startsWith(PARAMETER_NAME_CLIENT_NAME.toLowerCase() + "=")) { + parseClientName(builder, queryParam); + } + if (forStartWith.startsWith(PARAMETER_NAME_SENTINEL_MASTER_ID.toLowerCase() + "=")) { parseSentinelMasterId(builder, queryParam); } @@ -568,6 +594,10 @@ private String getQueryString() { queryPairs.add(PARAMETER_NAME_DATABASE + "=" + database); } + if (clientName != null) { + queryPairs.add(PARAMETER_NAME_CLIENT_NAME + "=" + urlEncode(clientName)); + } + if (sentinelMasterId != null) { queryPairs.add(PARAMETER_NAME_SENTINEL_MASTER_ID + "=" + urlEncode(sentinelMasterId)); } @@ -763,18 +793,31 @@ private static void parseDatabase(Builder builder, String queryParam) { } } - private static void parseSentinelMasterId(Builder builder, String queryParam) { - int index = queryParam.indexOf('='); - if (index < 0) { - return; + private static void parseClientName(Builder builder, String queryParam) { + + String clientName = getValuePart(queryParam); + if (isNotEmpty(clientName)) { + builder.withClientName(clientName); } + } - String masterIdString = queryParam.substring(index + 1); + private static void parseSentinelMasterId(Builder builder, String queryParam) { + + String masterIdString = getValuePart(queryParam); if (isNotEmpty(masterIdString)) { builder.withSentinelMasterId(masterIdString); } } + private static String getValuePart(String queryParam) { + int index = queryParam.indexOf('='); + if (index < 0) { + return null; + } + + return queryParam.substring(index + 1); + } + private static Builder configureStandalone(URI uri) { Builder builder = null; @@ -876,6 +919,7 @@ public static class Builder { private String sentinelMasterId; private int port; private int database; + private String clientName; private char[] password; private boolean ssl = false; private boolean verifyPeer = true; @@ -1086,7 +1130,7 @@ public Builder withVerifyPeer(boolean verifyPeer) { } /** - * Adds database selection. + * Configures the database number. * * @param database the database number * @return the builder @@ -1100,7 +1144,21 @@ public Builder withDatabase(int database) { } /** - * Adds authentication. + * Configures a client name. + * + * @param clientName the client name + * @return the builder + */ + public Builder withClientName(String clientName) { + + LettuceAssert.notNull(clientName, "Client name must not be null"); + + this.clientName = clientName; + return this; + } + + /** + * Configures authentication. * * @param password the password * @return the builder @@ -1114,9 +1172,9 @@ public Builder withPassword(String password) { } /** - * Adds timeout. + * Configures a timeout. * - * @param timeout must be greater or equal 0" + * @param timeout must be greater or equal 0. * @param unit the timeout time unit. * @return the builder */ @@ -1131,7 +1189,7 @@ public Builder withTimeout(long timeout, TimeUnit unit) { } /** - * Adds a sentinel master Id. + * Configures a sentinel master Id. * * @param sentinelMasterId sentinel master id, must not be empty or {@literal null} * @return the builder @@ -1145,7 +1203,6 @@ public Builder withSentinelMasterId(String sentinelMasterId) { } /** - * * @return the RedisURI. */ public RedisURI build() { @@ -1160,6 +1217,7 @@ public RedisURI build() { redisURI.setPort(port); redisURI.password = password; redisURI.setDatabase(database); + redisURI.setClientName(clientName); redisURI.setSentinelMasterId(sentinelMasterId); diff --git a/src/main/java/com/lambdaworks/redis/StatefulRedisConnectionImpl.java b/src/main/java/com/lambdaworks/redis/StatefulRedisConnectionImpl.java index 8ce815ca42..e2e2f6b798 100644 --- a/src/main/java/com/lambdaworks/redis/StatefulRedisConnectionImpl.java +++ b/src/main/java/com/lambdaworks/redis/StatefulRedisConnectionImpl.java @@ -32,11 +32,10 @@ import com.lambdaworks.redis.api.sync.RedisCommands; import com.lambdaworks.redis.cluster.api.sync.RedisClusterCommands; import com.lambdaworks.redis.codec.RedisCodec; +import com.lambdaworks.redis.codec.StringCodec; import com.lambdaworks.redis.output.MultiOutput; -import com.lambdaworks.redis.protocol.CompleteableCommand; -import com.lambdaworks.redis.protocol.ConnectionWatchdog; -import com.lambdaworks.redis.protocol.RedisCommand; -import com.lambdaworks.redis.protocol.TransactionalCommand; +import com.lambdaworks.redis.output.StatusOutput; +import com.lambdaworks.redis.protocol.*; import io.netty.channel.ChannelHandler; /** @@ -60,6 +59,7 @@ public class StatefulRedisConnectionImpl extends RedisChannelHandler private char[] password; private int db; private boolean readOnly; + private String clientName; /** * Initialize a new connection. @@ -138,6 +138,10 @@ public void activated() { async.selectAsync(db); } + if (clientName != null) { + setClientName(clientName); + } + if (readOnly) { async.readOnly(); } @@ -219,4 +223,13 @@ private RedisCommand attachOnComplete(RedisCommand command return command; } + public void setClientName(String clientName) { + + CommandArgs args = new CommandArgs<>(StringCodec.UTF8).add(CommandKeyword.SETNAME).addValue(clientName); + AsyncCommand async = new AsyncCommand<>( + new Command<>(CommandType.CLIENT, new StatusOutput<>(StringCodec.UTF8), args)); + this.clientName = clientName; + + dispatch((RedisCommand) async); + } } diff --git a/src/main/java/com/lambdaworks/redis/cluster/RedisClusterClient.java b/src/main/java/com/lambdaworks/redis/cluster/RedisClusterClient.java index 0cfedb6788..2b55af3dce 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/RedisClusterClient.java +++ b/src/main/java/com/lambdaworks/redis/cluster/RedisClusterClient.java @@ -599,6 +599,10 @@ private void connectStateful(StatefulRedisConnectionImpl connection if (connectionSettings.getPassword() != null && connectionSettings.getPassword().length != 0) { connection.async().auth(new String(connectionSettings.getPassword())); } + + if (LettuceStrings.isNotEmpty(connectionSettings.getClientName())) { + connection.setClientName(connectionSettings.getClientName()); + } } /** @@ -615,6 +619,10 @@ private void connectStateful(DefaultEndpoint endpoint, StatefulRedisClust if (connectionSettings.getPassword() != null && connectionSettings.getPassword().length != 0) { connection.async().auth(new String(connectionSettings.getPassword())); } + + if (LettuceStrings.isNotEmpty(connectionSettings.getClientName())) { + connection.setClientName(connectionSettings.getClientName()); + } } /** diff --git a/src/main/java/com/lambdaworks/redis/cluster/StatefulRedisClusterConnectionImpl.java b/src/main/java/com/lambdaworks/redis/cluster/StatefulRedisClusterConnectionImpl.java index 4a2ca950af..18670a99ff 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/StatefulRedisClusterConnectionImpl.java +++ b/src/main/java/com/lambdaworks/redis/cluster/StatefulRedisClusterConnectionImpl.java @@ -36,10 +36,10 @@ import com.lambdaworks.redis.cluster.models.partitions.Partitions; import com.lambdaworks.redis.cluster.models.partitions.RedisClusterNode; import com.lambdaworks.redis.codec.RedisCodec; +import com.lambdaworks.redis.codec.StringCodec; import com.lambdaworks.redis.internal.LettuceAssert; -import com.lambdaworks.redis.protocol.CompleteableCommand; -import com.lambdaworks.redis.protocol.ConnectionWatchdog; -import com.lambdaworks.redis.protocol.RedisCommand; +import com.lambdaworks.redis.output.StatusOutput; +import com.lambdaworks.redis.protocol.*; import io.netty.channel.ChannelHandler; @@ -59,6 +59,7 @@ public class StatefulRedisClusterConnectionImpl extends RedisChannelHandle private char[] password; private boolean readOnly; + private String clientName; protected final RedisCodec codec; protected final RedisAdvancedClusterCommands sync; @@ -147,11 +148,25 @@ public void activated() { async.authAsync(new String(password)); } + if (clientName != null) { + setClientName(clientName); + } + if (readOnly) { async.readOnly(); } } + void setClientName(String clientName) { + + CommandArgs args = new CommandArgs<>(StringCodec.UTF8).add(CommandKeyword.SETNAME).addValue(clientName); + AsyncCommand async = new AsyncCommand<>( + new Command<>(CommandType.CLIENT, new StatusOutput<>(StringCodec.UTF8), args)); + this.clientName = clientName; + + dispatch((RedisCommand) async); + } + @Override public > C dispatch(C cmd) { diff --git a/src/main/java/com/lambdaworks/redis/masterslave/MasterSlaveConnectionProvider.java b/src/main/java/com/lambdaworks/redis/masterslave/MasterSlaveConnectionProvider.java index 887537faf7..bcfe3c5876 100644 --- a/src/main/java/com/lambdaworks/redis/masterslave/MasterSlaveConnectionProvider.java +++ b/src/main/java/com/lambdaworks/redis/masterslave/MasterSlaveConnectionProvider.java @@ -253,6 +253,9 @@ public StatefulRedisConnection apply(ConnectionKey key) { builder.withPassword(new String(initialRedisUri.getPassword())); } + if (initialRedisUri.getClientName() != null) { + builder.withClientName(initialRedisUri.getClientName()); + } builder.withDatabase(initialRedisUri.getDatabase()); StatefulRedisConnection connection = redisClient.connect(redisCodec, builder.build()); diff --git a/src/main/java/com/lambdaworks/redis/masterslave/RedisMasterSlaveNode.java b/src/main/java/com/lambdaworks/redis/masterslave/RedisMasterSlaveNode.java index 0bfd9b9fa2..7a84a207c9 100644 --- a/src/main/java/com/lambdaworks/redis/masterslave/RedisMasterSlaveNode.java +++ b/src/main/java/com/lambdaworks/redis/masterslave/RedisMasterSlaveNode.java @@ -35,7 +35,13 @@ public RedisMasterSlaveNode(String host, int port, RedisURI seed, Role role) { builder.withPassword(new String(seed.getPassword())); } - this.redisURI = builder.withDatabase(seed.getDatabase()).build(); + if (seed.getClientName() != null) { + builder.withClientName(seed.getClientName()); + } + + builder.withDatabase(seed.getDatabase()); + + this.redisURI = builder.build(); this.role = role; } diff --git a/src/main/java/com/lambdaworks/redis/sentinel/StatefulRedisSentinelConnectionImpl.java b/src/main/java/com/lambdaworks/redis/sentinel/StatefulRedisSentinelConnectionImpl.java index a0e2254c02..b678ad6eb3 100644 --- a/src/main/java/com/lambdaworks/redis/sentinel/StatefulRedisSentinelConnectionImpl.java +++ b/src/main/java/com/lambdaworks/redis/sentinel/StatefulRedisSentinelConnectionImpl.java @@ -20,7 +20,9 @@ import com.lambdaworks.redis.RedisChannelHandler; import com.lambdaworks.redis.RedisChannelWriter; import com.lambdaworks.redis.codec.RedisCodec; -import com.lambdaworks.redis.protocol.RedisCommand; +import com.lambdaworks.redis.codec.StringCodec; +import com.lambdaworks.redis.output.StatusOutput; +import com.lambdaworks.redis.protocol.*; import com.lambdaworks.redis.sentinel.api.StatefulRedisSentinelConnection; import com.lambdaworks.redis.sentinel.api.async.RedisSentinelAsyncCommands; import com.lambdaworks.redis.sentinel.api.reactive.RedisSentinelReactiveCommands; @@ -38,6 +40,8 @@ public class StatefulRedisSentinelConnectionImpl extends RedisChannelHandl protected final RedisSentinelAsyncCommands async; protected final RedisSentinelReactiveCommands reactive; + private String clientName; + public StatefulRedisSentinelConnectionImpl(RedisChannelWriter writer, RedisCodec codec, long timeout, TimeUnit unit) { super(writer, timeout, unit); @@ -67,4 +71,24 @@ public RedisSentinelAsyncCommands async() { public RedisSentinelReactiveCommands reactive() { return reactive; } + + @Override + public void activated() { + + super.activated(); + + if (clientName != null) { + setClientName(clientName); + } + } + + public void setClientName(String clientName) { + + CommandArgs args = new CommandArgs<>(StringCodec.UTF8).add(CommandKeyword.SETNAME).addValue(clientName); + AsyncCommand async = new AsyncCommand<>( + new Command<>(CommandType.CLIENT, new StatusOutput<>(StringCodec.UTF8), args)); + this.clientName = clientName; + + dispatch((RedisCommand) async); + } } diff --git a/src/test/java/com/lambdaworks/redis/ClientTest.java b/src/test/java/com/lambdaworks/redis/ClientTest.java index b0fe55932c..f1873dd64d 100644 --- a/src/test/java/com/lambdaworks/redis/ClientTest.java +++ b/src/test/java/com/lambdaworks/redis/ClientTest.java @@ -39,6 +39,7 @@ */ @FixMethodOrder(MethodSorters.NAME_ASCENDING) public class ClientTest extends AbstractRedisClientTest { + @Rule public ExpectedException exception = ExpectedException.none(); @@ -263,4 +264,36 @@ public void reset() throws Exception { connection.close(); } + @Test + public void standaloneConnectionShouldSetClientName() throws Exception { + + RedisURI redisURI = RedisURI.create(host, port); + redisURI.setClientName("my-client"); + + StatefulRedisConnection connection = client.connect(redisURI); + + assertThat(connection.sync().clientGetname()).isEqualTo(redisURI.getClientName()); + + connection.sync().quit(); + assertThat(connection.sync().clientGetname()).isEqualTo(redisURI.getClientName()); + + connection.close(); + } + + @Test + public void pubSubConnectionShouldSetClientName() throws Exception { + + RedisURI redisURI = RedisURI.create(host, port); + redisURI.setClientName("my-client"); + + StatefulRedisConnection connection = client.connectPubSub(redisURI); + + assertThat(connection.sync().clientGetname()).isEqualTo(redisURI.getClientName()); + + connection.sync().quit(); + assertThat(connection.sync().clientGetname()).isEqualTo(redisURI.getClientName()); + + connection.close(); + } + } diff --git a/src/test/java/com/lambdaworks/redis/RedisURIBuilderTest.java b/src/test/java/com/lambdaworks/redis/RedisURIBuilderTest.java index 6dd30fbd5b..b4a244f22d 100644 --- a/src/test/java/com/lambdaworks/redis/RedisURIBuilderTest.java +++ b/src/test/java/com/lambdaworks/redis/RedisURIBuilderTest.java @@ -22,6 +22,9 @@ import org.junit.Test; +/** + * @author Mark Paluch + */ public class RedisURIBuilderTest { @Test @@ -68,6 +71,14 @@ public void redisWithPort() throws Exception { assertThat(result.getPort()).isEqualTo(1234); } + @Test + public void redisWithClientName() throws Exception { + RedisURI result = RedisURI.Builder.redis("localhost").withClientName("hello").build(); + + assertThat(result.getHost()).isEqualTo("localhost"); + assertThat(result.getClientName()).isEqualTo("hello"); + } + @Test(expected = IllegalArgumentException.class) public void redisHostAndPortWithInvalidPort() throws Exception { RedisURI.Builder.redis("localhost", -1); diff --git a/src/test/java/com/lambdaworks/redis/RedisURITest.java b/src/test/java/com/lambdaworks/redis/RedisURITest.java index 6335f6e23b..84938194b1 100644 --- a/src/test/java/com/lambdaworks/redis/RedisURITest.java +++ b/src/test/java/com/lambdaworks/redis/RedisURITest.java @@ -208,6 +208,14 @@ public void databaseParsingTest() { assertThat(redisURI.toURI().toString()).isEqualTo("redis://auth@localhost:1234?database=5"); } + @Test + public void clientNameParsingTest() { + RedisURI redisURI = RedisURI.create("redis://auth@localhost:1234/?clientName=hello"); + assertThat(redisURI.getClientName()).isEqualTo("hello"); + + assertThat(redisURI.toURI().toString()).isEqualTo("redis://auth@localhost:1234?clientName=hello"); + } + @Test public void parsingWithInvalidValuesTest() { RedisURI redisURI = RedisURI diff --git a/src/test/java/com/lambdaworks/redis/cluster/RedisClusterClientTest.java b/src/test/java/com/lambdaworks/redis/cluster/RedisClusterClientTest.java index b79872966c..15d18f5bf5 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/RedisClusterClientTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/RedisClusterClientTest.java @@ -41,6 +41,7 @@ import com.lambdaworks.redis.cluster.api.sync.RedisClusterCommands; import com.lambdaworks.redis.cluster.models.partitions.Partitions; import com.lambdaworks.redis.cluster.models.partitions.RedisClusterNode; +import com.lambdaworks.redis.cluster.pubsub.StatefulRedisClusterPubSubConnection; import com.lambdaworks.redis.protocol.AsyncCommand; import com.lambdaworks.redis.pubsub.StatefulRedisPubSubConnection; @@ -66,7 +67,8 @@ public class RedisClusterClientTest extends AbstractClusterTest { public static void setupClient() throws Exception { setupClusterClient(); client = RedisClient.create(TestClientResources.get(), RedisURI.Builder.redis(host, port1).build()); - clusterClient = RedisClusterClient.create(TestClientResources.get(), Collections.singletonList(RedisURI.Builder.redis(host, port1).build())); + clusterClient = RedisClusterClient + .create(TestClientResources.get(), Collections.singletonList(RedisURI.Builder.redis(host, port1).withClientName("my-client").build())); } @AfterClass @@ -169,6 +171,42 @@ public void shouldApplyTimeoutOnPubSubConnectionUsingCodec() throws Exception { connection.close(); } + @Test + public void clusterConnectionShouldSetClientName() throws Exception { + + StatefulRedisClusterConnection connection = clusterClient.connect(); + + assertThat(connection.sync().clientGetname()).isEqualTo("my-client"); + connection.sync().quit(); + assertThat(connection.sync().clientGetname()).isEqualTo("my-client"); + + StatefulRedisConnection nodeConnection = connection + .getConnection(connection.getPartitions().getPartition(0).getNodeId()); + assertThat(nodeConnection.sync().clientGetname()).isEqualTo("my-client"); + nodeConnection.sync().quit(); + assertThat(nodeConnection.sync().clientGetname()).isEqualTo("my-client"); + + connection.close(); + } + + @Test + public void pubSubclusterConnectionShouldSetClientName() throws Exception { + + StatefulRedisClusterPubSubConnection connection = clusterClient.connectPubSub(); + + assertThat(connection.sync().clientGetname()).isEqualTo("my-client"); + connection.sync().quit(); + assertThat(connection.sync().clientGetname()).isEqualTo("my-client"); + + StatefulRedisConnection nodeConnection = connection + .getConnection(connection.getPartitions().getPartition(0).getNodeId()); + assertThat(nodeConnection.sync().clientGetname()).isEqualTo("my-client"); + nodeConnection.sync().quit(); + assertThat(nodeConnection.sync().clientGetname()).isEqualTo("my-client"); + + connection.close(); + } + @Test public void reloadPartitions() throws Exception { assertThat(clusterClient.getPartitions()).hasSize(4); diff --git a/src/test/java/com/lambdaworks/redis/masterslave/MasterSlaveSentinelTest.java b/src/test/java/com/lambdaworks/redis/masterslave/MasterSlaveSentinelTest.java index 05779d808d..5ab7ff8ac3 100644 --- a/src/test/java/com/lambdaworks/redis/masterslave/MasterSlaveSentinelTest.java +++ b/src/test/java/com/lambdaworks/redis/masterslave/MasterSlaveSentinelTest.java @@ -73,6 +73,21 @@ public void testMasterSlaveSentinelBasic() throws Exception { connection.close(); } + @Test + public void masterSlaveConnectionShouldSetClientName() throws Exception { + + RedisURI redisURI = RedisURI.Builder.sentinel(TestSettings.host(), MASTER_ID).withClientName("my-client").build(); + + StatefulRedisMasterSlaveConnection connection = MasterSlave.connect(sentinelClient, + new Utf8StringCodec(), redisURI); + + assertThat(connection.sync().clientGetname()).isEqualTo(redisURI.getClientName()); + connection.sync().quit(); + assertThat(connection.sync().clientGetname()).isEqualTo(redisURI.getClientName()); + + connection.close(); + } + @Test public void testMasterSlaveSentinelWithTwoUnavailableSentinels() throws Exception { @@ -91,8 +106,7 @@ public void testMasterSlaveSentinelWithTwoUnavailableSentinels() throws Exceptio @Test public void testMasterSlaveSentinelWithUnavailableSentinels() throws Exception { - RedisURI uri = RedisURI - .create("redis-sentinel://127.0.0.1:21379,127.0.0.1:21379?sentinelMasterId=mymaster&timeout=5s"); + RedisURI uri = RedisURI.create("redis-sentinel://127.0.0.1:21379,127.0.0.1:21379?sentinelMasterId=mymaster&timeout=5s"); try { MasterSlave.connect(sentinelClient, new Utf8StringCodec(), uri); diff --git a/src/test/java/com/lambdaworks/redis/masterslave/MasterSlaveTest.java b/src/test/java/com/lambdaworks/redis/masterslave/MasterSlaveTest.java index 3bd186ba91..5f05b36354 100644 --- a/src/test/java/com/lambdaworks/redis/masterslave/MasterSlaveTest.java +++ b/src/test/java/com/lambdaworks/redis/masterslave/MasterSlaveTest.java @@ -41,8 +41,9 @@ */ public class MasterSlaveTest extends AbstractRedisClientTest { - private RedisURI masterURI = RedisURI.Builder.redis(host, TestSettings.port(3)).withPassword(passwd).withDatabase(5) - .build(); + private RedisURI masterURI = RedisURI.Builder.redis(host, TestSettings.port(3)).withPassword(passwd) + .withClientName("my-client").withDatabase(5).build(); + private StatefulRedisMasterSlaveConnectionImpl connection; private RedisAsyncCommands connectionToNode1; private RedisAsyncCommands connectionToNode2; @@ -167,6 +168,16 @@ public List select(Nodes nodes) { slaveCall(connection); } + @Test + public void masterSlaveConnectionShouldSetClientName() throws Exception { + + assertThat(connection.sync().clientGetname()).isEqualTo(masterURI.getClientName()); + connection.sync().quit(); + assertThat(connection.sync().clientGetname()).isEqualTo(masterURI.getClientName()); + + connection.close(); + } + @Test public void testConnectionCount() throws Exception { diff --git a/src/test/java/com/lambdaworks/redis/masterslave/StaticMasterSlaveTest.java b/src/test/java/com/lambdaworks/redis/masterslave/StaticMasterSlaveTest.java index 13d78ce0cf..9c6f09fd44 100644 --- a/src/test/java/com/lambdaworks/redis/masterslave/StaticMasterSlaveTest.java +++ b/src/test/java/com/lambdaworks/redis/masterslave/StaticMasterSlaveTest.java @@ -51,8 +51,8 @@ public class StaticMasterSlaveTest extends AbstractRedisClientTest { @Before public void before() throws Exception { - RedisURI node1 = RedisURI.Builder.redis(host, TestSettings.port(3)).withDatabase(2).build(); - RedisURI node2 = RedisURI.Builder.redis(host, TestSettings.port(4)).withDatabase(2).build(); + RedisURI node1 = RedisURI.Builder.redis(host, TestSettings.port(3)).withClientName("my-client").withDatabase(2).build(); + RedisURI node2 = RedisURI.Builder.redis(host, TestSettings.port(4)).withClientName("my-client").withDatabase(2).build(); connectionToNode1 = client.connect(node1).async(); connectionToNode2 = client.connect(node2).async(); @@ -178,6 +178,16 @@ public void noMasterForWrite() throws Exception { connection.sync().set(key, value); } + @Test + public void masterSlaveConnectionShouldSetClientName() throws Exception { + + assertThat(connection.sync().clientGetname()).isEqualTo("my-client"); + connection.sync().quit(); + assertThat(connection.sync().clientGetname()).isEqualTo("my-client"); + + connection.close(); + } + @Test public void testConnectionCount() throws Exception { diff --git a/src/test/java/com/lambdaworks/redis/sentinel/SentinelConnectionTest.java b/src/test/java/com/lambdaworks/redis/sentinel/SentinelConnectionTest.java index 8f6decc055..e85a0d35a1 100644 --- a/src/test/java/com/lambdaworks/redis/sentinel/SentinelConnectionTest.java +++ b/src/test/java/com/lambdaworks/redis/sentinel/SentinelConnectionTest.java @@ -22,16 +22,17 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; -import com.lambdaworks.TestClientResources; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; +import com.lambdaworks.TestClientResources; import com.lambdaworks.Wait; import com.lambdaworks.redis.RedisClient; import com.lambdaworks.redis.RedisFuture; import com.lambdaworks.redis.RedisURI; import com.lambdaworks.redis.TestSettings; +import com.lambdaworks.redis.api.StatefulRedisConnection; import com.lambdaworks.redis.codec.ByteArrayCodec; import com.lambdaworks.redis.sentinel.api.StatefulRedisSentinelConnection; import com.lambdaworks.redis.sentinel.api.async.RedisSentinelAsyncCommands; @@ -47,7 +48,8 @@ public class SentinelConnectionTest extends AbstractSentinelTest { @BeforeClass public static void setupClient() { - sentinelClient = RedisClient.create(TestClientResources.get(), RedisURI.Builder.sentinel(TestSettings.host(), MASTER_ID).build()); + sentinelClient = RedisClient.create(TestClientResources.get(), + RedisURI.Builder.sentinel(TestSettings.host(), MASTER_ID).build()); } @Before @@ -140,10 +142,38 @@ public void connectToOneNode() throws Exception { assertThat(connection.ping()).isEqualTo("PONG"); connection.getStatefulConnection().close(); } + @Test public void connectWithByteCodec() throws Exception { RedisSentinelCommands connection = sentinelClient.connectSentinel(new ByteArrayCodec()).sync(); assertThat(connection.master(MASTER_ID.getBytes())).isNotNull(); connection.getStatefulConnection().close(); } + + @Test + public void sentinelConnectionShouldSetClientName() throws Exception { + + RedisURI redisURI = RedisURI.Builder.sentinel(TestSettings.host(), MASTER_ID).withClientName("my-client").build(); + + StatefulRedisSentinelConnection connection = sentinelClient.connectSentinel(redisURI); + + assertThat(connection.sync().clientGetname()).isEqualTo(redisURI.getClientName()); + + connection.close(); + } + + @Test + public void sentinelManagedConnectionShouldSetClientName() throws Exception { + + RedisURI redisURI = RedisURI.Builder.sentinel(TestSettings.host(), MASTER_ID).withClientName("my-client").build(); + + StatefulRedisConnection connection = sentinelClient.connect(redisURI); + + assertThat(connection.sync().clientGetname()).isEqualTo(redisURI.getClientName()); + + connection.sync().quit(); + assertThat(connection.sync().clientGetname()).isEqualTo(redisURI.getClientName()); + + connection.close(); + } } From 8b0a19ec06c9b515c3fc9587b1854703ab2d2a43 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Tue, 6 Dec 2016 17:17:05 +0100 Subject: [PATCH 083/808] Document RedisClient and RedisClusterClient implementation hooks #392 --- .../com/lambdaworks/redis/RedisClient.java | 124 +++++++----- .../redis/cluster/RedisClusterClient.java | 190 +++++++++++------- 2 files changed, 195 insertions(+), 119 deletions(-) diff --git a/src/main/java/com/lambdaworks/redis/RedisClient.java b/src/main/java/com/lambdaworks/redis/RedisClient.java index d16aa8e2e1..d7647a2d2d 100644 --- a/src/main/java/com/lambdaworks/redis/RedisClient.java +++ b/src/main/java/com/lambdaworks/redis/RedisClient.java @@ -421,8 +421,34 @@ private StatefulRedisSentinelConnection connectSentinel(RedisCodec< return connection; } + /** + * Set the {@link ClientOptions} for the client. + * + * @param clientOptions the new client options + * @throws IllegalArgumentException if {@literal clientOptions} is null + */ + @Override + public void setOptions(ClientOptions clientOptions) { + super.setOptions(clientOptions); + } + + /** + * Returns the {@link ClientResources} which are used with that client. + * + * @return the {@link ClientResources} for this client + */ + public ClientResources getResources() { + return clientResources; + } + + // ------------------------------------------------------------------------- + // Implementation hooks and helper methods + // ------------------------------------------------------------------------- + /** * Create a new instance of {@link StatefulRedisPubSubConnectionImpl} or a subclass. + *

    + * Subclasses of {@link RedisClient} may override that method. * * @param endpoint the endpoint * @param channelWriter the channel writer @@ -440,6 +466,8 @@ protected StatefulRedisPubSubConnectionImpl newStatefulRedisPubSubC /** * Create a new instance of {@link StatefulRedisSentinelConnectionImpl} or a subclass. + *

    + * Subclasses of {@link RedisClient} may override that method. * * @param channelWriter the channel writer * @param codec codec @@ -456,6 +484,8 @@ protected StatefulRedisSentinelConnectionImpl newStatefulRedisSenti /** * Create a new instance of {@link StatefulRedisConnectionImpl} or a subclass. + *

    + * Subclasses of {@link RedisClient} may override that method. * * @param channelWriter the channel writer * @param codec codec @@ -470,6 +500,51 @@ protected StatefulRedisConnectionImpl newStatefulRedisConnection(Re return new StatefulRedisConnectionImpl<>(channelWriter, codec, timeout, unit); } + /** + * Resolve a {@link RedisURI} to a {@link SocketAddress}. Resolution is performed either using Redis Sentinel (if the + * {@link RedisURI} is configured with Sentinels) or via DNS resolution. + *

    + * Subclasses of {@link RedisClient} may override that method. + * + * @param redisURI must not be {@literal null}. + * @return the resolved {@link SocketAddress}. + * @throws InterruptedException + * @throws TimeoutException + * @throws ExecutionException + * @see ClientResources#dnsResolver() + * @see RedisURI#getSentinels() + * @see RedisURI#getSentinelMasterId() + */ + protected SocketAddress getSocketAddress(RedisURI redisURI) + throws InterruptedException, TimeoutException, ExecutionException { + SocketAddress redisAddress; + + if (redisURI.getSentinelMasterId() != null && !redisURI.getSentinels().isEmpty()) { + logger.debug("Connecting to Redis using Sentinels {}, MasterId {}", redisURI.getSentinels(), + redisURI.getSentinelMasterId()); + redisAddress = lookupRedis(redisURI); + + if (redisAddress == null) { + throw new RedisConnectionException( + "Cannot provide redisAddress using sentinel for masterId " + redisURI.getSentinelMasterId()); + } + + } else { + redisAddress = SocketAddressResolver.resolve(redisURI, clientResources.dnsResolver()); + } + return redisAddress; + } + + /** + * Returns a {@link String} {@link RedisCodec codec}. + * + * @return a {@link String} {@link RedisCodec codec}. + * @see StringCodec#UTF8 + */ + protected RedisCodec newStringStringCodec() { + return StringCodec.UTF8; + } + private void validateUrisAreOfSameConnectionType(List redisUris) { boolean unixDomainSocket = false; boolean inetSocket = false; @@ -502,41 +577,9 @@ private Supplier getSocketAddressSupplier(final RedisURI redisURI }; } - /** - * Returns the {@link ClientResources} which are used with that client. - * - * @return the {@link ClientResources} for this client - */ - public ClientResources getResources() { - return clientResources; - } - - private SocketAddress getSocketAddress(RedisURI redisURI) - throws InterruptedException, TimeoutException, ExecutionException { - SocketAddress redisAddress; - - if (redisURI.getSentinelMasterId() != null && !redisURI.getSentinels().isEmpty()) { - logger.debug("Connecting to Redis using Sentinels {}, MasterId {}", redisURI.getSentinels(), - redisURI.getSentinelMasterId()); - redisAddress = lookupRedis(redisURI); - - if (redisAddress == null) { - throw new RedisConnectionException( - "Cannot provide redisAddress using sentinel for masterId " + redisURI.getSentinelMasterId()); - } - - } else { - redisAddress = SocketAddressResolver.resolve(redisURI, clientResources.dnsResolver()); - } - return redisAddress; - } - private SocketAddress lookupRedis(RedisURI sentinelUri) throws InterruptedException, TimeoutException, ExecutionException { - StatefulRedisSentinelConnection connection = connectSentinel(sentinelUri); - try { + try (StatefulRedisSentinelConnection connection = connectSentinel(sentinelUri)) { return connection.async().getMasterAddrByName(sentinelUri.getSentinelMasterId()).get(timeout, unit); - } finally { - connection.close(); } } @@ -562,10 +605,6 @@ private void checkValidRedisURI(RedisURI redisURI) { } } - protected RedisCodec newStringStringCodec() { - return StringCodec.UTF8; - } - private static void assertNotNull(RedisCodec codec) { LettuceAssert.notNull(codec, "RedisCodec must not be null"); } @@ -584,17 +623,6 @@ private void checkForRedisURI() { checkValidRedisURI(this.redisURI); } - /** - * Set the {@link ClientOptions} for the client. - * - * @param clientOptions the new client options - * @throws IllegalArgumentException if {@literal clientOptions} is null - */ - @Override - public void setOptions(ClientOptions clientOptions) { - super.setOptions(clientOptions); - } - private Timeout defaultTimeout() { return Timeout.of(timeout, unit); } diff --git a/src/main/java/com/lambdaworks/redis/cluster/RedisClusterClient.java b/src/main/java/com/lambdaworks/redis/cluster/RedisClusterClient.java index 2b55af3dce..229e268770 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/RedisClusterClient.java +++ b/src/main/java/com/lambdaworks/redis/cluster/RedisClusterClient.java @@ -773,41 +773,6 @@ private void activateTopologyRefreshIfNeeded() { } } - protected RedisURI getFirstUri() { - assertNotEmpty(initialUris); - Iterator iterator = initialUris.iterator(); - return iterator.next(); - } - - /** - * Returns a {@link Supplier} for {@link SocketAddress connection points}. - * - * @param sortFunction Sort function to enforce a specific order. The sort function must not change the order or the input - * parameter but create a new collection with the desired order, must not be {@literal null}. - * @return {@link Supplier} for {@link SocketAddress connection points}. - */ - protected Supplier getSocketAddressSupplier( - Function> sortFunction) { - - LettuceAssert.notNull(sortFunction, "Sort function must not be null"); - - final RoundRobinSocketAddressSupplier socketAddressSupplier = new RoundRobinSocketAddressSupplier(partitions, - sortFunction, clientResources); - return () -> { - if (partitions.isEmpty()) { - SocketAddress socketAddress = SocketAddressResolver.resolve(getFirstUri(), clientResources.dnsResolver()); - logger.debug("Resolved SocketAddress {} using {}", socketAddress, getFirstUri()); - return socketAddress; - } - - return socketAddressSupplier.get(); - }; - } - - protected RedisCodec newStringStringCodec() { - return StringCodec.UTF8; - } - /** * Sets the new cluster topology. The partitions are not applied to existing connections. * @@ -852,14 +817,88 @@ public void shutdown(long quietPeriod, long timeout, TimeUnit timeUnit) { super.shutdown(quietPeriod, timeout, timeUnit); } + /** + * Set the {@link ClusterClientOptions} for the client. + * + * @param clientOptions client options for the client and connections that are created after setting the options + */ + public void setOptions(ClusterClientOptions clientOptions) { + super.setOptions(clientOptions); + } + + // ------------------------------------------------------------------------- + // Implementation hooks and helper methods + // ------------------------------------------------------------------------- + + /** + * Returns the first {@link RedisURI} configured with this {@link RedisClusterClient} instance. + * + * @return the first {@link RedisURI}. + */ + protected RedisURI getFirstUri() { + assertNotEmpty(initialUris); + Iterator iterator = initialUris.iterator(); + return iterator.next(); + } + + /** + * Returns a {@link Supplier} for {@link SocketAddress connection points}. + * + * @param sortFunction Sort function to enforce a specific order. The sort function must not change the order or the input + * parameter but create a new collection with the desired order, must not be {@literal null}. + * @return {@link Supplier} for {@link SocketAddress connection points}. + */ + protected Supplier getSocketAddressSupplier( + Function> sortFunction) { + + LettuceAssert.notNull(sortFunction, "Sort function must not be null"); + + final RoundRobinSocketAddressSupplier socketAddressSupplier = new RoundRobinSocketAddressSupplier(partitions, + sortFunction, clientResources); + return () -> { + if (partitions.isEmpty()) { + SocketAddress socketAddress = SocketAddressResolver.resolve(getFirstUri(), clientResources.dnsResolver()); + logger.debug("Resolved SocketAddress {} using {}", socketAddress, getFirstUri()); + return socketAddress; + } + + return socketAddressSupplier.get(); + }; + } + + /** + * Returns an {@link Iterable} of the initial {@link RedisURI URIs}. + * + * @return the initial {@link RedisURI URIs} + */ + protected Iterable getInitialUris() { + return initialUris; + } + + /** + * Apply a {@link Consumer} of {@link StatefulRedisClusterConnectionImpl} to all active connections. + * + * @param function the {@link Consumer}. + */ protected void forEachClusterConnection(Consumer> function) { forEachCloseable(input -> input instanceof StatefulRedisClusterConnectionImpl, function); } + /** + * Apply a {@link Consumer} of {@link StatefulRedisClusterPubSubConnectionImpl} to all active connections. + * + * @param function the {@link Consumer}. + */ protected void forEachClusterPubSubConnection(Consumer> function) { forEachCloseable(input -> input instanceof StatefulRedisClusterPubSubConnectionImpl, function); } + /** + * Apply a {@link Consumer} of {@link Closeable} to all active connections. + * + * @param function the {@link Consumer}. + */ + @SuppressWarnings("unchecked") protected void forEachCloseable(Predicate selector, Consumer function) { for (Closeable c : closeableResources) { if (selector.test(c)) { @@ -869,21 +908,57 @@ protected void forEachCloseable(Predicate + * Subclasses of {@link RedisClusterClient} may override that method. + * + * @return {@link Iterable} of {@link RedisURI} for the next topology refresh. */ - public void setOptions(ClusterClientOptions clientOptions) { - super.setOptions(clientOptions); + protected Iterable getTopologyRefreshSource() { + + boolean initialSeedNodes = !useDynamicRefreshSources(); + + Iterable seed; + if (initialSeedNodes || partitions == null || partitions.isEmpty()) { + seed = RedisClusterClient.this.initialUris; + } else { + List uris = new ArrayList<>(); + for (RedisClusterNode partition : TopologyComparators.sortByUri(partitions)) { + uris.add(partition.getUri()); + } + seed = uris; + } + return seed; } /** - * Returns the initial {@link RedisURI URIs}. + * Returns {@link true} if {@link ClusterTopologyRefreshOptions#useDynamicRefreshSources() dynamic refresh sources} are + * enabled. + *

    + * Subclasses of {@link RedisClusterClient} may override that method. * - * @return the initial {@link RedisURI URIs} + * @return {@link true} if dynamic refresh sources are used. + * @see ClusterTopologyRefreshOptions#useDynamicRefreshSources() */ - protected Iterable getInitialUris() { - return initialUris; + protected boolean useDynamicRefreshSources() { + + if (getClusterClientOptions() != null) { + ClusterTopologyRefreshOptions topologyRefreshOptions = getClusterClientOptions().getTopologyRefreshOptions(); + + return topologyRefreshOptions.useDynamicRefreshSources(); + } + return true; + } + + /** + * Returns a {@link String} {@link RedisCodec codec}. + * + * @return a {@link String} {@link RedisCodec codec}. + * @see StringCodec#UTF8 + */ + protected RedisCodec newStringStringCodec() { + return StringCodec.UTF8; } ClusterClientOptions getClusterClientOptions() { @@ -915,33 +990,6 @@ private static void assertNotNull(ClientResources clientResources) { LettuceAssert.notNull(clientResources, "ClientResources must not be null"); } - protected Iterable getTopologyRefreshSource() { - - boolean initialSeedNodes = !useDynamicRefreshSources(); - - Iterable seed; - if (initialSeedNodes || partitions == null || partitions.isEmpty()) { - seed = RedisClusterClient.this.initialUris; - } else { - List uris = new ArrayList<>(); - for (RedisClusterNode partition : TopologyComparators.sortByUri(partitions)) { - uris.add(partition.getUri()); - } - seed = uris; - } - return seed; - } - - protected boolean useDynamicRefreshSources() { - - if (getClusterClientOptions() != null) { - ClusterTopologyRefreshOptions topologyRefreshOptions = getClusterClientOptions().getTopologyRefreshOptions(); - - return topologyRefreshOptions.useDynamicRefreshSources(); - } - return true; - } - private class NodeConnectionFactoryImpl implements NodeConnectionFactory { @Override public StatefulRedisConnection connectToNode(RedisCodec codec, SocketAddress socketAddress) { From fadc8ecef56ce5c9fa90cc7110801dc26fb952b9 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Tue, 6 Dec 2016 17:34:23 +0100 Subject: [PATCH 084/808] Disable WAIT as Read-Only command #418 --- .../java/com/lambdaworks/redis/cluster/ReadOnlyCommands.java | 2 +- .../com/lambdaworks/redis/masterslave/ReadOnlyCommands.java | 2 +- .../com/lambdaworks/redis/cluster/ReadOnlyCommandsTest.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/lambdaworks/redis/cluster/ReadOnlyCommands.java b/src/main/java/com/lambdaworks/redis/cluster/ReadOnlyCommands.java index 8f708e2a6a..22972885da 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/ReadOnlyCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/ReadOnlyCommands.java @@ -48,7 +48,7 @@ enum CommandName { HVALS, INFO, KEYS, LINDEX, LLEN, LRANGE, MGET, MULTI, PFCOUNT, PTTL, // RANDOMKEY, READWRITE, SCAN, SCARD, SCRIPT, // SDIFF, SINTER, SISMEMBER, SMEMBERS, SRANDMEMBER, SSCAN, STRLEN, // - SUNION, TIME, TTL, TYPE, WAIT, ZCARD, ZCOUNT, ZLEXCOUNT, ZRANGE, // + SUNION, TIME, TTL, TYPE, ZCARD, ZCOUNT, ZLEXCOUNT, ZRANGE, // ZRANGEBYLEX, ZRANGEBYSCORE, ZRANK, ZREVRANGE, ZREVRANGEBYLEX, ZREVRANGEBYSCORE, ZREVRANK, ZSCAN, ZSCORE, // // Pub/Sub commands are no key-space commands so they are safe to execute on slave nodes diff --git a/src/main/java/com/lambdaworks/redis/masterslave/ReadOnlyCommands.java b/src/main/java/com/lambdaworks/redis/masterslave/ReadOnlyCommands.java index 6df5ed08bf..f5952854db 100644 --- a/src/main/java/com/lambdaworks/redis/masterslave/ReadOnlyCommands.java +++ b/src/main/java/com/lambdaworks/redis/masterslave/ReadOnlyCommands.java @@ -48,7 +48,7 @@ enum CommandName { HVALS, INFO, KEYS, LINDEX, LLEN, LRANGE, MGET, MULTI, PFCOUNT, PTTL, // RANDOMKEY, READWRITE, SCAN, SCARD, SCRIPT, // SDIFF, SINTER, SISMEMBER, SMEMBERS, SRANDMEMBER, SSCAN, STRLEN, // - SUNION, TIME, TTL, TYPE, WAIT, ZCARD, ZCOUNT, ZLEXCOUNT, ZRANGE, // + SUNION, TIME, TTL, TYPE, ZCARD, ZCOUNT, ZLEXCOUNT, ZRANGE, // ZRANGEBYLEX, ZRANGEBYSCORE, ZRANK, ZREVRANGE, ZREVRANGEBYLEX, ZREVRANGEBYSCORE, ZREVRANK, ZSCAN, ZSCORE, } } diff --git a/src/test/java/com/lambdaworks/redis/cluster/ReadOnlyCommandsTest.java b/src/test/java/com/lambdaworks/redis/cluster/ReadOnlyCommandsTest.java index 528efd5564..d8c346c563 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/ReadOnlyCommandsTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/ReadOnlyCommandsTest.java @@ -28,7 +28,7 @@ public class ReadOnlyCommandsTest { @Test public void testCount() throws Exception { - assertThat(ReadOnlyCommands.READ_ONLY_COMMANDS).hasSize(72); + assertThat(ReadOnlyCommands.READ_ONLY_COMMANDS).hasSize(71); } @Test From fcf1320e292fce34dfbdc8c2c4ccb35df3dd4832 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Wed, 7 Dec 2016 08:35:26 +0100 Subject: [PATCH 085/808] Allow databases greater than 15 in RedisURI #420 --- src/main/java/com/lambdaworks/redis/RedisURI.java | 5 ++++- .../java/com/lambdaworks/redis/RedisURIBuilderTest.java | 3 ++- src/test/java/com/lambdaworks/redis/RedisURITest.java | 6 +++--- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/lambdaworks/redis/RedisURI.java b/src/main/java/com/lambdaworks/redis/RedisURI.java index fa74b34184..9e14520874 100644 --- a/src/main/java/com/lambdaworks/redis/RedisURI.java +++ b/src/main/java/com/lambdaworks/redis/RedisURI.java @@ -386,6 +386,9 @@ public int getDatabase() { * @param database the Redis database number. */ public void setDatabase(int database) { + + LettuceAssert.isTrue(database >= 0, "Invalid database number: " + database); + this.database = database; } @@ -1137,7 +1140,7 @@ public Builder withVerifyPeer(boolean verifyPeer) { */ public Builder withDatabase(int database) { - LettuceAssert.isTrue(database >= 0 && database <= 15, "Invalid database number: " + database); + LettuceAssert.isTrue(database >= 0, "Invalid database number: " + database); this.database = database; return this; diff --git a/src/test/java/com/lambdaworks/redis/RedisURIBuilderTest.java b/src/test/java/com/lambdaworks/redis/RedisURIBuilderTest.java index b4a244f22d..8737991561 100644 --- a/src/test/java/com/lambdaworks/redis/RedisURIBuilderTest.java +++ b/src/test/java/com/lambdaworks/redis/RedisURIBuilderTest.java @@ -91,12 +91,13 @@ public void redisWithInvalidPort() throws Exception { @Test public void redisFromUrl() throws Exception { - RedisURI result = RedisURI.create(RedisURI.URI_SCHEME_REDIS + "://password@localhost/1"); + RedisURI result = RedisURI.create(RedisURI.URI_SCHEME_REDIS + "://password@localhost/21"); assertThat(result.getSentinels()).isEmpty(); assertThat(result.getHost()).isEqualTo("localhost"); assertThat(result.getPort()).isEqualTo(RedisURI.DEFAULT_REDIS_PORT); assertThat(result.getPassword()).isEqualTo("password".toCharArray()); + assertThat(result.getDatabase()).isEqualTo(21); assertThat(result.isSsl()).isFalse(); } diff --git a/src/test/java/com/lambdaworks/redis/RedisURITest.java b/src/test/java/com/lambdaworks/redis/RedisURITest.java index 84938194b1..f0898ea236 100644 --- a/src/test/java/com/lambdaworks/redis/RedisURITest.java +++ b/src/test/java/com/lambdaworks/redis/RedisURITest.java @@ -202,10 +202,10 @@ private RedisURI checkUriTimeout(String uri, long expectedTimeout, TimeUnit expe @Test public void databaseParsingTest() { - RedisURI redisURI = RedisURI.create("redis://auth@localhost:1234/?database=5"); - assertThat(redisURI.getDatabase()).isEqualTo(5); + RedisURI redisURI = RedisURI.create("redis://auth@localhost:1234/?database=21"); + assertThat(redisURI.getDatabase()).isEqualTo(21); - assertThat(redisURI.toURI().toString()).isEqualTo("redis://auth@localhost:1234?database=5"); + assertThat(redisURI.toURI().toString()).isEqualTo("redis://auth@localhost:1234?database=21"); } @Test From 95a4a41fc0ec67a2a95fc74a13827d8c81203a7d Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Sat, 10 Dec 2016 15:18:36 +0100 Subject: [PATCH 086/808] Polishing #414 Optimize Imports in API package. Add missing @Deprecated annotations. Copy file header comment in interface generator. --- .../api/async/BaseRedisAsyncCommands.java | 5 +- .../api/async/RedisGeoAsyncCommands.java | 4 +- .../api/async/RedisHashAsyncCommands.java | 9 +- .../api/async/RedisKeyAsyncCommands.java | 10 +- .../api/async/RedisListAsyncCommands.java | 3 +- .../async/RedisScriptingAsyncCommands.java | 3 +- .../api/async/RedisServerAsyncCommands.java | 7 +- .../api/async/RedisSetAsyncCommands.java | 7 +- .../async/RedisSortedSetAsyncCommands.java | 13 +-- .../api/async/RedisStringAsyncCommands.java | 101 +++++++++--------- .../RedisTransactionalAsyncCommands.java | 3 +- .../reactive/BaseRedisReactiveCommands.java | 5 +- .../reactive/RedisGeoReactiveCommands.java | 2 - .../reactive/RedisHLLReactiveCommands.java | 1 - .../reactive/RedisHashReactiveCommands.java | 10 +- .../reactive/RedisKeyReactiveCommands.java | 11 +- .../reactive/RedisListReactiveCommands.java | 2 +- .../RedisScriptingReactiveCommands.java | 2 +- .../reactive/RedisServerReactiveCommands.java | 4 +- .../reactive/RedisSetReactiveCommands.java | 2 +- .../RedisSortedSetReactiveCommands.java | 13 +-- .../reactive/RedisStringReactiveCommands.java | 99 ++++++++--------- .../RedisTransactionalReactiveCommands.java | 3 +- .../redis/api/sync/BaseRedisCommands.java | 3 +- .../redis/api/sync/RedisGeoCommands.java | 4 +- .../redis/api/sync/RedisHashCommands.java | 8 +- .../redis/api/sync/RedisKeyCommands.java | 9 +- .../redis/api/sync/RedisListCommands.java | 1 + .../api/sync/RedisScriptingCommands.java | 1 + .../redis/api/sync/RedisServerCommands.java | 5 + .../redis/api/sync/RedisSetCommands.java | 1 + .../api/sync/RedisSortedSetCommands.java | 12 +-- .../redis/api/sync/RedisStringCommands.java | 99 +++++++++-------- .../api/sync/RedisTransactionalCommands.java | 1 - .../async/BaseNodeSelectionAsyncCommands.java | 19 +--- .../async/NodeSelectionGeoAsyncCommands.java | 4 +- .../async/NodeSelectionHLLAsyncCommands.java | 2 - .../async/NodeSelectionHashAsyncCommands.java | 9 +- .../async/NodeSelectionKeyAsyncCommands.java | 10 +- .../async/NodeSelectionListAsyncCommands.java | 2 +- .../NodeSelectionScriptingAsyncCommands.java | 2 +- .../NodeSelectionServerAsyncCommands.java | 2 +- .../async/NodeSelectionSetAsyncCommands.java | 1 + .../NodeSelectionSortedSetAsyncCommands.java | 13 +-- .../NodeSelectionStringAsyncCommands.java | 100 +++++++++-------- .../api/sync/BaseNodeSelectionCommands.java | 19 ---- .../redis/cluster/api/sync/Executions.java | 1 - .../api/sync/NodeSelectionGeoCommands.java | 4 +- .../api/sync/NodeSelectionHashCommands.java | 8 +- .../api/sync/NodeSelectionKeyCommands.java | 9 +- .../api/sync/NodeSelectionListCommands.java | 1 + .../sync/NodeSelectionScriptingCommands.java | 1 + .../api/sync/NodeSelectionServerCommands.java | 1 + .../api/sync/NodeSelectionSetCommands.java | 1 + .../sync/NodeSelectionSortedSetCommands.java | 12 +-- .../api/sync/NodeSelectionStringCommands.java | 99 +++++++++-------- .../redis/api/RedisGeoCommands.java | 6 +- .../redis/api/RedisHashCommands.java | 7 +- .../redis/api/RedisKeyCommands.java | 8 +- .../redis/api/RedisSortedSetCommands.java | 11 +- .../redis/api/RedisStringCommands.java | 96 ++++++++--------- .../apigenerator/CompilationUnitFactory.java | 1 + .../apigenerator/CreateAsyncApi.java | 15 ++- .../CreateAsyncNodeSelectionClusterApi.java | 11 +- .../CreateSyncNodeSelectionClusterApi.java | 2 +- 65 files changed, 407 insertions(+), 533 deletions(-) diff --git a/src/main/java/com/lambdaworks/redis/api/async/BaseRedisAsyncCommands.java b/src/main/java/com/lambdaworks/redis/api/async/BaseRedisAsyncCommands.java index 6386425395..aea62fdae5 100644 --- a/src/main/java/com/lambdaworks/redis/api/async/BaseRedisAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/async/BaseRedisAsyncCommands.java @@ -17,10 +17,11 @@ import java.util.List; import java.util.Map; + +import com.lambdaworks.redis.RedisFuture; +import com.lambdaworks.redis.output.CommandOutput; import com.lambdaworks.redis.protocol.CommandArgs; import com.lambdaworks.redis.protocol.ProtocolKeyword; -import com.lambdaworks.redis.output.CommandOutput; -import com.lambdaworks.redis.RedisFuture; /** * diff --git a/src/main/java/com/lambdaworks/redis/api/async/RedisGeoAsyncCommands.java b/src/main/java/com/lambdaworks/redis/api/async/RedisGeoAsyncCommands.java index b2a04755de..962e8c4742 100644 --- a/src/main/java/com/lambdaworks/redis/api/async/RedisGeoAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/async/RedisGeoAsyncCommands.java @@ -15,11 +15,11 @@ */ package com.lambdaworks.redis.api.async; -import com.lambdaworks.redis.*; - import java.util.List; import java.util.Set; +import com.lambdaworks.redis.*; + /** * Asynchronous executed commands for the Geo-API. * diff --git a/src/main/java/com/lambdaworks/redis/api/async/RedisHashAsyncCommands.java b/src/main/java/com/lambdaworks/redis/api/async/RedisHashAsyncCommands.java index a06772c2a7..90806cc534 100644 --- a/src/main/java/com/lambdaworks/redis/api/async/RedisHashAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/async/RedisHashAsyncCommands.java @@ -17,16 +17,11 @@ import java.util.List; import java.util.Map; -import com.lambdaworks.redis.KeyValue; -import com.lambdaworks.redis.Value; -import com.lambdaworks.redis.MapScanCursor; -import com.lambdaworks.redis.ScanArgs; -import com.lambdaworks.redis.ScanCursor; -import com.lambdaworks.redis.StreamScanCursor; + +import com.lambdaworks.redis.*; import com.lambdaworks.redis.output.KeyStreamingChannel; import com.lambdaworks.redis.output.KeyValueStreamingChannel; import com.lambdaworks.redis.output.ValueStreamingChannel; -import com.lambdaworks.redis.RedisFuture; /** * Asynchronous executed commands for Hashes (Key-Value pairs). diff --git a/src/main/java/com/lambdaworks/redis/api/async/RedisKeyAsyncCommands.java b/src/main/java/com/lambdaworks/redis/api/async/RedisKeyAsyncCommands.java index ed80797eed..2d3ca33f3f 100644 --- a/src/main/java/com/lambdaworks/redis/api/async/RedisKeyAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/async/RedisKeyAsyncCommands.java @@ -17,16 +17,10 @@ import java.util.Date; import java.util.List; -import com.lambdaworks.redis.Value; -import com.lambdaworks.redis.KeyScanCursor; -import com.lambdaworks.redis.MigrateArgs; -import com.lambdaworks.redis.ScanArgs; -import com.lambdaworks.redis.ScanCursor; -import com.lambdaworks.redis.SortArgs; -import com.lambdaworks.redis.StreamScanCursor; + +import com.lambdaworks.redis.*; import com.lambdaworks.redis.output.KeyStreamingChannel; import com.lambdaworks.redis.output.ValueStreamingChannel; -import com.lambdaworks.redis.RedisFuture; /** * Asynchronous executed commands for Keys (Key manipulation/querying). diff --git a/src/main/java/com/lambdaworks/redis/api/async/RedisListAsyncCommands.java b/src/main/java/com/lambdaworks/redis/api/async/RedisListAsyncCommands.java index 944dcd69b7..071461cf84 100644 --- a/src/main/java/com/lambdaworks/redis/api/async/RedisListAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/async/RedisListAsyncCommands.java @@ -16,9 +16,10 @@ package com.lambdaworks.redis.api.async; import java.util.List; + import com.lambdaworks.redis.KeyValue; -import com.lambdaworks.redis.output.ValueStreamingChannel; import com.lambdaworks.redis.RedisFuture; +import com.lambdaworks.redis.output.ValueStreamingChannel; /** * Asynchronous executed commands for Lists. diff --git a/src/main/java/com/lambdaworks/redis/api/async/RedisScriptingAsyncCommands.java b/src/main/java/com/lambdaworks/redis/api/async/RedisScriptingAsyncCommands.java index b890923184..f6038c852b 100644 --- a/src/main/java/com/lambdaworks/redis/api/async/RedisScriptingAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/async/RedisScriptingAsyncCommands.java @@ -16,8 +16,9 @@ package com.lambdaworks.redis.api.async; import java.util.List; -import com.lambdaworks.redis.ScriptOutputType; + import com.lambdaworks.redis.RedisFuture; +import com.lambdaworks.redis.ScriptOutputType; /** * Asynchronous executed commands for Scripting. diff --git a/src/main/java/com/lambdaworks/redis/api/async/RedisServerAsyncCommands.java b/src/main/java/com/lambdaworks/redis/api/async/RedisServerAsyncCommands.java index dfd6d79389..17da5436bd 100644 --- a/src/main/java/com/lambdaworks/redis/api/async/RedisServerAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/async/RedisServerAsyncCommands.java @@ -17,9 +17,10 @@ import java.util.Date; import java.util.List; + import com.lambdaworks.redis.KillArgs; -import com.lambdaworks.redis.protocol.CommandType; import com.lambdaworks.redis.RedisFuture; +import com.lambdaworks.redis.protocol.CommandType; /** * Asynchronous executed commands for Server Control. @@ -187,11 +188,15 @@ public interface RedisServerAsyncCommands { /** * Make the server crash: Out of memory. + * + * @return nothing, because the server crashes before returning. */ void debugOom(); /** * Make the server crash: Invalid pointer access. + * + * @return nothing, because the server crashes before returning. */ void debugSegfault(); diff --git a/src/main/java/com/lambdaworks/redis/api/async/RedisSetAsyncCommands.java b/src/main/java/com/lambdaworks/redis/api/async/RedisSetAsyncCommands.java index 54c2be87b2..6177ae50f6 100644 --- a/src/main/java/com/lambdaworks/redis/api/async/RedisSetAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/async/RedisSetAsyncCommands.java @@ -17,12 +17,9 @@ import java.util.List; import java.util.Set; -import com.lambdaworks.redis.ScanArgs; -import com.lambdaworks.redis.ScanCursor; -import com.lambdaworks.redis.StreamScanCursor; -import com.lambdaworks.redis.ValueScanCursor; + +import com.lambdaworks.redis.*; import com.lambdaworks.redis.output.ValueStreamingChannel; -import com.lambdaworks.redis.RedisFuture; /** * Asynchronous executed commands for Sets. diff --git a/src/main/java/com/lambdaworks/redis/api/async/RedisSortedSetAsyncCommands.java b/src/main/java/com/lambdaworks/redis/api/async/RedisSortedSetAsyncCommands.java index babe589e87..a76354f598 100644 --- a/src/main/java/com/lambdaworks/redis/api/async/RedisSortedSetAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/async/RedisSortedSetAsyncCommands.java @@ -16,18 +16,10 @@ package com.lambdaworks.redis.api.async; import java.util.List; -import com.lambdaworks.redis.Limit; -import com.lambdaworks.redis.Range; -import com.lambdaworks.redis.ScanArgs; -import com.lambdaworks.redis.ScanCursor; -import com.lambdaworks.redis.ScoredValue; -import com.lambdaworks.redis.ScoredValueScanCursor; -import com.lambdaworks.redis.StreamScanCursor; -import com.lambdaworks.redis.ZAddArgs; -import com.lambdaworks.redis.ZStoreArgs; + +import com.lambdaworks.redis.*; import com.lambdaworks.redis.output.ScoredValueStreamingChannel; import com.lambdaworks.redis.output.ValueStreamingChannel; -import com.lambdaworks.redis.RedisFuture; /** * Asynchronous executed commands for Sorted Sets. @@ -524,6 +516,7 @@ public interface RedisSortedSetAsyncCommands { * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range, Limit limit)} */ + @Deprecated RedisFuture>> zrangebyscoreWithScores(K key, double min, double max, long offset, long count); /** diff --git a/src/main/java/com/lambdaworks/redis/api/async/RedisStringAsyncCommands.java b/src/main/java/com/lambdaworks/redis/api/async/RedisStringAsyncCommands.java index 90ac8f8c6e..e58204512b 100644 --- a/src/main/java/com/lambdaworks/redis/api/async/RedisStringAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/async/RedisStringAsyncCommands.java @@ -17,17 +17,16 @@ import java.util.List; import java.util.Map; -import com.lambdaworks.redis.output.KeyValueStreamingChannel; -import com.lambdaworks.redis.output.ValueStreamingChannel; + import com.lambdaworks.redis.BitFieldArgs; import com.lambdaworks.redis.KeyValue; -import com.lambdaworks.redis.SetArgs; -import com.lambdaworks.redis.Value; import com.lambdaworks.redis.RedisFuture; +import com.lambdaworks.redis.SetArgs; +import com.lambdaworks.redis.output.KeyValueStreamingChannel; /** * Asynchronous executed commands for Strings. - * + * * @param Key type. * @param Value type. * @author Mark Paluch @@ -38,7 +37,7 @@ public interface RedisStringAsyncCommands { /** * Append a value to a key. - * + * * @param key the key * @param value the value * @return Long integer-reply the length of the string after the append operation. @@ -47,52 +46,52 @@ public interface RedisStringAsyncCommands { /** * Count set bits in a string. - * + * * @param key the key - * + * * @return Long integer-reply The number of bits set to 1. */ RedisFuture bitcount(K key); /** * Count set bits in a string. - * + * * @param key the key * @param start the start * @param end the end - * + * * @return Long integer-reply The number of bits set to 1. */ RedisFuture bitcount(K key, long start, long end); /** * Execute {@code BITFIELD} with its subcommands. - * + * * @param key the key * @param bitFieldArgs the args containing subcommands, must not be {@literal null}. - * + * * @return Long bulk-reply the results from the bitfield commands. */ RedisFuture> bitfield(K key, BitFieldArgs bitFieldArgs); /** * Find first bit set or clear in a string. - * + * * @param key the key * @param state the state - * + * * @return Long integer-reply The command returns the position of the first bit set to 1 or 0 according to the request. - * + * * If we look for set bits (the bit argument is 1) and the string is empty or composed of just zero bytes, -1 is * returned. - * + * * If we look for clear bits (the bit argument is 0) and the string only contains bit set to 1, the function returns * the first bit not part of the string on the right. So if the string is tree bytes set to the value 0xff the * command {@code BITPOS key 0} will return 24, since up to bit 23 all the bits are 1. - * + * * Basically the function consider the right of the string as padded with zeros if you look for clear bits and * specify no range or the start argument only. - * + * * However this behavior changes if you are looking for clear bits and specify a range with both * start and end. If no clear bit is found in the specified range, the function * returns -1 as the user specified a clear range and there are no 0 bits in that range. @@ -101,23 +100,23 @@ public interface RedisStringAsyncCommands { /** * Find first bit set or clear in a string. - * + * * @param key the key * @param state the bit type: long * @param start the start type: long * @param end the end type: long * @return Long integer-reply The command returns the position of the first bit set to 1 or 0 according to the request. - * + * * If we look for set bits (the bit argument is 1) and the string is empty or composed of just zero bytes, -1 is * returned. - * + * * If we look for clear bits (the bit argument is 0) and the string only contains bit set to 1, the function returns * the first bit not part of the string on the right. So if the string is tree bytes set to the value 0xff the * command {@code BITPOS key 0} will return 24, since up to bit 23 all the bits are 1. - * + * * Basically the function consider the right of the string as padded with zeros if you look for clear bits and * specify no range or the start argument only. - * + * * However this behavior changes if you are looking for clear bits and specify a range with both * start and end. If no clear bit is found in the specified range, the function * returns -1 as the user specified a clear range and there are no 0 bits in that range. @@ -126,7 +125,7 @@ public interface RedisStringAsyncCommands { /** * Perform bitwise AND between strings. - * + * * @param destination result key of the operation * @param keys operation input key names * @return Long integer-reply The size of the string stored in the destination key, that is equal to the size of the longest @@ -136,7 +135,7 @@ public interface RedisStringAsyncCommands { /** * Perform bitwise NOT between strings. - * + * * @param destination result key of the operation * @param source operation input key names * @return Long integer-reply The size of the string stored in the destination key, that is equal to the size of the longest @@ -146,7 +145,7 @@ public interface RedisStringAsyncCommands { /** * Perform bitwise OR between strings. - * + * * @param destination result key of the operation * @param keys operation input key names * @return Long integer-reply The size of the string stored in the destination key, that is equal to the size of the longest @@ -156,7 +155,7 @@ public interface RedisStringAsyncCommands { /** * Perform bitwise XOR between strings. - * + * * @param destination result key of the operation * @param keys operation input key names * @return Long integer-reply The size of the string stored in the destination key, that is equal to the size of the longest @@ -166,7 +165,7 @@ public interface RedisStringAsyncCommands { /** * Decrement the integer value of a key by one. - * + * * @param key the key * @return Long integer-reply the value of {@code key} after the decrement */ @@ -174,7 +173,7 @@ public interface RedisStringAsyncCommands { /** * Decrement the integer value of a key by the given number. - * + * * @param key the key * @param amount the decrement type: long * @return Long integer-reply the value of {@code key} after the decrement @@ -183,7 +182,7 @@ public interface RedisStringAsyncCommands { /** * Get the value of a key. - * + * * @param key the key * @return V bulk-string-reply the value of {@code key}, or {@literal null} when {@code key} does not exist. */ @@ -191,7 +190,7 @@ public interface RedisStringAsyncCommands { /** * Returns the bit value at offset in the string value stored at key. - * + * * @param key the key * @param offset the offset type: long * @return Long integer-reply the bit value stored at offset. @@ -200,7 +199,7 @@ public interface RedisStringAsyncCommands { /** * Get a substring of the string stored at a key. - * + * * @param key the key * @param start the start type: long * @param end the end type: long @@ -210,7 +209,7 @@ public interface RedisStringAsyncCommands { /** * Set the string value of a key and return its old value. - * + * * @param key the key * @param value the value * @return V bulk-string-reply the old value stored at {@code key}, or {@literal null} when {@code key} did not exist. @@ -219,7 +218,7 @@ public interface RedisStringAsyncCommands { /** * Increment the integer value of a key by one. - * + * * @param key the key * @return Long integer-reply the value of {@code key} after the increment */ @@ -227,7 +226,7 @@ public interface RedisStringAsyncCommands { /** * Increment the integer value of a key by the given amount. - * + * * @param key the key * @param amount the increment type: long * @return Long integer-reply the value of {@code key} after the increment @@ -236,7 +235,7 @@ public interface RedisStringAsyncCommands { /** * Increment the float value of a key by the given amount. - * + * * @param key the key * @param amount the increment type: double * @return Double bulk-string-reply the value of {@code key} after the increment. @@ -245,7 +244,7 @@ public interface RedisStringAsyncCommands { /** * Get the values of all the given keys. - * + * * @param keys the key * @return List<V> array-reply list of values at the specified keys. */ @@ -263,7 +262,7 @@ public interface RedisStringAsyncCommands { /** * Set multiple keys to multiple values. - * + * * @param map the null * @return String simple-string-reply always {@code OK} since {@code MSET} can't fail. */ @@ -271,38 +270,38 @@ public interface RedisStringAsyncCommands { /** * Set multiple keys to multiple values, only if none of the keys exist. - * + * * @param map the null * @return Boolean integer-reply specifically: - * + * * {@code 1} if the all the keys were set. {@code 0} if no key was set (at least one key already existed). */ RedisFuture msetnx(Map map); /** * Set the string value of a key. - * + * * @param key the key * @param value the value - * + * * @return String simple-string-reply {@code OK} if {@code SET} was executed correctly. */ RedisFuture set(K key, V value); /** * Set the string value of a key. - * + * * @param key the key * @param value the value * @param setArgs the setArgs - * + * * @return String simple-string-reply {@code OK} if {@code SET} was executed correctly. */ RedisFuture set(K key, V value, SetArgs setArgs); /** * Sets or clears the bit at offset in the string value stored at key. - * + * * @param key the key * @param offset the offset type: long * @param value the value type: string @@ -312,7 +311,7 @@ public interface RedisStringAsyncCommands { /** * Set the value and expiration of a key. - * + * * @param key the key * @param seconds the seconds type: long * @param value the value @@ -322,7 +321,7 @@ public interface RedisStringAsyncCommands { /** * Set the value and expiration in milliseconds of a key. - * + * * @param key the key * @param milliseconds the milliseconds type: long * @param value the value @@ -332,18 +331,18 @@ public interface RedisStringAsyncCommands { /** * Set the value of a key, only if the key does not exist. - * + * * @param key the key * @param value the value * @return Boolean integer-reply specifically: - * + * * {@code 1} if the key was set {@code 0} if the key was not set */ RedisFuture setnx(K key, V value); /** * Overwrite part of a string at key starting at the specified offset. - * + * * @param key the key * @param offset the offset type: long * @param value the value @@ -353,7 +352,7 @@ public interface RedisStringAsyncCommands { /** * Get the length of the value stored in a key. - * + * * @param key the key * @return Long integer-reply the length of the string at {@code key}, or {@code 0} when {@code key} does not exist. */ diff --git a/src/main/java/com/lambdaworks/redis/api/async/RedisTransactionalAsyncCommands.java b/src/main/java/com/lambdaworks/redis/api/async/RedisTransactionalAsyncCommands.java index 71076f08d0..e7f55f29c5 100644 --- a/src/main/java/com/lambdaworks/redis/api/async/RedisTransactionalAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/async/RedisTransactionalAsyncCommands.java @@ -15,9 +15,8 @@ */ package com.lambdaworks.redis.api.async; -import java.util.List; -import com.lambdaworks.redis.TransactionResult; import com.lambdaworks.redis.RedisFuture; +import com.lambdaworks.redis.TransactionResult; /** * Asynchronous executed commands for Transactions. diff --git a/src/main/java/com/lambdaworks/redis/api/reactive/BaseRedisReactiveCommands.java b/src/main/java/com/lambdaworks/redis/api/reactive/BaseRedisReactiveCommands.java index 76d0fe8161..735e33aa7c 100644 --- a/src/main/java/com/lambdaworks/redis/api/reactive/BaseRedisReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/reactive/BaseRedisReactiveCommands.java @@ -15,11 +15,12 @@ */ package com.lambdaworks.redis.api.reactive; -import java.util.List; import java.util.Map; + +import com.lambdaworks.redis.output.CommandOutput; import com.lambdaworks.redis.protocol.CommandArgs; import com.lambdaworks.redis.protocol.ProtocolKeyword; -import com.lambdaworks.redis.output.CommandOutput; + import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; diff --git a/src/main/java/com/lambdaworks/redis/api/reactive/RedisGeoReactiveCommands.java b/src/main/java/com/lambdaworks/redis/api/reactive/RedisGeoReactiveCommands.java index 5eccc74ac6..5de0c6ba20 100644 --- a/src/main/java/com/lambdaworks/redis/api/reactive/RedisGeoReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/reactive/RedisGeoReactiveCommands.java @@ -17,8 +17,6 @@ import com.lambdaworks.redis.*; -import java.util.List; -import java.util.Set; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; diff --git a/src/main/java/com/lambdaworks/redis/api/reactive/RedisHLLReactiveCommands.java b/src/main/java/com/lambdaworks/redis/api/reactive/RedisHLLReactiveCommands.java index 953c1080b1..0eddbd8a14 100644 --- a/src/main/java/com/lambdaworks/redis/api/reactive/RedisHLLReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/reactive/RedisHLLReactiveCommands.java @@ -15,7 +15,6 @@ */ package com.lambdaworks.redis.api.reactive; -import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; /** diff --git a/src/main/java/com/lambdaworks/redis/api/reactive/RedisHashReactiveCommands.java b/src/main/java/com/lambdaworks/redis/api/reactive/RedisHashReactiveCommands.java index 2804603b6e..dd48f79069 100644 --- a/src/main/java/com/lambdaworks/redis/api/reactive/RedisHashReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/reactive/RedisHashReactiveCommands.java @@ -15,17 +15,13 @@ */ package com.lambdaworks.redis.api.reactive; -import java.util.List; import java.util.Map; -import com.lambdaworks.redis.KeyValue; -import com.lambdaworks.redis.Value; -import com.lambdaworks.redis.MapScanCursor; -import com.lambdaworks.redis.ScanArgs; -import com.lambdaworks.redis.ScanCursor; -import com.lambdaworks.redis.StreamScanCursor; + +import com.lambdaworks.redis.*; import com.lambdaworks.redis.output.KeyStreamingChannel; import com.lambdaworks.redis.output.KeyValueStreamingChannel; import com.lambdaworks.redis.output.ValueStreamingChannel; + import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; diff --git a/src/main/java/com/lambdaworks/redis/api/reactive/RedisKeyReactiveCommands.java b/src/main/java/com/lambdaworks/redis/api/reactive/RedisKeyReactiveCommands.java index d5c232a2da..882bc699d7 100644 --- a/src/main/java/com/lambdaworks/redis/api/reactive/RedisKeyReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/reactive/RedisKeyReactiveCommands.java @@ -16,16 +16,11 @@ package com.lambdaworks.redis.api.reactive; import java.util.Date; -import java.util.List; -import com.lambdaworks.redis.Value; -import com.lambdaworks.redis.KeyScanCursor; -import com.lambdaworks.redis.MigrateArgs; -import com.lambdaworks.redis.ScanArgs; -import com.lambdaworks.redis.ScanCursor; -import com.lambdaworks.redis.SortArgs; -import com.lambdaworks.redis.StreamScanCursor; + +import com.lambdaworks.redis.*; import com.lambdaworks.redis.output.KeyStreamingChannel; import com.lambdaworks.redis.output.ValueStreamingChannel; + import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; diff --git a/src/main/java/com/lambdaworks/redis/api/reactive/RedisListReactiveCommands.java b/src/main/java/com/lambdaworks/redis/api/reactive/RedisListReactiveCommands.java index 704999d4c3..7fb36bc541 100644 --- a/src/main/java/com/lambdaworks/redis/api/reactive/RedisListReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/reactive/RedisListReactiveCommands.java @@ -15,9 +15,9 @@ */ package com.lambdaworks.redis.api.reactive; -import java.util.List; import com.lambdaworks.redis.KeyValue; import com.lambdaworks.redis.output.ValueStreamingChannel; + import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; diff --git a/src/main/java/com/lambdaworks/redis/api/reactive/RedisScriptingReactiveCommands.java b/src/main/java/com/lambdaworks/redis/api/reactive/RedisScriptingReactiveCommands.java index d8ee26f1a9..c8fe5da3c1 100644 --- a/src/main/java/com/lambdaworks/redis/api/reactive/RedisScriptingReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/reactive/RedisScriptingReactiveCommands.java @@ -15,8 +15,8 @@ */ package com.lambdaworks.redis.api.reactive; -import java.util.List; import com.lambdaworks.redis.ScriptOutputType; + import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; diff --git a/src/main/java/com/lambdaworks/redis/api/reactive/RedisServerReactiveCommands.java b/src/main/java/com/lambdaworks/redis/api/reactive/RedisServerReactiveCommands.java index 896c8173d4..6169fac93e 100644 --- a/src/main/java/com/lambdaworks/redis/api/reactive/RedisServerReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/reactive/RedisServerReactiveCommands.java @@ -16,9 +16,10 @@ package com.lambdaworks.redis.api.reactive; import java.util.Date; -import java.util.List; + import com.lambdaworks.redis.KillArgs; import com.lambdaworks.redis.protocol.CommandType; + import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -283,7 +284,6 @@ public interface RedisServerReactiveCommands { * Synchronously save the dataset to disk and then shut down the server. * * @param save {@literal true} force save operation - * @return nothing */ Mono shutdown(boolean save); diff --git a/src/main/java/com/lambdaworks/redis/api/reactive/RedisSetReactiveCommands.java b/src/main/java/com/lambdaworks/redis/api/reactive/RedisSetReactiveCommands.java index c6bac5e5ef..80e9a1f44a 100644 --- a/src/main/java/com/lambdaworks/redis/api/reactive/RedisSetReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/reactive/RedisSetReactiveCommands.java @@ -15,12 +15,12 @@ */ package com.lambdaworks.redis.api.reactive; -import java.util.Set; import com.lambdaworks.redis.ScanArgs; import com.lambdaworks.redis.ScanCursor; import com.lambdaworks.redis.StreamScanCursor; import com.lambdaworks.redis.ValueScanCursor; import com.lambdaworks.redis.output.ValueStreamingChannel; + import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; diff --git a/src/main/java/com/lambdaworks/redis/api/reactive/RedisSortedSetReactiveCommands.java b/src/main/java/com/lambdaworks/redis/api/reactive/RedisSortedSetReactiveCommands.java index 4924a4758e..b1b4cd7a3f 100644 --- a/src/main/java/com/lambdaworks/redis/api/reactive/RedisSortedSetReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/reactive/RedisSortedSetReactiveCommands.java @@ -15,18 +15,10 @@ */ package com.lambdaworks.redis.api.reactive; -import java.util.List; -import com.lambdaworks.redis.Limit; -import com.lambdaworks.redis.Range; -import com.lambdaworks.redis.ScanArgs; -import com.lambdaworks.redis.ScanCursor; -import com.lambdaworks.redis.ScoredValue; -import com.lambdaworks.redis.ScoredValueScanCursor; -import com.lambdaworks.redis.StreamScanCursor; -import com.lambdaworks.redis.ZAddArgs; -import com.lambdaworks.redis.ZStoreArgs; +import com.lambdaworks.redis.*; import com.lambdaworks.redis.output.ScoredValueStreamingChannel; import com.lambdaworks.redis.output.ValueStreamingChannel; + import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -525,6 +517,7 @@ public interface RedisSortedSetReactiveCommands { * @return ScoredValue<V> array-reply list of elements in the specified score range. * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range, Limit limit)} */ + @Deprecated Flux> zrangebyscoreWithScores(K key, double min, double max, long offset, long count); /** diff --git a/src/main/java/com/lambdaworks/redis/api/reactive/RedisStringReactiveCommands.java b/src/main/java/com/lambdaworks/redis/api/reactive/RedisStringReactiveCommands.java index 09366de970..24ad9c610a 100644 --- a/src/main/java/com/lambdaworks/redis/api/reactive/RedisStringReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/reactive/RedisStringReactiveCommands.java @@ -16,17 +16,19 @@ package com.lambdaworks.redis.api.reactive; import java.util.Map; -import com.lambdaworks.redis.output.KeyValueStreamingChannel; + import com.lambdaworks.redis.BitFieldArgs; import com.lambdaworks.redis.KeyValue; import com.lambdaworks.redis.SetArgs; import com.lambdaworks.redis.Value; +import com.lambdaworks.redis.output.KeyValueStreamingChannel; + import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; /** * Reactive executed commands for Strings. - * + * * @param Key type. * @param Value type. * @author Mark Paluch @@ -37,7 +39,7 @@ public interface RedisStringReactiveCommands { /** * Append a value to a key. - * + * * @param key the key * @param value the value * @return Long integer-reply the length of the string after the append operation. @@ -46,52 +48,52 @@ public interface RedisStringReactiveCommands { /** * Count set bits in a string. - * + * * @param key the key - * + * * @return Long integer-reply The number of bits set to 1. */ Mono bitcount(K key); /** * Count set bits in a string. - * + * * @param key the key * @param start the start * @param end the end - * + * * @return Long integer-reply The number of bits set to 1. */ Mono bitcount(K key, long start, long end); /** * Execute {@code BITFIELD} with its subcommands. - * + * * @param key the key * @param bitFieldArgs the args containing subcommands, must not be {@literal null}. - * + * * @return Long bulk-reply the results from the bitfield commands. */ Flux> bitfield(K key, BitFieldArgs bitFieldArgs); /** * Find first bit set or clear in a string. - * + * * @param key the key * @param state the state - * + * * @return Long integer-reply The command returns the position of the first bit set to 1 or 0 according to the request. - * + * * If we look for set bits (the bit argument is 1) and the string is empty or composed of just zero bytes, -1 is * returned. - * + * * If we look for clear bits (the bit argument is 0) and the string only contains bit set to 1, the function returns * the first bit not part of the string on the right. So if the string is tree bytes set to the value 0xff the * command {@code BITPOS key 0} will return 24, since up to bit 23 all the bits are 1. - * + * * Basically the function consider the right of the string as padded with zeros if you look for clear bits and * specify no range or the start argument only. - * + * * However this behavior changes if you are looking for clear bits and specify a range with both * start and end. If no clear bit is found in the specified range, the function * returns -1 as the user specified a clear range and there are no 0 bits in that range. @@ -100,23 +102,23 @@ public interface RedisStringReactiveCommands { /** * Find first bit set or clear in a string. - * + * * @param key the key * @param state the bit type: long * @param start the start type: long * @param end the end type: long * @return Long integer-reply The command returns the position of the first bit set to 1 or 0 according to the request. - * + * * If we look for set bits (the bit argument is 1) and the string is empty or composed of just zero bytes, -1 is * returned. - * + * * If we look for clear bits (the bit argument is 0) and the string only contains bit set to 1, the function returns * the first bit not part of the string on the right. So if the string is tree bytes set to the value 0xff the * command {@code BITPOS key 0} will return 24, since up to bit 23 all the bits are 1. - * + * * Basically the function consider the right of the string as padded with zeros if you look for clear bits and * specify no range or the start argument only. - * + * * However this behavior changes if you are looking for clear bits and specify a range with both * start and end. If no clear bit is found in the specified range, the function * returns -1 as the user specified a clear range and there are no 0 bits in that range. @@ -124,7 +126,8 @@ public interface RedisStringReactiveCommands { Mono bitpos(K key, boolean state, long start, long end); /** - * + * Perform bitwise AND between strings. + * * @param destination result key of the operation * @param keys operation input key names * @return Long integer-reply The size of the string stored in the destination key, that is equal to the size of the longest @@ -134,7 +137,7 @@ public interface RedisStringReactiveCommands { /** * Perform bitwise NOT between strings. - * + * * @param destination result key of the operation * @param source operation input key names * @return Long integer-reply The size of the string stored in the destination key, that is equal to the size of the longest @@ -144,7 +147,7 @@ public interface RedisStringReactiveCommands { /** * Perform bitwise OR between strings. - * + * * @param destination result key of the operation * @param keys operation input key names * @return Long integer-reply The size of the string stored in the destination key, that is equal to the size of the longest @@ -154,7 +157,7 @@ public interface RedisStringReactiveCommands { /** * Perform bitwise XOR between strings. - * + * * @param destination result key of the operation * @param keys operation input key names * @return Long integer-reply The size of the string stored in the destination key, that is equal to the size of the longest @@ -164,7 +167,7 @@ public interface RedisStringReactiveCommands { /** * Decrement the integer value of a key by one. - * + * * @param key the key * @return Long integer-reply the value of {@code key} after the decrement */ @@ -172,7 +175,7 @@ public interface RedisStringReactiveCommands { /** * Decrement the integer value of a key by the given number. - * + * * @param key the key * @param amount the decrement type: long * @return Long integer-reply the value of {@code key} after the decrement @@ -181,7 +184,7 @@ public interface RedisStringReactiveCommands { /** * Get the value of a key. - * + * * @param key the key * @return V bulk-string-reply the value of {@code key}, or {@literal null} when {@code key} does not exist. */ @@ -189,7 +192,7 @@ public interface RedisStringReactiveCommands { /** * Returns the bit value at offset in the string value stored at key. - * + * * @param key the key * @param offset the offset type: long * @return Long integer-reply the bit value stored at offset. @@ -198,7 +201,7 @@ public interface RedisStringReactiveCommands { /** * Get a substring of the string stored at a key. - * + * * @param key the key * @param start the start type: long * @param end the end type: long @@ -208,7 +211,7 @@ public interface RedisStringReactiveCommands { /** * Set the string value of a key and return its old value. - * + * * @param key the key * @param value the value * @return V bulk-string-reply the old value stored at {@code key}, or {@literal null} when {@code key} did not exist. @@ -217,7 +220,7 @@ public interface RedisStringReactiveCommands { /** * Increment the integer value of a key by one. - * + * * @param key the key * @return Long integer-reply the value of {@code key} after the increment */ @@ -225,7 +228,7 @@ public interface RedisStringReactiveCommands { /** * Increment the integer value of a key by the given amount. - * + * * @param key the key * @param amount the increment type: long * @return Long integer-reply the value of {@code key} after the increment @@ -234,7 +237,7 @@ public interface RedisStringReactiveCommands { /** * Increment the float value of a key by the given amount. - * + * * @param key the key * @param amount the increment type: double * @return Double bulk-string-reply the value of {@code key} after the increment. @@ -243,7 +246,7 @@ public interface RedisStringReactiveCommands { /** * Get the values of all the given keys. - * + * * @param keys the key * @return V array-reply list of values at the specified keys. */ @@ -261,7 +264,7 @@ public interface RedisStringReactiveCommands { /** * Set multiple keys to multiple values. - * + * * @param map the null * @return String simple-string-reply always {@code OK} since {@code MSET} can't fail. */ @@ -269,38 +272,38 @@ public interface RedisStringReactiveCommands { /** * Set multiple keys to multiple values, only if none of the keys exist. - * + * * @param map the null * @return Boolean integer-reply specifically: - * + * * {@code 1} if the all the keys were set. {@code 0} if no key was set (at least one key already existed). */ Mono msetnx(Map map); /** * Set the string value of a key. - * + * * @param key the key * @param value the value - * + * * @return String simple-string-reply {@code OK} if {@code SET} was executed correctly. */ Mono set(K key, V value); /** * Set the string value of a key. - * + * * @param key the key * @param value the value * @param setArgs the setArgs - * + * * @return String simple-string-reply {@code OK} if {@code SET} was executed correctly. */ Mono set(K key, V value, SetArgs setArgs); /** * Sets or clears the bit at offset in the string value stored at key. - * + * * @param key the key * @param offset the offset type: long * @param value the value type: string @@ -310,7 +313,7 @@ public interface RedisStringReactiveCommands { /** * Set the value and expiration of a key. - * + * * @param key the key * @param seconds the seconds type: long * @param value the value @@ -320,7 +323,7 @@ public interface RedisStringReactiveCommands { /** * Set the value and expiration in milliseconds of a key. - * + * * @param key the key * @param milliseconds the milliseconds type: long * @param value the value @@ -330,18 +333,18 @@ public interface RedisStringReactiveCommands { /** * Set the value of a key, only if the key does not exist. - * + * * @param key the key * @param value the value * @return Boolean integer-reply specifically: - * + * * {@code 1} if the key was set {@code 0} if the key was not set */ Mono setnx(K key, V value); /** * Overwrite part of a string at key starting at the specified offset. - * + * * @param key the key * @param offset the offset type: long * @param value the value @@ -351,7 +354,7 @@ public interface RedisStringReactiveCommands { /** * Get the length of the value stored in a key. - * + * * @param key the key * @return Long integer-reply the length of the string at {@code key}, or {@code 0} when {@code key} does not exist. */ diff --git a/src/main/java/com/lambdaworks/redis/api/reactive/RedisTransactionalReactiveCommands.java b/src/main/java/com/lambdaworks/redis/api/reactive/RedisTransactionalReactiveCommands.java index 1bbc8a2107..a25836c2aa 100644 --- a/src/main/java/com/lambdaworks/redis/api/reactive/RedisTransactionalReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/reactive/RedisTransactionalReactiveCommands.java @@ -15,9 +15,8 @@ */ package com.lambdaworks.redis.api.reactive; -import java.util.List; import com.lambdaworks.redis.TransactionResult; -import reactor.core.publisher.Flux; + import reactor.core.publisher.Mono; /** diff --git a/src/main/java/com/lambdaworks/redis/api/sync/BaseRedisCommands.java b/src/main/java/com/lambdaworks/redis/api/sync/BaseRedisCommands.java index fe72ac174b..b5d567ab86 100644 --- a/src/main/java/com/lambdaworks/redis/api/sync/BaseRedisCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/sync/BaseRedisCommands.java @@ -17,9 +17,10 @@ import java.util.List; import java.util.Map; + +import com.lambdaworks.redis.output.CommandOutput; import com.lambdaworks.redis.protocol.CommandArgs; import com.lambdaworks.redis.protocol.ProtocolKeyword; -import com.lambdaworks.redis.output.CommandOutput; /** * diff --git a/src/main/java/com/lambdaworks/redis/api/sync/RedisGeoCommands.java b/src/main/java/com/lambdaworks/redis/api/sync/RedisGeoCommands.java index 41ef7080e8..625ad6aaae 100644 --- a/src/main/java/com/lambdaworks/redis/api/sync/RedisGeoCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/sync/RedisGeoCommands.java @@ -15,11 +15,11 @@ */ package com.lambdaworks.redis.api.sync; -import com.lambdaworks.redis.*; - import java.util.List; import java.util.Set; +import com.lambdaworks.redis.*; + /** * Synchronous executed commands for the Geo-API. * diff --git a/src/main/java/com/lambdaworks/redis/api/sync/RedisHashCommands.java b/src/main/java/com/lambdaworks/redis/api/sync/RedisHashCommands.java index f3f535c878..a6be8df68b 100644 --- a/src/main/java/com/lambdaworks/redis/api/sync/RedisHashCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/sync/RedisHashCommands.java @@ -17,12 +17,8 @@ import java.util.List; import java.util.Map; -import com.lambdaworks.redis.KeyValue; -import com.lambdaworks.redis.Value; -import com.lambdaworks.redis.MapScanCursor; -import com.lambdaworks.redis.ScanArgs; -import com.lambdaworks.redis.ScanCursor; -import com.lambdaworks.redis.StreamScanCursor; + +import com.lambdaworks.redis.*; import com.lambdaworks.redis.output.KeyStreamingChannel; import com.lambdaworks.redis.output.KeyValueStreamingChannel; import com.lambdaworks.redis.output.ValueStreamingChannel; diff --git a/src/main/java/com/lambdaworks/redis/api/sync/RedisKeyCommands.java b/src/main/java/com/lambdaworks/redis/api/sync/RedisKeyCommands.java index 07c301ecbc..285b04d15f 100644 --- a/src/main/java/com/lambdaworks/redis/api/sync/RedisKeyCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/sync/RedisKeyCommands.java @@ -17,13 +17,8 @@ import java.util.Date; import java.util.List; -import com.lambdaworks.redis.Value; -import com.lambdaworks.redis.KeyScanCursor; -import com.lambdaworks.redis.MigrateArgs; -import com.lambdaworks.redis.ScanArgs; -import com.lambdaworks.redis.ScanCursor; -import com.lambdaworks.redis.SortArgs; -import com.lambdaworks.redis.StreamScanCursor; + +import com.lambdaworks.redis.*; import com.lambdaworks.redis.output.KeyStreamingChannel; import com.lambdaworks.redis.output.ValueStreamingChannel; diff --git a/src/main/java/com/lambdaworks/redis/api/sync/RedisListCommands.java b/src/main/java/com/lambdaworks/redis/api/sync/RedisListCommands.java index 734dfede07..93c1b00c0e 100644 --- a/src/main/java/com/lambdaworks/redis/api/sync/RedisListCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/sync/RedisListCommands.java @@ -16,6 +16,7 @@ package com.lambdaworks.redis.api.sync; import java.util.List; + import com.lambdaworks.redis.KeyValue; import com.lambdaworks.redis.output.ValueStreamingChannel; diff --git a/src/main/java/com/lambdaworks/redis/api/sync/RedisScriptingCommands.java b/src/main/java/com/lambdaworks/redis/api/sync/RedisScriptingCommands.java index 69b676b36f..705e6a4f4d 100644 --- a/src/main/java/com/lambdaworks/redis/api/sync/RedisScriptingCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/sync/RedisScriptingCommands.java @@ -16,6 +16,7 @@ package com.lambdaworks.redis.api.sync; import java.util.List; + import com.lambdaworks.redis.ScriptOutputType; /** diff --git a/src/main/java/com/lambdaworks/redis/api/sync/RedisServerCommands.java b/src/main/java/com/lambdaworks/redis/api/sync/RedisServerCommands.java index 27a1dfb6d4..1f7a4a021e 100644 --- a/src/main/java/com/lambdaworks/redis/api/sync/RedisServerCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/sync/RedisServerCommands.java @@ -17,6 +17,7 @@ import java.util.Date; import java.util.List; + import com.lambdaworks.redis.KillArgs; import com.lambdaworks.redis.protocol.CommandType; @@ -186,11 +187,15 @@ public interface RedisServerCommands { /** * Make the server crash: Out of memory. + * + * @return nothing, because the server crashes before returning. */ void debugOom(); /** * Make the server crash: Invalid pointer access. + * + * @return nothing, because the server crashes before returning. */ void debugSegfault(); diff --git a/src/main/java/com/lambdaworks/redis/api/sync/RedisSetCommands.java b/src/main/java/com/lambdaworks/redis/api/sync/RedisSetCommands.java index acdb6856fc..69e8220df9 100644 --- a/src/main/java/com/lambdaworks/redis/api/sync/RedisSetCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/sync/RedisSetCommands.java @@ -17,6 +17,7 @@ import java.util.List; import java.util.Set; + import com.lambdaworks.redis.ScanArgs; import com.lambdaworks.redis.ScanCursor; import com.lambdaworks.redis.StreamScanCursor; diff --git a/src/main/java/com/lambdaworks/redis/api/sync/RedisSortedSetCommands.java b/src/main/java/com/lambdaworks/redis/api/sync/RedisSortedSetCommands.java index 550745ae00..42baa2c1e6 100644 --- a/src/main/java/com/lambdaworks/redis/api/sync/RedisSortedSetCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/sync/RedisSortedSetCommands.java @@ -16,15 +16,8 @@ package com.lambdaworks.redis.api.sync; import java.util.List; -import com.lambdaworks.redis.Limit; -import com.lambdaworks.redis.Range; -import com.lambdaworks.redis.ScanArgs; -import com.lambdaworks.redis.ScanCursor; -import com.lambdaworks.redis.ScoredValue; -import com.lambdaworks.redis.ScoredValueScanCursor; -import com.lambdaworks.redis.StreamScanCursor; -import com.lambdaworks.redis.ZAddArgs; -import com.lambdaworks.redis.ZStoreArgs; + +import com.lambdaworks.redis.*; import com.lambdaworks.redis.output.ScoredValueStreamingChannel; import com.lambdaworks.redis.output.ValueStreamingChannel; @@ -523,6 +516,7 @@ public interface RedisSortedSetCommands { * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range, Limit limit)} */ + @Deprecated List> zrangebyscoreWithScores(K key, double min, double max, long offset, long count); /** diff --git a/src/main/java/com/lambdaworks/redis/api/sync/RedisStringCommands.java b/src/main/java/com/lambdaworks/redis/api/sync/RedisStringCommands.java index 26c194e20b..3d504eeb42 100644 --- a/src/main/java/com/lambdaworks/redis/api/sync/RedisStringCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/sync/RedisStringCommands.java @@ -17,16 +17,15 @@ import java.util.List; import java.util.Map; -import com.lambdaworks.redis.output.KeyValueStreamingChannel; -import com.lambdaworks.redis.output.ValueStreamingChannel; + import com.lambdaworks.redis.BitFieldArgs; import com.lambdaworks.redis.KeyValue; import com.lambdaworks.redis.SetArgs; -import com.lambdaworks.redis.Value; +import com.lambdaworks.redis.output.KeyValueStreamingChannel; /** * Synchronous executed commands for Strings. - * + * * @param Key type. * @param Value type. * @author Mark Paluch @@ -37,7 +36,7 @@ public interface RedisStringCommands { /** * Append a value to a key. - * + * * @param key the key * @param value the value * @return Long integer-reply the length of the string after the append operation. @@ -46,52 +45,52 @@ public interface RedisStringCommands { /** * Count set bits in a string. - * + * * @param key the key - * + * * @return Long integer-reply The number of bits set to 1. */ Long bitcount(K key); /** * Count set bits in a string. - * + * * @param key the key * @param start the start * @param end the end - * + * * @return Long integer-reply The number of bits set to 1. */ Long bitcount(K key, long start, long end); /** * Execute {@code BITFIELD} with its subcommands. - * + * * @param key the key * @param bitFieldArgs the args containing subcommands, must not be {@literal null}. - * + * * @return Long bulk-reply the results from the bitfield commands. */ List bitfield(K key, BitFieldArgs bitFieldArgs); /** * Find first bit set or clear in a string. - * + * * @param key the key * @param state the state - * + * * @return Long integer-reply The command returns the position of the first bit set to 1 or 0 according to the request. - * + * * If we look for set bits (the bit argument is 1) and the string is empty or composed of just zero bytes, -1 is * returned. - * + * * If we look for clear bits (the bit argument is 0) and the string only contains bit set to 1, the function returns * the first bit not part of the string on the right. So if the string is tree bytes set to the value 0xff the * command {@code BITPOS key 0} will return 24, since up to bit 23 all the bits are 1. - * + * * Basically the function consider the right of the string as padded with zeros if you look for clear bits and * specify no range or the start argument only. - * + * * However this behavior changes if you are looking for clear bits and specify a range with both * start and end. If no clear bit is found in the specified range, the function * returns -1 as the user specified a clear range and there are no 0 bits in that range. @@ -100,23 +99,23 @@ public interface RedisStringCommands { /** * Find first bit set or clear in a string. - * + * * @param key the key * @param state the bit type: long * @param start the start type: long * @param end the end type: long * @return Long integer-reply The command returns the position of the first bit set to 1 or 0 according to the request. - * + * * If we look for set bits (the bit argument is 1) and the string is empty or composed of just zero bytes, -1 is * returned. - * + * * If we look for clear bits (the bit argument is 0) and the string only contains bit set to 1, the function returns * the first bit not part of the string on the right. So if the string is tree bytes set to the value 0xff the * command {@code BITPOS key 0} will return 24, since up to bit 23 all the bits are 1. - * + * * Basically the function consider the right of the string as padded with zeros if you look for clear bits and * specify no range or the start argument only. - * + * * However this behavior changes if you are looking for clear bits and specify a range with both * start and end. If no clear bit is found in the specified range, the function * returns -1 as the user specified a clear range and there are no 0 bits in that range. @@ -125,7 +124,7 @@ public interface RedisStringCommands { /** * Perform bitwise AND between strings. - * + * * @param destination result key of the operation * @param keys operation input key names * @return Long integer-reply The size of the string stored in the destination key, that is equal to the size of the longest @@ -135,7 +134,7 @@ public interface RedisStringCommands { /** * Perform bitwise NOT between strings. - * + * * @param destination result key of the operation * @param source operation input key names * @return Long integer-reply The size of the string stored in the destination key, that is equal to the size of the longest @@ -145,7 +144,7 @@ public interface RedisStringCommands { /** * Perform bitwise OR between strings. - * + * * @param destination result key of the operation * @param keys operation input key names * @return Long integer-reply The size of the string stored in the destination key, that is equal to the size of the longest @@ -155,7 +154,7 @@ public interface RedisStringCommands { /** * Perform bitwise XOR between strings. - * + * * @param destination result key of the operation * @param keys operation input key names * @return Long integer-reply The size of the string stored in the destination key, that is equal to the size of the longest @@ -165,7 +164,7 @@ public interface RedisStringCommands { /** * Decrement the integer value of a key by one. - * + * * @param key the key * @return Long integer-reply the value of {@code key} after the decrement */ @@ -173,7 +172,7 @@ public interface RedisStringCommands { /** * Decrement the integer value of a key by the given number. - * + * * @param key the key * @param amount the decrement type: long * @return Long integer-reply the value of {@code key} after the decrement @@ -182,7 +181,7 @@ public interface RedisStringCommands { /** * Get the value of a key. - * + * * @param key the key * @return V bulk-string-reply the value of {@code key}, or {@literal null} when {@code key} does not exist. */ @@ -190,7 +189,7 @@ public interface RedisStringCommands { /** * Returns the bit value at offset in the string value stored at key. - * + * * @param key the key * @param offset the offset type: long * @return Long integer-reply the bit value stored at offset. @@ -199,7 +198,7 @@ public interface RedisStringCommands { /** * Get a substring of the string stored at a key. - * + * * @param key the key * @param start the start type: long * @param end the end type: long @@ -209,7 +208,7 @@ public interface RedisStringCommands { /** * Set the string value of a key and return its old value. - * + * * @param key the key * @param value the value * @return V bulk-string-reply the old value stored at {@code key}, or {@literal null} when {@code key} did not exist. @@ -218,7 +217,7 @@ public interface RedisStringCommands { /** * Increment the integer value of a key by one. - * + * * @param key the key * @return Long integer-reply the value of {@code key} after the increment */ @@ -226,7 +225,7 @@ public interface RedisStringCommands { /** * Increment the integer value of a key by the given amount. - * + * * @param key the key * @param amount the increment type: long * @return Long integer-reply the value of {@code key} after the increment @@ -235,7 +234,7 @@ public interface RedisStringCommands { /** * Increment the float value of a key by the given amount. - * + * * @param key the key * @param amount the increment type: double * @return Double bulk-string-reply the value of {@code key} after the increment. @@ -244,7 +243,7 @@ public interface RedisStringCommands { /** * Get the values of all the given keys. - * + * * @param keys the key * @return List<V> array-reply list of values at the specified keys. */ @@ -262,7 +261,7 @@ public interface RedisStringCommands { /** * Set multiple keys to multiple values. - * + * * @param map the null * @return String simple-string-reply always {@code OK} since {@code MSET} can't fail. */ @@ -270,38 +269,38 @@ public interface RedisStringCommands { /** * Set multiple keys to multiple values, only if none of the keys exist. - * + * * @param map the null * @return Boolean integer-reply specifically: - * + * * {@code 1} if the all the keys were set. {@code 0} if no key was set (at least one key already existed). */ Boolean msetnx(Map map); /** * Set the string value of a key. - * + * * @param key the key * @param value the value - * + * * @return String simple-string-reply {@code OK} if {@code SET} was executed correctly. */ String set(K key, V value); /** * Set the string value of a key. - * + * * @param key the key * @param value the value * @param setArgs the setArgs - * + * * @return String simple-string-reply {@code OK} if {@code SET} was executed correctly. */ String set(K key, V value, SetArgs setArgs); /** * Sets or clears the bit at offset in the string value stored at key. - * + * * @param key the key * @param offset the offset type: long * @param value the value type: string @@ -311,7 +310,7 @@ public interface RedisStringCommands { /** * Set the value and expiration of a key. - * + * * @param key the key * @param seconds the seconds type: long * @param value the value @@ -321,7 +320,7 @@ public interface RedisStringCommands { /** * Set the value and expiration in milliseconds of a key. - * + * * @param key the key * @param milliseconds the milliseconds type: long * @param value the value @@ -331,18 +330,18 @@ public interface RedisStringCommands { /** * Set the value of a key, only if the key does not exist. - * + * * @param key the key * @param value the value * @return Boolean integer-reply specifically: - * + * * {@code 1} if the key was set {@code 0} if the key was not set */ Boolean setnx(K key, V value); /** * Overwrite part of a string at key starting at the specified offset. - * + * * @param key the key * @param offset the offset type: long * @param value the value @@ -352,7 +351,7 @@ public interface RedisStringCommands { /** * Get the length of the value stored in a key. - * + * * @param key the key * @return Long integer-reply the length of the string at {@code key}, or {@code 0} when {@code key} does not exist. */ diff --git a/src/main/java/com/lambdaworks/redis/api/sync/RedisTransactionalCommands.java b/src/main/java/com/lambdaworks/redis/api/sync/RedisTransactionalCommands.java index 4a8a67a352..3c3ddd77df 100644 --- a/src/main/java/com/lambdaworks/redis/api/sync/RedisTransactionalCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/sync/RedisTransactionalCommands.java @@ -15,7 +15,6 @@ */ package com.lambdaworks.redis.api.sync; -import java.util.List; import com.lambdaworks.redis.TransactionResult; /** diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/async/BaseNodeSelectionAsyncCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/async/BaseNodeSelectionAsyncCommands.java index e5643cf65a..47b80257d0 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/async/BaseNodeSelectionAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/async/BaseNodeSelectionAsyncCommands.java @@ -17,10 +17,10 @@ import java.util.List; import java.util.Map; + +import com.lambdaworks.redis.output.CommandOutput; import com.lambdaworks.redis.protocol.CommandArgs; import com.lambdaworks.redis.protocol.ProtocolKeyword; -import com.lambdaworks.redis.output.CommandOutput; -import com.lambdaworks.redis.RedisFuture; /** * @@ -132,19 +132,4 @@ public interface BaseNodeSelectionAsyncCommands { * @return the command response */ AsyncExecutions dispatch(ProtocolKeyword type, CommandOutput output, CommandArgs args); - - /** - * Disable or enable auto-flush behavior. Default is {@literal true}. If autoFlushCommands is disabled, multiple commands - * can be issued without writing them actually to the transport. Commands are buffered until a {@link #flushCommands()} is - * issued. After calling {@link #flushCommands()} commands are sent to the transport and executed by Redis. - * - * @param autoFlush state of autoFlush. - */ - void setAutoFlushCommands(boolean autoFlush); - - /** - * Flush pending commands. This commands forces a flush on the channel and can be used to buffer ("pipeline") commands to - * achieve batching. No-op if channel is not connected. - */ - void flushCommands(); } diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionGeoAsyncCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionGeoAsyncCommands.java index 0844bf1732..ad290a4125 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionGeoAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionGeoAsyncCommands.java @@ -15,11 +15,11 @@ */ package com.lambdaworks.redis.cluster.api.async; -import com.lambdaworks.redis.*; - import java.util.List; import java.util.Set; +import com.lambdaworks.redis.*; + /** * Asynchronous executed commands on a node selection for the Geo-API. * diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionHLLAsyncCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionHLLAsyncCommands.java index 391a7db9ea..ac0226b4e8 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionHLLAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionHLLAsyncCommands.java @@ -15,8 +15,6 @@ */ package com.lambdaworks.redis.cluster.api.async; -import com.lambdaworks.redis.RedisFuture; - /** * Asynchronous executed commands on a node selection for HyperLogLog (PF* commands). * diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionHashAsyncCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionHashAsyncCommands.java index 2d9e8894f5..36433c2f61 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionHashAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionHashAsyncCommands.java @@ -17,16 +17,11 @@ import java.util.List; import java.util.Map; -import com.lambdaworks.redis.KeyValue; -import com.lambdaworks.redis.Value; -import com.lambdaworks.redis.MapScanCursor; -import com.lambdaworks.redis.ScanArgs; -import com.lambdaworks.redis.ScanCursor; -import com.lambdaworks.redis.StreamScanCursor; + +import com.lambdaworks.redis.*; import com.lambdaworks.redis.output.KeyStreamingChannel; import com.lambdaworks.redis.output.KeyValueStreamingChannel; import com.lambdaworks.redis.output.ValueStreamingChannel; -import com.lambdaworks.redis.RedisFuture; /** * Asynchronous executed commands on a node selection for Hashes (Key-Value pairs). diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionKeyAsyncCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionKeyAsyncCommands.java index 7349be15d3..2bf737915e 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionKeyAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionKeyAsyncCommands.java @@ -17,16 +17,10 @@ import java.util.Date; import java.util.List; -import com.lambdaworks.redis.Value; -import com.lambdaworks.redis.KeyScanCursor; -import com.lambdaworks.redis.MigrateArgs; -import com.lambdaworks.redis.ScanArgs; -import com.lambdaworks.redis.ScanCursor; -import com.lambdaworks.redis.SortArgs; -import com.lambdaworks.redis.StreamScanCursor; + +import com.lambdaworks.redis.*; import com.lambdaworks.redis.output.KeyStreamingChannel; import com.lambdaworks.redis.output.ValueStreamingChannel; -import com.lambdaworks.redis.RedisFuture; /** * Asynchronous executed commands on a node selection for Keys (Key manipulation/querying). diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionListAsyncCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionListAsyncCommands.java index d7fa53dea9..9aab6b92de 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionListAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionListAsyncCommands.java @@ -16,9 +16,9 @@ package com.lambdaworks.redis.cluster.api.async; import java.util.List; + import com.lambdaworks.redis.KeyValue; import com.lambdaworks.redis.output.ValueStreamingChannel; -import com.lambdaworks.redis.RedisFuture; /** * Asynchronous executed commands on a node selection for Lists. diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionScriptingAsyncCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionScriptingAsyncCommands.java index b0e8006fb0..7e6ec4e76f 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionScriptingAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionScriptingAsyncCommands.java @@ -16,8 +16,8 @@ package com.lambdaworks.redis.cluster.api.async; import java.util.List; + import com.lambdaworks.redis.ScriptOutputType; -import com.lambdaworks.redis.RedisFuture; /** * Asynchronous executed commands on a node selection for Scripting. diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionServerAsyncCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionServerAsyncCommands.java index fdecccfa25..aa73c895b0 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionServerAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionServerAsyncCommands.java @@ -17,9 +17,9 @@ import java.util.Date; import java.util.List; + import com.lambdaworks.redis.KillArgs; import com.lambdaworks.redis.protocol.CommandType; -import com.lambdaworks.redis.RedisFuture; /** * Asynchronous executed commands on a node selection for Server Control. diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionSetAsyncCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionSetAsyncCommands.java index f00b8b5fd9..6986a9b072 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionSetAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionSetAsyncCommands.java @@ -17,6 +17,7 @@ import java.util.List; import java.util.Set; + import com.lambdaworks.redis.ScanArgs; import com.lambdaworks.redis.ScanCursor; import com.lambdaworks.redis.StreamScanCursor; diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionSortedSetAsyncCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionSortedSetAsyncCommands.java index 9b62840312..2824320f06 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionSortedSetAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionSortedSetAsyncCommands.java @@ -16,18 +16,10 @@ package com.lambdaworks.redis.cluster.api.async; import java.util.List; -import com.lambdaworks.redis.Limit; -import com.lambdaworks.redis.Range; -import com.lambdaworks.redis.ScanArgs; -import com.lambdaworks.redis.ScanCursor; -import com.lambdaworks.redis.ScoredValue; -import com.lambdaworks.redis.ScoredValueScanCursor; -import com.lambdaworks.redis.StreamScanCursor; -import com.lambdaworks.redis.ZAddArgs; -import com.lambdaworks.redis.ZStoreArgs; + +import com.lambdaworks.redis.*; import com.lambdaworks.redis.output.ScoredValueStreamingChannel; import com.lambdaworks.redis.output.ValueStreamingChannel; -import com.lambdaworks.redis.RedisFuture; /** * Asynchronous executed commands on a node selection for Sorted Sets. @@ -524,6 +516,7 @@ public interface NodeSelectionSortedSetAsyncCommands { * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range, Limit limit)} */ + @Deprecated AsyncExecutions>> zrangebyscoreWithScores(K key, double min, double max, long offset, long count); /** diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionStringAsyncCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionStringAsyncCommands.java index 382ff7a4e1..43aaa246f1 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionStringAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/async/NodeSelectionStringAsyncCommands.java @@ -17,17 +17,15 @@ import java.util.List; import java.util.Map; -import com.lambdaworks.redis.output.KeyValueStreamingChannel; -import com.lambdaworks.redis.output.ValueStreamingChannel; + import com.lambdaworks.redis.BitFieldArgs; import com.lambdaworks.redis.KeyValue; import com.lambdaworks.redis.SetArgs; -import com.lambdaworks.redis.Value; -import com.lambdaworks.redis.RedisFuture; +import com.lambdaworks.redis.output.KeyValueStreamingChannel; /** * Asynchronous executed commands on a node selection for Strings. - * + * * @param Key type. * @param Value type. * @author Mark Paluch @@ -38,7 +36,7 @@ public interface NodeSelectionStringAsyncCommands { /** * Append a value to a key. - * + * * @param key the key * @param value the value * @return Long integer-reply the length of the string after the append operation. @@ -47,52 +45,52 @@ public interface NodeSelectionStringAsyncCommands { /** * Count set bits in a string. - * + * * @param key the key - * + * * @return Long integer-reply The number of bits set to 1. */ AsyncExecutions bitcount(K key); /** * Count set bits in a string. - * + * * @param key the key * @param start the start * @param end the end - * + * * @return Long integer-reply The number of bits set to 1. */ AsyncExecutions bitcount(K key, long start, long end); /** * Execute {@code BITFIELD} with its subcommands. - * + * * @param key the key * @param bitFieldArgs the args containing subcommands, must not be {@literal null}. - * + * * @return Long bulk-reply the results from the bitfield commands. */ AsyncExecutions> bitfield(K key, BitFieldArgs bitFieldArgs); /** * Find first bit set or clear in a string. - * + * * @param key the key * @param state the state - * + * * @return Long integer-reply The command returns the position of the first bit set to 1 or 0 according to the request. - * + * * If we look for set bits (the bit argument is 1) and the string is empty or composed of just zero bytes, -1 is * returned. - * + * * If we look for clear bits (the bit argument is 0) and the string only contains bit set to 1, the function returns * the first bit not part of the string on the right. So if the string is tree bytes set to the value 0xff the * command {@code BITPOS key 0} will return 24, since up to bit 23 all the bits are 1. - * + * * Basically the function consider the right of the string as padded with zeros if you look for clear bits and * specify no range or the start argument only. - * + * * However this behavior changes if you are looking for clear bits and specify a range with both * start and end. If no clear bit is found in the specified range, the function * returns -1 as the user specified a clear range and there are no 0 bits in that range. @@ -101,23 +99,23 @@ public interface NodeSelectionStringAsyncCommands { /** * Find first bit set or clear in a string. - * + * * @param key the key * @param state the bit type: long * @param start the start type: long * @param end the end type: long * @return Long integer-reply The command returns the position of the first bit set to 1 or 0 according to the request. - * + * * If we look for set bits (the bit argument is 1) and the string is empty or composed of just zero bytes, -1 is * returned. - * + * * If we look for clear bits (the bit argument is 0) and the string only contains bit set to 1, the function returns * the first bit not part of the string on the right. So if the string is tree bytes set to the value 0xff the * command {@code BITPOS key 0} will return 24, since up to bit 23 all the bits are 1. - * + * * Basically the function consider the right of the string as padded with zeros if you look for clear bits and * specify no range or the start argument only. - * + * * However this behavior changes if you are looking for clear bits and specify a range with both * start and end. If no clear bit is found in the specified range, the function * returns -1 as the user specified a clear range and there are no 0 bits in that range. @@ -126,7 +124,7 @@ public interface NodeSelectionStringAsyncCommands { /** * Perform bitwise AND between strings. - * + * * @param destination result key of the operation * @param keys operation input key names * @return Long integer-reply The size of the string stored in the destination key, that is equal to the size of the longest @@ -136,7 +134,7 @@ public interface NodeSelectionStringAsyncCommands { /** * Perform bitwise NOT between strings. - * + * * @param destination result key of the operation * @param source operation input key names * @return Long integer-reply The size of the string stored in the destination key, that is equal to the size of the longest @@ -146,7 +144,7 @@ public interface NodeSelectionStringAsyncCommands { /** * Perform bitwise OR between strings. - * + * * @param destination result key of the operation * @param keys operation input key names * @return Long integer-reply The size of the string stored in the destination key, that is equal to the size of the longest @@ -156,7 +154,7 @@ public interface NodeSelectionStringAsyncCommands { /** * Perform bitwise XOR between strings. - * + * * @param destination result key of the operation * @param keys operation input key names * @return Long integer-reply The size of the string stored in the destination key, that is equal to the size of the longest @@ -166,7 +164,7 @@ public interface NodeSelectionStringAsyncCommands { /** * Decrement the integer value of a key by one. - * + * * @param key the key * @return Long integer-reply the value of {@code key} after the decrement */ @@ -174,7 +172,7 @@ public interface NodeSelectionStringAsyncCommands { /** * Decrement the integer value of a key by the given number. - * + * * @param key the key * @param amount the decrement type: long * @return Long integer-reply the value of {@code key} after the decrement @@ -183,7 +181,7 @@ public interface NodeSelectionStringAsyncCommands { /** * Get the value of a key. - * + * * @param key the key * @return V bulk-string-reply the value of {@code key}, or {@literal null} when {@code key} does not exist. */ @@ -191,7 +189,7 @@ public interface NodeSelectionStringAsyncCommands { /** * Returns the bit value at offset in the string value stored at key. - * + * * @param key the key * @param offset the offset type: long * @return Long integer-reply the bit value stored at offset. @@ -200,7 +198,7 @@ public interface NodeSelectionStringAsyncCommands { /** * Get a substring of the string stored at a key. - * + * * @param key the key * @param start the start type: long * @param end the end type: long @@ -210,7 +208,7 @@ public interface NodeSelectionStringAsyncCommands { /** * Set the string value of a key and return its old value. - * + * * @param key the key * @param value the value * @return V bulk-string-reply the old value stored at {@code key}, or {@literal null} when {@code key} did not exist. @@ -219,7 +217,7 @@ public interface NodeSelectionStringAsyncCommands { /** * Increment the integer value of a key by one. - * + * * @param key the key * @return Long integer-reply the value of {@code key} after the increment */ @@ -227,7 +225,7 @@ public interface NodeSelectionStringAsyncCommands { /** * Increment the integer value of a key by the given amount. - * + * * @param key the key * @param amount the increment type: long * @return Long integer-reply the value of {@code key} after the increment @@ -236,7 +234,7 @@ public interface NodeSelectionStringAsyncCommands { /** * Increment the float value of a key by the given amount. - * + * * @param key the key * @param amount the increment type: double * @return Double bulk-string-reply the value of {@code key} after the increment. @@ -245,7 +243,7 @@ public interface NodeSelectionStringAsyncCommands { /** * Get the values of all the given keys. - * + * * @param keys the key * @return List<V> array-reply list of values at the specified keys. */ @@ -263,7 +261,7 @@ public interface NodeSelectionStringAsyncCommands { /** * Set multiple keys to multiple values. - * + * * @param map the null * @return String simple-string-reply always {@code OK} since {@code MSET} can't fail. */ @@ -271,38 +269,38 @@ public interface NodeSelectionStringAsyncCommands { /** * Set multiple keys to multiple values, only if none of the keys exist. - * + * * @param map the null * @return Boolean integer-reply specifically: - * + * * {@code 1} if the all the keys were set. {@code 0} if no key was set (at least one key already existed). */ AsyncExecutions msetnx(Map map); /** * Set the string value of a key. - * + * * @param key the key * @param value the value - * + * * @return String simple-string-reply {@code OK} if {@code SET} was executed correctly. */ AsyncExecutions set(K key, V value); /** * Set the string value of a key. - * + * * @param key the key * @param value the value * @param setArgs the setArgs - * + * * @return String simple-string-reply {@code OK} if {@code SET} was executed correctly. */ AsyncExecutions set(K key, V value, SetArgs setArgs); /** * Sets or clears the bit at offset in the string value stored at key. - * + * * @param key the key * @param offset the offset type: long * @param value the value type: string @@ -312,7 +310,7 @@ public interface NodeSelectionStringAsyncCommands { /** * Set the value and expiration of a key. - * + * * @param key the key * @param seconds the seconds type: long * @param value the value @@ -322,7 +320,7 @@ public interface NodeSelectionStringAsyncCommands { /** * Set the value and expiration in milliseconds of a key. - * + * * @param key the key * @param milliseconds the milliseconds type: long * @param value the value @@ -332,18 +330,18 @@ public interface NodeSelectionStringAsyncCommands { /** * Set the value of a key, only if the key does not exist. - * + * * @param key the key * @param value the value * @return Boolean integer-reply specifically: - * + * * {@code 1} if the key was set {@code 0} if the key was not set */ AsyncExecutions setnx(K key, V value); /** * Overwrite part of a string at key starting at the specified offset. - * + * * @param key the key * @param offset the offset type: long * @param value the value @@ -353,7 +351,7 @@ public interface NodeSelectionStringAsyncCommands { /** * Get the length of the value stored in a key. - * + * * @param key the key * @return Long integer-reply the length of the string at {@code key}, or {@code 0} when {@code key} does not exist. */ diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/sync/BaseNodeSelectionCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/sync/BaseNodeSelectionCommands.java index 2100440d45..834b4b8cfd 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/sync/BaseNodeSelectionCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/sync/BaseNodeSelectionCommands.java @@ -17,9 +17,6 @@ import java.util.List; import java.util.Map; -import com.lambdaworks.redis.protocol.CommandArgs; -import com.lambdaworks.redis.protocol.ProtocolKeyword; -import com.lambdaworks.redis.output.CommandOutput; /** * @@ -110,20 +107,4 @@ public interface BaseNodeSelectionCommands { * @return number of replicas */ Executions waitForReplication(int replicas, long timeout); - - /** - * Disable or enable auto-flush behavior. Default is {@literal true}. If autoFlushCommands is disabled, multiple commands - * can be issued without writing them actually to the transport. Commands are buffered until a {@link #flushCommands()} is - * issued. After calling {@link #flushCommands()} commands are sent to the transport and executed by Redis. - * - * @param autoFlush state of autoFlush. - */ - void setAutoFlushCommands(boolean autoFlush); - - /** - * Flush pending commands. This commands forces a flush on the channel and can be used to buffer ("pipeline") commands to - * achieve batching. No-op if channel is not connected. - * - */ - void flushCommands(); } diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/sync/Executions.java b/src/main/java/com/lambdaworks/redis/cluster/api/sync/Executions.java index f893cff23d..7507441831 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/sync/Executions.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/sync/Executions.java @@ -16,7 +16,6 @@ package com.lambdaworks.redis.cluster.api.sync; import java.util.*; -import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; import java.util.stream.Stream; import java.util.stream.StreamSupport; diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionGeoCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionGeoCommands.java index 3dadf4b9ef..fce9623874 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionGeoCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionGeoCommands.java @@ -15,11 +15,11 @@ */ package com.lambdaworks.redis.cluster.api.sync; -import com.lambdaworks.redis.*; - import java.util.List; import java.util.Set; +import com.lambdaworks.redis.*; + /** * Synchronous executed commands on a node selection for the Geo-API. * diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionHashCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionHashCommands.java index ef2119b84e..2c4764680e 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionHashCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionHashCommands.java @@ -17,12 +17,8 @@ import java.util.List; import java.util.Map; -import com.lambdaworks.redis.KeyValue; -import com.lambdaworks.redis.Value; -import com.lambdaworks.redis.MapScanCursor; -import com.lambdaworks.redis.ScanArgs; -import com.lambdaworks.redis.ScanCursor; -import com.lambdaworks.redis.StreamScanCursor; + +import com.lambdaworks.redis.*; import com.lambdaworks.redis.output.KeyStreamingChannel; import com.lambdaworks.redis.output.KeyValueStreamingChannel; import com.lambdaworks.redis.output.ValueStreamingChannel; diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionKeyCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionKeyCommands.java index 2494895f3c..d241449851 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionKeyCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionKeyCommands.java @@ -17,13 +17,8 @@ import java.util.Date; import java.util.List; -import com.lambdaworks.redis.Value; -import com.lambdaworks.redis.KeyScanCursor; -import com.lambdaworks.redis.MigrateArgs; -import com.lambdaworks.redis.ScanArgs; -import com.lambdaworks.redis.ScanCursor; -import com.lambdaworks.redis.SortArgs; -import com.lambdaworks.redis.StreamScanCursor; + +import com.lambdaworks.redis.*; import com.lambdaworks.redis.output.KeyStreamingChannel; import com.lambdaworks.redis.output.ValueStreamingChannel; diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionListCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionListCommands.java index de8a6c67cf..e6d5484183 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionListCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionListCommands.java @@ -16,6 +16,7 @@ package com.lambdaworks.redis.cluster.api.sync; import java.util.List; + import com.lambdaworks.redis.KeyValue; import com.lambdaworks.redis.output.ValueStreamingChannel; diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionScriptingCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionScriptingCommands.java index efa3535149..c8498524ba 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionScriptingCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionScriptingCommands.java @@ -16,6 +16,7 @@ package com.lambdaworks.redis.cluster.api.sync; import java.util.List; + import com.lambdaworks.redis.ScriptOutputType; /** diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionServerCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionServerCommands.java index 90205f9ec6..4779b8beec 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionServerCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionServerCommands.java @@ -17,6 +17,7 @@ import java.util.Date; import java.util.List; + import com.lambdaworks.redis.KillArgs; import com.lambdaworks.redis.protocol.CommandType; diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionSetCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionSetCommands.java index da18f015e3..11f815be83 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionSetCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionSetCommands.java @@ -17,6 +17,7 @@ import java.util.List; import java.util.Set; + import com.lambdaworks.redis.ScanArgs; import com.lambdaworks.redis.ScanCursor; import com.lambdaworks.redis.StreamScanCursor; diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionSortedSetCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionSortedSetCommands.java index ef869892f1..0e51823977 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionSortedSetCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionSortedSetCommands.java @@ -16,15 +16,8 @@ package com.lambdaworks.redis.cluster.api.sync; import java.util.List; -import com.lambdaworks.redis.Limit; -import com.lambdaworks.redis.Range; -import com.lambdaworks.redis.ScanArgs; -import com.lambdaworks.redis.ScanCursor; -import com.lambdaworks.redis.ScoredValue; -import com.lambdaworks.redis.ScoredValueScanCursor; -import com.lambdaworks.redis.StreamScanCursor; -import com.lambdaworks.redis.ZAddArgs; -import com.lambdaworks.redis.ZStoreArgs; + +import com.lambdaworks.redis.*; import com.lambdaworks.redis.output.ScoredValueStreamingChannel; import com.lambdaworks.redis.output.ValueStreamingChannel; @@ -523,6 +516,7 @@ public interface NodeSelectionSortedSetCommands { * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range, Limit limit)} */ + @Deprecated Executions>> zrangebyscoreWithScores(K key, double min, double max, long offset, long count); /** diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionStringCommands.java b/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionStringCommands.java index d37b6344dc..d10d413b16 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionStringCommands.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelectionStringCommands.java @@ -17,16 +17,15 @@ import java.util.List; import java.util.Map; -import com.lambdaworks.redis.output.KeyValueStreamingChannel; -import com.lambdaworks.redis.output.ValueStreamingChannel; + import com.lambdaworks.redis.BitFieldArgs; import com.lambdaworks.redis.KeyValue; import com.lambdaworks.redis.SetArgs; -import com.lambdaworks.redis.Value; +import com.lambdaworks.redis.output.KeyValueStreamingChannel; /** * Synchronous executed commands on a node selection for Strings. - * + * * @param Key type. * @param Value type. * @author Mark Paluch @@ -37,7 +36,7 @@ public interface NodeSelectionStringCommands { /** * Append a value to a key. - * + * * @param key the key * @param value the value * @return Long integer-reply the length of the string after the append operation. @@ -46,52 +45,52 @@ public interface NodeSelectionStringCommands { /** * Count set bits in a string. - * + * * @param key the key - * + * * @return Long integer-reply The number of bits set to 1. */ Executions bitcount(K key); /** * Count set bits in a string. - * + * * @param key the key * @param start the start * @param end the end - * + * * @return Long integer-reply The number of bits set to 1. */ Executions bitcount(K key, long start, long end); /** * Execute {@code BITFIELD} with its subcommands. - * + * * @param key the key * @param bitFieldArgs the args containing subcommands, must not be {@literal null}. - * + * * @return Long bulk-reply the results from the bitfield commands. */ Executions> bitfield(K key, BitFieldArgs bitFieldArgs); /** * Find first bit set or clear in a string. - * + * * @param key the key * @param state the state - * + * * @return Long integer-reply The command returns the position of the first bit set to 1 or 0 according to the request. - * + * * If we look for set bits (the bit argument is 1) and the string is empty or composed of just zero bytes, -1 is * returned. - * + * * If we look for clear bits (the bit argument is 0) and the string only contains bit set to 1, the function returns * the first bit not part of the string on the right. So if the string is tree bytes set to the value 0xff the * command {@code BITPOS key 0} will return 24, since up to bit 23 all the bits are 1. - * + * * Basically the function consider the right of the string as padded with zeros if you look for clear bits and * specify no range or the start argument only. - * + * * However this behavior changes if you are looking for clear bits and specify a range with both * start and end. If no clear bit is found in the specified range, the function * returns -1 as the user specified a clear range and there are no 0 bits in that range. @@ -100,23 +99,23 @@ public interface NodeSelectionStringCommands { /** * Find first bit set or clear in a string. - * + * * @param key the key * @param state the bit type: long * @param start the start type: long * @param end the end type: long * @return Long integer-reply The command returns the position of the first bit set to 1 or 0 according to the request. - * + * * If we look for set bits (the bit argument is 1) and the string is empty or composed of just zero bytes, -1 is * returned. - * + * * If we look for clear bits (the bit argument is 0) and the string only contains bit set to 1, the function returns * the first bit not part of the string on the right. So if the string is tree bytes set to the value 0xff the * command {@code BITPOS key 0} will return 24, since up to bit 23 all the bits are 1. - * + * * Basically the function consider the right of the string as padded with zeros if you look for clear bits and * specify no range or the start argument only. - * + * * However this behavior changes if you are looking for clear bits and specify a range with both * start and end. If no clear bit is found in the specified range, the function * returns -1 as the user specified a clear range and there are no 0 bits in that range. @@ -125,7 +124,7 @@ public interface NodeSelectionStringCommands { /** * Perform bitwise AND between strings. - * + * * @param destination result key of the operation * @param keys operation input key names * @return Long integer-reply The size of the string stored in the destination key, that is equal to the size of the longest @@ -135,7 +134,7 @@ public interface NodeSelectionStringCommands { /** * Perform bitwise NOT between strings. - * + * * @param destination result key of the operation * @param source operation input key names * @return Long integer-reply The size of the string stored in the destination key, that is equal to the size of the longest @@ -145,7 +144,7 @@ public interface NodeSelectionStringCommands { /** * Perform bitwise OR between strings. - * + * * @param destination result key of the operation * @param keys operation input key names * @return Long integer-reply The size of the string stored in the destination key, that is equal to the size of the longest @@ -155,7 +154,7 @@ public interface NodeSelectionStringCommands { /** * Perform bitwise XOR between strings. - * + * * @param destination result key of the operation * @param keys operation input key names * @return Long integer-reply The size of the string stored in the destination key, that is equal to the size of the longest @@ -165,7 +164,7 @@ public interface NodeSelectionStringCommands { /** * Decrement the integer value of a key by one. - * + * * @param key the key * @return Long integer-reply the value of {@code key} after the decrement */ @@ -173,7 +172,7 @@ public interface NodeSelectionStringCommands { /** * Decrement the integer value of a key by the given number. - * + * * @param key the key * @param amount the decrement type: long * @return Long integer-reply the value of {@code key} after the decrement @@ -182,7 +181,7 @@ public interface NodeSelectionStringCommands { /** * Get the value of a key. - * + * * @param key the key * @return V bulk-string-reply the value of {@code key}, or {@literal null} when {@code key} does not exist. */ @@ -190,7 +189,7 @@ public interface NodeSelectionStringCommands { /** * Returns the bit value at offset in the string value stored at key. - * + * * @param key the key * @param offset the offset type: long * @return Long integer-reply the bit value stored at offset. @@ -199,7 +198,7 @@ public interface NodeSelectionStringCommands { /** * Get a substring of the string stored at a key. - * + * * @param key the key * @param start the start type: long * @param end the end type: long @@ -209,7 +208,7 @@ public interface NodeSelectionStringCommands { /** * Set the string value of a key and return its old value. - * + * * @param key the key * @param value the value * @return V bulk-string-reply the old value stored at {@code key}, or {@literal null} when {@code key} did not exist. @@ -218,7 +217,7 @@ public interface NodeSelectionStringCommands { /** * Increment the integer value of a key by one. - * + * * @param key the key * @return Long integer-reply the value of {@code key} after the increment */ @@ -226,7 +225,7 @@ public interface NodeSelectionStringCommands { /** * Increment the integer value of a key by the given amount. - * + * * @param key the key * @param amount the increment type: long * @return Long integer-reply the value of {@code key} after the increment @@ -235,7 +234,7 @@ public interface NodeSelectionStringCommands { /** * Increment the float value of a key by the given amount. - * + * * @param key the key * @param amount the increment type: double * @return Double bulk-string-reply the value of {@code key} after the increment. @@ -244,7 +243,7 @@ public interface NodeSelectionStringCommands { /** * Get the values of all the given keys. - * + * * @param keys the key * @return List<V> array-reply list of values at the specified keys. */ @@ -262,7 +261,7 @@ public interface NodeSelectionStringCommands { /** * Set multiple keys to multiple values. - * + * * @param map the null * @return String simple-string-reply always {@code OK} since {@code MSET} can't fail. */ @@ -270,38 +269,38 @@ public interface NodeSelectionStringCommands { /** * Set multiple keys to multiple values, only if none of the keys exist. - * + * * @param map the null * @return Boolean integer-reply specifically: - * + * * {@code 1} if the all the keys were set. {@code 0} if no key was set (at least one key already existed). */ Executions msetnx(Map map); /** * Set the string value of a key. - * + * * @param key the key * @param value the value - * + * * @return String simple-string-reply {@code OK} if {@code SET} was executed correctly. */ Executions set(K key, V value); /** * Set the string value of a key. - * + * * @param key the key * @param value the value * @param setArgs the setArgs - * + * * @return String simple-string-reply {@code OK} if {@code SET} was executed correctly. */ Executions set(K key, V value, SetArgs setArgs); /** * Sets or clears the bit at offset in the string value stored at key. - * + * * @param key the key * @param offset the offset type: long * @param value the value type: string @@ -311,7 +310,7 @@ public interface NodeSelectionStringCommands { /** * Set the value and expiration of a key. - * + * * @param key the key * @param seconds the seconds type: long * @param value the value @@ -321,7 +320,7 @@ public interface NodeSelectionStringCommands { /** * Set the value and expiration in milliseconds of a key. - * + * * @param key the key * @param milliseconds the milliseconds type: long * @param value the value @@ -331,18 +330,18 @@ public interface NodeSelectionStringCommands { /** * Set the value of a key, only if the key does not exist. - * + * * @param key the key * @param value the value * @return Boolean integer-reply specifically: - * + * * {@code 1} if the key was set {@code 0} if the key was not set */ Executions setnx(K key, V value); /** * Overwrite part of a string at key starting at the specified offset. - * + * * @param key the key * @param offset the offset type: long * @param value the value @@ -352,7 +351,7 @@ public interface NodeSelectionStringCommands { /** * Get the length of the value stored in a key. - * + * * @param key the key * @return Long integer-reply the length of the string at {@code key}, or {@code 0} when {@code key} does not exist. */ diff --git a/src/main/templates/com/lambdaworks/redis/api/RedisGeoCommands.java b/src/main/templates/com/lambdaworks/redis/api/RedisGeoCommands.java index 2071b92634..04bd3ff2d7 100644 --- a/src/main/templates/com/lambdaworks/redis/api/RedisGeoCommands.java +++ b/src/main/templates/com/lambdaworks/redis/api/RedisGeoCommands.java @@ -15,11 +15,7 @@ */ package com.lambdaworks.redis; -import com.lambdaworks.redis.GeoArgs; -import com.lambdaworks.redis.GeoCoordinates; -import com.lambdaworks.redis.GeoRadiusStoreArgs; -import com.lambdaworks.redis.GeoWithin; -import com.lambdaworks.redis.Value; +import com.lambdaworks.redis.*; import java.util.List; import java.util.Set; diff --git a/src/main/templates/com/lambdaworks/redis/api/RedisHashCommands.java b/src/main/templates/com/lambdaworks/redis/api/RedisHashCommands.java index b392fce6b8..408df3049a 100644 --- a/src/main/templates/com/lambdaworks/redis/api/RedisHashCommands.java +++ b/src/main/templates/com/lambdaworks/redis/api/RedisHashCommands.java @@ -18,12 +18,7 @@ import java.util.List; import java.util.Map; -import com.lambdaworks.redis.KeyValue; -import com.lambdaworks.redis.Value; -import com.lambdaworks.redis.MapScanCursor; -import com.lambdaworks.redis.ScanArgs; -import com.lambdaworks.redis.ScanCursor; -import com.lambdaworks.redis.StreamScanCursor; +import com.lambdaworks.redis.*; import com.lambdaworks.redis.output.KeyStreamingChannel; import com.lambdaworks.redis.output.KeyValueStreamingChannel; import com.lambdaworks.redis.output.ValueStreamingChannel; diff --git a/src/main/templates/com/lambdaworks/redis/api/RedisKeyCommands.java b/src/main/templates/com/lambdaworks/redis/api/RedisKeyCommands.java index 9e809c9fc1..9ca45cc9a7 100644 --- a/src/main/templates/com/lambdaworks/redis/api/RedisKeyCommands.java +++ b/src/main/templates/com/lambdaworks/redis/api/RedisKeyCommands.java @@ -18,13 +18,7 @@ import java.util.Date; import java.util.List; -import com.lambdaworks.redis.Value; -import com.lambdaworks.redis.KeyScanCursor; -import com.lambdaworks.redis.MigrateArgs; -import com.lambdaworks.redis.ScanArgs; -import com.lambdaworks.redis.ScanCursor; -import com.lambdaworks.redis.SortArgs; -import com.lambdaworks.redis.StreamScanCursor; +import com.lambdaworks.redis.*; import com.lambdaworks.redis.output.KeyStreamingChannel; import com.lambdaworks.redis.output.ValueStreamingChannel; diff --git a/src/main/templates/com/lambdaworks/redis/api/RedisSortedSetCommands.java b/src/main/templates/com/lambdaworks/redis/api/RedisSortedSetCommands.java index 2d0ef979f5..d6a4eda2e1 100644 --- a/src/main/templates/com/lambdaworks/redis/api/RedisSortedSetCommands.java +++ b/src/main/templates/com/lambdaworks/redis/api/RedisSortedSetCommands.java @@ -17,15 +17,7 @@ import java.util.List; -import com.lambdaworks.redis.Limit; -import com.lambdaworks.redis.Range; -import com.lambdaworks.redis.ScanArgs; -import com.lambdaworks.redis.ScanCursor; -import com.lambdaworks.redis.ScoredValue; -import com.lambdaworks.redis.ScoredValueScanCursor; -import com.lambdaworks.redis.StreamScanCursor; -import com.lambdaworks.redis.ZAddArgs; -import com.lambdaworks.redis.ZStoreArgs; +import com.lambdaworks.redis.*; import com.lambdaworks.redis.output.ScoredValueStreamingChannel; import com.lambdaworks.redis.output.ValueStreamingChannel; @@ -523,6 +515,7 @@ public interface RedisSortedSetCommands { * @return List<ScoredValue<V>> array-reply list of elements in the specified score range. * @deprecated Use {@link #zrangebyscoreWithScores(java.lang.Object, Range, Limit limit)} */ + @Deprecated List> zrangebyscoreWithScores(K key, double min, double max, long offset, long count); /** diff --git a/src/main/templates/com/lambdaworks/redis/api/RedisStringCommands.java b/src/main/templates/com/lambdaworks/redis/api/RedisStringCommands.java index 1e84a6d89f..e01479587a 100644 --- a/src/main/templates/com/lambdaworks/redis/api/RedisStringCommands.java +++ b/src/main/templates/com/lambdaworks/redis/api/RedisStringCommands.java @@ -27,7 +27,7 @@ /** * ${intent} for Strings. - * + * * @param Key type. * @param Value type. * @author Mark Paluch @@ -37,7 +37,7 @@ public interface RedisStringCommands { /** * Append a value to a key. - * + * * @param key the key * @param value the value * @return Long integer-reply the length of the string after the append operation. @@ -46,52 +46,52 @@ public interface RedisStringCommands { /** * Count set bits in a string. - * + * * @param key the key - * + * * @return Long integer-reply The number of bits set to 1. */ Long bitcount(K key); /** * Count set bits in a string. - * + * * @param key the key * @param start the start * @param end the end - * + * * @return Long integer-reply The number of bits set to 1. */ Long bitcount(K key, long start, long end); - + /** * Execute {@code BITFIELD} with its subcommands. - * + * * @param key the key * @param bitFieldArgs the args containing subcommands, must not be {@literal null}. - * + * * @return Long bulk-reply the results from the bitfield commands. */ List bitfield(K key, BitFieldArgs bitFieldArgs); /** * Find first bit set or clear in a string. - * + * * @param key the key * @param state the state - * + * * @return Long integer-reply The command returns the position of the first bit set to 1 or 0 according to the request. - * + * * If we look for set bits (the bit argument is 1) and the string is empty or composed of just zero bytes, -1 is * returned. - * + * * If we look for clear bits (the bit argument is 0) and the string only contains bit set to 1, the function returns * the first bit not part of the string on the right. So if the string is tree bytes set to the value 0xff the * command {@code BITPOS key 0} will return 24, since up to bit 23 all the bits are 1. - * + * * Basically the function consider the right of the string as padded with zeros if you look for clear bits and * specify no range or the start argument only. - * + * * However this behavior changes if you are looking for clear bits and specify a range with both * start and end. If no clear bit is found in the specified range, the function * returns -1 as the user specified a clear range and there are no 0 bits in that range. @@ -100,23 +100,23 @@ public interface RedisStringCommands { /** * Find first bit set or clear in a string. - * + * * @param key the key * @param state the bit type: long * @param start the start type: long * @param end the end type: long * @return Long integer-reply The command returns the position of the first bit set to 1 or 0 according to the request. - * + * * If we look for set bits (the bit argument is 1) and the string is empty or composed of just zero bytes, -1 is * returned. - * + * * If we look for clear bits (the bit argument is 0) and the string only contains bit set to 1, the function returns * the first bit not part of the string on the right. So if the string is tree bytes set to the value 0xff the * command {@code BITPOS key 0} will return 24, since up to bit 23 all the bits are 1. - * + * * Basically the function consider the right of the string as padded with zeros if you look for clear bits and * specify no range or the start argument only. - * + * * However this behavior changes if you are looking for clear bits and specify a range with both * start and end. If no clear bit is found in the specified range, the function * returns -1 as the user specified a clear range and there are no 0 bits in that range. @@ -125,7 +125,7 @@ public interface RedisStringCommands { /** * Perform bitwise AND between strings. - * + * * @param destination result key of the operation * @param keys operation input key names * @return Long integer-reply The size of the string stored in the destination key, that is equal to the size of the longest @@ -135,7 +135,7 @@ public interface RedisStringCommands { /** * Perform bitwise NOT between strings. - * + * * @param destination result key of the operation * @param source operation input key names * @return Long integer-reply The size of the string stored in the destination key, that is equal to the size of the longest @@ -145,7 +145,7 @@ public interface RedisStringCommands { /** * Perform bitwise OR between strings. - * + * * @param destination result key of the operation * @param keys operation input key names * @return Long integer-reply The size of the string stored in the destination key, that is equal to the size of the longest @@ -155,7 +155,7 @@ public interface RedisStringCommands { /** * Perform bitwise XOR between strings. - * + * * @param destination result key of the operation * @param keys operation input key names * @return Long integer-reply The size of the string stored in the destination key, that is equal to the size of the longest @@ -165,7 +165,7 @@ public interface RedisStringCommands { /** * Decrement the integer value of a key by one. - * + * * @param key the key * @return Long integer-reply the value of {@code key} after the decrement */ @@ -173,7 +173,7 @@ public interface RedisStringCommands { /** * Decrement the integer value of a key by the given number. - * + * * @param key the key * @param amount the decrement type: long * @return Long integer-reply the value of {@code key} after the decrement @@ -182,7 +182,7 @@ public interface RedisStringCommands { /** * Get the value of a key. - * + * * @param key the key * @return V bulk-string-reply the value of {@code key}, or {@literal null} when {@code key} does not exist. */ @@ -190,7 +190,7 @@ public interface RedisStringCommands { /** * Returns the bit value at offset in the string value stored at key. - * + * * @param key the key * @param offset the offset type: long * @return Long integer-reply the bit value stored at offset. @@ -199,7 +199,7 @@ public interface RedisStringCommands { /** * Get a substring of the string stored at a key. - * + * * @param key the key * @param start the start type: long * @param end the end type: long @@ -209,7 +209,7 @@ public interface RedisStringCommands { /** * Set the string value of a key and return its old value. - * + * * @param key the key * @param value the value * @return V bulk-string-reply the old value stored at {@code key}, or {@literal null} when {@code key} did not exist. @@ -218,7 +218,7 @@ public interface RedisStringCommands { /** * Increment the integer value of a key by one. - * + * * @param key the key * @return Long integer-reply the value of {@code key} after the increment */ @@ -226,7 +226,7 @@ public interface RedisStringCommands { /** * Increment the integer value of a key by the given amount. - * + * * @param key the key * @param amount the increment type: long * @return Long integer-reply the value of {@code key} after the increment @@ -235,7 +235,7 @@ public interface RedisStringCommands { /** * Increment the float value of a key by the given amount. - * + * * @param key the key * @param amount the increment type: double * @return Double bulk-string-reply the value of {@code key} after the increment. @@ -244,7 +244,7 @@ public interface RedisStringCommands { /** * Get the values of all the given keys. - * + * * @param keys the key * @return List<V> array-reply list of values at the specified keys. */ @@ -262,7 +262,7 @@ public interface RedisStringCommands { /** * Set multiple keys to multiple values. - * + * * @param map the null * @return String simple-string-reply always {@code OK} since {@code MSET} can't fail. */ @@ -270,38 +270,38 @@ public interface RedisStringCommands { /** * Set multiple keys to multiple values, only if none of the keys exist. - * + * * @param map the null * @return Boolean integer-reply specifically: - * + * * {@code 1} if the all the keys were set. {@code 0} if no key was set (at least one key already existed). */ Boolean msetnx(Map map); /** * Set the string value of a key. - * + * * @param key the key * @param value the value - * + * * @return String simple-string-reply {@code OK} if {@code SET} was executed correctly. */ String set(K key, V value); /** * Set the string value of a key. - * + * * @param key the key * @param value the value * @param setArgs the setArgs - * + * * @return String simple-string-reply {@code OK} if {@code SET} was executed correctly. */ String set(K key, V value, SetArgs setArgs); /** * Sets or clears the bit at offset in the string value stored at key. - * + * * @param key the key * @param offset the offset type: long * @param value the value type: string @@ -311,7 +311,7 @@ public interface RedisStringCommands { /** * Set the value and expiration of a key. - * + * * @param key the key * @param seconds the seconds type: long * @param value the value @@ -321,7 +321,7 @@ public interface RedisStringCommands { /** * Set the value and expiration in milliseconds of a key. - * + * * @param key the key * @param milliseconds the milliseconds type: long * @param value the value @@ -331,18 +331,18 @@ public interface RedisStringCommands { /** * Set the value of a key, only if the key does not exist. - * + * * @param key the key * @param value the value * @return Boolean integer-reply specifically: - * + * * {@code 1} if the key was set {@code 0} if the key was not set */ Boolean setnx(K key, V value); /** * Overwrite part of a string at key starting at the specified offset. - * + * * @param key the key * @param offset the offset type: long * @param value the value @@ -352,7 +352,7 @@ public interface RedisStringCommands { /** * Get the length of the value stored in a key. - * + * * @param key the key * @return Long integer-reply the length of the string at {@code key}, or {@code 0} when {@code key} does not exist. */ diff --git a/src/test/java/com/lambdaworks/apigenerator/CompilationUnitFactory.java b/src/test/java/com/lambdaworks/apigenerator/CompilationUnitFactory.java index fe132bfbc0..1954e5d566 100644 --- a/src/test/java/com/lambdaworks/apigenerator/CompilationUnitFactory.java +++ b/src/test/java/com/lambdaworks/apigenerator/CompilationUnitFactory.java @@ -102,6 +102,7 @@ public void createInterface() throws Exception { } resultType.setComment(new JavadocComment(typeDocFunction.apply(templateTypeDeclaration.getComment().getContent()))); + result.setComment(template.getComment()); result.setImports(new ArrayList<>()); ASTHelper.addTypeDeclaration(result, resultType); diff --git a/src/test/java/com/lambdaworks/apigenerator/CreateAsyncApi.java b/src/test/java/com/lambdaworks/apigenerator/CreateAsyncApi.java index c9f1ce7abd..a0cb4c791e 100644 --- a/src/test/java/com/lambdaworks/apigenerator/CreateAsyncApi.java +++ b/src/test/java/com/lambdaworks/apigenerator/CreateAsyncApi.java @@ -16,24 +16,23 @@ package com.lambdaworks.apigenerator; import java.io.File; -import java.util.*; -import java.util.function.Consumer; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Set; import java.util.function.Function; import java.util.function.Supplier; -import com.lambdaworks.redis.internal.LettuceSets; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; -import com.github.javaparser.ast.CompilationUnit; -import com.github.javaparser.ast.ImportDeclaration; import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration; import com.github.javaparser.ast.body.MethodDeclaration; -import com.github.javaparser.ast.expr.NameExpr; import com.github.javaparser.ast.type.ClassOrInterfaceType; import com.github.javaparser.ast.type.ReferenceType; import com.github.javaparser.ast.type.Type; +import com.lambdaworks.redis.internal.LettuceSets; /** * Create async API based on the templates. @@ -43,8 +42,8 @@ @RunWith(Parameterized.class) public class CreateAsyncApi { - private Set KEEP_METHOD_RESULT_TYPE = LettuceSets.unmodifiableSet("shutdown", "debugOom", "debugSegfault", - "digest", "close", "isOpen", "BaseRedisCommands.reset", "getStatefulConnection"); + private Set KEEP_METHOD_RESULT_TYPE = LettuceSets.unmodifiableSet("shutdown", "debugOom", "debugSegfault", "digest", + "close", "isOpen", "BaseRedisCommands.reset", "getStatefulConnection", "setAutoFlushCommands", "flushCommands"); private CompilationUnitFactory factory; diff --git a/src/test/java/com/lambdaworks/apigenerator/CreateAsyncNodeSelectionClusterApi.java b/src/test/java/com/lambdaworks/apigenerator/CreateAsyncNodeSelectionClusterApi.java index 507e4ddd98..571d6f0aa2 100644 --- a/src/test/java/com/lambdaworks/apigenerator/CreateAsyncNodeSelectionClusterApi.java +++ b/src/test/java/com/lambdaworks/apigenerator/CreateAsyncNodeSelectionClusterApi.java @@ -16,12 +16,14 @@ package com.lambdaworks.apigenerator; import java.io.File; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Set; import java.util.function.Function; import java.util.function.Predicate; import java.util.function.Supplier; -import com.lambdaworks.redis.internal.LettuceSets; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -31,6 +33,7 @@ import com.github.javaparser.ast.type.ClassOrInterfaceType; import com.github.javaparser.ast.type.ReferenceType; import com.github.javaparser.ast.type.Type; +import com.lambdaworks.redis.internal.LettuceSets; /** * Create async API based on the templates. @@ -40,8 +43,8 @@ @RunWith(Parameterized.class) public class CreateAsyncNodeSelectionClusterApi { - private Set FILTER_METHODS = LettuceSets.unmodifiableSet("shutdown", "debugOom", "debugSegfault", "digest", - "close", "isOpen", "BaseRedisCommands.reset", "readOnly", "readWrite"); + private Set FILTER_METHODS = LettuceSets.unmodifiableSet("shutdown", "debugOom", "debugSegfault", "digest", "close", + "isOpen", "BaseRedisCommands.reset", "readOnly", "readWrite", "setAutoFlushCommands", "flushCommands"); private CompilationUnitFactory factory; diff --git a/src/test/java/com/lambdaworks/apigenerator/CreateSyncNodeSelectionClusterApi.java b/src/test/java/com/lambdaworks/apigenerator/CreateSyncNodeSelectionClusterApi.java index 7487e21f2f..990c6025c1 100644 --- a/src/test/java/com/lambdaworks/apigenerator/CreateSyncNodeSelectionClusterApi.java +++ b/src/test/java/com/lambdaworks/apigenerator/CreateSyncNodeSelectionClusterApi.java @@ -44,7 +44,7 @@ public class CreateSyncNodeSelectionClusterApi { private Set FILTER_METHODS = LettuceSets.unmodifiableSet("shutdown", "debugOom", "debugSegfault", "digest", "close", - "isOpen", "BaseRedisCommands.reset", "readOnly", "readWrite", "dispatch"); + "isOpen", "BaseRedisCommands.reset", "readOnly", "readWrite", "dispatch", "setAutoFlushCommands", "flushCommands"); private CompilationUnitFactory factory; From 6636773bda25a5f30a457015015df427737e45d6 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Sat, 10 Dec 2016 15:47:44 +0100 Subject: [PATCH 087/808] Remove ExperimentalByteArrayCodec and enhance ByteArrayCodec #389 Remove ExperimentalByteArrayCodec in favor of an enhanced ByteArrayCodec. ByteArrayCodec now implements ToByteBufEncoder that writes data directly on ByteBuf. This change reduces GC pressure as ByteBuffer wrapping is no longer required. --- .../redis/codec/ByteArrayCodec.java | 39 ++++++++--- .../redis/protocol/CommandArgs.java | 49 +------------ .../lambdaworks/redis/CustomCodecTest.java | 68 +++++++++++++++---- .../redis/protocol/CommandArgsTest.java | 56 ++------------- 4 files changed, 92 insertions(+), 120 deletions(-) diff --git a/src/main/java/com/lambdaworks/redis/codec/ByteArrayCodec.java b/src/main/java/com/lambdaworks/redis/codec/ByteArrayCodec.java index ac9622a005..ace3afaf87 100644 --- a/src/main/java/com/lambdaworks/redis/codec/ByteArrayCodec.java +++ b/src/main/java/com/lambdaworks/redis/codec/ByteArrayCodec.java @@ -17,17 +17,42 @@ import java.nio.ByteBuffer; +import io.netty.buffer.ByteBuf; + /** - * A {@link RedisCodec} that uses plain byte arrays. + * A {@link RedisCodec} that uses plain byte arrays without further transformations. * * @author Mark Paluch * @since 3.3 */ -public class ByteArrayCodec implements RedisCodec { +public class ByteArrayCodec implements RedisCodec, ToByteBufEncoder { public static final ByteArrayCodec INSTANCE = new ByteArrayCodec(); private static final byte[] EMPTY = new byte[0]; + @Override + public void encodeKey(byte[] key, ByteBuf target) { + + if (key != null) { + target.writeBytes(key); + } + } + + @Override + public void encodeValue(byte[] value, ByteBuf target) { + encodeKey(value, target); + } + + @Override + public int estimateSize(Object keyOrValue) { + + if (keyOrValue == null) { + return 0; + } + + return ((byte[]) keyOrValue).length; + } + @Override public byte[] decodeKey(ByteBuffer bytes) { return getBytes(bytes); @@ -41,7 +66,7 @@ public byte[] decodeValue(ByteBuffer bytes) { @Override public ByteBuffer encodeKey(byte[] key) { - if(key == null){ + if (key == null) { return ByteBuffer.wrap(EMPTY); } @@ -50,12 +75,7 @@ public ByteBuffer encodeKey(byte[] key) { @Override public ByteBuffer encodeValue(byte[] value) { - - if(value == null){ - return ByteBuffer.wrap(EMPTY); - } - - return ByteBuffer.wrap(value); + return encodeKey(value); } private static byte[] getBytes(ByteBuffer buffer) { @@ -63,5 +83,4 @@ private static byte[] getBytes(ByteBuffer buffer) { buffer.get(b); return b; } - } diff --git a/src/main/java/com/lambdaworks/redis/protocol/CommandArgs.java b/src/main/java/com/lambdaworks/redis/protocol/CommandArgs.java index 21878cf8cf..d52c7175b6 100644 --- a/src/main/java/com/lambdaworks/redis/protocol/CommandArgs.java +++ b/src/main/java/com/lambdaworks/redis/protocol/CommandArgs.java @@ -304,7 +304,7 @@ public String toString() { * Returns a command string representation of {@link CommandArgs} with annotated key and value parameters. * * {@code args.addKey("mykey").add(2.0)} will return {@code key 2.0}. - * + * * @return the command string representation. */ public String toCommandString() { @@ -562,15 +562,10 @@ static KeyArgument of(K key, RedisCodec codec) { @Override void encode(ByteBuf target) { - if (codec == ExperimentalByteArrayCodec.INSTANCE) { - ((ExperimentalByteArrayCodec) codec).encodeKey(target, (byte[]) key); - return; - } - if (codec instanceof ToByteBufEncoder) { ToByteBufEncoder toByteBufEncoder = (ToByteBufEncoder) codec; - ByteBuf temporaryBuffer = target.alloc().buffer(toByteBufEncoder.estimateSize(key)); + ByteBuf temporaryBuffer = target.alloc().buffer(toByteBufEncoder.estimateSize(key) + 6); toByteBufEncoder.encodeKey(key, temporaryBuffer); ByteBufferArgument.writeByteBuf(target, temporaryBuffer); @@ -605,15 +600,10 @@ static ValueArgument of(V val, RedisCodec codec) { @Override void encode(ByteBuf target) { - if (codec == ExperimentalByteArrayCodec.INSTANCE) { - ((ExperimentalByteArrayCodec) codec).encodeValue(target, (byte[]) val); - return; - } - if (codec instanceof ToByteBufEncoder) { ToByteBufEncoder toByteBufEncoder = (ToByteBufEncoder) codec; - ByteBuf temporaryBuffer = target.alloc().buffer(toByteBufEncoder.estimateSize(val)); + ByteBuf temporaryBuffer = target.alloc().buffer(toByteBufEncoder.estimateSize(val) + 6); toByteBufEncoder.encodeValue(val, temporaryBuffer); ByteBufferArgument.writeByteBuf(target, temporaryBuffer); @@ -630,37 +620,4 @@ public String toString() { return String.format("value<%s>", new StringCodec().decodeValue(codec.encodeValue(val))); } } - - /** - * This codec writes directly {@code byte[]} to the target buffer without wrapping it in a {@link ByteBuffer} to reduce GC - * pressure. - */ - public static final class ExperimentalByteArrayCodec extends ByteArrayCodec { - - public static final ExperimentalByteArrayCodec INSTANCE = new ExperimentalByteArrayCodec(); - - private ExperimentalByteArrayCodec() { - - } - - public void encodeKey(ByteBuf target, byte[] key) { - - target.writeByte('$'); - - if (key == null) { - target.writeBytes("0\r\n\r\n".getBytes()); - return; - } - - IntegerArgument.writeInteger(target, key.length); - target.writeBytes(CRLF); - - target.writeBytes(key); - target.writeBytes(CRLF); - } - - public void encodeValue(ByteBuf target, byte[] value) { - encodeKey(target, value); - } - } } diff --git a/src/test/java/com/lambdaworks/redis/CustomCodecTest.java b/src/test/java/com/lambdaworks/redis/CustomCodecTest.java index c83e386585..7a1dbc9d89 100644 --- a/src/test/java/com/lambdaworks/redis/CustomCodecTest.java +++ b/src/test/java/com/lambdaworks/redis/CustomCodecTest.java @@ -26,6 +26,8 @@ import java.nio.charset.Charset; import java.util.List; +import org.junit.Test; + import com.lambdaworks.redis.api.StatefulRedisConnection; import com.lambdaworks.redis.api.sync.RedisCommands; import com.lambdaworks.redis.protocol.CommandArgs; @@ -35,6 +37,7 @@ import com.lambdaworks.redis.codec.ByteArrayCodec; import com.lambdaworks.redis.codec.CompressionCodec; import com.lambdaworks.redis.codec.RedisCodec; +import com.lambdaworks.redis.protocol.CommandArgs; /** * @author Will Glozer @@ -71,8 +74,10 @@ public void testJavaSerializerReactive() throws Exception { @Test public void testDeflateCompressedJavaSerializer() throws Exception { - RedisCommands connection = client.connect( - CompressionCodec.valueCompressor(new SerializedObjectCodec(), CompressionCodec.CompressionType.DEFLATE)).sync(); + RedisCommands connection = client + .connect( + CompressionCodec.valueCompressor(new SerializedObjectCodec(), CompressionCodec.CompressionType.DEFLATE)) + .sync(); List list = list("one", "two"); connection.set(key, list); assertThat(connection.get(key)).isEqualTo(list); @@ -82,8 +87,9 @@ public void testDeflateCompressedJavaSerializer() throws Exception { @Test public void testGzipompressedJavaSerializer() throws Exception { - RedisCommands connection = client.connect( - CompressionCodec.valueCompressor(new SerializedObjectCodec(), CompressionCodec.CompressionType.GZIP)).sync(); + RedisCommands connection = client + .connect(CompressionCodec.valueCompressor(new SerializedObjectCodec(), CompressionCodec.CompressionType.GZIP)) + .sync(); List list = list("one", "two"); connection.set(key, list); assertThat(connection.get(key)).isEqualTo(list); @@ -107,20 +113,29 @@ public void testByteCodec() throws Exception { } @Test - public void testExperimentalByteCodec() throws Exception { - RedisCommands connection = client.connect(CommandArgs.ExperimentalByteArrayCodec.INSTANCE).sync(); + public void testByteBufferCodec() throws Exception { + + RedisCommands connection = client.connect(new ByteBufferCodec()).sync(); String value = "üöäü+#"; - connection.set(key.getBytes(), value.getBytes()); - assertThat(connection.get(key.getBytes())).isEqualTo(value.getBytes()); - connection.set(key.getBytes(), null); - assertThat(connection.get(key.getBytes())).isEqualTo(new byte[0]); - List keys = connection.keys(key.getBytes()); - assertThat(keys).contains(key.getBytes()); + ByteBuffer wrap = ByteBuffer.wrap(value.getBytes()); + + connection.set(wrap, wrap); + + List keys = connection.keys(wrap); + assertThat(keys).hasSize(1); + ByteBuffer byteBuffer = keys.get(0); + byte[] bytes = new byte[byteBuffer.remaining()]; + byteBuffer.get(bytes); + + assertThat(bytes).isEqualTo(value.getBytes()); + connection.getStatefulConnection().close(); } + public class SerializedObjectCodec implements RedisCodec { + private Charset charset = Charset.forName("UTF-8"); @Override @@ -157,4 +172,33 @@ public ByteBuffer encodeValue(Object value) { } } } + + public class ByteBufferCodec implements RedisCodec { + + @Override + public ByteBuffer decodeKey(ByteBuffer bytes) { + + ByteBuffer decoupled = ByteBuffer.allocate(bytes.remaining()); + decoupled.put(bytes); + return (ByteBuffer) decoupled.flip(); + } + + @Override + public ByteBuffer decodeValue(ByteBuffer bytes) { + + ByteBuffer decoupled = ByteBuffer.allocate(bytes.remaining()); + decoupled.put(bytes); + return (ByteBuffer) decoupled.flip(); + } + + @Override + public ByteBuffer encodeKey(ByteBuffer key) { + return key.asReadOnlyBuffer(); + } + + @Override + public ByteBuffer encodeValue(ByteBuffer value) { + return value.asReadOnlyBuffer(); + } + } } diff --git a/src/test/java/com/lambdaworks/redis/protocol/CommandArgsTest.java b/src/test/java/com/lambdaworks/redis/protocol/CommandArgsTest.java index 416cef16f6..e6107131ea 100644 --- a/src/test/java/com/lambdaworks/redis/protocol/CommandArgsTest.java +++ b/src/test/java/com/lambdaworks/redis/protocol/CommandArgsTest.java @@ -20,9 +20,9 @@ import java.nio.ByteBuffer; import java.util.Arrays; -import com.lambdaworks.redis.codec.ByteArrayCodec; import org.junit.Test; +import com.lambdaworks.redis.codec.ByteArrayCodec; import com.lambdaworks.redis.codec.Utf8StringCodec; import io.netty.buffer.ByteBuf; @@ -111,56 +111,10 @@ public void addByte() throws Exception { assertThat(buffer.toString(LettuceCharsets.ASCII)).isEqualTo(expected.toString(LettuceCharsets.ASCII)); } - @Test - public void addByteUsingDirectByteCodec() throws Exception { - - CommandArgs args = new CommandArgs<>(CommandArgs.ExperimentalByteArrayCodec.INSTANCE) - .add("one".getBytes()); - - ByteBuf buffer = Unpooled.buffer(); - args.encode(buffer); - - ByteBuf expected = Unpooled.buffer(); - expected.writeBytes(("$3\r\n" + "one\r\n").getBytes()); - - assertThat(buffer.toString(LettuceCharsets.ASCII)).isEqualTo(expected.toString(LettuceCharsets.ASCII)); - } - - @Test - public void addValueUsingDirectByteCodec() throws Exception { - - CommandArgs args = new CommandArgs<>(CommandArgs.ExperimentalByteArrayCodec.INSTANCE) - .addValue("one".getBytes()); - - ByteBuf buffer = Unpooled.buffer(); - args.encode(buffer); - - ByteBuf expected = Unpooled.buffer(); - expected.writeBytes(("$3\r\n" + "one\r\n").getBytes()); - - assertThat(buffer.toString(LettuceCharsets.ASCII)).isEqualTo(expected.toString(LettuceCharsets.ASCII)); - } - - @Test - public void addKeyUsingDirectByteCodec() throws Exception { - - CommandArgs args = new CommandArgs<>(CommandArgs.ExperimentalByteArrayCodec.INSTANCE) - .addValue("one".getBytes()); - - ByteBuf buffer = Unpooled.buffer(); - args.encode(buffer); - - ByteBuf expected = Unpooled.buffer(); - expected.writeBytes(("$3\r\n" + "one\r\n").getBytes()); - - assertThat(buffer.toString(LettuceCharsets.ASCII)).isEqualTo(expected.toString(LettuceCharsets.ASCII)); - } - @Test public void addByteUsingByteCodec() throws Exception { - CommandArgs args = new CommandArgs<>(ByteArrayCodec.INSTANCE) - .add("one".getBytes()); + CommandArgs args = new CommandArgs<>(ByteArrayCodec.INSTANCE).add("one".getBytes()); ByteBuf buffer = Unpooled.buffer(); args.encode(buffer); @@ -174,8 +128,7 @@ public void addByteUsingByteCodec() throws Exception { @Test public void addValueUsingByteCodec() throws Exception { - CommandArgs args = new CommandArgs<>(ByteArrayCodec.INSTANCE) - .addValue("one".getBytes()); + CommandArgs args = new CommandArgs<>(ByteArrayCodec.INSTANCE).addValue("one".getBytes()); ByteBuf buffer = Unpooled.buffer(); args.encode(buffer); @@ -189,8 +142,7 @@ public void addValueUsingByteCodec() throws Exception { @Test public void addKeyUsingByteCodec() throws Exception { - CommandArgs args = new CommandArgs<>(ByteArrayCodec.INSTANCE) - .addValue("one".getBytes()); + CommandArgs args = new CommandArgs<>(ByteArrayCodec.INSTANCE).addValue("one".getBytes()); ByteBuf buffer = Unpooled.buffer(); args.encode(buffer); From 6bc9c7d403460c38e10cbe1e446e25ffd9880c32 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Sat, 10 Dec 2016 15:48:03 +0100 Subject: [PATCH 088/808] Mark NodeSelection API as stable #389 --- .../redis/cluster/api/async/AsyncExecutions.java | 7 +------ .../redis/cluster/api/async/AsyncNodeSelection.java | 10 +++------- .../redis/cluster/api/sync/Executions.java | 7 +------ .../redis/cluster/api/sync/NodeSelection.java | 6 ------ .../pubsub/api/async/PubSubAsyncNodeSelection.java | 12 +++--------- 5 files changed, 8 insertions(+), 34 deletions(-) diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/async/AsyncExecutions.java b/src/main/java/com/lambdaworks/redis/cluster/api/async/AsyncExecutions.java index 16ac15791e..11cf72ac69 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/async/AsyncExecutions.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/async/AsyncExecutions.java @@ -24,13 +24,8 @@ import com.lambdaworks.redis.cluster.models.partitions.RedisClusterNode; /** - * Result holder for a command that was executed asynchronously on multiple nodes. This API is subject to incompatible changes - * in a future release. The API is exempt from any compatibility guarantees made by lettuce. The current state implies nothing - * about the quality or performance of the API in question, only the fact that it is not "API-frozen." + * Result holder for a command that was executed asynchronously on multiple nodes. * - * The NodeSelection command API and its result types are a base for discussions. - * - * * @author Mark Paluch * @since 4.0 */ diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/async/AsyncNodeSelection.java b/src/main/java/com/lambdaworks/redis/cluster/api/async/AsyncNodeSelection.java index 23a2131197..c206c4ffc3 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/async/AsyncNodeSelection.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/async/AsyncNodeSelection.java @@ -19,16 +19,12 @@ import com.lambdaworks.redis.cluster.api.NodeSelectionSupport; /** - * Node selection with access to asynchronous executed commands on the set. This API is subject to incompatible changes in a - * future release. The API is exempt from any compatibility guarantees made by lettuce. The current state implies nothing about - * the quality or performance of the API in question, only the fact that it is not "API-frozen." - * - * The NodeSelection command API and its result types are a base for discussions. + * Node selection with access to asynchronous executed commands on the set. * * @author Mark Paluch * @since 4.0 */ -public interface AsyncNodeSelection extends - NodeSelectionSupport, NodeSelectionAsyncCommands> { +public interface AsyncNodeSelection + extends NodeSelectionSupport, NodeSelectionAsyncCommands> { } diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/sync/Executions.java b/src/main/java/com/lambdaworks/redis/cluster/api/sync/Executions.java index 7507441831..302b1206f2 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/sync/Executions.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/sync/Executions.java @@ -23,12 +23,7 @@ import com.lambdaworks.redis.cluster.models.partitions.RedisClusterNode; /** - * Result holder for a command that was executed synchronously on multiple nodes. This API is subject to incompatible changes in - * a future release. The API is exempt from any compatibility guarantees made by lettuce. The current state implies nothing - * about the quality or performance of the API in question, only the fact that it is not "API-frozen." - * - * The NodeSelection command API and its result types are a base for discussions. - * + * Result holder for a command that was executed synchronously on multiple nodes. * * @author Mark Paluch * @since 4.0 diff --git a/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelection.java b/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelection.java index d89d79ac5d..1f330a9449 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelection.java +++ b/src/main/java/com/lambdaworks/redis/cluster/api/sync/NodeSelection.java @@ -21,12 +21,6 @@ /** * Node selection with access to synchronous executed commands on the set. Commands are triggered concurrently to the selected * nodes and synchronized afterwards. - * - * This API is subject to incompatible changes in a future release. The API is exempt from any compatibility guarantees made by - * lettuce. The current state implies nothing about the quality or performance of the API in question, only the fact that it is - * not "API-frozen." - * - * The NodeSelection command API and its result types are a base for discussions. * * @author Mark Paluch * @since 4.0 diff --git a/src/main/java/com/lambdaworks/redis/cluster/pubsub/api/async/PubSubAsyncNodeSelection.java b/src/main/java/com/lambdaworks/redis/cluster/pubsub/api/async/PubSubAsyncNodeSelection.java index cb08366da9..6cad1ae454 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/pubsub/api/async/PubSubAsyncNodeSelection.java +++ b/src/main/java/com/lambdaworks/redis/cluster/pubsub/api/async/PubSubAsyncNodeSelection.java @@ -15,22 +15,16 @@ */ package com.lambdaworks.redis.cluster.pubsub.api.async; -import com.lambdaworks.redis.api.async.RedisAsyncCommands; import com.lambdaworks.redis.cluster.api.NodeSelectionSupport; -import com.lambdaworks.redis.cluster.api.async.NodeSelectionAsyncCommands; import com.lambdaworks.redis.pubsub.api.async.RedisPubSubAsyncCommands; /** - * Node selection with access to asynchronous executed commands on the set. This API is subject to incompatible changes in a - * future release. The API is exempt from any compatibility guarantees made by lettuce. The current state implies nothing about - * the quality or performance of the API in question, only the fact that it is not "API-frozen." - * - * The NodeSelection command API and its result types are a base for discussions. + * Node selection with access to asynchronous executed commands on the set. * * @author Mark Paluch * @since 4.4 */ -public interface PubSubAsyncNodeSelection extends - NodeSelectionSupport, NodeSelectionPubSubAsyncCommands> { +public interface PubSubAsyncNodeSelection + extends NodeSelectionSupport, NodeSelectionPubSubAsyncCommands> { } From 860cdde61ec1e081a25d20c9bf7871d6ada9882a Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Sun, 11 Dec 2016 15:33:05 +0100 Subject: [PATCH 089/808] Polishing Fix modifier order. --- src/main/java/com/lambdaworks/redis/ScanIterator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/lambdaworks/redis/ScanIterator.java b/src/main/java/com/lambdaworks/redis/ScanIterator.java index 4b59f2f327..86805619a9 100644 --- a/src/main/java/com/lambdaworks/redis/ScanIterator.java +++ b/src/main/java/com/lambdaworks/redis/ScanIterator.java @@ -38,7 +38,7 @@ * @author Mark Paluch * @since 4.4 */ -abstract public class ScanIterator implements Iterator { +public abstract class ScanIterator implements Iterator { /** * Sequentially iterate over keys in the keyspace. This method uses {@code SCAN} to perform an iterative scan. From 16982163221761f7d1ed2e19aff713a40b42bb43 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Sun, 11 Dec 2016 16:17:25 +0100 Subject: [PATCH 090/808] Decompose array parameters into single command arguments #421 Array parameters (such as varargs) are decomposed into single elements that are bound as single elements. All array types except byte arrays are decomposed. interface KeyCommands { List mget(String... keys); } commands.mget("key1", "key2") results in MGET key1 key2 --- .../redis/dynamic/ParameterBinder.java | 46 ++++++++++++++++--- .../redis/protocol/CommandArgs.java | 1 - .../CommandSegmentCommandFactoryTest.java | 42 ++++++++++------- .../redis/dynamic/ParameterBinderTest.java | 16 +++++++ .../redis/dynamic/RedisCommandsTest.java | 20 ++++++++ 5 files changed, 101 insertions(+), 24 deletions(-) diff --git a/src/main/java/com/lambdaworks/redis/dynamic/ParameterBinder.java b/src/main/java/com/lambdaworks/redis/dynamic/ParameterBinder.java index 11707fa617..77b8ee9093 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/ParameterBinder.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/ParameterBinder.java @@ -17,9 +17,8 @@ import static com.lambdaworks.redis.protocol.CommandKeyword.LIMIT; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; +import java.lang.reflect.Array; +import java.util.*; import com.lambdaworks.redis.*; import com.lambdaworks.redis.dynamic.parameter.MethodParametersAccessor; @@ -91,6 +90,15 @@ private void bind(CommandArgs args, Object argument, int index, Met return; } + if (argument instanceof byte[]) { + args.add((byte[]) argument); + return; + } + + if (argument.getClass().isArray()) { + argument = asIterable(argument); + } + if (index != -1) { if (accessor.isKey(index)) { @@ -118,12 +126,20 @@ private void bind(CommandArgs args, Object argument, int index, Met } } - if (argument instanceof String) { - args.add((String) argument); + if (argument instanceof Iterable) { + for (Object argumentElement : (Iterable) argument) { + bindArgument(args, argumentElement); + } + } else { + bindArgument(args, argument); } + } - if (argument instanceof byte[]) { - args.add((byte[]) argument); + @SuppressWarnings("unchecked") + private void bindArgument(CommandArgs args, Object argument) { + + if (argument instanceof String) { + args.add((String) argument); } if (argument instanceof Double) { @@ -247,4 +263,20 @@ private String max(Range range) { return upper.getValue().toString(); } + + private Object asIterable(Object argument) { + + if (argument.getClass().getComponentType().isPrimitive()) { + + int length = Array.getLength(argument); + + List elements = new ArrayList<>(length); + for (int i = 0; i < length; i++) { + elements.add(Array.get(argument, i)); + } + + return elements; + } + return Arrays.asList((Object[]) argument); + } } diff --git a/src/main/java/com/lambdaworks/redis/protocol/CommandArgs.java b/src/main/java/com/lambdaworks/redis/protocol/CommandArgs.java index d52c7175b6..05ea3a47a5 100644 --- a/src/main/java/com/lambdaworks/redis/protocol/CommandArgs.java +++ b/src/main/java/com/lambdaworks/redis/protocol/CommandArgs.java @@ -63,7 +63,6 @@ public class CommandArgs { private K firstKey; /** - * * @param codec Codec used to encode/decode keys and values, must not be {@literal null}. */ public CommandArgs(RedisCodec codec) { diff --git a/src/test/java/com/lambdaworks/redis/dynamic/CommandSegmentCommandFactoryTest.java b/src/test/java/com/lambdaworks/redis/dynamic/CommandSegmentCommandFactoryTest.java index b773a497b8..a7351b36f0 100644 --- a/src/test/java/com/lambdaworks/redis/dynamic/CommandSegmentCommandFactoryTest.java +++ b/src/test/java/com/lambdaworks/redis/dynamic/CommandSegmentCommandFactoryTest.java @@ -18,12 +18,11 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.fail; -import java.util.List; import java.util.concurrent.Future; import org.junit.Test; -import org.springframework.test.util.ReflectionTestUtils; +import com.lambdaworks.redis.ScanArgs; import com.lambdaworks.redis.SetArgs; import com.lambdaworks.redis.codec.ByteArrayCodec; import com.lambdaworks.redis.codec.RedisCodec; @@ -38,7 +37,6 @@ import com.lambdaworks.redis.dynamic.segment.AnnotationCommandSegmentFactory; import com.lambdaworks.redis.dynamic.segment.CommandSegmentFactory; import com.lambdaworks.redis.dynamic.support.ReflectionUtils; -import com.lambdaworks.redis.protocol.CommandArgs; import com.lambdaworks.redis.protocol.RedisCommand; /** @@ -49,7 +47,7 @@ public class CommandSegmentCommandFactoryTest { @Test public void setKeyValue() { - RedisCommand command = createCommand(createCommandMethod(Commands.class, "set", String.class, String.class), + RedisCommand command = createCommand(methodOf(Commands.class, "set", String.class, String.class), new StringCodec(), "key", "value"); assertThat(toString(command)).isEqualTo("SET key key"); @@ -58,7 +56,7 @@ public void setKeyValue() { @Test public void setKeyValueWithByteArrayCodec() { - RedisCommand command = createCommand(createCommandMethod(Commands.class, "set", String.class, String.class), + RedisCommand command = createCommand(methodOf(Commands.class, "set", String.class, String.class), new ByteArrayCodec(), "key", "value"); assertThat(toString(command)).isEqualTo("SET key value"); @@ -67,7 +65,7 @@ public void setKeyValueWithByteArrayCodec() { @Test public void setKeyValueWithHintedValue() { - RedisCommand command = createCommand(createCommandMethod(Commands.class, "set2", String.class, String.class), + RedisCommand command = createCommand(methodOf(Commands.class, "set2", String.class, String.class), new StringCodec(), "key", "value"); assertThat(toString(command)).isEqualTo("SET key value"); @@ -77,16 +75,26 @@ public void setKeyValueWithHintedValue() { public void setWithArgs() { RedisCommand command = createCommand( - createCommandMethod(Commands.class, "set", String.class, String.class, SetArgs.class), new StringCodec(), "key", - "value", SetArgs.Builder.ex(123).nx()); + methodOf(Commands.class, "set", String.class, String.class, SetArgs.class), new StringCodec(), "key", "value", + SetArgs.Builder.ex(123).nx()); assertThat(toString(command)).isEqualTo("SET key key EX 123 NX"); } + @Test + public void varargsMethodWithParameterIndexAccess() { + + RedisCommand command = createCommand( + methodOf(Commands.class, "varargsWithParamIndexes", ScanArgs.class, String[].class), new StringCodec(), + ScanArgs.Builder.limit(1), new String[] { "a", "b" }); + + assertThat(toString(command)).isEqualTo("MGET a b Q09VTlQ= 1"); + } + @Test public void clientSetname() { - RedisCommand command = createCommand(createCommandMethod(Commands.class, "clientSetname", String.class), + RedisCommand command = createCommand(methodOf(Commands.class, "clientSetname", String.class), new ByteArrayCodec(), "name"); assertThat(toString(command)).isEqualTo("CLIENT SETNAME name"); @@ -95,7 +103,7 @@ public void clientSetname() { @Test public void annotatedClientSetname() { - RedisCommand command = createCommand(createCommandMethod(Commands.class, "woohoo", String.class), + RedisCommand command = createCommand(methodOf(Commands.class, "methodWithNamedParameters", String.class), new StringCodec(), "name"); assertThat(toString(command)).isEqualTo("CLIENT SETNAME key"); @@ -105,8 +113,7 @@ public void annotatedClientSetname() { public void asyncWithTimeout() { try { - createCommand(createCommandMethod(MethodsWithTimeout.class, "async", String.class, Timeout.class), - new StringCodec()); + createCommand(methodOf(MethodsWithTimeout.class, "async", String.class, Timeout.class), new StringCodec()); fail("Missing CommandCreationException"); } catch (CommandCreationException e) { assertThat(e).hasMessageContaining("Asynchronous command methods do not support Timeout parameters"); @@ -116,11 +123,11 @@ public void asyncWithTimeout() { @Test public void syncWithTimeout() { - createCommand(createCommandMethod(MethodsWithTimeout.class, "sync", String.class, Timeout.class), new StringCodec(), - "hello", null); + createCommand(methodOf(MethodsWithTimeout.class, "sync", String.class, Timeout.class), new StringCodec(), "hello", + null); } - private CommandMethod createCommandMethod(Class commandInterface, String methodName, Class... args) { + private CommandMethod methodOf(Class commandInterface, String methodName, Class... args) { return new CommandMethod(ReflectionUtils.findMethod(commandInterface, methodName, args)); } @@ -158,7 +165,10 @@ interface Commands { boolean clientSetname(String connectionName); @Command("CLIENT SETNAME :connectionName") - boolean woohoo(@Param("connectionName") String connectionName); + boolean methodWithNamedParameters(@Param("connectionName") String connectionName); + + @Command("MGET ?1 ?0") + String varargsWithParamIndexes(ScanArgs scanArgs, String... keys); } static interface MethodsWithTimeout { diff --git a/src/test/java/com/lambdaworks/redis/dynamic/ParameterBinderTest.java b/src/test/java/com/lambdaworks/redis/dynamic/ParameterBinderTest.java index 5ba7a037e4..cc912b0bc0 100644 --- a/src/test/java/com/lambdaworks/redis/dynamic/ParameterBinderTest.java +++ b/src/test/java/com/lambdaworks/redis/dynamic/ParameterBinderTest.java @@ -57,6 +57,22 @@ public void bindsStringCorrectly() { assertThat(args.toCommandString()).isEqualTo("string"); } + @Test + public void bindsStringArrayCorrectly() { + + CommandArgs args = bind(new String[] { "arg1", "arg2" }); + + assertThat(args.toCommandString()).isEqualTo("arg1 arg2"); + } + + @Test + public void bindsIntArrayCorrectly() { + + CommandArgs args = bind(new int[] { 1, 2, 3 }); + + assertThat(args.toCommandString()).isEqualTo("1 2 3"); + } + @Test public void bindsValueCorrectly() { diff --git a/src/test/java/com/lambdaworks/redis/dynamic/RedisCommandsTest.java b/src/test/java/com/lambdaworks/redis/dynamic/RedisCommandsTest.java index 426b22eb1c..a29049354d 100644 --- a/src/test/java/com/lambdaworks/redis/dynamic/RedisCommandsTest.java +++ b/src/test/java/com/lambdaworks/redis/dynamic/RedisCommandsTest.java @@ -18,6 +18,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.fail; +import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; @@ -25,6 +26,7 @@ import org.junit.Test; import com.lambdaworks.redis.AbstractRedisClientTest; +import com.lambdaworks.redis.Value; import com.lambdaworks.redis.dynamic.annotation.Command; import com.lambdaworks.redis.dynamic.domain.Timeout; @@ -47,6 +49,21 @@ public void sync() throws Exception { assertThat(api.getAsBytes("key")).isEqualTo("value".getBytes()); } + @Test + public void mgetAsValues() throws Exception { + + redis.set(key, value); + + RedisCommandFactory factory = new RedisCommandFactory(redis.getStatefulConnection()); + + TestInterface api = factory.getCommands(TestInterface.class); + + List> values = api.mgetAsValues(key, "key2"); + assertThat(values).hasSize(2); + assertThat(values.get(0)).isEqualTo(Value.just(value)); + assertThat(values.get(1)).isEqualTo(Value.empty()); + } + @Test public void async() throws Exception { @@ -105,6 +122,9 @@ static interface TestInterface extends Commands { @Command("SET") Mono setReactive(String key, String value); + + @Command("MGET") + List> mgetAsValues(String... keys); } static interface TooFewParameters extends Commands { From e9b5623e8d8e8a03582e2735335c4b8931d88641 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Sun, 11 Dec 2016 16:23:23 +0100 Subject: [PATCH 091/808] Polishing #421 Use ProtocolKeywordArgument to render protocol keywords. Improve test names. --- .../redis/protocol/CommandArgs.java | 28 +++++++++++++++++-- .../CommandSegmentCommandFactoryTest.java | 2 +- .../redis/dynamic/ParameterBinderTest.java | 14 +++++----- .../dynamic/ReactiveTypeAdaptionTest.java | 21 ++++++++------ .../redis/dynamic/RedisCommandsTest.java | 10 +++---- 5 files changed, 52 insertions(+), 23 deletions(-) diff --git a/src/main/java/com/lambdaworks/redis/protocol/CommandArgs.java b/src/main/java/com/lambdaworks/redis/protocol/CommandArgs.java index 05ea3a47a5..bdcbca1e67 100644 --- a/src/main/java/com/lambdaworks/redis/protocol/CommandArgs.java +++ b/src/main/java/com/lambdaworks/redis/protocol/CommandArgs.java @@ -22,7 +22,6 @@ import java.util.Map; import com.lambdaworks.redis.LettuceStrings; -import com.lambdaworks.redis.codec.ByteArrayCodec; import com.lambdaworks.redis.codec.RedisCodec; import com.lambdaworks.redis.codec.StringCodec; import com.lambdaworks.redis.codec.ToByteBufEncoder; @@ -277,7 +276,9 @@ public CommandArgs add(CommandType type) { public CommandArgs add(ProtocolKeyword keyword) { LettuceAssert.notNull(keyword, "CommandKeyword must not be null"); - return add(keyword.getBytes()); + + singularArguments.add(ProtocolKeywordArgument.of(keyword)); + return this; } @Override @@ -371,6 +372,29 @@ static abstract class SingularArgument { abstract void encode(ByteBuf buffer); } + static class ProtocolKeywordArgument extends SingularArgument { + + final ProtocolKeyword protocolKeyword; + + private ProtocolKeywordArgument(ProtocolKeyword protocolKeyword) { + this.protocolKeyword = protocolKeyword; + } + + static ProtocolKeywordArgument of(ProtocolKeyword val) { + return new ProtocolKeywordArgument(val); + } + + @Override + void encode(ByteBuf buffer) { + BytesArgument.writeBytes(buffer, protocolKeyword.getBytes()); + } + + @Override + public String toString() { + return protocolKeyword.name(); + } + } + static class BytesArgument extends SingularArgument { final byte[] val; diff --git a/src/test/java/com/lambdaworks/redis/dynamic/CommandSegmentCommandFactoryTest.java b/src/test/java/com/lambdaworks/redis/dynamic/CommandSegmentCommandFactoryTest.java index a7351b36f0..01e31131d0 100644 --- a/src/test/java/com/lambdaworks/redis/dynamic/CommandSegmentCommandFactoryTest.java +++ b/src/test/java/com/lambdaworks/redis/dynamic/CommandSegmentCommandFactoryTest.java @@ -88,7 +88,7 @@ public void varargsMethodWithParameterIndexAccess() { methodOf(Commands.class, "varargsWithParamIndexes", ScanArgs.class, String[].class), new StringCodec(), ScanArgs.Builder.limit(1), new String[] { "a", "b" }); - assertThat(toString(command)).isEqualTo("MGET a b Q09VTlQ= 1"); + assertThat(toString(command)).isEqualTo("MGET a b COUNT 1"); } @Test diff --git a/src/test/java/com/lambdaworks/redis/dynamic/ParameterBinderTest.java b/src/test/java/com/lambdaworks/redis/dynamic/ParameterBinderTest.java index cc912b0bc0..2fab33fb11 100644 --- a/src/test/java/com/lambdaworks/redis/dynamic/ParameterBinderTest.java +++ b/src/test/java/com/lambdaworks/redis/dynamic/ParameterBinderTest.java @@ -117,7 +117,7 @@ public void bindsLimitCorrectly() { CommandArgs args = bind(Limit.create(10, 100)); - assertThat(args.toCommandString()).isEqualTo("TElNSVQ= 10 100"); + assertThat(args.toCommandString()).isEqualTo("LIMIT 10 100"); } @Test @@ -150,7 +150,7 @@ public void rejectsStringUpperValue() { public void bindsValueRangeCorrectly() { CommandMethod commandMethod = new CommandMethod( - ReflectionUtils.findMethod(MyCommands.class, "someMethod", Range.class)); + ReflectionUtils.findMethod(MyCommands.class, "valueRange", Range.class)); CommandArgs args = bind(commandMethod, Range.from(Range.Boundary.including("lower"), Range.Boundary.excluding("upper"))); @@ -163,7 +163,7 @@ public void bindsValueRangeCorrectly() { public void bindsUnboundedValueRangeCorrectly() { CommandMethod commandMethod = new CommandMethod( - ReflectionUtils.findMethod(MyCommands.class, "someMethod", Range.class)); + ReflectionUtils.findMethod(MyCommands.class, "valueRange", Range.class)); CommandArgs args = bind(commandMethod, Range.unbounded()); @@ -184,12 +184,12 @@ public void bindsProtocolKeywordCorrectly() { CommandArgs args = bind(CommandType.LINDEX); - assertThat(args.toCommandString()).isEqualTo(Base64Utils.encodeToString("LINDEX".getBytes())); + assertThat(args.toCommandString()).isEqualTo("LINDEX"); } private CommandArgs bind(Object object) { CommandMethod commandMethod = new CommandMethod( - ReflectionUtils.findMethod(MyCommands.class, "someMethod", Object.class)); + ReflectionUtils.findMethod(MyCommands.class, "justObject", Object.class)); return bind(commandMethod, object); } @@ -205,8 +205,8 @@ private CommandArgs bind(CommandMethod commandMethod, Object obj private interface MyCommands { - void someMethod(Object object); + void justObject(Object object); - void someMethod(@com.lambdaworks.redis.dynamic.annotation.Value Range value); + void valueRange(@com.lambdaworks.redis.dynamic.annotation.Value Range value); } } diff --git a/src/test/java/com/lambdaworks/redis/dynamic/ReactiveTypeAdaptionTest.java b/src/test/java/com/lambdaworks/redis/dynamic/ReactiveTypeAdaptionTest.java index cc1f36c24c..02e129eaff 100644 --- a/src/test/java/com/lambdaworks/redis/dynamic/ReactiveTypeAdaptionTest.java +++ b/src/test/java/com/lambdaworks/redis/dynamic/ReactiveTypeAdaptionTest.java @@ -31,7 +31,8 @@ */ public class ReactiveTypeAdaptionTest extends AbstractRedisClientTest { - private TestInterface api; + private RxJava1Types rxjava1; + private RxJava2Types rxjava2; @Before public void before() throws Exception { @@ -39,51 +40,55 @@ public void before() throws Exception { redis.set(key, value); RedisCommandFactory factory = new RedisCommandFactory(redis.getStatefulConnection()); - this.api = factory.getCommands(TestInterface.class); + this.rxjava1 = factory.getCommands(RxJava1Types.class); + this.rxjava2 = factory.getCommands(RxJava2Types.class); } @Test public void rxJava1Single() throws Exception { - Single single = api.getRxJava1Single(key); + Single single = rxjava1.getRxJava1Single(key); assertThat(single.toBlocking().value()).isEqualTo(value); } @Test public void rxJava1Observable() throws Exception { - Observable observable = api.getRxJava1Observable(key); + Observable observable = rxjava1.getRxJava1Observable(key); assertThat(observable.toBlocking().last()).isEqualTo(value); } @Test public void rxJava2Single() throws Exception { - io.reactivex.Single single = api.getRxJava2Single(key); + io.reactivex.Single single = rxjava2.getRxJava2Single(key); assertThat(single.blockingGet()).isEqualTo(value); } @Test public void rxJava2Maybe() throws Exception { - io.reactivex.Maybe maybe = api.getRxJava2Maybe(key); + io.reactivex.Maybe maybe = rxjava2.getRxJava2Maybe(key); assertThat(maybe.blockingGet()).isEqualTo(value); } @Test public void rxJava2Observable() throws Exception { - io.reactivex.Observable observable = api.getRxJava2Observable(key); + io.reactivex.Observable observable = rxjava2.getRxJava2Observable(key); assertThat(observable.blockingFirst()).isEqualTo(value); } - static interface TestInterface extends Commands { + static interface RxJava1Types extends Commands { @Command("GET") Single getRxJava1Single(String key); @Command("GET") Observable getRxJava1Observable(String key); + } + + static interface RxJava2Types extends Commands { @Command("GET") io.reactivex.Single getRxJava2Single(String key); diff --git a/src/test/java/com/lambdaworks/redis/dynamic/RedisCommandsTest.java b/src/test/java/com/lambdaworks/redis/dynamic/RedisCommandsTest.java index a29049354d..06357ee7ca 100644 --- a/src/test/java/com/lambdaworks/redis/dynamic/RedisCommandsTest.java +++ b/src/test/java/com/lambdaworks/redis/dynamic/RedisCommandsTest.java @@ -42,7 +42,7 @@ public void sync() throws Exception { RedisCommandFactory factory = new RedisCommandFactory(redis.getStatefulConnection()); - TestInterface api = factory.getCommands(TestInterface.class); + MultipleExecutionModels api = factory.getCommands(MultipleExecutionModels.class); api.setSync(key, value, Timeout.create(10, TimeUnit.SECONDS)); assertThat(api.get("key")).isEqualTo("value"); @@ -56,7 +56,7 @@ public void mgetAsValues() throws Exception { RedisCommandFactory factory = new RedisCommandFactory(redis.getStatefulConnection()); - TestInterface api = factory.getCommands(TestInterface.class); + MultipleExecutionModels api = factory.getCommands(MultipleExecutionModels.class); List> values = api.mgetAsValues(key, "key2"); assertThat(values).hasSize(2); @@ -69,7 +69,7 @@ public void async() throws Exception { RedisCommandFactory factory = new RedisCommandFactory(redis.getStatefulConnection()); - TestInterface api = factory.getCommands(TestInterface.class); + MultipleExecutionModels api = factory.getCommands(MultipleExecutionModels.class); Future set = api.set(key, value); assertThat(set).isInstanceOf(CompletableFuture.class); @@ -81,7 +81,7 @@ public void reactive() throws Exception { RedisCommandFactory factory = new RedisCommandFactory(redis.getStatefulConnection()); - TestInterface api = factory.getCommands(TestInterface.class); + MultipleExecutionModels api = factory.getCommands(MultipleExecutionModels.class); Mono set = api.setReactive(key, value); assertThat(set.block()).isEqualTo("OK"); @@ -108,7 +108,7 @@ public void verifierShouldCatchBuggyDeclarations() throws Exception { } - static interface TestInterface extends Commands { + static interface MultipleExecutionModels extends Commands { String get(String key); From 91ae55e41b6160cdb0404110f6ba8a0cae4a4c9e Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Sun, 11 Dec 2016 16:40:09 +0100 Subject: [PATCH 092/808] Synchronize KeyValueStreamingAdapter Add synchronization to prevent element loss during concurrent access --- .../java/com/lambdaworks/redis/KeyValueStreamingAdapter.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/test/java/com/lambdaworks/redis/KeyValueStreamingAdapter.java b/src/test/java/com/lambdaworks/redis/KeyValueStreamingAdapter.java index 463cbb59ea..038cb6a7c1 100644 --- a/src/test/java/com/lambdaworks/redis/KeyValueStreamingAdapter.java +++ b/src/test/java/com/lambdaworks/redis/KeyValueStreamingAdapter.java @@ -35,7 +35,10 @@ public class KeyValueStreamingAdapter implements KeyValueStreamingChannel< @Override public void onKeyValue(K key, V value) { - map.put(key, value); + + synchronized (map) { + map.put(key, value); + } } public Map getMap() { From 8fd306bfc34042a43c6cbed6830de355bbb478a4 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Sun, 11 Dec 2016 16:49:54 +0100 Subject: [PATCH 093/808] Add missing JavaDoc #421 --- pom.xml | 2 +- .../com/lambdaworks/redis/ScanIterator.java | 17 +++++++++++++++++ .../api/async/RedisServerAsyncCommands.java | 4 ---- .../reactive/RedisServerReactiveCommands.java | 1 + .../redis/api/sync/RedisServerCommands.java | 4 ---- .../redis/cluster/RedisClusterClient.java | 1 + .../pubsub/RedisClusterPubSubListener.java | 13 +++++++++---- .../redis/dynamic/RedisCommandFactory.java | 1 + .../dynamic/output/CommandOutputFactory.java | 2 ++ 9 files changed, 32 insertions(+), 13 deletions(-) diff --git a/pom.xml b/pom.xml index 37f350fe91..eae715420e 100644 --- a/pom.xml +++ b/pom.xml @@ -518,7 +518,7 @@ http://commons.apache.org/proper/commons-pool/api-2.4.2/ https://docs.oracle.com/javase/8/docs/api/ - -Xdoclint:all -Xdoclint:-html -Xdoclint:-syntax + -Xdoclint:all -Xdoclint:-html -Xdoclint:-syntax -Xdoclint:-missing generated diff --git a/src/main/java/com/lambdaworks/redis/ScanIterator.java b/src/main/java/com/lambdaworks/redis/ScanIterator.java index 86805619a9..cf306af142 100644 --- a/src/main/java/com/lambdaworks/redis/ScanIterator.java +++ b/src/main/java/com/lambdaworks/redis/ScanIterator.java @@ -35,6 +35,7 @@ * ({@code ZSCAN}), and hashes ({@code HSCAN}). A {@link ScanIterator} is stateful and not thread-safe. Instances can be used * only once to iterate over results. * + * @param Element type * @author Mark Paluch * @since 4.4 */ @@ -44,6 +45,8 @@ public abstract class ScanIterator implements Iterator { * Sequentially iterate over keys in the keyspace. This method uses {@code SCAN} to perform an iterative scan. * * @param commands the commands interface, must not be {@literal null}. + * @param Key type. + * @param Value type. * @return a new {@link ScanIterator}. */ public static ScanIterator scan(RedisKeyCommands commands) { @@ -55,6 +58,8 @@ public static ScanIterator scan(RedisKeyCommands commands) { * * @param commands the commands interface, must not be {@literal null}. * @param scanArgs the scan arguments, must not be {@literal null}. + * @param Key type. + * @param Value type. * @return a new {@link ScanIterator}. */ public static ScanIterator scan(RedisKeyCommands commands, ScanArgs scanArgs) { @@ -95,6 +100,8 @@ private KeyScanCursor getNextScanCursor(ScanCursor scanCursor) { * iterative scan. * * @param commands the commands interface, must not be {@literal null}. + * @param Key type. + * @param Value type. * @return a new {@link ScanIterator}. */ public static ScanIterator> hscan(RedisHashCommands commands, K key) { @@ -107,6 +114,8 @@ public static ScanIterator> hscan(RedisHashCommands * * @param commands the commands interface, must not be {@literal null}. * @param scanArgs the scan arguments, must not be {@literal null}. + * @param Key type. + * @param Value type. * @return a new {@link ScanIterator}. */ public static ScanIterator> hscan(RedisHashCommands commands, K key, ScanArgs scanArgs) { @@ -149,6 +158,8 @@ private MapScanCursor getNextScanCursor(ScanCursor scanCursor) { * iterative scan. * * @param commands the commands interface, must not be {@literal null}. + * @param Key type. + * @param Value type. * @return a new {@link ScanIterator}. */ public static ScanIterator sscan(RedisSetCommands commands, K key) { @@ -161,6 +172,8 @@ public static ScanIterator sscan(RedisSetCommands commands, K ke * * @param commands the commands interface, must not be {@literal null}. * @param scanArgs the scan arguments, must not be {@literal null}. + * @param Key type. + * @param Value type. * @return a new {@link ScanIterator}. */ public static ScanIterator sscan(RedisSetCommands commands, K key, ScanArgs scanArgs) { @@ -202,6 +215,8 @@ private ValueScanCursor getNextScanCursor(ScanCursor scanCursor) { * perform an iterative scan. * * @param commands the commands interface, must not be {@literal null}. + * @param Key type. + * @param Value type. * @return a new {@link ScanIterator}. */ public static ScanIterator> zscan(RedisSortedSetCommands commands, K key) { @@ -214,6 +229,8 @@ public static ScanIterator> zscan(RedisSortedSetCommands Key type. + * @param Value type. * @return a new {@link ScanIterator}. */ public static ScanIterator> zscan(RedisSortedSetCommands commands, K key, ScanArgs scanArgs) { diff --git a/src/main/java/com/lambdaworks/redis/api/async/RedisServerAsyncCommands.java b/src/main/java/com/lambdaworks/redis/api/async/RedisServerAsyncCommands.java index 17da5436bd..af87fe4b33 100644 --- a/src/main/java/com/lambdaworks/redis/api/async/RedisServerAsyncCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/async/RedisServerAsyncCommands.java @@ -188,15 +188,11 @@ public interface RedisServerAsyncCommands { /** * Make the server crash: Out of memory. - * - * @return nothing, because the server crashes before returning. */ void debugOom(); /** * Make the server crash: Invalid pointer access. - * - * @return nothing, because the server crashes before returning. */ void debugSegfault(); diff --git a/src/main/java/com/lambdaworks/redis/api/reactive/RedisServerReactiveCommands.java b/src/main/java/com/lambdaworks/redis/api/reactive/RedisServerReactiveCommands.java index 6169fac93e..67c8b0bb09 100644 --- a/src/main/java/com/lambdaworks/redis/api/reactive/RedisServerReactiveCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/reactive/RedisServerReactiveCommands.java @@ -284,6 +284,7 @@ public interface RedisServerReactiveCommands { * Synchronously save the dataset to disk and then shut down the server. * * @param save {@literal true} force save operation + * @return String simple-string-reply The commands returns OK on success. */ Mono shutdown(boolean save); diff --git a/src/main/java/com/lambdaworks/redis/api/sync/RedisServerCommands.java b/src/main/java/com/lambdaworks/redis/api/sync/RedisServerCommands.java index 1f7a4a021e..6adcfe2137 100644 --- a/src/main/java/com/lambdaworks/redis/api/sync/RedisServerCommands.java +++ b/src/main/java/com/lambdaworks/redis/api/sync/RedisServerCommands.java @@ -187,15 +187,11 @@ public interface RedisServerCommands { /** * Make the server crash: Out of memory. - * - * @return nothing, because the server crashes before returning. */ void debugOom(); /** * Make the server crash: Invalid pointer access. - * - * @return nothing, because the server crashes before returning. */ void debugSegfault(); diff --git a/src/main/java/com/lambdaworks/redis/cluster/RedisClusterClient.java b/src/main/java/com/lambdaworks/redis/cluster/RedisClusterClient.java index 229e268770..d6e8f71bbc 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/RedisClusterClient.java +++ b/src/main/java/com/lambdaworks/redis/cluster/RedisClusterClient.java @@ -896,6 +896,7 @@ protected void forEachClusterPubSubConnection(Consumer * @param function the {@link Consumer}. */ @SuppressWarnings("unchecked") diff --git a/src/main/java/com/lambdaworks/redis/cluster/pubsub/RedisClusterPubSubListener.java b/src/main/java/com/lambdaworks/redis/cluster/pubsub/RedisClusterPubSubListener.java index b3ab77f8c8..5479c94717 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/pubsub/RedisClusterPubSubListener.java +++ b/src/main/java/com/lambdaworks/redis/cluster/pubsub/RedisClusterPubSubListener.java @@ -30,6 +30,7 @@ public interface RedisClusterPubSubListener { /** * Message received from a channel subscription. * + * @param node the {@link RedisClusterNode} where the {@literal message} originates. * @param channel Channel. * @param message Message. */ @@ -37,7 +38,8 @@ public interface RedisClusterPubSubListener { /** * Message received from a pattern subscription. - * + * + * @param node the {@link RedisClusterNode} where the {@literal message} originates. * @param pattern Pattern * @param channel Channel * @param message Message @@ -46,7 +48,8 @@ public interface RedisClusterPubSubListener { /** * Subscribed to a channel. - * + * + * @param node the {@link RedisClusterNode} where the {@literal message} originates. * @param channel Channel * @param count Subscription count. */ @@ -62,7 +65,8 @@ public interface RedisClusterPubSubListener { /** * Unsubscribed from a channel. - * + * + * @param node the {@link RedisClusterNode} where the {@literal message} originates. * @param channel Channel * @param count Subscription count. */ @@ -70,7 +74,8 @@ public interface RedisClusterPubSubListener { /** * Unsubscribed from a pattern. - * + * + * @param node the {@link RedisClusterNode} where the {@literal message} originates. * @param pattern Channel * @param count Subscription count. */ diff --git a/src/main/java/com/lambdaworks/redis/dynamic/RedisCommandFactory.java b/src/main/java/com/lambdaworks/redis/dynamic/RedisCommandFactory.java index 4c61cac856..aa69f0d7ac 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/RedisCommandFactory.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/RedisCommandFactory.java @@ -177,6 +177,7 @@ public void setVerifyCommandMethods(boolean verifyCommandMethods) { * Returns a Redis Command instance for the given interface. * * @param commandInterface must not be {@literal null}. + * @param command interface type. * @return the implemented Redis Commands interface. */ public T getCommands(Class commandInterface) { diff --git a/src/main/java/com/lambdaworks/redis/dynamic/output/CommandOutputFactory.java b/src/main/java/com/lambdaworks/redis/dynamic/output/CommandOutputFactory.java index ca6c55ed22..a53d1eb5b1 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/output/CommandOutputFactory.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/output/CommandOutputFactory.java @@ -33,6 +33,8 @@ public interface CommandOutputFactory { * Create and initialize a new {@link CommandOutput} given {@link RedisCodec}. * * @param codec must not be {@literal null}. + * @param Key type. + * @param Value type. * @return the new {@link CommandOutput}. */ CommandOutput create(RedisCodec codec); From a0f63ed0ff15fc396133a57d12c6c576796916ab Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Mon, 12 Dec 2016 20:18:14 +0100 Subject: [PATCH 094/808] Polishing Split executionmodel-specific tests. --- .../dynamic/CommandMethodVerifierTest.java | 8 +- .../CommandSegmentCommandFactoryTest.java | 3 +- .../redis/dynamic/ConversionServiceTest.java | 2 +- .../redis/dynamic/RedisCommandsAsyncTest.java | 47 ++++++++++ .../dynamic/RedisCommandsReactiveTest.java | 47 ++++++++++ .../redis/dynamic/RedisCommandsSyncTest.java | 76 ++++++++++++++++ .../redis/dynamic/RedisCommandsTest.java | 88 ++----------------- .../AnnotationCommandSegmentFactoryTest.java | 1 - 8 files changed, 185 insertions(+), 87 deletions(-) create mode 100644 src/test/java/com/lambdaworks/redis/dynamic/RedisCommandsAsyncTest.java create mode 100644 src/test/java/com/lambdaworks/redis/dynamic/RedisCommandsReactiveTest.java create mode 100644 src/test/java/com/lambdaworks/redis/dynamic/RedisCommandsSyncTest.java diff --git a/src/test/java/com/lambdaworks/redis/dynamic/CommandMethodVerifierTest.java b/src/test/java/com/lambdaworks/redis/dynamic/CommandMethodVerifierTest.java index 789d2fe3bb..4e5b7f261c 100644 --- a/src/test/java/com/lambdaworks/redis/dynamic/CommandMethodVerifierTest.java +++ b/src/test/java/com/lambdaworks/redis/dynamic/CommandMethodVerifierTest.java @@ -19,13 +19,13 @@ import static org.assertj.core.api.Fail.fail; import java.lang.reflect.Method; -import java.util.Arrays; +import java.util.Collections; -import com.lambdaworks.redis.GeoCoordinates; -import com.lambdaworks.redis.KeyValue; import org.junit.Before; import org.junit.Test; +import com.lambdaworks.redis.GeoCoordinates; +import com.lambdaworks.redis.KeyValue; import com.lambdaworks.redis.dynamic.segment.CommandSegment; import com.lambdaworks.redis.dynamic.segment.CommandSegments; import com.lambdaworks.redis.dynamic.support.ReflectionUtils; @@ -111,7 +111,7 @@ private void validateMethod(String methodName, Class... parameterTypes) { Method method = ReflectionUtils.findMethod(MyInterface.class, methodName, parameterTypes); CommandMethod commandMethod = new CommandMethod(method); - sut.validate(new CommandSegments(Arrays.asList(CommandSegment.constant(methodName))), commandMethod); + sut.validate(new CommandSegments(Collections.singletonList(CommandSegment.constant(methodName))), commandMethod); } static interface MyInterface { diff --git a/src/test/java/com/lambdaworks/redis/dynamic/CommandSegmentCommandFactoryTest.java b/src/test/java/com/lambdaworks/redis/dynamic/CommandSegmentCommandFactoryTest.java index 01e31131d0..6fca07596d 100644 --- a/src/test/java/com/lambdaworks/redis/dynamic/CommandSegmentCommandFactoryTest.java +++ b/src/test/java/com/lambdaworks/redis/dynamic/CommandSegmentCommandFactoryTest.java @@ -131,13 +131,14 @@ private CommandMethod methodOf(Class commandInterface, String methodName, Cla return new CommandMethod(ReflectionUtils.findMethod(commandInterface, methodName, args)); } + @SuppressWarnings("unchecked") private RedisCommand createCommand(CommandMethod commandMethod, RedisCodec codec, Object... args) { CommandSegmentFactory segmentFactory = new AnnotationCommandSegmentFactory(); CodecAwareOutputFactoryResolver outputFactoryResolver = new CodecAwareOutputFactoryResolver( new OutputRegistryCommandOutputFactoryResolver(new OutputRegistry()), codec); CommandSegmentCommandFactory factory = new CommandSegmentCommandFactory( - segmentFactory.createCommandSegments(commandMethod), commandMethod, (RedisCodec) codec, outputFactoryResolver); + segmentFactory.createCommandSegments(commandMethod), commandMethod, codec, outputFactoryResolver); return factory.createCommand(args); } diff --git a/src/test/java/com/lambdaworks/redis/dynamic/ConversionServiceTest.java b/src/test/java/com/lambdaworks/redis/dynamic/ConversionServiceTest.java index 2e520306fd..8be5e8dc55 100644 --- a/src/test/java/com/lambdaworks/redis/dynamic/ConversionServiceTest.java +++ b/src/test/java/com/lambdaworks/redis/dynamic/ConversionServiceTest.java @@ -31,7 +31,7 @@ */ public class ConversionServiceTest { - ConversionService sut = new ConversionService(); + private ConversionService sut = new ConversionService(); @Test public void getConverter() { diff --git a/src/test/java/com/lambdaworks/redis/dynamic/RedisCommandsAsyncTest.java b/src/test/java/com/lambdaworks/redis/dynamic/RedisCommandsAsyncTest.java new file mode 100644 index 0000000000..b35021bdb5 --- /dev/null +++ b/src/test/java/com/lambdaworks/redis/dynamic/RedisCommandsAsyncTest.java @@ -0,0 +1,47 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.lambdaworks.redis.dynamic; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Future; + +import org.junit.Test; + +import com.lambdaworks.redis.AbstractRedisClientTest; + +/** + * @author Mark Paluch + */ +public class RedisCommandsAsyncTest extends AbstractRedisClientTest { + + @Test + public void async() throws Exception { + + RedisCommandFactory factory = new RedisCommandFactory(redis.getStatefulConnection()); + + MultipleExecutionModels api = factory.getCommands(MultipleExecutionModels.class); + + Future set = api.set(key, value); + assertThat(set).isInstanceOf(CompletableFuture.class); + set.get(); + } + + static interface MultipleExecutionModels extends Commands { + Future set(String key, String value); + } +} diff --git a/src/test/java/com/lambdaworks/redis/dynamic/RedisCommandsReactiveTest.java b/src/test/java/com/lambdaworks/redis/dynamic/RedisCommandsReactiveTest.java new file mode 100644 index 0000000000..a168d14915 --- /dev/null +++ b/src/test/java/com/lambdaworks/redis/dynamic/RedisCommandsReactiveTest.java @@ -0,0 +1,47 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.lambdaworks.redis.dynamic; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.Test; + +import com.lambdaworks.redis.AbstractRedisClientTest; +import com.lambdaworks.redis.dynamic.annotation.Command; + +import reactor.core.publisher.Mono; + +/** + * @author Mark Paluch + */ +public class RedisCommandsReactiveTest extends AbstractRedisClientTest { + + @Test + public void reactive() throws Exception { + + RedisCommandFactory factory = new RedisCommandFactory(redis.getStatefulConnection()); + + MultipleExecutionModels api = factory.getCommands(MultipleExecutionModels.class); + + Mono set = api.setReactive(key, value); + assertThat(set.block()).isEqualTo("OK"); + } + + static interface MultipleExecutionModels extends Commands { + @Command("SET") + Mono setReactive(String key, String value); + } +} diff --git a/src/test/java/com/lambdaworks/redis/dynamic/RedisCommandsSyncTest.java b/src/test/java/com/lambdaworks/redis/dynamic/RedisCommandsSyncTest.java new file mode 100644 index 0000000000..efc16a4616 --- /dev/null +++ b/src/test/java/com/lambdaworks/redis/dynamic/RedisCommandsSyncTest.java @@ -0,0 +1,76 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.lambdaworks.redis.dynamic; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.List; +import java.util.concurrent.TimeUnit; + +import org.junit.Test; + +import com.lambdaworks.redis.AbstractRedisClientTest; +import com.lambdaworks.redis.Value; +import com.lambdaworks.redis.dynamic.annotation.Command; +import com.lambdaworks.redis.dynamic.domain.Timeout; + +/** + * @author Mark Paluch + */ +public class RedisCommandsSyncTest extends AbstractRedisClientTest { + + @Test + public void sync() throws Exception { + + RedisCommandFactory factory = new RedisCommandFactory(redis.getStatefulConnection()); + + MultipleExecutionModels api = factory.getCommands(MultipleExecutionModels.class); + + api.setSync(key, value, Timeout.create(10, TimeUnit.SECONDS)); + assertThat(api.get("key")).isEqualTo("value"); + assertThat(api.getAsBytes("key")).isEqualTo("value".getBytes()); + } + + @Test + public void mgetAsValues() throws Exception { + + redis.set(key, value); + + RedisCommandFactory factory = new RedisCommandFactory(redis.getStatefulConnection()); + + MultipleExecutionModels api = factory.getCommands(MultipleExecutionModels.class); + + List> values = api.mgetAsValues(key, "key2"); + assertThat(values).hasSize(2); + assertThat(values.get(0)).isEqualTo(Value.just(value)); + assertThat(values.get(1)).isEqualTo(Value.empty()); + } + + static interface MultipleExecutionModels extends Commands { + + String get(String key); + + @Command("GET") + byte[] getAsBytes(String key); + + @Command("SET") + String setSync(String key, String value, Timeout timeout); + + @Command("MGET") + List> mgetAsValues(String... keys); + } + +} diff --git a/src/test/java/com/lambdaworks/redis/dynamic/RedisCommandsTest.java b/src/test/java/com/lambdaworks/redis/dynamic/RedisCommandsTest.java index 06357ee7ca..9d30c2831d 100644 --- a/src/test/java/com/lambdaworks/redis/dynamic/RedisCommandsTest.java +++ b/src/test/java/com/lambdaworks/redis/dynamic/RedisCommandsTest.java @@ -18,19 +18,9 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.fail; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; - import org.junit.Test; import com.lambdaworks.redis.AbstractRedisClientTest; -import com.lambdaworks.redis.Value; -import com.lambdaworks.redis.dynamic.annotation.Command; -import com.lambdaworks.redis.dynamic.domain.Timeout; - -import reactor.core.publisher.Mono; /** * @author Mark Paluch @@ -38,57 +28,21 @@ public class RedisCommandsTest extends AbstractRedisClientTest { @Test - public void sync() throws Exception { - - RedisCommandFactory factory = new RedisCommandFactory(redis.getStatefulConnection()); - - MultipleExecutionModels api = factory.getCommands(MultipleExecutionModels.class); - - api.setSync(key, value, Timeout.create(10, TimeUnit.SECONDS)); - assertThat(api.get("key")).isEqualTo("value"); - assertThat(api.getAsBytes("key")).isEqualTo("value".getBytes()); - } - - @Test - public void mgetAsValues() throws Exception { - - redis.set(key, value); + public void verifierShouldCatchMisspelledDeclarations() throws Exception { RedisCommandFactory factory = new RedisCommandFactory(redis.getStatefulConnection()); - MultipleExecutionModels api = factory.getCommands(MultipleExecutionModels.class); - - List> values = api.mgetAsValues(key, "key2"); - assertThat(values).hasSize(2); - assertThat(values.get(0)).isEqualTo(Value.just(value)); - assertThat(values.get(1)).isEqualTo(Value.empty()); - } - - @Test - public void async() throws Exception { - - RedisCommandFactory factory = new RedisCommandFactory(redis.getStatefulConnection()); - - MultipleExecutionModels api = factory.getCommands(MultipleExecutionModels.class); - - Future set = api.set(key, value); - assertThat(set).isInstanceOf(CompletableFuture.class); - set.get(); - } - - @Test - public void reactive() throws Exception { - - RedisCommandFactory factory = new RedisCommandFactory(redis.getStatefulConnection()); - - MultipleExecutionModels api = factory.getCommands(MultipleExecutionModels.class); + try { + factory.getCommands(WithTypo.class); + fail("Missing CommandCreationException"); + } catch (CommandCreationException e) { + assertThat(e).hasMessageContaining("Command GAT does not exist."); + } - Mono set = api.setReactive(key, value); - assertThat(set.block()).isEqualTo("OK"); } @Test - public void verifierShouldCatchBuggyDeclarations() throws Exception { + public void verifierShouldCatchTooFewParametersDeclarations() throws Exception { RedisCommandFactory factory = new RedisCommandFactory(redis.getStatefulConnection()); @@ -99,32 +53,6 @@ public void verifierShouldCatchBuggyDeclarations() throws Exception { assertThat(e).hasMessageContaining("Command GET accepts 1 parameters but method declares 0 parameter"); } - try { - factory.getCommands(WithTypo.class); - fail("Missing CommandCreationException"); - } catch (CommandCreationException e) { - assertThat(e).hasMessageContaining("Command GAT does not exist."); - } - - } - - static interface MultipleExecutionModels extends Commands { - - String get(String key); - - @Command("GET") - byte[] getAsBytes(String key); - - @Command("SET") - String setSync(String key, String value, Timeout timeout); - - Future set(String key, String value); - - @Command("SET") - Mono setReactive(String key, String value); - - @Command("MGET") - List> mgetAsValues(String... keys); } static interface TooFewParameters extends Commands { diff --git a/src/test/java/com/lambdaworks/redis/dynamic/segment/AnnotationCommandSegmentFactoryTest.java b/src/test/java/com/lambdaworks/redis/dynamic/segment/AnnotationCommandSegmentFactoryTest.java index f7085678d1..fbaeda6e10 100644 --- a/src/test/java/com/lambdaworks/redis/dynamic/segment/AnnotationCommandSegmentFactoryTest.java +++ b/src/test/java/com/lambdaworks/redis/dynamic/segment/AnnotationCommandSegmentFactoryTest.java @@ -121,5 +121,4 @@ private static interface Defaulted { void clientSetname(); } - } From ab8e6122c9f476603c3c122e75499b5b607e6165 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Mon, 12 Dec 2016 20:20:06 +0100 Subject: [PATCH 095/808] Add test for RxJava2 Flowable use in dynamic API --- .../redis/dynamic/ReactiveTypeAdaptionTest.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/test/java/com/lambdaworks/redis/dynamic/ReactiveTypeAdaptionTest.java b/src/test/java/com/lambdaworks/redis/dynamic/ReactiveTypeAdaptionTest.java index 02e129eaff..63f0cadc45 100644 --- a/src/test/java/com/lambdaworks/redis/dynamic/ReactiveTypeAdaptionTest.java +++ b/src/test/java/com/lambdaworks/redis/dynamic/ReactiveTypeAdaptionTest.java @@ -79,6 +79,13 @@ public void rxJava2Observable() throws Exception { assertThat(observable.blockingFirst()).isEqualTo(value); } + @Test + public void rxJava2Flowable() throws Exception { + + io.reactivex.Flowable flowable = rxjava2.getRxJava2Flowable(key); + assertThat(flowable.blockingFirst()).isEqualTo(value); + } + static interface RxJava1Types extends Commands { @Command("GET") @@ -98,5 +105,8 @@ static interface RxJava2Types extends Commands { @Command("GET") io.reactivex.Observable getRxJava2Observable(String key); + + @Command("GET") + io.reactivex.Flowable getRxJava2Flowable(String key); } } From ae531cf2bad06c168db58d890fc3dd382fcad65c Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Mon, 12 Dec 2016 20:58:01 +0100 Subject: [PATCH 096/808] Support value ranges #384 Redis Command Interfaces support now value-typed ranges. public interface SortedSetCommands extends Commands { List zrangebylex(String key, @Value Range range); } --- .../dynamic/CommandSegmentCommandFactory.java | 2 +- .../redis/dynamic/ParameterBinder.java | 98 ++++++++++++++----- .../redis/dynamic/ParameterBinderTest.java | 6 +- 3 files changed, 75 insertions(+), 31 deletions(-) diff --git a/src/main/java/com/lambdaworks/redis/dynamic/CommandSegmentCommandFactory.java b/src/main/java/com/lambdaworks/redis/dynamic/CommandSegmentCommandFactory.java index cbd4cada03..b8df2b3987 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/CommandSegmentCommandFactory.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/CommandSegmentCommandFactory.java @@ -89,7 +89,7 @@ protected CommandOutputFactory resolveCommandOutputFactory(OutputSelector output com.lambdaworks.redis.protocol.Command command = new com.lambdaworks.redis.protocol.Command<>( this.segments.getCommandType(), output, args); - parameterBinder.bind(args, segments, parametersAccessor); + parameterBinder.bind(args, redisCodec, segments, parametersAccessor); return command; } diff --git a/src/main/java/com/lambdaworks/redis/dynamic/ParameterBinder.java b/src/main/java/com/lambdaworks/redis/dynamic/ParameterBinder.java index 77b8ee9093..84d35a5d69 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/ParameterBinder.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/ParameterBinder.java @@ -18,9 +18,11 @@ import static com.lambdaworks.redis.protocol.CommandKeyword.LIMIT; import java.lang.reflect.Array; +import java.nio.ByteBuffer; import java.util.*; import com.lambdaworks.redis.*; +import com.lambdaworks.redis.codec.RedisCodec; import com.lambdaworks.redis.dynamic.parameter.MethodParametersAccessor; import com.lambdaworks.redis.dynamic.segment.CommandSegment; import com.lambdaworks.redis.dynamic.segment.CommandSegment.ArgumentContribution; @@ -42,14 +44,14 @@ class ParameterBinder { /** * Bind {@link CommandSegments} and method parameters to {@link CommandArgs}. * - * @param args - * @param commandSegments - * @param accessor - * @param - * @param + * @param args the command arguments. + * @param codec the codec. + * @param commandSegments the command segments. + * @param accessor the parameter accessor. * @return */ - CommandArgs bind(CommandArgs args, CommandSegments commandSegments, MethodParametersAccessor accessor) { + CommandArgs bind(CommandArgs args, RedisCodec codec, CommandSegments commandSegments, + MethodParametersAccessor accessor) { int parameterCount = accessor.getParameterCount(); @@ -58,7 +60,7 @@ CommandArgs bind(CommandArgs args, CommandSegments commandSeg for (CommandSegment commandSegment : commandSegments) { ArgumentContribution argumentContribution = commandSegment.contribute(accessor); - bind(args, argumentContribution.getValue(), argumentContribution.getParameterIndex(), accessor); + bind(args, codec, argumentContribution.getValue(), argumentContribution.getParameterIndex(), accessor); eatenParameters.add(argumentContribution.getParameterIndex()); } @@ -70,7 +72,7 @@ CommandArgs bind(CommandArgs args, CommandSegments commandSeg } Object bindableValue = accessor.getBindableValue(i); - bind(args, bindableValue, i, accessor); + bind(args, codec, bindableValue, i, accessor); eatenParameters.add(i); } @@ -78,8 +80,12 @@ CommandArgs bind(CommandArgs args, CommandSegments commandSeg return args; } + /* + * Bind key/value/byte[] arguments. Other arguments are unwound, if applicable, and bound according to their type. + */ @SuppressWarnings("unchecked") - private void bind(CommandArgs args, Object argument, int index, MethodParametersAccessor accessor) { + private void bind(CommandArgs args, RedisCodec codec, Object argument, int index, + MethodParametersAccessor accessor) { if (argument == null) { @@ -114,7 +120,8 @@ private void bind(CommandArgs args, Object argument, int index, Met if (accessor.isValue(index)) { if (argument instanceof Range) { - throw new UnsupportedOperationException("Value Range is not supported."); + bindValueRange(args, codec, (Range) argument); + return; } if (argument instanceof Iterable) { @@ -135,6 +142,10 @@ private void bind(CommandArgs args, Object argument, int index, Met } } + /* + * Bind generic-handled arguments (String, ProtocolKeyword, Double, Map, Value hierarchy, Limit, Range, GeoCoordinates, + * Composite Arguments). + */ @SuppressWarnings("unchecked") private void bindArgument(CommandArgs args, Object argument) { @@ -201,21 +212,8 @@ private void bindArgument(CommandArgs args, Object argument) { if (argument instanceof Range) { - Range range = (Range) argument; - - if (range.getLower().getValue() != null && !(range.getLower().getValue() instanceof Number)) { - throw new IllegalArgumentException( - "Cannot bind non-numeric lower range value for a numeric Range. Annotate with @Value if the Range contains a value range."); - } - - if (range.getUpper().getValue() != null && !(range.getUpper().getValue() instanceof Number)) { - throw new IllegalArgumentException( - "Cannot bind non-numeric upper range value for a numeric Range. Annotate with @Value if the Range contains a value range."); - } - - args.add(min((Range) range)); - args.add(max((Range) range)); - + Range range = (Range) argument; + bindNumericRange(args, range); return; } @@ -232,7 +230,29 @@ private void bindArgument(CommandArgs args, Object argument) { } } - private String min(Range range) { + private void bindValueRange(CommandArgs args, RedisCodec codec, Range range) { + + args.add(minValue(codec, range)); + args.add(maxValue(codec, range)); + } + + private void bindNumericRange(CommandArgs args, Range range) { + + if (range.getLower().getValue() != null && !(range.getLower().getValue() instanceof Number)) { + throw new IllegalArgumentException( + "Cannot bind non-numeric lower range value for a numeric Range. Annotate with @Value if the Range contains a value range."); + } + + if (range.getUpper().getValue() != null && !(range.getUpper().getValue() instanceof Number)) { + throw new IllegalArgumentException( + "Cannot bind non-numeric upper range value for a numeric Range. Annotate with @Value if the Range contains a value range."); + } + + args.add(minNumeric(range)); + args.add(maxNumeric(range)); + } + + private String minNumeric(Range range) { Range.Boundary lower = range.getLower(); @@ -248,7 +268,7 @@ private String min(Range range) { return lower.getValue().toString(); } - private String max(Range range) { + private String maxNumeric(Range range) { Range.Boundary upper = range.getUpper(); @@ -264,6 +284,30 @@ private String max(Range range) { return upper.getValue().toString(); } + private byte[] minValue(RedisCodec codec, Range range) { + return valueRange(range.getLower(), MINUS_BYTES, codec); + } + + private byte[] maxValue(RedisCodec codec, Range range) { + return valueRange(range.getUpper(), PLUS_BYTES, codec); + } + + private byte[] valueRange(Range.Boundary boundary, byte[] unbounded, RedisCodec codec) { + + if (boundary.getValue() == null) { + return unbounded; + } + + ByteBuffer encodeValue = codec.encodeValue(boundary.getValue()); + byte[] argument = new byte[encodeValue.remaining() + 1]; + + argument[0] = (byte) (boundary.isIncluding() ? '[' : '('); + + encodeValue.get(argument, 1, argument.length - 1); + + return argument; + } + private Object asIterable(Object argument) { if (argument.getClass().getComponentType().isPrimitive()) { diff --git a/src/test/java/com/lambdaworks/redis/dynamic/ParameterBinderTest.java b/src/test/java/com/lambdaworks/redis/dynamic/ParameterBinderTest.java index 2fab33fb11..f19f7f3459 100644 --- a/src/test/java/com/lambdaworks/redis/dynamic/ParameterBinderTest.java +++ b/src/test/java/com/lambdaworks/redis/dynamic/ParameterBinderTest.java @@ -146,7 +146,7 @@ public void rejectsStringUpperValue() { bind(Range.from(Range.Boundary.including(11), Range.Boundary.excluding("hello"))); } - @Test(expected = UnsupportedOperationException.class) + @Test public void bindsValueRangeCorrectly() { CommandMethod commandMethod = new CommandMethod( @@ -159,7 +159,7 @@ public void bindsValueRangeCorrectly() { Base64Utils.encodeToString("(upper".getBytes()))); } - @Test(expected = UnsupportedOperationException.class) + @Test public void bindsUnboundedValueRangeCorrectly() { CommandMethod commandMethod = new CommandMethod( @@ -198,7 +198,7 @@ private CommandArgs bind(CommandMethod commandMethod, Object obj object); CommandArgs args = new CommandArgs<>(new StringCodec()); - binder.bind(args, segments, parametersAccessor); + binder.bind(args, StringCodec.UTF8, segments, parametersAccessor); return args; } From 41dcd208ec2f775f541254047e960b98351bb9fb Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Mon, 12 Dec 2016 22:11:18 +0100 Subject: [PATCH 097/808] Consider key/value type of parameter wrappers in codec resolution #423 Codec resolution for wrapped parameter types (such as Value, KeyValue, Map, Iterable) considers their Key/Value type. --- .../codec/AnnotationRedisCodecResolver.java | 129 +++++++++++++-- .../AnnotationRedisCodecResolverTest.java | 25 ++- .../dynamic/codec/ParameterWrappersTest.java | 147 ++++++++++++++++++ 3 files changed, 283 insertions(+), 18 deletions(-) create mode 100644 src/test/java/com/lambdaworks/redis/dynamic/codec/ParameterWrappersTest.java diff --git a/src/main/java/com/lambdaworks/redis/dynamic/codec/AnnotationRedisCodecResolver.java b/src/main/java/com/lambdaworks/redis/dynamic/codec/AnnotationRedisCodecResolver.java index cc39dc3c7c..431da9ee7c 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/codec/AnnotationRedisCodecResolver.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/codec/AnnotationRedisCodecResolver.java @@ -15,16 +15,13 @@ */ package com.lambdaworks.redis.dynamic.codec; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Set; +import java.util.*; import java.util.stream.Collectors; -import com.lambdaworks.redis.dynamic.annotation.Key; -import com.lambdaworks.redis.dynamic.annotation.Value; import com.lambdaworks.redis.codec.RedisCodec; import com.lambdaworks.redis.dynamic.CommandMethod; +import com.lambdaworks.redis.dynamic.annotation.Key; +import com.lambdaworks.redis.dynamic.annotation.Value; import com.lambdaworks.redis.dynamic.parameter.Parameter; import com.lambdaworks.redis.dynamic.support.ClassTypeInformation; import com.lambdaworks.redis.dynamic.support.TypeInformation; @@ -94,6 +91,7 @@ public AnnotationRedisCodecResolver(List> codecs) { commandMethod.getParameters().getBindableParameters().forEach(parameter -> { for (Voted> vote : votes) { + ClassTypeInformation typeInformation = ClassTypeInformation.from(vote.subject.getClass()); TypeInformation superTypeInformation = typeInformation.getSuperTypeInformation(RedisCodec.class); @@ -104,14 +102,18 @@ public AnnotationRedisCodecResolver(List> codecs) { continue; } + TypeInformation parameterType = parameter.getTypeInformation(); + TypeInformation parameterKeyType = ParameterWrappers.getKeyType(parameterType); + TypeInformation parameterValueType = ParameterWrappers.getValueType(parameterType); + TypeInformation keyType = typeArguments.get(0); TypeInformation valueType = typeArguments.get(1); - if (keyType.isAssignableFrom(parameter.getTypeInformation())) { + if (keyType.isAssignableFrom(parameterKeyType)) { vote.votes++; } - if (valueType.isAssignableFrom(parameter.getTypeInformation())) { + if (valueType.isAssignableFrom(parameterValueType)) { vote.votes++; } } @@ -173,20 +175,24 @@ public AnnotationRedisCodecResolver(List> codecs) { return null; } - private Set> findTypes(CommandMethod commandMethod, Class annotation) { + Set> findTypes(CommandMethod commandMethod, Class annotation) { - Set> types = new HashSet<>(); + Set> types = new LinkedHashSet<>(); for (Parameter parameter : commandMethod.getParameters().getBindableParameters()) { types.addAll(parameter.getAnnotations().stream() .filter(parameterAnnotation -> annotation.isAssignableFrom(parameterAnnotation.getClass())) .map(parameterAnnotation -> { - if (parameter.getTypeInformation().isCollectionLike() - && !parameter.getTypeInformation().getType().isArray()) { - return parameter.getTypeInformation().getComponentType().getType(); + + TypeInformation typeInformation = parameter.getTypeInformation(); + + if (annotation == Key.class && ParameterWrappers.hasKeyType(typeInformation)) { + TypeInformation parameterKeyType = ParameterWrappers.getKeyType(typeInformation); + return parameterKeyType.getType(); } - return parameter.getTypeInformation().getType(); + + return ParameterWrappers.getValueType(typeInformation).getType(); }).collect(Collectors.toList())); } @@ -199,7 +205,7 @@ private static class Voted implements Comparable> { private T subject; private int votes; - public Voted(T subject, int votes) { + Voted(T subject, int votes) { this.subject = subject; this.votes = votes; } @@ -209,4 +215,97 @@ public int compareTo(Voted o) { return votes - o.votes; } } + + /** + * Parameter wrapper support for types that encapsulate one or more parameter values. + */ + protected static class ParameterWrappers { + + private final static Set> WRAPPERS = new HashSet<>(); + private final static Set> WITH_KEY_TYPE = new HashSet<>(); + private final static Set> WITH_VALUE_TYPE = new HashSet<>(); + + static { + + WRAPPERS.add(com.lambdaworks.redis.Value.class); + WRAPPERS.add(com.lambdaworks.redis.KeyValue.class); + WRAPPERS.add(com.lambdaworks.redis.ScoredValue.class); + WRAPPERS.add(com.lambdaworks.redis.Range.class); + + WRAPPERS.add(List.class); + WRAPPERS.add(Collection.class); + WRAPPERS.add(Set.class); + WRAPPERS.add(Iterable.class); + WRAPPERS.add(Map.class); + + WITH_VALUE_TYPE.add(com.lambdaworks.redis.Value.class); + WITH_VALUE_TYPE.add(com.lambdaworks.redis.KeyValue.class); + WITH_KEY_TYPE.add(com.lambdaworks.redis.KeyValue.class); + WITH_VALUE_TYPE.add(com.lambdaworks.redis.ScoredValue.class); + + WITH_KEY_TYPE.add(Map.class); + WITH_VALUE_TYPE.add(Map.class); + } + + /** + * @param typeInformation must not be {@literal null}. + * @return {@literal true} if {@code parameterClass} is a parameter wrapper. + */ + public static boolean supports(TypeInformation typeInformation) { + return WRAPPERS.contains(typeInformation.getType()) + || (typeInformation.getType().isArray() && !(typeInformation.getType().equals(byte[].class))); + } + + /** + * @param typeInformation must not be {@literal null}. + * @return {@literal true} if the type has a key type variable. + */ + public static boolean hasKeyType(TypeInformation typeInformation) { + return WITH_KEY_TYPE.contains(typeInformation.getType()); + } + + /** + * @param typeInformation must not be {@literal null}. + * @return {@literal true} if the type has a value type variable. + */ + public static boolean hasValueType(TypeInformation typeInformation) { + return WITH_VALUE_TYPE.contains(typeInformation.getType()); + } + + /** + * @param typeInformation must not be {@literal null}. + * @return the key type. + */ + public static TypeInformation getKeyType(TypeInformation typeInformation) { + + if (!supports(typeInformation) || !hasKeyType(typeInformation)) { + return typeInformation; + } + + return typeInformation.getComponentType(); + } + + /** + * @param typeInformation must not be {@literal null}. + * @return the value type. + */ + public static TypeInformation getValueType(TypeInformation typeInformation) { + + if (!supports(typeInformation) || typeInformation.getComponentType() == null) { + return typeInformation; + } + + if (!hasValueType(typeInformation)) { + return typeInformation.getComponentType(); + } + + List> typeArguments = typeInformation.getTypeArguments(); + + if (hasKeyType(typeInformation)) { + return typeArguments.get(1); + } + + return typeArguments.get(0); + } + } } diff --git a/src/test/java/com/lambdaworks/redis/dynamic/codec/AnnotationRedisCodecResolverTest.java b/src/test/java/com/lambdaworks/redis/dynamic/codec/AnnotationRedisCodecResolverTest.java index 8747fdfadb..61d4f4a51c 100644 --- a/src/test/java/com/lambdaworks/redis/dynamic/codec/AnnotationRedisCodecResolverTest.java +++ b/src/test/java/com/lambdaworks/redis/dynamic/codec/AnnotationRedisCodecResolverTest.java @@ -20,15 +20,18 @@ import java.lang.reflect.Method; import java.util.Arrays; import java.util.List; +import java.util.Map; +import java.util.Set; -import com.lambdaworks.redis.dynamic.CommandMethod; import org.junit.Test; -import com.lambdaworks.redis.dynamic.annotation.Key; -import com.lambdaworks.redis.dynamic.annotation.Value; +import com.lambdaworks.redis.Range; import com.lambdaworks.redis.codec.ByteArrayCodec; import com.lambdaworks.redis.codec.RedisCodec; import com.lambdaworks.redis.codec.StringCodec; +import com.lambdaworks.redis.dynamic.CommandMethod; +import com.lambdaworks.redis.dynamic.annotation.Key; +import com.lambdaworks.redis.dynamic.annotation.Value; import com.lambdaworks.redis.dynamic.support.ReflectionUtils; /** @@ -90,7 +93,19 @@ public void resolutionShouldFail() { resolve(method); } + @Test + public void shouldDiscoverCodecTypesFromWrappers() { + + Method method = ReflectionUtils.findMethod(CommandMethods.class, "withWrappers", Range.class, + com.lambdaworks.redis.Value.class); + + Set> types = new AnnotationRedisCodecResolver(codecs).findTypes(new CommandMethod(method), Value.class); + + assertThat(types).contains(String.class, Number.class); + } + protected RedisCodec resolve(Method method) { + CommandMethod commandMethod = new CommandMethod(method); AnnotationRedisCodecResolver resolver = new AnnotationRedisCodecResolver(codecs); @@ -110,6 +125,10 @@ private static interface CommandMethods { String nothingAnnotated(String key, String value); String mixedTypes(@Key String key, @Value byte[] value); + + String withWrappers(@Value Range range, @Value com.lambdaworks.redis.Value value); + + String withMap(Map map); } } diff --git a/src/test/java/com/lambdaworks/redis/dynamic/codec/ParameterWrappersTest.java b/src/test/java/com/lambdaworks/redis/dynamic/codec/ParameterWrappersTest.java new file mode 100644 index 0000000000..4747cd283b --- /dev/null +++ b/src/test/java/com/lambdaworks/redis/dynamic/codec/ParameterWrappersTest.java @@ -0,0 +1,147 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.lambdaworks.redis.dynamic.codec; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.lang.reflect.Method; +import java.util.List; +import java.util.Map; + +import org.junit.Test; + +import com.lambdaworks.redis.KeyValue; +import com.lambdaworks.redis.Range; +import com.lambdaworks.redis.Value; +import com.lambdaworks.redis.dynamic.codec.AnnotationRedisCodecResolver.ParameterWrappers; +import com.lambdaworks.redis.dynamic.parameter.Parameter; +import com.lambdaworks.redis.dynamic.support.ReflectionUtils; +import com.lambdaworks.redis.dynamic.support.TypeInformation; + +/** + * @author Mark Paluch + */ +public class ParameterWrappersTest { + + @Test + public void shouldReturnValueTypeForRange() { + + Method method = ReflectionUtils.findMethod(CommandMethods.class, "range", Range.class); + + TypeInformation typeInformation = new Parameter(method, 0).getTypeInformation(); + + assertThat(ParameterWrappers.hasKeyType(typeInformation)).isFalse(); + assertThat(ParameterWrappers.hasValueType(typeInformation)).isFalse(); + assertThat(ParameterWrappers.supports(typeInformation)).isTrue(); + assertThat(ParameterWrappers.getValueType(typeInformation).getType()).isEqualTo(String.class); + } + + @Test + public void shouldReturnValueTypeForValue() { + + Method method = ReflectionUtils.findMethod(CommandMethods.class, "value", Value.class); + + TypeInformation typeInformation = new Parameter(method, 0).getTypeInformation(); + + assertThat(ParameterWrappers.hasKeyType(typeInformation)).isFalse(); + assertThat(ParameterWrappers.hasValueType(typeInformation)).isTrue(); + assertThat(ParameterWrappers.getValueType(typeInformation).getType()).isEqualTo(String.class); + } + + @Test + public void shouldReturnValueTypeForKeyValue() { + + Method method = ReflectionUtils.findMethod(CommandMethods.class, "keyValue", KeyValue.class); + + TypeInformation typeInformation = new Parameter(method, 0).getTypeInformation(); + + assertThat(ParameterWrappers.hasKeyType(typeInformation)).isTrue(); + assertThat(ParameterWrappers.getKeyType(typeInformation).getType()).isEqualTo(Integer.class); + + assertThat(ParameterWrappers.hasValueType(typeInformation)).isTrue(); + assertThat(ParameterWrappers.getValueType(typeInformation).getType()).isEqualTo(String.class); + } + + @Test + public void shouldReturnValueTypeForArray() { + + Method method = ReflectionUtils.findMethod(CommandMethods.class, "array", String[].class); + + TypeInformation typeInformation = new Parameter(method, 0).getTypeInformation(); + + assertThat(ParameterWrappers.hasKeyType(typeInformation)).isFalse(); + assertThat(ParameterWrappers.supports(typeInformation)).isTrue(); + assertThat(ParameterWrappers.getValueType(typeInformation).getType()).isEqualTo(String.class); + } + + @Test + public void shouldNotSupportByteArray() { + + Method method = ReflectionUtils.findMethod(CommandMethods.class, "byteArray", byte[].class); + + TypeInformation typeInformation = new Parameter(method, 0).getTypeInformation(); + + assertThat(ParameterWrappers.supports(typeInformation)).isFalse(); + } + + @Test + public void shouldReturnValueTypeForList() { + + Method method = ReflectionUtils.findMethod(CommandMethods.class, "withList", List.class); + + TypeInformation typeInformation = new Parameter(method, 0).getTypeInformation(); + + assertThat(ParameterWrappers.hasKeyType(typeInformation)).isFalse(); + + assertThat(ParameterWrappers.supports(typeInformation)).isTrue(); + assertThat(ParameterWrappers.getValueType(typeInformation).getType()).isEqualTo(String.class); + } + + @Test + public void shouldReturnValueTypeForMap() { + + Method method = ReflectionUtils.findMethod(CommandMethods.class, "withMap", Map.class); + + TypeInformation typeInformation = new Parameter(method, 0).getTypeInformation(); + + assertThat(ParameterWrappers.hasKeyType(typeInformation)).isTrue(); + assertThat(ParameterWrappers.getKeyType(typeInformation).getType()).isEqualTo(Integer.class); + + assertThat(ParameterWrappers.hasValueType(typeInformation)).isTrue(); + assertThat(ParameterWrappers.getValueType(typeInformation).getType()).isEqualTo(String.class); + } + + private static interface CommandMethods { + + String range(Range range); + + String value(Value range); + + String keyValue(KeyValue range); + + String array(String[] values); + + String byteArray(byte[] values); + + String withWrappers(Range range, com.lambdaworks.redis.Value value, + com.lambdaworks.redis.KeyValue keyValue); + + String withList(List map); + + String withMap(Map map); + } + +} \ No newline at end of file From 9e2df7c2b95abc7fa7cba8e9c4b49320af49bedb Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Mon, 12 Dec 2016 22:11:39 +0100 Subject: [PATCH 098/808] Polishing #423 --- src/main/java/com/lambdaworks/redis/LettuceFutures.java | 1 - src/main/java/com/lambdaworks/redis/LettuceStrings.java | 4 ++++ .../com/lambdaworks/redis/internal/LettuceClassUtils.java | 3 --- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/lambdaworks/redis/LettuceFutures.java b/src/main/java/com/lambdaworks/redis/LettuceFutures.java index 2aae3610c3..3478631b23 100644 --- a/src/main/java/com/lambdaworks/redis/LettuceFutures.java +++ b/src/main/java/com/lambdaworks/redis/LettuceFutures.java @@ -30,7 +30,6 @@ public class LettuceFutures { private LettuceFutures() { - } /** diff --git a/src/main/java/com/lambdaworks/redis/LettuceStrings.java b/src/main/java/com/lambdaworks/redis/LettuceStrings.java index 6a9c668157..dcf786d760 100644 --- a/src/main/java/com/lambdaworks/redis/LettuceStrings.java +++ b/src/main/java/com/lambdaworks/redis/LettuceStrings.java @@ -108,12 +108,15 @@ public static String digest(ByteBuffer script) { * @return the delimited {@code String} */ public static String arrayToDelimitedString(Object[] arr, String delim) { + if ((arr == null || arr.length == 0)) { return ""; } + if (arr.length == 1) { return "" + arr[0]; } + StringBuilder sb = new StringBuilder(); for (int i = 0; i < arr.length; i++) { if (i > 0) { @@ -140,6 +143,7 @@ public static String collectionToDelimitedString(Collection coll, String deli if (coll == null || coll.isEmpty()) { return ""; } + StringBuilder sb = new StringBuilder(); Iterator it = coll.iterator(); while (it.hasNext()) { diff --git a/src/main/java/com/lambdaworks/redis/internal/LettuceClassUtils.java b/src/main/java/com/lambdaworks/redis/internal/LettuceClassUtils.java index 80708cca51..f3b2792638 100644 --- a/src/main/java/com/lambdaworks/redis/internal/LettuceClassUtils.java +++ b/src/main/java/com/lambdaworks/redis/internal/LettuceClassUtils.java @@ -18,8 +18,6 @@ import java.util.IdentityHashMap; import java.util.Map; -import org.springframework.util.TypeUtils; - import com.lambdaworks.redis.JavaRuntime; /** @@ -143,7 +141,6 @@ private static ClassLoader getDefaultClassLoader() { * @param lhsType the target type * @param rhsType the value type that should be assigned to the target type * @return if the target type is assignable from the value type - * @see TypeUtils#isAssignable */ public static boolean isAssignable(Class lhsType, Class rhsType) { From 15ce1f9651bf04326d675e5139c5e9c9b596fbcd Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Wed, 14 Dec 2016 22:15:24 +0100 Subject: [PATCH 099/808] Return ClusterClientOptions.Builder in socketOptions and sslOptions methods #425 --- .../lambdaworks/redis/cluster/ClusterClientOptions.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/lambdaworks/redis/cluster/ClusterClientOptions.java b/src/main/java/com/lambdaworks/redis/cluster/ClusterClientOptions.java index 084b7fc5a7..6fcf2fbb33 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/ClusterClientOptions.java +++ b/src/main/java/com/lambdaworks/redis/cluster/ClusterClientOptions.java @@ -19,6 +19,7 @@ import com.lambdaworks.redis.ClientOptions; import com.lambdaworks.redis.SocketOptions; +import com.lambdaworks.redis.SslOptions; /** * Client Options to control the behavior of {@link RedisClusterClient}. @@ -183,11 +184,17 @@ public Builder disconnectedBehavior(DisconnectedBehavior disconnectedBehavior) { } @Override - public ClientOptions.Builder socketOptions(SocketOptions socketOptions) { + public Builder socketOptions(SocketOptions socketOptions) { super.socketOptions(socketOptions); return this; } + @Override + public Builder sslOptions(SslOptions sslOptions) { + super.sslOptions(sslOptions); + return this; + } + /** * Create a new instance of {@link ClusterClientOptions} * From a4655b98b6ec0fb2027167168a09f5c8d46da2be Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Sat, 17 Dec 2016 21:30:10 +0100 Subject: [PATCH 100/808] Propagate asynchronous connection initialization #429 Lettuce now connects asynchronously with a late synchronization. This allows post-connect initializations to be part of the asynchronous completion chain. NodeConnectionFactory exposes also connectToNodeAsync. --- .../redis/AbstractRedisClient.java | 411 ++++++++++++++++-- .../com/lambdaworks/redis/RedisClient.java | 33 +- .../redis/cluster/RedisClusterClient.java | 143 +++--- .../topology/NodeConnectionFactory.java | 18 +- 4 files changed, 504 insertions(+), 101 deletions(-) diff --git a/src/main/java/com/lambdaworks/redis/AbstractRedisClient.java b/src/main/java/com/lambdaworks/redis/AbstractRedisClient.java index f8d6eb0715..3a12b0ecdf 100644 --- a/src/main/java/com/lambdaworks/redis/AbstractRedisClient.java +++ b/src/main/java/com/lambdaworks/redis/AbstractRedisClient.java @@ -21,11 +21,9 @@ import java.util.List; import java.util.Map; import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; +import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.function.Supplier; +import java.util.function.*; import com.lambdaworks.redis.Transports.NativeTransports; import com.lambdaworks.redis.internal.LettuceAssert; @@ -117,7 +115,7 @@ public void setDefaultTimeout(long timeout, TimeUnit unit) { /** * Populate connection builder with necessary resources. - * + * * @param socketAddressSupplier address supplier for initial connect and re-connect * @param connectionBuilder connection builder to configure the connection * @param redisURI URI of the redis instance @@ -198,50 +196,103 @@ private void checkForEpollLibrary() { EpollProvider.checkForEpollLibrary(); } + /** + * Retrieve the connection from {@link ConnectionFuture}. Performs a blocking {@link ConnectionFuture#get()} to synchronize + * the channel/connection initialization. Any exception is rethrown as {@link RedisConnectionException}. + * + * @param connectionFuture must not be null. + * @param Connection type. + * @return the connection. + * @throws RedisConnectionException in case of connection failures. + * @since 4.4 + */ + protected T getConnection(ConnectionFuture connectionFuture) { + + String msg = String.format("Unable to connect to %s", connectionFuture.getRemoteAddress()); + + try { + return connectionFuture.get(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new RedisConnectionException(msg, e); + } catch (Exception e) { + + if (e instanceof ExecutionException) { + throw new RedisConnectionException(msg, e.getCause()); + } + + throw new RedisConnectionException(msg, e); + } + } + + /** + * Connect and initialize a channel from {@link ConnectionBuilder}. + * + * @param connectionBuilder must not be {@literal null}. + * @return the {@link ConnectionFuture} to synchronize the connection process. + * @since 4.4 + */ @SuppressWarnings("unchecked") - protected > T initializeChannel(ConnectionBuilder connectionBuilder) { + protected > ConnectionFuture initializeChannelAsync( + ConnectionBuilder connectionBuilder) { - RedisChannelHandler connection = connectionBuilder.connection(); SocketAddress redisAddress = connectionBuilder.socketAddress(); if (clientResources.eventExecutorGroup().isShuttingDown()) { - throw new IllegalStateException("Cannot connect. Worker pool not running"); + throw new IllegalStateException("Cannot connect, Event executor group is terminated."); } - try { + logger.debug("Connecting to Redis at {}", redisAddress); - logger.debug("Connecting to Redis at {}", redisAddress); + CompletableFuture channelReadyFuture = new CompletableFuture<>(); + Bootstrap redisBootstrap = connectionBuilder.bootstrap(); + RedisChannelInitializer initializer = connectionBuilder.build(); + redisBootstrap.handler(initializer); + ChannelFuture connectFuture = redisBootstrap.connect(redisAddress); - Bootstrap redisBootstrap = connectionBuilder.bootstrap(); - RedisChannelInitializer initializer = connectionBuilder.build(); - redisBootstrap.handler(initializer); - ChannelFuture connectFuture = redisBootstrap.connect(redisAddress); + connectFuture.addListener(future -> { - connectFuture.await(); + if (!future.isSuccess()) { - if (!connectFuture.isSuccess()) { - if (connectFuture.cause() instanceof Exception) { - throw (Exception) connectFuture.cause(); - } - connectFuture.get(); + logger.debug("Connecting to Redis at {}: {}", redisAddress, future.cause()); + connectionBuilder.endpoint().initialState(); + channelReadyFuture.completeExceptionally(future.cause()); + return; } - try { - initializer.channelInitialized().get(connectionBuilder.getTimeout(), connectionBuilder.getTimeUnit()); - } catch (TimeoutException e) { - throw new RedisConnectionException("Could not initialize channel within " + connectionBuilder.getTimeout() + " " - + connectionBuilder.getTimeUnit(), e); - } - connection.registerCloseables(closeableResources, connection); + CompletableFuture initFuture = (CompletableFuture) initializer.channelInitialized(); + initFuture.whenComplete((success, throwable) -> { - return (T) connection; - } catch (RedisException e) { - connectionBuilder.endpoint().initialState(); - throw e; - } catch (Exception e) { - connectionBuilder.endpoint().initialState(); - throw new RedisConnectionException("Unable to connect to " + redisAddress, e); - } + if (throwable == null) { + logger.debug("Connecting to Redis at {}: Success", redisAddress); + RedisChannelHandler connection = connectionBuilder.connection(); + connection.registerCloseables(closeableResources, connection); + channelReadyFuture.complete(connectFuture.channel()); + return; + } + + logger.debug("Connecting to Redis at {}, initialization: {}", redisAddress, throwable); + connectionBuilder.endpoint().initialState(); + Throwable failure; + + if (throwable instanceof RedisConnectionException) { + failure = throwable; + } else if (throwable instanceof TimeoutException) { + failure = new RedisConnectionException("Could not initialize channel within " + + connectionBuilder.getTimeout() + " " + connectionBuilder.getTimeUnit(), throwable); + } else { + failure = throwable; + } + channelReadyFuture.completeExceptionally(failure); + + CompletableFuture response = new CompletableFuture<>(); + response.completeExceptionally(failure); + + }); + }); + + return new ConnectionFuture(redisAddress, + channelReadyFuture.thenApply(channel -> (T) connectionBuilder.connection())); } /** @@ -362,4 +413,294 @@ protected void setOptions(ClientOptions clientOptions) { LettuceAssert.notNull(clientOptions, "ClientOptions must not be null"); this.clientOptions = clientOptions; } + + /** + * lettuce-specific connection {@link CompletableFuture future}. Delegates calls to the decorated {@link CompletableFuture} + * and provides a {@link SocketAddress}. + * + * @since 4.4 + */ + protected class ConnectionFuture extends CompletableFuture { + + private final SocketAddress remoteAddress; + private final CompletableFuture delegate; + + protected ConnectionFuture(SocketAddress remoteAddress, CompletableFuture delegate) { + + this.remoteAddress = remoteAddress; + this.delegate = delegate; + } + + public SocketAddress getRemoteAddress() { + return remoteAddress; + } + + private ConnectionFuture adopt(CompletableFuture newFuture) { + return new ConnectionFuture<>(remoteAddress, newFuture); + } + + @Override + public boolean isDone() { + return delegate.isDone(); + } + + @Override + public T get() throws InterruptedException, ExecutionException { + return delegate.get(); + } + + @Override + public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { + return delegate.get(timeout, unit); + } + + @Override + public T join() { + return delegate.join(); + } + + @Override + public T getNow(T valueIfAbsent) { + return delegate.getNow(valueIfAbsent); + } + + @Override + public boolean complete(T value) { + return delegate.complete(value); + } + + @Override + public boolean completeExceptionally(Throwable ex) { + return delegate.completeExceptionally(ex); + } + + @Override + public ConnectionFuture thenApply(Function fn) { + return adopt(delegate.thenApply(fn)); + } + + @Override + public ConnectionFuture thenApplyAsync(Function fn) { + return adopt(delegate.thenApplyAsync(fn)); + } + + @Override + public ConnectionFuture thenApplyAsync(Function fn, Executor executor) { + return adopt(delegate.thenApplyAsync(fn, executor)); + } + + @Override + public ConnectionFuture thenAccept(Consumer action) { + return adopt(delegate.thenAccept(action)); + } + + @Override + public ConnectionFuture thenAcceptAsync(Consumer action) { + return adopt(delegate.thenAcceptAsync(action)); + } + + @Override + public ConnectionFuture thenAcceptAsync(Consumer action, Executor executor) { + return adopt(delegate.thenAcceptAsync(action, executor)); + } + + @Override + public ConnectionFuture thenRun(Runnable action) { + return adopt(delegate.thenRun(action)); + } + + @Override + public ConnectionFuture thenRunAsync(Runnable action) { + return adopt(delegate.thenRunAsync(action)); + } + + @Override + public ConnectionFuture thenRunAsync(Runnable action, Executor executor) { + return adopt(delegate.thenRunAsync(action, executor)); + } + + @Override + public ConnectionFuture thenCombine(CompletionStage other, + BiFunction fn) { + return adopt(delegate.thenCombine(other, fn)); + } + + @Override + public ConnectionFuture thenCombineAsync(CompletionStage other, + BiFunction fn) { + return adopt(delegate.thenCombineAsync(other, fn)); + } + + @Override + public ConnectionFuture thenCombineAsync(CompletionStage other, + BiFunction fn, Executor executor) { + return adopt(delegate.thenCombineAsync(other, fn, executor)); + } + + @Override + public ConnectionFuture thenAcceptBoth(CompletionStage other, + BiConsumer action) { + return adopt(delegate.thenAcceptBoth(other, action)); + } + + @Override + public ConnectionFuture thenAcceptBothAsync(CompletionStage other, + BiConsumer action) { + return adopt(delegate.thenAcceptBothAsync(other, action)); + } + + @Override + public ConnectionFuture thenAcceptBothAsync(CompletionStage other, + BiConsumer action, Executor executor) { + return adopt(delegate.thenAcceptBothAsync(other, action, executor)); + } + + @Override + public ConnectionFuture runAfterBoth(CompletionStage other, Runnable action) { + return adopt(delegate.runAfterBoth(other, action)); + } + + @Override + public ConnectionFuture runAfterBothAsync(CompletionStage other, Runnable action) { + return adopt(delegate.runAfterBothAsync(other, action)); + } + + @Override + public ConnectionFuture runAfterBothAsync(CompletionStage other, Runnable action, Executor executor) { + return adopt(delegate.runAfterBothAsync(other, action, executor)); + } + + @Override + public ConnectionFuture applyToEither(CompletionStage other, Function fn) { + return adopt(delegate.applyToEither(other, fn)); + } + + @Override + public ConnectionFuture applyToEitherAsync(CompletionStage other, Function fn) { + return adopt(delegate.applyToEitherAsync(other, fn)); + } + + @Override + public ConnectionFuture applyToEitherAsync(CompletionStage other, Function fn, + Executor executor) { + return adopt(delegate.applyToEitherAsync(other, fn, executor)); + } + + @Override + public ConnectionFuture acceptEither(CompletionStage other, Consumer action) { + return adopt(delegate.acceptEither(other, action)); + } + + @Override + public ConnectionFuture acceptEitherAsync(CompletionStage other, Consumer action) { + return adopt(delegate.acceptEitherAsync(other, action)); + } + + @Override + public ConnectionFuture acceptEitherAsync(CompletionStage other, Consumer action, + Executor executor) { + return adopt(delegate.acceptEitherAsync(other, action, executor)); + } + + @Override + public ConnectionFuture runAfterEither(CompletionStage other, Runnable action) { + return adopt(delegate.runAfterEither(other, action)); + } + + @Override + public ConnectionFuture runAfterEitherAsync(CompletionStage other, Runnable action) { + return adopt(delegate.runAfterEitherAsync(other, action)); + } + + @Override + public ConnectionFuture runAfterEitherAsync(CompletionStage other, Runnable action, Executor executor) { + return adopt(delegate.runAfterEitherAsync(other, action, executor)); + } + + @Override + public ConnectionFuture thenCompose(Function> fn) { + return adopt(delegate.thenCompose(fn)); + } + + @Override + public ConnectionFuture thenComposeAsync(Function> fn) { + return adopt(delegate.thenComposeAsync(fn)); + } + + @Override + public ConnectionFuture thenComposeAsync(Function> fn, + Executor executor) { + return adopt(delegate.thenComposeAsync(fn, executor)); + } + + @Override + public ConnectionFuture whenComplete(BiConsumer action) { + return adopt(delegate.whenComplete(action)); + } + + @Override + public ConnectionFuture whenCompleteAsync(BiConsumer action) { + return adopt(delegate.whenCompleteAsync(action)); + } + + @Override + public ConnectionFuture whenCompleteAsync(BiConsumer action, Executor executor) { + return adopt(delegate.whenCompleteAsync(action, executor)); + } + + @Override + public ConnectionFuture handle(BiFunction fn) { + return adopt(delegate.handle(fn)); + } + + @Override + public ConnectionFuture handleAsync(BiFunction fn) { + return adopt(delegate.handleAsync(fn)); + } + + @Override + public ConnectionFuture handleAsync(BiFunction fn, Executor executor) { + return adopt(delegate.handleAsync(fn, executor)); + } + + @Override + public CompletableFuture toCompletableFuture() { + return delegate.toCompletableFuture(); + } + + @Override + public ConnectionFuture exceptionally(Function fn) { + return adopt(delegate.exceptionally(fn)); + } + + @Override + public boolean cancel(boolean mayInterruptIfRunning) { + return delegate.cancel(mayInterruptIfRunning); + } + + @Override + public boolean isCancelled() { + return delegate.isCancelled(); + } + + @Override + public boolean isCompletedExceptionally() { + return delegate.isCompletedExceptionally(); + } + + @Override + public void obtrudeValue(T value) { + delegate.obtrudeValue(value); + } + + @Override + public void obtrudeException(Throwable ex) { + delegate.obtrudeException(ex); + } + + @Override + public int getNumberOfDependents() { + return delegate.getNumberOfDependents(); + } + } } diff --git a/src/main/java/com/lambdaworks/redis/RedisClient.java b/src/main/java/com/lambdaworks/redis/RedisClient.java index d7647a2d2d..7d639f17a2 100644 --- a/src/main/java/com/lambdaworks/redis/RedisClient.java +++ b/src/main/java/com/lambdaworks/redis/RedisClient.java @@ -205,7 +205,7 @@ private StatefulRedisConnection connectStandalone(RedisCodec DefaultEndpoint endpoint = new DefaultEndpoint(clientOptions); - StatefulRedisConnectionImpl connection = newStatefulRedisConnection((RedisChannelWriter) endpoint, codec, + StatefulRedisConnectionImpl connection = newStatefulRedisConnection(endpoint, codec, timeout.timeout, timeout.timeUnit); connectStateful(connection, redisURI, endpoint, () -> new CommandHandler(clientResources, endpoint)); return connection; @@ -230,19 +230,38 @@ private void connectStateful(StatefulRedisConnectionImpl connection connectionBuilder(getSocketAddressSupplier(redisURI), connectionBuilder, redisURI); channelType(connectionBuilder, redisURI); - initializeChannel(connectionBuilder); + + ConnectionFuture> future = initializeChannelAsync(connectionBuilder); if (redisURI.getPassword() != null && redisURI.getPassword().length != 0) { - connection.async().auth(new String(redisURI.getPassword())); + + future = future.thenApplyAsync(channelHandler -> { + + connection.async().auth(new String(redisURI.getPassword())); + + return channelHandler; + }, clientResources.eventExecutorGroup()); } if (LettuceStrings.isNotEmpty(redisURI.getClientName())) { - connection.setClientName(redisURI.getClientName()); + future.thenApply(channelHandler -> { + connection.setClientName(redisURI.getClientName()); + return channelHandler; + }); + } if (redisURI.getDatabase() != 0) { - connection.async().select(redisURI.getDatabase()); + + future = future.thenApplyAsync(channelHandler -> { + + connection.async().select(redisURI.getDatabase()); + + return channelHandler; + }, clientResources.eventExecutorGroup()); } + + getConnection(future); } /** @@ -379,7 +398,7 @@ private StatefulRedisSentinelConnection connectSentinel(RedisCodec< if (redisURI.getSentinels().isEmpty() && (isNotEmpty(redisURI.getHost()) || !isEmpty(redisURI.getSocket()))) { channelType(connectionBuilder, redisURI); - initializeChannel(connectionBuilder); + getConnection(initializeChannelAsync(connectionBuilder)); } else { boolean connected = false; boolean first = true; @@ -397,7 +416,7 @@ private StatefulRedisSentinelConnection connectSentinel(RedisCodec< logger.debug("Connecting to Sentinel, address: " + socketAddress); } try { - initializeChannel(connectionBuilder); + getConnection(initializeChannelAsync(connectionBuilder)); connected = true; break; } catch (Exception e) { diff --git a/src/main/java/com/lambdaworks/redis/cluster/RedisClusterClient.java b/src/main/java/com/lambdaworks/redis/cluster/RedisClusterClient.java index d6e8f71bbc..e30d316a45 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/RedisClusterClient.java +++ b/src/main/java/com/lambdaworks/redis/cluster/RedisClusterClient.java @@ -19,6 +19,7 @@ import java.net.SocketAddress; import java.net.URI; import java.util.*; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; @@ -373,12 +374,7 @@ public StatefulRedisClusterPubSubConnection connectPubSub(RedisCode } protected StatefulRedisConnection connectToNode(final SocketAddress socketAddress) { - return connectToNode(newStringStringCodec(), socketAddress.toString(), null, new Supplier() { - @Override - public SocketAddress get() { - return socketAddress; - } - }); + return connectToNode(newStringStringCodec(), socketAddress.toString(), null, () -> socketAddress); } /** @@ -394,28 +390,42 @@ public SocketAddress get() { */ StatefulRedisConnection connectToNode(RedisCodec codec, String nodeId, RedisChannelWriter clusterWriter, final Supplier socketAddressSupplier) { + return getConnection(connectToNodeAsync(codec, nodeId, clusterWriter, socketAddressSupplier)); + } + + /** + * Create a connection to a redis socket address. + * + * @param codec Use this codec to encode/decode keys and values, must not be {@literal null} + * @param nodeId the nodeId + * @param clusterWriter global cluster writer + * @param socketAddressSupplier supplier for the socket address + * @param Key type + * @param Value type + * @return A new connection + */ + private ConnectionFuture> connectToNodeAsync(RedisCodec codec, String nodeId, + RedisChannelWriter clusterWriter, final Supplier socketAddressSupplier) { assertNotNull(codec); assertNotEmpty(initialUris); - LettuceAssert.notNull(socketAddressSupplier, "SocketAddressSupplier must not be null"); - logger.debug("connectNode(" + nodeId + ")"); + SocketAddress socketAddress = socketAddressSupplier.get(); + + logger.debug(String.format("connectToNodeAsync(%s at %s)", nodeId, socketAddress)); ClusterNodeEndpoint endpoint = new ClusterNodeEndpoint(clientOptions, getResources(), clusterWriter); StatefulRedisConnectionImpl connection = new StatefulRedisConnectionImpl(endpoint, codec, timeout, unit); - try { - connectStateful(connection, endpoint, getFirstUri(), socketAddressSupplier, - () -> new CommandHandler(clientResources, endpoint)); + ConnectionFuture> connectionFuture = connectStatefulAsync(connection, endpoint, + getFirstUri(), socketAddressSupplier, () -> new CommandHandler(clientResources, endpoint)); - connection.registerCloseables(closeableResources, connection); - } catch (RedisException e) { - connection.close(); - throw e; - } - - return connection; + return connectionFuture.whenComplete((conn, throwable) -> { + if (throwable != null) { + connection.close(); + } + }); } /** @@ -445,8 +455,6 @@ StatefulRedisPubSubConnection connectPubSubToNode(RedisCodec try { connectStateful(connection, endpoint, getFirstUri(), socketAddressSupplier, () -> new PubSubCommandHandler(clientResources, codec, endpoint)); - - connection.registerCloseables(closeableResources, connection); } catch (RedisException e) { connection.close(); throw e; @@ -496,7 +504,7 @@ StatefulRedisClusterConnectionImpl connectClusterImpl(RedisCodec new CommandHandler(clientResources, endpoint)); connected = true; break; @@ -513,7 +521,7 @@ StatefulRedisClusterConnectionImpl connectClusterImpl(RedisCodec StatefulRedisClusterPubSubConnection connectClusterPubSubImpl(Redis } } - connection.registerCloseables(closeableResources, connection, clusterWriter, pooledClusterConnectionProvider); - - if (getFirstUri().getPassword() != null) { - connection.async().auth(new String(getFirstUri().getPassword())); - } + connection.registerCloseables(closeableResources, clusterWriter, pooledClusterConnectionProvider); return connection; } @@ -588,48 +592,73 @@ StatefulRedisClusterPubSubConnection connectClusterPubSubImpl(Redis /** * Connect to a endpoint provided by {@code socketAddressSupplier} using connection settings (authentication, SSL) from * {@code connectionSettings}. - * */ private void connectStateful(StatefulRedisConnectionImpl connection, DefaultEndpoint endpoint, RedisURI connectionSettings, Supplier socketAddressSupplier, Supplier commandHandlerSupplier) { - - connectStateful0(connection, endpoint, connectionSettings, socketAddressSupplier, commandHandlerSupplier); - - if (connectionSettings.getPassword() != null && connectionSettings.getPassword().length != 0) { - connection.async().auth(new String(connectionSettings.getPassword())); - } - - if (LettuceStrings.isNotEmpty(connectionSettings.getClientName())) { - connection.setClientName(connectionSettings.getClientName()); - } + getConnection( + connectStatefulAsync(connection, endpoint, connectionSettings, socketAddressSupplier, commandHandlerSupplier)); } /** * Connect to a endpoint provided by {@code socketAddressSupplier} using connection settings (authentication, SSL) from * {@code connectionSettings}. - * */ - private void connectStateful(DefaultEndpoint endpoint, StatefulRedisClusterConnectionImpl connection, + private void connectStateful(StatefulRedisClusterConnectionImpl connection, DefaultEndpoint endpoint, RedisURI connectionSettings, Supplier socketAddressSupplier, Supplier commandHandlerSupplier) { + getConnection( + connectStatefulAsync(connection, endpoint, connectionSettings, socketAddressSupplier, commandHandlerSupplier)); + } - connectStateful0(connection, endpoint, connectionSettings, socketAddressSupplier, commandHandlerSupplier); + /** + * Initiates a channel connection considering {@link ClientOptions} initialization options, authentication and client name + * options. + */ + private , S> ConnectionFuture connectStatefulAsync(T connection, + DefaultEndpoint endpoint, RedisURI connectionSettings, Supplier socketAddressSupplier, + Supplier commandHandlerSupplier) { + + ConnectionBuilder connectionBuilder = createConnectionBuilder(connection, endpoint, connectionSettings, + socketAddressSupplier, commandHandlerSupplier); + + ConnectionFuture> future = initializeChannelAsync(connectionBuilder); if (connectionSettings.getPassword() != null && connectionSettings.getPassword().length != 0) { - connection.async().auth(new String(connectionSettings.getPassword())); + future = future.thenApplyAsync(channelHandler -> { + + if (connection instanceof StatefulRedisClusterConnectionImpl) { + ((StatefulRedisClusterConnectionImpl) connection).async() + .auth(new String(connectionSettings.getPassword())); + } + + if (connection instanceof StatefulRedisConnectionImpl) { + ((StatefulRedisConnectionImpl) connection).async().auth(new String(connectionSettings.getPassword())); + } + + return channelHandler; + }, clientResources.eventExecutorGroup()); + } if (LettuceStrings.isNotEmpty(connectionSettings.getClientName())) { - connection.setClientName(connectionSettings.getClientName()); + future = future.thenApply(channelHandler -> { + + if (connection instanceof StatefulRedisClusterConnectionImpl) { + ((StatefulRedisClusterConnectionImpl) connection).setClientName(connectionSettings.getClientName()); + } + + if (connection instanceof StatefulRedisConnectionImpl) { + ((StatefulRedisConnectionImpl) connection).setClientName(connectionSettings.getClientName()); + } + return channelHandler; + }); } + + return future.thenApply(channelHandler -> (S) connection); } - /** - * Connect to a endpoint provided by {@code socketAddressSupplier} using connection settings (SSL) from {@code - * connectionSettings}. - */ - private void connectStateful0(RedisChannelHandler connection, DefaultEndpoint endpoint, + private ConnectionBuilder createConnectionBuilder(RedisChannelHandler connection, DefaultEndpoint endpoint, RedisURI connectionSettings, Supplier socketAddressSupplier, Supplier commandHandlerSupplier) { @@ -650,8 +679,7 @@ private void connectStateful0(RedisChannelHandler connection, Defau connectionBuilder.commandHandler(commandHandlerSupplier); connectionBuilder(socketAddressSupplier, connectionBuilder, connectionSettings); channelType(connectionBuilder, connectionSettings); - - initializeChannel(connectionBuilder); + return connectionBuilder; } /** @@ -992,15 +1020,16 @@ private static void assertNotNull(ClientResources clientResources) { } private class NodeConnectionFactoryImpl implements NodeConnectionFactory { + @Override public StatefulRedisConnection connectToNode(RedisCodec codec, SocketAddress socketAddress) { - return RedisClusterClient.this.connectToNode(codec, socketAddress.toString(), null, new Supplier() { - @Override - public SocketAddress get() { - return socketAddress; - } - }); + return RedisClusterClient.this.connectToNode(codec, socketAddress.toString(), null, () -> socketAddress); } - } + @Override + public CompletableFuture> connectToNodeAsync(RedisCodec codec, + SocketAddress socketAddress) { + return RedisClusterClient.this.connectToNodeAsync(codec, socketAddress.toString(), null, () -> socketAddress); + } + } } diff --git a/src/main/java/com/lambdaworks/redis/cluster/topology/NodeConnectionFactory.java b/src/main/java/com/lambdaworks/redis/cluster/topology/NodeConnectionFactory.java index f2edcac8b0..8563869eec 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/topology/NodeConnectionFactory.java +++ b/src/main/java/com/lambdaworks/redis/cluster/topology/NodeConnectionFactory.java @@ -16,6 +16,7 @@ package com.lambdaworks.redis.cluster.topology; import java.net.SocketAddress; +import java.util.concurrent.CompletableFuture; import com.lambdaworks.redis.api.StatefulRedisConnection; import com.lambdaworks.redis.codec.RedisCodec; @@ -33,9 +34,22 @@ public interface NodeConnectionFactory { * * @param codec must not be {@literal null}. * @param socketAddress must not be {@literal null}. - * @param - * @param + * @param Key type. + * @param Value type. * @return a new {@link StatefulRedisConnection} */ StatefulRedisConnection connectToNode(RedisCodec codec, SocketAddress socketAddress); + + /** + * Connects to a {@link SocketAddress} with the given {@link RedisCodec} asynchronously. + * + * @param codec must not be {@literal null}. + * @param socketAddress must not be {@literal null}. + * @param Key type. + * @param Value type. + * @return a new {@link StatefulRedisConnection} + * @since 4.4 + */ + CompletableFuture> connectToNodeAsync(RedisCodec codec, + SocketAddress socketAddress); } From a2316f8f8cd2be622afd427c21d868c323677c1e Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Sun, 18 Dec 2016 23:49:51 +0100 Subject: [PATCH 101/808] Connect asynchronously in cluster topology refresh #424 Switch from blocking to asynchronous connection initialization when connecting Redis Cluster nodes for topology refresh. Asynchronous connection allows connecting concurrently. --- .../ClusterTopologyRefreshScheduler.java | 6 +- .../cluster/topology/AsyncConnections.java | 78 +++++++++++++++++++ .../topology/ClusterTopologyRefresh.java | 44 ++++++++--- .../redis/cluster/topology/Connections.java | 22 +++--- .../cluster/topology/RefreshFutures.java | 55 +++++++++++++ .../redis/cluster/topology/Requests.java | 25 +----- .../topology/ClusterTopologyRefreshTest.java | 75 ++++++++++-------- 7 files changed, 226 insertions(+), 79 deletions(-) create mode 100644 src/main/java/com/lambdaworks/redis/cluster/topology/AsyncConnections.java create mode 100644 src/main/java/com/lambdaworks/redis/cluster/topology/RefreshFutures.java diff --git a/src/main/java/com/lambdaworks/redis/cluster/ClusterTopologyRefreshScheduler.java b/src/main/java/com/lambdaworks/redis/cluster/ClusterTopologyRefreshScheduler.java index 39d6250b6e..cadb0d6378 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/ClusterTopologyRefreshScheduler.java +++ b/src/main/java/com/lambdaworks/redis/cluster/ClusterTopologyRefreshScheduler.java @@ -195,7 +195,11 @@ public void run() { logger.debug("ClusterTopologyRefreshTask requesting partitions from {}", redisClusterClient.getTopologyRefreshSource()); } - redisClusterClient.reloadPartitions(); + try { + redisClusterClient.reloadPartitions(); + } catch (Exception e) { + logger.warn("Cannot refresh Redis Cluster topology", e); + } } } } diff --git a/src/main/java/com/lambdaworks/redis/cluster/topology/AsyncConnections.java b/src/main/java/com/lambdaworks/redis/cluster/topology/AsyncConnections.java new file mode 100644 index 0000000000..eda0aacb0e --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/cluster/topology/AsyncConnections.java @@ -0,0 +1,78 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.lambdaworks.redis.cluster.topology; + +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; + +import com.lambdaworks.redis.RedisConnectionException; +import com.lambdaworks.redis.RedisURI; +import com.lambdaworks.redis.api.StatefulRedisConnection; + +/** + * @author Mark Paluch + */ +class AsyncConnections { + + private final Map>> futures = new TreeMap<>( + TopologyComparators.RedisURIComparator.INSTANCE); + + public AsyncConnections() { + } + + /** + * Add a connection for a {@link RedisURI} + * + * @param redisURI + * @param connection + */ + public void addConnection(RedisURI redisURI, CompletableFuture> connection) { + futures.put(redisURI, connection); + } + + /** + * + * @return a set of {@link RedisURI} for which {@link Connections} has a connection. + */ + public Set connectedNodes() { + return futures.keySet(); + } + + /** + * @return the {@link Connections}. + * @throws RedisConnectionException if no connection could be established. + */ + public Connections get(long timeout, TimeUnit timeUnit) throws InterruptedException { + + Connections connections = new Connections(); + List> sync = new ArrayList<>(this.futures.size()); + + for (Map.Entry>> entry : this.futures.entrySet()) { + + CompletableFuture> future = entry.getValue(); + + sync.add(future.thenAccept((connection) -> { + connections.addConnection(entry.getKey(), connection); + })); + } + + RefreshFutures.awaitAll(timeout, timeUnit, sync); + + return connections; + } +} diff --git a/src/main/java/com/lambdaworks/redis/cluster/topology/ClusterTopologyRefresh.java b/src/main/java/com/lambdaworks/redis/cluster/topology/ClusterTopologyRefresh.java index 2606a06f93..a0481961c0 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/topology/ClusterTopologyRefresh.java +++ b/src/main/java/com/lambdaworks/redis/cluster/topology/ClusterTopologyRefresh.java @@ -17,6 +17,7 @@ import java.net.SocketAddress; import java.util.*; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; @@ -64,13 +65,15 @@ public ClusterTopologyRefresh(NodeConnectionFactory nodeConnectionFactory, Clien */ public Map loadViews(Iterable seed, boolean discovery) { - Connections connections = getConnections(seed); - Requests requestedTopology = connections.requestTopology(); - Requests requestedClients = connections.requestClients(); - long commandTimeoutNs = getCommandTimeoutNs(seed); + Connections connections = null; try { + connections = getConnections(seed).get(commandTimeoutNs, TimeUnit.NANOSECONDS); + + Requests requestedTopology = connections.requestTopology(); + Requests requestedClients = connections.requestClients(); + NodeTopologyViews nodeSpecificViews = getNodeSpecificViews(requestedTopology, requestedClients, commandTimeoutNs); if (discovery) { @@ -78,7 +81,8 @@ public Map loadViews(Iterable seed, boolean disc Set discoveredNodes = difference(allKnownUris, toSet(seed)); if (!discoveredNodes.isEmpty()) { - Connections discoveredConnections = getConnections(discoveredNodes); + Connections discoveredConnections = getConnections(discoveredNodes).get(commandTimeoutNs, + TimeUnit.NANOSECONDS); connections = connections.mergeWith(discoveredConnections); requestedTopology = requestedTopology.mergeWith(discoveredConnections.requestTopology()); @@ -97,7 +101,9 @@ public Map loadViews(Iterable seed, boolean disc Thread.currentThread().interrupt(); throw new RedisCommandInterruptedException(e); } finally { - connections.close(); + if (connections != null) { + connections.close(); + } } } @@ -190,9 +196,9 @@ private static boolean validNode(RedisClusterNode redisClusterNode) { /* * Open connections where an address can be resolved. */ - private Connections getConnections(Iterable redisURIs) { + private AsyncConnections getConnections(Iterable redisURIs) throws InterruptedException { - Connections connections = new Connections(); + AsyncConnections connections = new AsyncConnections(); for (RedisURI redisURI : redisURIs) { if (redisURI.getHost() == null || connections.connectedNodes().contains(redisURI)) { @@ -201,10 +207,25 @@ private Connections getConnections(Iterable redisURIs) { try { SocketAddress socketAddress = SocketAddressResolver.resolve(redisURI, clientResources.dnsResolver()); - StatefulRedisConnection connection = nodeConnectionFactory.connectToNode(CODEC, socketAddress); - connection.async().clientSetname("lettuce#ClusterTopologyRefresh"); - connections.addConnection(redisURI, connection); + CompletableFuture> connectionFuture = nodeConnectionFactory + .connectToNodeAsync(CODEC, socketAddress); + + connectionFuture.thenAccept(connection -> connection.async().clientSetname("lettuce#ClusterTopologyRefresh")); + + CompletableFuture> sync = new CompletableFuture<>(); + + connectionFuture.whenComplete((connection, throwable) -> { + + if (throwable != null) { + sync.completeExceptionally(new RedisConnectionException( + String.format("Unable to connect to %s", socketAddress), throwable)); + } else { + sync.complete(connection); + } + }); + + connections.addConnection(redisURI, sync); } catch (RedisConnectionException e) { if (logger.isDebugEnabled()) { @@ -216,6 +237,7 @@ private Connections getConnections(Iterable redisURIs) { logger.warn(String.format("Cannot connect to %s", redisURI), e); } } + return connections; } diff --git a/src/main/java/com/lambdaworks/redis/cluster/topology/Connections.java b/src/main/java/com/lambdaworks/redis/cluster/topology/Connections.java index dadfb03c68..60e43e8022 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/topology/Connections.java +++ b/src/main/java/com/lambdaworks/redis/cluster/topology/Connections.java @@ -16,7 +16,6 @@ package com.lambdaworks.redis.cluster.topology; import java.util.Map; -import java.util.Set; import java.util.TreeMap; import com.lambdaworks.redis.RedisURI; @@ -49,7 +48,18 @@ private Connections(Map> conne * @param connection */ public void addConnection(RedisURI redisURI, StatefulRedisConnection connection) { - connections.put(redisURI, connection); + synchronized (connections) { + connections.put(redisURI, connection); + } + } + + /** + * @return {@literal true} if no connections present. + */ + public boolean isEmpty() { + synchronized (connections) { + return connections.isEmpty(); + } } /* @@ -107,14 +117,6 @@ public void close() { } } - /** - * - * @return a set of {@link RedisURI} for which {@link Connections} has a connection. - */ - public Set connectedNodes() { - return connections.keySet(); - } - public Connections mergeWith(Connections discoveredConnections) { Map> result = new TreeMap<>( diff --git a/src/main/java/com/lambdaworks/redis/cluster/topology/RefreshFutures.java b/src/main/java/com/lambdaworks/redis/cluster/topology/RefreshFutures.java new file mode 100644 index 0000000000..3a8463e427 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/cluster/topology/RefreshFutures.java @@ -0,0 +1,55 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.lambdaworks.redis.cluster.topology; + +import java.util.Collection; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; + +/** + * @author Mark Paluch + */ +class RefreshFutures { + + static long awaitAll(long timeout, TimeUnit timeUnit, Collection> futures) throws InterruptedException { + + long waitTime = 0; + + for (Future future : futures) { + + long timeoutLeft = timeUnit.toNanos(timeout) - waitTime; + + if (timeoutLeft <= 0) { + break; + } + + long startWait = System.nanoTime(); + + try { + future.get(timeoutLeft, TimeUnit.NANOSECONDS); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw e; + } catch (Exception e) { + continue; + } finally { + waitTime += System.nanoTime() - startWait; + } + + } + return waitTime; + } +} diff --git a/src/main/java/com/lambdaworks/redis/cluster/topology/Requests.java b/src/main/java/com/lambdaworks/redis/cluster/topology/Requests.java index e49f068a13..58fb8fcf3e 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/topology/Requests.java +++ b/src/main/java/com/lambdaworks/redis/cluster/topology/Requests.java @@ -20,7 +20,6 @@ import java.util.TreeMap; import java.util.concurrent.TimeUnit; -import com.lambdaworks.redis.RedisFuture; import com.lambdaworks.redis.RedisURI; /** @@ -43,29 +42,7 @@ void addRequest(RedisURI redisURI, TimedAsyncCommand com } long await(long timeout, TimeUnit timeUnit) throws InterruptedException { - - long waitTime = 0; - - for (Map.Entry> entry : rawViews.entrySet()) { - long timeoutLeft = timeUnit.toNanos(timeout) - waitTime; - - if (timeoutLeft <= 0) { - break; - } - - long startWait = System.nanoTime(); - RedisFuture future = entry.getValue(); - - try { - if (!future.await(timeoutLeft, TimeUnit.NANOSECONDS)) { - break; - } - } finally { - waitTime += System.nanoTime() - startWait; - } - - } - return waitTime; + return RefreshFutures.awaitAll(timeout, timeUnit, rawViews.values()); } Set nodes() { diff --git a/src/test/java/com/lambdaworks/redis/cluster/topology/ClusterTopologyRefreshTest.java b/src/test/java/com/lambdaworks/redis/cluster/topology/ClusterTopologyRefreshTest.java index 6a1123c3fc..bc15a9a2ec 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/topology/ClusterTopologyRefreshTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/topology/ClusterTopologyRefreshTest.java @@ -15,6 +15,7 @@ */ package com.lambdaworks.redis.cluster.topology; +import static java.util.concurrent.CompletableFuture.completedFuture; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Matchers.any; import static org.mockito.Matchers.eq; @@ -25,6 +26,7 @@ import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.util.*; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; import org.junit.Before; @@ -207,15 +209,15 @@ public void shouldAttemptToConnectOnlyOnce() throws Exception { List seed = Arrays.asList(RedisURI.create("127.0.0.1", 7380), RedisURI.create("127.0.0.1", 7381)); - when(nodeConnectionFactory.connectToNode(any(RedisCodec.class), eq(new InetSocketAddress("127.0.0.1", 7380)))) - .thenReturn((StatefulRedisConnection) connection1); - when(nodeConnectionFactory.connectToNode(any(RedisCodec.class), eq(new InetSocketAddress("127.0.0.1", 7381)))) - .thenThrow(new RedisException("connection failed")); + when(nodeConnectionFactory.connectToNodeAsync(any(RedisCodec.class), eq(new InetSocketAddress("127.0.0.1", 7380)))) + .thenReturn(completedFuture((StatefulRedisConnection) connection1)); + when(nodeConnectionFactory.connectToNodeAsync(any(RedisCodec.class), eq(new InetSocketAddress("127.0.0.1", 7381)))) + .thenReturn(completedWithException(new RedisException("connection failed"))); sut.loadViews(seed, true); - verify(nodeConnectionFactory).connectToNode(any(RedisCodec.class), eq(new InetSocketAddress("127.0.0.1", 7380))); - verify(nodeConnectionFactory).connectToNode(any(RedisCodec.class), eq(new InetSocketAddress("127.0.0.1", 7381))); + verify(nodeConnectionFactory).connectToNodeAsync(any(RedisCodec.class), eq(new InetSocketAddress("127.0.0.1", 7380))); + verify(nodeConnectionFactory).connectToNodeAsync(any(RedisCodec.class), eq(new InetSocketAddress("127.0.0.1", 7381))); } @Test @@ -223,15 +225,15 @@ public void shouldShouldDiscoverNodes() throws Exception { List seed = Arrays.asList(RedisURI.create("127.0.0.1", 7380)); - when(nodeConnectionFactory.connectToNode(any(RedisCodec.class), eq(new InetSocketAddress("127.0.0.1", 7380)))) - .thenReturn((StatefulRedisConnection) connection1); - when(nodeConnectionFactory.connectToNode(any(RedisCodec.class), eq(new InetSocketAddress("127.0.0.1", 7381)))) - .thenReturn((StatefulRedisConnection) connection2); + when(nodeConnectionFactory.connectToNodeAsync(any(RedisCodec.class), eq(new InetSocketAddress("127.0.0.1", 7380)))) + .thenReturn(completedFuture((StatefulRedisConnection) connection1)); + when(nodeConnectionFactory.connectToNodeAsync(any(RedisCodec.class), eq(new InetSocketAddress("127.0.0.1", 7381)))) + .thenReturn(completedFuture((StatefulRedisConnection) connection2)); sut.loadViews(seed, true); - verify(nodeConnectionFactory).connectToNode(any(RedisCodec.class), eq(new InetSocketAddress("127.0.0.1", 7380))); - verify(nodeConnectionFactory).connectToNode(any(RedisCodec.class), eq(new InetSocketAddress("127.0.0.1", 7381))); + verify(nodeConnectionFactory).connectToNodeAsync(any(RedisCodec.class), eq(new InetSocketAddress("127.0.0.1", 7380))); + verify(nodeConnectionFactory).connectToNodeAsync(any(RedisCodec.class), eq(new InetSocketAddress("127.0.0.1", 7381))); } @Test @@ -239,12 +241,12 @@ public void shouldShouldNotDiscoverNodes() throws Exception { List seed = Arrays.asList(RedisURI.create("127.0.0.1", 7380)); - when(nodeConnectionFactory.connectToNode(any(RedisCodec.class), eq(new InetSocketAddress("127.0.0.1", 7380)))) - .thenReturn((StatefulRedisConnection) connection1); + when(nodeConnectionFactory.connectToNodeAsync(any(RedisCodec.class), eq(new InetSocketAddress("127.0.0.1", 7380)))) + .thenReturn(completedFuture((StatefulRedisConnection) connection1)); sut.loadViews(seed, false); - verify(nodeConnectionFactory).connectToNode(any(RedisCodec.class), eq(new InetSocketAddress("127.0.0.1", 7380))); + verify(nodeConnectionFactory).connectToNodeAsync(any(RedisCodec.class), eq(new InetSocketAddress("127.0.0.1", 7380))); verifyNoMoreInteractions(nodeConnectionFactory); } @@ -254,16 +256,16 @@ public void shouldNotFailOnDuplicateSeedNodes() throws Exception { List seed = Arrays.asList(RedisURI.create("127.0.0.1", 7380), RedisURI.create("127.0.0.1", 7381), RedisURI.create("127.0.0.1", 7381)); - when(nodeConnectionFactory.connectToNode(any(RedisCodec.class), eq(new InetSocketAddress("127.0.0.1", 7380)))) - .thenReturn((StatefulRedisConnection) connection1); + when(nodeConnectionFactory.connectToNodeAsync(any(RedisCodec.class), eq(new InetSocketAddress("127.0.0.1", 7380)))) + .thenReturn(completedFuture((StatefulRedisConnection) connection1)); - when(nodeConnectionFactory.connectToNode(any(RedisCodec.class), eq(new InetSocketAddress("127.0.0.1", 7381)))) - .thenReturn((StatefulRedisConnection) connection2); + when(nodeConnectionFactory.connectToNodeAsync(any(RedisCodec.class), eq(new InetSocketAddress("127.0.0.1", 7381)))) + .thenReturn(completedFuture((StatefulRedisConnection) connection2)); sut.loadViews(seed, true); - verify(nodeConnectionFactory).connectToNode(any(RedisCodec.class), eq(new InetSocketAddress("127.0.0.1", 7380))); - verify(nodeConnectionFactory).connectToNode(any(RedisCodec.class), eq(new InetSocketAddress("127.0.0.1", 7381))); + verify(nodeConnectionFactory).connectToNodeAsync(any(RedisCodec.class), eq(new InetSocketAddress("127.0.0.1", 7380))); + verify(nodeConnectionFactory).connectToNodeAsync(any(RedisCodec.class), eq(new InetSocketAddress("127.0.0.1", 7381))); } @Test @@ -271,8 +273,8 @@ public void undiscoveredAdditionalNodesShouldBeLastUsingClientCount() throws Exc List seed = Arrays.asList(RedisURI.create("127.0.0.1", 7380)); - when(nodeConnectionFactory.connectToNode(any(RedisCodec.class), eq(new InetSocketAddress("127.0.0.1", 7380)))) - .thenReturn((StatefulRedisConnection) connection1); + when(nodeConnectionFactory.connectToNodeAsync(any(RedisCodec.class), eq(new InetSocketAddress("127.0.0.1", 7380)))) + .thenReturn(completedFuture((StatefulRedisConnection) connection1)); Map partitionsMap = sut.loadViews(seed, false); @@ -289,10 +291,10 @@ public void discoveredAdditionalNodesShouldBeOrderedUsingClientCount() throws Ex List seed = Arrays.asList(RedisURI.create("127.0.0.1", 7380)); - when(nodeConnectionFactory.connectToNode(any(RedisCodec.class), eq(new InetSocketAddress("127.0.0.1", 7380)))) - .thenReturn((StatefulRedisConnection) connection1); - when(nodeConnectionFactory.connectToNode(any(RedisCodec.class), eq(new InetSocketAddress("127.0.0.1", 7381)))) - .thenReturn((StatefulRedisConnection) connection2); + when(nodeConnectionFactory.connectToNodeAsync(any(RedisCodec.class), eq(new InetSocketAddress("127.0.0.1", 7380)))) + .thenReturn(completedFuture((StatefulRedisConnection) connection1)); + when(nodeConnectionFactory.connectToNodeAsync(any(RedisCodec.class), eq(new InetSocketAddress("127.0.0.1", 7381)))) + .thenReturn(completedFuture((StatefulRedisConnection) connection2)); Map partitionsMap = sut.loadViews(seed, true); @@ -309,8 +311,8 @@ public void undiscoveredAdditionalNodesShouldBeLastUsingLatency() throws Excepti List seed = Arrays.asList(RedisURI.create("127.0.0.1", 7380)); - when(nodeConnectionFactory.connectToNode(any(RedisCodec.class), eq(new InetSocketAddress("127.0.0.1", 7380)))) - .thenReturn((StatefulRedisConnection) connection1); + when(nodeConnectionFactory.connectToNodeAsync(any(RedisCodec.class), eq(new InetSocketAddress("127.0.0.1", 7380)))) + .thenReturn(completedFuture((StatefulRedisConnection) connection1)); Map partitionsMap = sut.loadViews(seed, false); @@ -327,10 +329,10 @@ public void discoveredAdditionalNodesShouldBeOrderedUsingLatency() throws Except List seed = Arrays.asList(RedisURI.create("127.0.0.1", 7380)); - when(nodeConnectionFactory.connectToNode(any(RedisCodec.class), eq(new InetSocketAddress("127.0.0.1", 7380)))) - .thenReturn((StatefulRedisConnection) connection1); - when(nodeConnectionFactory.connectToNode(any(RedisCodec.class), eq(new InetSocketAddress("127.0.0.1", 7381)))) - .thenReturn((StatefulRedisConnection) connection2); + when(nodeConnectionFactory.connectToNodeAsync(any(RedisCodec.class), eq(new InetSocketAddress("127.0.0.1", 7380)))) + .thenReturn(completedFuture((StatefulRedisConnection) connection1)); + when(nodeConnectionFactory.connectToNodeAsync(any(RedisCodec.class), eq(new InetSocketAddress("127.0.0.1", 7381)))) + .thenReturn(completedFuture((StatefulRedisConnection) connection2)); Map partitionsMap = sut.loadViews(seed, true); @@ -374,4 +376,11 @@ protected Requests createClientListRequests(int duration, String response) { return requests; } + + private static CompletableFuture completedWithException(Exception e) { + + CompletableFuture future = new CompletableFuture(); + future.completeExceptionally(e); + return future; + } } From bc05815bfbaa7d2ea81b049700ed273e811226dd Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Mon, 19 Dec 2016 00:13:45 +0100 Subject: [PATCH 102/808] Propagate cause if cluster topology refresh can't connect to any node #427 RedisClusterClient.loadPartitions now propagates the cause if lettuce can't connect to any of the topology refresh sources (initial seed nodes). Cause propagation covers I/O errors and authentication issues. Command execution issues are just logged. --- .../redis/cluster/RedisClusterClient.java | 37 +++++++------- .../cluster/topology/AsyncConnections.java | 39 ++++++++++++++- .../topology/ClusterTopologyRefresh.java | 48 ++++++++++--------- .../cluster/ClusterPartiallyDownTest.java | 12 ++--- .../topology/ClusterTopologyRefreshTest.java | 26 +++++++++- 5 files changed, 114 insertions(+), 48 deletions(-) diff --git a/src/main/java/com/lambdaworks/redis/cluster/RedisClusterClient.java b/src/main/java/com/lambdaworks/redis/cluster/RedisClusterClient.java index e30d316a45..2d142bcb38 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/RedisClusterClient.java +++ b/src/main/java/com/lambdaworks/redis/cluster/RedisClusterClient.java @@ -721,9 +721,7 @@ protected void updatePartitionsInConnections() { } protected void initializePartitions() { - - Partitions loadedPartitions = loadPartitions(); - this.partitions = loadedPartitions; + this.partitions = loadPartitions(); } /** @@ -746,25 +744,32 @@ public Partitions getPartitions() { protected Partitions loadPartitions() { Iterable topologyRefreshSource = getTopologyRefreshSource(); - Map partitions = refresh.loadViews(topologyRefreshSource, useDynamicRefreshSources()); - if (partitions.isEmpty()) { - throw new RedisException("Cannot retrieve initial cluster partitions from initial URIs " + topologyRefreshSource); - } + String message = "Cannot retrieve initial cluster partitions from initial URIs " + topologyRefreshSource; + try { + Map partitions = refresh.loadViews(topologyRefreshSource, useDynamicRefreshSources()); + + if (partitions.isEmpty()) { + throw new RedisException(message); + } - Partitions loadedPartitions = determinePartitions(this.partitions, partitions); - RedisURI viewedBy = refresh.getViewedBy(partitions, loadedPartitions); + Partitions loadedPartitions = determinePartitions(this.partitions, partitions); + RedisURI viewedBy = refresh.getViewedBy(partitions, loadedPartitions); - for (RedisClusterNode partition : loadedPartitions) { - if (viewedBy != null) { - RedisURI uri = partition.getUri(); - RedisClusterURIUtil.applyUriConnectionSettings(viewedBy, uri); + for (RedisClusterNode partition : loadedPartitions) { + if (viewedBy != null) { + RedisURI uri = partition.getUri(); + RedisClusterURIUtil.applyUriConnectionSettings(viewedBy, uri); + } } - } - activateTopologyRefreshIfNeeded(); + activateTopologyRefreshIfNeeded(); - return loadedPartitions; + return loadedPartitions; + + } catch (RedisConnectionException e) { + throw new RedisException(message, e); + } } /** diff --git a/src/main/java/com/lambdaworks/redis/cluster/topology/AsyncConnections.java b/src/main/java/com/lambdaworks/redis/cluster/topology/AsyncConnections.java index eda0aacb0e..da15091ef1 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/topology/AsyncConnections.java +++ b/src/main/java/com/lambdaworks/redis/cluster/topology/AsyncConnections.java @@ -17,6 +17,7 @@ import java.util.*; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; @@ -46,7 +47,6 @@ public void addConnection(RedisURI redisURI, CompletableFuture connectedNodes() { @@ -59,6 +59,43 @@ public Set connectedNodes() { */ public Connections get(long timeout, TimeUnit timeUnit) throws InterruptedException { + Connections connections = new Connections(); + List exceptions = new CopyOnWriteArrayList<>(); + List> sync = new ArrayList<>(this.futures.size()); + + for (Map.Entry>> entry : this.futures.entrySet()) { + + CompletableFuture> future = entry.getValue(); + + sync.add(future.whenComplete((connection, throwable) -> { + + if (throwable != null) { + exceptions.add(throwable); + } else { + connections.addConnection(entry.getKey(), connection); + } + })); + } + + RefreshFutures.awaitAll(timeout, timeUnit, sync); + + if (connections.isEmpty() && !sync.isEmpty() && !exceptions.isEmpty()) { + + RedisConnectionException collector = new RedisConnectionException( + "Unable to establish a connection to Redis Cluster"); + exceptions.forEach(collector::addSuppressed); + + throw collector; + } + + return connections; + } + + /** + * @return the {@link Connections}. + */ + public Connections optionalGet(long timeout, TimeUnit timeUnit) throws InterruptedException { + Connections connections = new Connections(); List> sync = new ArrayList<>(this.futures.size()); diff --git a/src/main/java/com/lambdaworks/redis/cluster/topology/ClusterTopologyRefresh.java b/src/main/java/com/lambdaworks/redis/cluster/topology/ClusterTopologyRefresh.java index a0481961c0..0629106d68 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/topology/ClusterTopologyRefresh.java +++ b/src/main/java/com/lambdaworks/redis/cluster/topology/ClusterTopologyRefresh.java @@ -81,7 +81,7 @@ public Map loadViews(Iterable seed, boolean disc Set discoveredNodes = difference(allKnownUris, toSet(seed)); if (!discoveredNodes.isEmpty()) { - Connections discoveredConnections = getConnections(discoveredNodes).get(commandTimeoutNs, + Connections discoveredConnections = getConnections(discoveredNodes).optionalGet(commandTimeoutNs, TimeUnit.NANOSECONDS); connections = connections.mergeWith(discoveredConnections); @@ -139,19 +139,18 @@ NodeTopologyViews getNodeSpecificViews(Requests requestedTopology, Requests requ .filter(ClusterTopologyRefresh::validNode) // .map(RedisClusterNodeSnapshot::new).collect(Collectors.toList()); - for (RedisClusterNodeSnapshot partition : nodeWithStats) { + nodeWithStats.stream() // + .filter(partition -> partition.is(RedisClusterNode.NodeFlag.MYSELF)) // + .forEach(partition -> { - if (partition.getFlags().contains(RedisClusterNode.NodeFlag.MYSELF)) { + if (partition.getUri() == null) { + partition.setUri(node); + } - if (partition.getUri() == null) { - partition.setUri(node); - } - - // record latency for later partition ordering - latencies.put(partition.getNodeId(), nodeTopologyView.getLatency()); - clientCountByNodeId.put(partition.getNodeId(), nodeTopologyView.getConnectedClients()); - } - } + // record latency for later partition ordering + latencies.put(partition.getNodeId(), nodeTopologyView.getLatency()); + clientCountByNodeId.put(partition.getNodeId(), nodeTopologyView.getConnectedClients()); + }); allNodes.addAll(nodeWithStats); @@ -211,28 +210,31 @@ private AsyncConnections getConnections(Iterable redisURIs) throws Int CompletableFuture> connectionFuture = nodeConnectionFactory .connectToNodeAsync(CODEC, socketAddress); - connectionFuture.thenAccept(connection -> connection.async().clientSetname("lettuce#ClusterTopologyRefresh")); - CompletableFuture> sync = new CompletableFuture<>(); connectionFuture.whenComplete((connection, throwable) -> { if (throwable != null) { - sync.completeExceptionally(new RedisConnectionException( - String.format("Unable to connect to %s", socketAddress), throwable)); + + String message = String.format("Unable to connect to %s", socketAddress); + if (throwable instanceof RedisConnectionException) { + if (logger.isDebugEnabled()) { + logger.debug(throwable.getMessage(), throwable); + } else { + logger.warn(throwable.getMessage()); + } + } else { + logger.warn(message, throwable); + } + + sync.completeExceptionally(new RedisConnectionException(message, throwable)); } else { + connection.async().clientSetname("lettuce#ClusterTopologyRefresh"); sync.complete(connection); } }); connections.addConnection(redisURI, sync); - } catch (RedisConnectionException e) { - - if (logger.isDebugEnabled()) { - logger.debug(e.getMessage(), e); - } else { - logger.warn(e.getMessage()); - } } catch (RuntimeException e) { logger.warn(String.format("Cannot connect to %s", redisURI), e); } diff --git a/src/test/java/com/lambdaworks/redis/cluster/ClusterPartiallyDownTest.java b/src/test/java/com/lambdaworks/redis/cluster/ClusterPartiallyDownTest.java index bfea690cea..1a98512dcf 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/ClusterPartiallyDownTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/ClusterPartiallyDownTest.java @@ -89,8 +89,7 @@ public void operateOnPartiallyDownCluster() throws Exception { connection.sync().get(key_10439); fail("Missing RedisException"); } catch (RedisConnectionException e) { - assertThat(e).hasRootCauseInstanceOf( - ConnectException.class); + assertThat(e).hasRootCauseInstanceOf(ConnectException.class); } connection.close(); @@ -106,7 +105,8 @@ public void seedNodesAreOffline() throws Exception { redisClusterClient.connect(); fail("Missing RedisException"); } catch (RedisException e) { - assertThat(e).hasNoCause(); + assertThat(e).hasCauseInstanceOf(RedisConnectionException.class); + assertThat(e.getCause()).hasMessage("Unable to establish a connection to Redis Cluster"); } } @@ -117,10 +117,8 @@ public void partitionNodesAreOffline() throws Exception { redisClusterClient = RedisClusterClient.create(clientResources, seed); Partitions partitions = new Partitions(); - partitions.addPartition( - new RedisClusterNode(URI_1, "a", true, null, 0, 0, 0, new ArrayList<>(), new HashSet<>())); - partitions.addPartition( - new RedisClusterNode(URI_2, "b", true, null, 0, 0, 0, new ArrayList<>(), new HashSet<>())); + partitions.addPartition(new RedisClusterNode(URI_1, "a", true, null, 0, 0, 0, new ArrayList<>(), new HashSet<>())); + partitions.addPartition(new RedisClusterNode(URI_2, "b", true, null, 0, 0, 0, new ArrayList<>(), new HashSet<>())); redisClusterClient.setPartitions(partitions); diff --git a/src/test/java/com/lambdaworks/redis/cluster/topology/ClusterTopologyRefreshTest.java b/src/test/java/com/lambdaworks/redis/cluster/topology/ClusterTopologyRefreshTest.java index bc15a9a2ec..d2addc8b78 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/topology/ClusterTopologyRefreshTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/topology/ClusterTopologyRefreshTest.java @@ -17,6 +17,7 @@ import static java.util.concurrent.CompletableFuture.completedFuture; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.fail; import static org.mockito.Matchers.any; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.verify; @@ -29,6 +30,7 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; +import io.netty.util.concurrent.ImmediateEventExecutor; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -90,6 +92,7 @@ public class ClusterTopologyRefreshTest { public void before() throws Exception { when(clientResources.dnsResolver()).thenReturn(DnsResolvers.JVM_DEFAULT); + when(clientResources.eventExecutorGroup()).thenReturn(ImmediateEventExecutor.INSTANCE); when(connection1.async()).thenReturn(asyncCommands1); when(connection2.async()).thenReturn(asyncCommands2); @@ -220,6 +223,28 @@ public void shouldAttemptToConnectOnlyOnce() throws Exception { verify(nodeConnectionFactory).connectToNodeAsync(any(RedisCodec.class), eq(new InetSocketAddress("127.0.0.1", 7381))); } + @Test + public void shouldFailIfNoNodeConnects() throws Exception { + + List seed = Arrays.asList(RedisURI.create("127.0.0.1", 7380), RedisURI.create("127.0.0.1", 7381)); + + when(nodeConnectionFactory.connectToNodeAsync(any(RedisCodec.class), eq(new InetSocketAddress("127.0.0.1", 7380)))) + .thenReturn(completedWithException(new RedisException("connection failed"))); + when(nodeConnectionFactory.connectToNodeAsync(any(RedisCodec.class), eq(new InetSocketAddress("127.0.0.1", 7381)))) + .thenReturn(completedWithException(new RedisException("connection failed"))); + + try { + sut.loadViews(seed, true); + fail("Missing RedisConnectionException"); + } catch (Exception e) { + assertThat(e).hasNoCause().hasMessage("Unable to establish a connection to Redis Cluster"); + assertThat(e.getSuppressed()).hasSize(2); + } + + verify(nodeConnectionFactory).connectToNodeAsync(any(RedisCodec.class), eq(new InetSocketAddress("127.0.0.1", 7380))); + verify(nodeConnectionFactory).connectToNodeAsync(any(RedisCodec.class), eq(new InetSocketAddress("127.0.0.1", 7381))); + } + @Test public void shouldShouldDiscoverNodes() throws Exception { @@ -359,7 +384,6 @@ protected Requests createClusterNodesRequests(int duration, String nodes) { command.completedAtNs = duration; return requests; - } protected Requests createClientListRequests(int duration, String response) { From 8cdab70b6baf756e8d077ee5d0e93f8ae18b7bc3 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Tue, 20 Dec 2016 21:30:10 +0100 Subject: [PATCH 103/808] Perform resilient Master/Slave topology refresh ping #424 Lettuce now connects Master/Slave nodes asynchronously and performs fail-safe topology refresh ping synchronization. Master/Slave node connections are established asynchronously, and the connection is synchronized with a timeout. Only connections that were able to initialize within the timeout are considered for the topology ping. Topology ping execution is also synchronized with a timeout. Nodes that responded within the timeout successfully are considered as Master/Slave members. Previously, connection was synchronous and if one node in the ping failed, the result of other nodes was discarded. --- .../com/lambdaworks/redis/RedisClient.java | 76 ++++-- .../redis/masterslave/AsyncConnections.java | 89 +++++++ .../redis/masterslave/Connections.java | 93 +++++++ .../MasterSlaveTopologyRefresh.java | 235 ++++++------------ .../redis/masterslave/MasterSlaveUtils.java | 25 ++ .../masterslave/NodeConnectionFactory.java | 43 ++++ .../ReflectiveNodeConnectionFactory.java | 67 +++++ .../redis/masterslave/RefreshFutures.java | 64 +++++ .../redis/masterslave/Requests.java | 53 ++++ .../masterslave/SentinelTopologyRefresh.java | 2 +- .../redis/masterslave/TimedAsyncCommand.java | 61 +++++ .../masterslave/TopologyComparators.java | 87 +++++++ .../topology/ClusterTopologyRefreshTest.java | 7 +- 13 files changed, 714 insertions(+), 188 deletions(-) create mode 100644 src/main/java/com/lambdaworks/redis/masterslave/AsyncConnections.java create mode 100644 src/main/java/com/lambdaworks/redis/masterslave/Connections.java create mode 100644 src/main/java/com/lambdaworks/redis/masterslave/NodeConnectionFactory.java create mode 100644 src/main/java/com/lambdaworks/redis/masterslave/ReflectiveNodeConnectionFactory.java create mode 100644 src/main/java/com/lambdaworks/redis/masterslave/RefreshFutures.java create mode 100644 src/main/java/com/lambdaworks/redis/masterslave/Requests.java create mode 100644 src/main/java/com/lambdaworks/redis/masterslave/TimedAsyncCommand.java create mode 100644 src/main/java/com/lambdaworks/redis/masterslave/TopologyComparators.java diff --git a/src/main/java/com/lambdaworks/redis/RedisClient.java b/src/main/java/com/lambdaworks/redis/RedisClient.java index 7d639f17a2..450bc1abaf 100644 --- a/src/main/java/com/lambdaworks/redis/RedisClient.java +++ b/src/main/java/com/lambdaworks/redis/RedisClient.java @@ -18,7 +18,6 @@ import static com.lambdaworks.redis.LettuceStrings.isEmpty; import static com.lambdaworks.redis.LettuceStrings.isNotEmpty; -import java.net.ConnectException; import java.net.SocketAddress; import java.util.List; import java.util.concurrent.ExecutionException; @@ -200,19 +199,44 @@ public StatefulRedisConnection connect(RedisCodec codec, Redi private StatefulRedisConnection connectStandalone(RedisCodec codec, RedisURI redisURI, Timeout timeout) { + ConnectionFuture> future = connectStandaloneAsync(codec, redisURI, timeout); + return getConnection(future); + } + + private ConnectionFuture> connectStandaloneAsync(RedisCodec codec, + RedisURI redisURI) { + return connectStandaloneAsync(codec, redisURI, Timeout.from(redisURI)); + } + + private ConnectionFuture> connectStandaloneAsync(RedisCodec codec, + RedisURI redisURI, Timeout timeout) { + assertNotNull(codec); checkValidRedisURI(redisURI); + logger.debug("Trying to get a Redis connection for: " + redisURI); + DefaultEndpoint endpoint = new DefaultEndpoint(clientOptions); - StatefulRedisConnectionImpl connection = newStatefulRedisConnection(endpoint, codec, - timeout.timeout, timeout.timeUnit); - connectStateful(connection, redisURI, endpoint, () -> new CommandHandler(clientResources, endpoint)); - return connection; + StatefulRedisConnectionImpl connection = newStatefulRedisConnection(endpoint, codec, timeout.timeout, + timeout.timeUnit); + ConnectionFuture> future = connectStatefulAsync(connection, endpoint, redisURI, + () -> new CommandHandler(clientResources, endpoint)); + + future.whenComplete((channelHandler, throwable) -> { + + if (throwable != null) { + connection.close(); + } + }); + + return future; } - private void connectStateful(StatefulRedisConnectionImpl connection, RedisURI redisURI, - DefaultEndpoint endpoint, Supplier commandHandlerSupplier) { + @SuppressWarnings("unchecked") + private , S> ConnectionFuture connectStatefulAsync( + StatefulRedisConnectionImpl connection, DefaultEndpoint endpoint, RedisURI redisURI, + Supplier commandHandlerSupplier) { ConnectionBuilder connectionBuilder; if (redisURI.isSsl()) { @@ -261,7 +285,7 @@ private void connectStateful(StatefulRedisConnectionImpl connection }, clientResources.eventExecutorGroup()); } - getConnection(future); + return future.thenApply(channelHandler -> (S) connection); } /** @@ -323,7 +347,15 @@ private StatefulRedisPubSubConnection connectPubSub(RedisCodec connection = newStatefulRedisPubSubConnection(endpoint, endpoint, codec, timeout.timeout, timeout.timeUnit); - connectStateful(connection, redisURI, endpoint, () -> new PubSubCommandHandler<>(clientResources, codec, endpoint)); + ConnectionFuture> future = connectStatefulAsync(connection, endpoint, redisURI, + () -> new PubSubCommandHandler<>(clientResources, codec, endpoint)); + + getConnection(future.whenComplete((conn, throwable) -> { + + if (throwable != null) { + conn.close(); + } + })); return connection; } @@ -390,7 +422,7 @@ private StatefulRedisSentinelConnection connectSentinel(RedisCodec< StatefulRedisSentinelConnectionImpl connection = newStatefulRedisSentinelConnection(endpoint, codec, timeout.timeout, timeout.timeUnit); - logger.debug("Trying to get a Sentinel connection for one of: " + redisURI.getSentinels()); + logger.debug("Trying to get a Redis Sentinel connection for one of: " + redisURI.getSentinels()); connectionBuilder.endpoint(endpoint).commandHandler(() -> new CommandHandler(clientResources, endpoint)) .connection(connection); @@ -398,12 +430,19 @@ private StatefulRedisSentinelConnection connectSentinel(RedisCodec< if (redisURI.getSentinels().isEmpty() && (isNotEmpty(redisURI.getHost()) || !isEmpty(redisURI.getSocket()))) { channelType(connectionBuilder, redisURI); - getConnection(initializeChannelAsync(connectionBuilder)); + try { + getConnection(initializeChannelAsync(connectionBuilder)); + } catch (RuntimeException e) { + connection.close(); + throw e; + } } else { + boolean connected = false; boolean first = true; Exception causingException = null; validateUrisAreOfSameConnectionType(redisURI.getSentinels()); + for (RedisURI uri : redisURI.getSentinels()) { if (first) { channelType(connectionBuilder, uri); @@ -413,22 +452,21 @@ private StatefulRedisSentinelConnection connectSentinel(RedisCodec< if (logger.isDebugEnabled()) { SocketAddress socketAddress = SocketAddressResolver.resolve(redisURI, clientResources.dnsResolver()); - logger.debug("Connecting to Sentinel, address: " + socketAddress); + logger.debug("Connecting to Redis Sentinel, address: " + socketAddress); } try { getConnection(initializeChannelAsync(connectionBuilder)); connected = true; break; } catch (Exception e) { - logger.warn("Cannot connect sentinel at " + uri + ": " + e.toString()); + logger.warn("Cannot connect Redis Sentinel at " + uri + ": " + e.toString()); causingException = e; - if (e instanceof ConnectException) { - continue; - } } } + if (!connected) { - throw new RedisConnectionException("Cannot connect to a sentinel: " + redisURI.getSentinels(), + connection.close(); + throw new RedisConnectionException("Cannot connect to a Redis Sentinel: " + redisURI.getSentinels(), causingException); } } @@ -524,7 +562,7 @@ protected StatefulRedisConnectionImpl newStatefulRedisConnection(Re * {@link RedisURI} is configured with Sentinels) or via DNS resolution. *

    * Subclasses of {@link RedisClient} may override that method. - * + * * @param redisURI must not be {@literal null}. * @return the resolved {@link SocketAddress}. * @throws InterruptedException @@ -604,7 +642,7 @@ private SocketAddress lookupRedis(RedisURI sentinelUri) throws InterruptedExcept private void checkValidRedisURI(RedisURI redisURI) { - LettuceAssert.notNull(redisURI, "A valid RedisURI is needed"); + LettuceAssert.notNull(redisURI, "A valid RedisURI is required"); if (redisURI.getSentinels().isEmpty()) { if (isEmpty(redisURI.getHost()) && isEmpty(redisURI.getSocket())) { diff --git a/src/main/java/com/lambdaworks/redis/masterslave/AsyncConnections.java b/src/main/java/com/lambdaworks/redis/masterslave/AsyncConnections.java new file mode 100644 index 0000000000..a136d0d97c --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/masterslave/AsyncConnections.java @@ -0,0 +1,89 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.lambdaworks.redis.masterslave; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; + +import com.lambdaworks.redis.RedisConnectionException; +import com.lambdaworks.redis.RedisURI; +import com.lambdaworks.redis.api.StatefulRedisConnection; + +/** + * @author Mark Paluch + */ +class AsyncConnections { + + private final Map>> futures = new TreeMap<>( + MasterSlaveUtils.RedisURIComparator.INSTANCE); + + public AsyncConnections() { + } + + /** + * Add a connection for a {@link RedisURI} + * + * @param redisURI + * @param connection + */ + public void addConnection(RedisURI redisURI, CompletableFuture> connection) { + futures.put(redisURI, connection); + } + + /** + * @return the {@link Connections}. + * @throws RedisConnectionException if no connection could be established. + */ + public Connections get(long timeout, TimeUnit timeUnit) throws InterruptedException { + + Connections connections = new Connections(); + List exceptions = new CopyOnWriteArrayList<>(); + List> sync = new ArrayList<>(this.futures.size()); + + for (Map.Entry>> entry : this.futures.entrySet()) { + + CompletableFuture> future = entry.getValue(); + + sync.add(future.whenComplete((connection, throwable) -> { + + if (throwable != null) { + exceptions.add(throwable); + } else { + connections.addConnection(entry.getKey(), connection); + } + })); + } + + RefreshFutures.awaitAll(timeout, timeUnit, sync); + + if (connections.isEmpty() && !sync.isEmpty() && !exceptions.isEmpty()) { + + RedisConnectionException collector = new RedisConnectionException( + "Unable to establish a connection to Redis Cluster"); + exceptions.forEach(collector::addSuppressed); + + throw collector; + } + + return connections; + } +} diff --git a/src/main/java/com/lambdaworks/redis/masterslave/Connections.java b/src/main/java/com/lambdaworks/redis/masterslave/Connections.java new file mode 100644 index 0000000000..1d84f48243 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/masterslave/Connections.java @@ -0,0 +1,93 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.lambdaworks.redis.masterslave; + +import java.util.Map; +import java.util.TreeMap; + +import com.lambdaworks.redis.RedisURI; +import com.lambdaworks.redis.api.StatefulRedisConnection; +import com.lambdaworks.redis.codec.StringCodec; +import com.lambdaworks.redis.output.StatusOutput; +import com.lambdaworks.redis.protocol.Command; +import com.lambdaworks.redis.protocol.CommandArgs; +import com.lambdaworks.redis.protocol.CommandKeyword; +import com.lambdaworks.redis.protocol.CommandType; + +/** + * @author Mark Paluch + */ +class Connections { + + private final Map> connections = new TreeMap<>( + MasterSlaveUtils.RedisURIComparator.INSTANCE); + + public Connections() { + } + + /** + * Add a connection for a {@link RedisURI} + * + * @param redisURI + * @param connection + */ + public void addConnection(RedisURI redisURI, StatefulRedisConnection connection) { + synchronized (connections) { + connections.put(redisURI, connection); + } + } + + /** + * @return {@literal true} if no connections present. + */ + public boolean isEmpty() { + synchronized (connections) { + return connections.isEmpty(); + } + } + + /* + * Initiate {@code PING} on all connections and return the {@link Requests}. + * + * @return the {@link Requests}. + */ + public Requests requestPing() { + + Requests requests = new Requests(); + + for (Map.Entry> entry : connections.entrySet()) { + + CommandArgs args = new CommandArgs<>(StringCodec.ASCII).add(CommandKeyword.NODES); + Command command = new Command<>(CommandType.PING, new StatusOutput<>(StringCodec.ASCII), + args); + TimedAsyncCommand timedCommand = new TimedAsyncCommand<>(command); + + entry.getValue().dispatch(timedCommand); + requests.addRequest(entry.getKey(), timedCommand); + } + + return requests; + } + + /** + * Close all connections. + */ + public void close() { + for (StatefulRedisConnection connection : connections.values()) { + connection.close(); + } + } +} diff --git a/src/main/java/com/lambdaworks/redis/masterslave/MasterSlaveTopologyRefresh.java b/src/main/java/com/lambdaworks/redis/masterslave/MasterSlaveTopologyRefresh.java index 860e429771..fe6550e58f 100644 --- a/src/main/java/com/lambdaworks/redis/masterslave/MasterSlaveTopologyRefresh.java +++ b/src/main/java/com/lambdaworks/redis/masterslave/MasterSlaveTopologyRefresh.java @@ -17,21 +17,22 @@ import static com.lambdaworks.redis.masterslave.MasterSlaveUtils.findNodeByUri; -import java.util.*; -import java.util.concurrent.ExecutionException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; import com.lambdaworks.redis.RedisClient; import com.lambdaworks.redis.RedisCommandInterruptedException; -import com.lambdaworks.redis.RedisFuture; +import com.lambdaworks.redis.RedisConnectionException; import com.lambdaworks.redis.RedisURI; import com.lambdaworks.redis.api.StatefulRedisConnection; import com.lambdaworks.redis.cluster.models.partitions.Partitions; +import com.lambdaworks.redis.codec.StringCodec; import com.lambdaworks.redis.models.role.RedisNodeDescription; -import com.lambdaworks.redis.output.StatusOutput; -import com.lambdaworks.redis.protocol.*; -import io.netty.buffer.ByteBuf; import io.netty.util.internal.logging.InternalLogger; import io.netty.util.internal.logging.InternalLoggerFactory; @@ -43,12 +44,14 @@ class MasterSlaveTopologyRefresh { private static final InternalLogger logger = InternalLoggerFactory.getInstance(MasterSlaveTopologyRefresh.class); + private static final StringCodec CODEC = StringCodec.UTF8; - private final RedisClient client; + private final NodeConnectionFactory nodeConnectionFactory; private final TopologyProvider topologyProvider; public MasterSlaveTopologyRefresh(RedisClient client, TopologyProvider topologyProvider) { - this.client = client; + + this.nodeConnectionFactory = new ReflectiveNodeConnectionFactory(client); this.topologyProvider = topologyProvider; } @@ -65,12 +68,23 @@ public List getNodes(RedisURI seed) { addPasswordIfNeeded(nodes, seed); - Map> connections = getConnections(nodes); - Map> rawViews = requestPing(connections); - List result = getNodeSpecificViews(rawViews, nodes, seed); - close(connections); + AsyncConnections asyncConnections = getConnections(nodes); + Connections connections = null; - return result; + try { + + connections = asyncConnections.get(seed.getTimeout(), seed.getUnit()); + Requests requestedPing = connections.requestPing(); + return getNodeSpecificViews(requestedPing, nodes, seed); + + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new RedisCommandInterruptedException(e); + } finally { + if (connections != null) { + connections.close(); + } + } } private void addPasswordIfNeeded(List nodes, RedisURI seed) { @@ -82,189 +96,80 @@ private void addPasswordIfNeeded(List nodes, RedisURI seed } } - protected List getNodeSpecificViews( - Map> rawViews, List nodes, RedisURI seed) { + private List getNodeSpecificViews(Requests requestedPing, List nodes, + RedisURI seed) throws InterruptedException { + List result = new ArrayList<>(); long timeout = seed.getUnit().toNanos(seed.getTimeout()); - long waitTime = 0; Map latencies = new HashMap<>(); - for (Map.Entry> entry : rawViews.entrySet()) { - long timeoutLeft = timeout - waitTime; - - if (timeoutLeft <= 0) { - break; - } + requestedPing.await(timeout, TimeUnit.NANOSECONDS); - long startWait = System.nanoTime(); - RedisFuture future = entry.getValue(); + for (RedisNodeDescription node : nodes) { - try { + TimedAsyncCommand future = requestedPing.getRequest(node.getUri()); - if (!future.await(timeoutLeft, TimeUnit.NANOSECONDS)) { - break; - } - waitTime += System.nanoTime() - startWait; - - future.get(); - - RedisNodeDescription redisNodeDescription = findNodeByUri(nodes, entry.getKey()); - latencies.put(redisNodeDescription, entry.getValue().duration()); - result.add(redisNodeDescription); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - throw new RedisCommandInterruptedException(e); - } catch (ExecutionException e) { - logger.warn("Cannot retrieve partition view from " + entry.getKey(), e); + if (!future.isDone()) { + continue; } + + RedisNodeDescription redisNodeDescription = findNodeByUri(nodes, node.getUri()); + latencies.put(redisNodeDescription, future.duration()); + result.add(redisNodeDescription); } - LatencyComparator comparator = new LatencyComparator(latencies); + TopologyComparators.LatencyComparator comparator = new TopologyComparators.LatencyComparator(latencies); - Collections.sort(result, comparator); + result.sort(comparator); return result; } /* - * Async request of views. + * Establish connections asynchronously. */ - @SuppressWarnings("unchecked") - private Map> requestPing( - Map> connections) { - Map> rawViews = new TreeMap<>(RedisUriComparator.INSTANCE); - for (Map.Entry> entry : connections.entrySet()) { - - TimedAsyncCommand timed = createPingCommand(); - - entry.getValue().dispatch(timed); - rawViews.put(entry.getKey(), timed); - } - return rawViews; - } + private AsyncConnections getConnections(Iterable nodes) { - protected TimedAsyncCommand createPingCommand() { - CommandArgs args = new CommandArgs<>(MasterSlaveUtils.CODEC); - Command command = new Command<>(CommandType.PING, new StatusOutput<>(MasterSlaveUtils.CODEC), - args); - return new TimedAsyncCommand<>(command); - } - - private void close(Map> connections) { - for (StatefulRedisConnection connection : connections.values()) { - connection.close(); - } - } - - /* - * Open connections where an address can be resolved. - */ - private Map> getConnections(Iterable nodes) { - Map> connections = new TreeMap<>(RedisUriComparator.INSTANCE); + AsyncConnections connections = new AsyncConnections(); for (RedisNodeDescription node : nodes) { + RedisURI redisURI = node.getUri(); + String message = String.format("Unable to connect to %s", redisURI); try { - StatefulRedisConnection connection = client.connect(node.getUri()); - connections.put(node.getUri(), connection); - } catch (RuntimeException e) { - logger.warn("Cannot connect to " + node.getUri(), e); - } - } - return connections; - } + CompletableFuture> connectionFuture = nodeConnectionFactory + .connectToNodeAsync(CODEC, redisURI); - /** - * Compare {@link RedisURI} based on their host and port representation. - */ - static class RedisUriComparator implements Comparator { + CompletableFuture> sync = new CompletableFuture<>(); - public static final RedisUriComparator INSTANCE = new RedisUriComparator(); + connectionFuture.whenComplete((connection, throwable) -> { - @Override - public int compare(RedisURI o1, RedisURI o2) { - String h1 = ""; - String h2 = ""; + if (throwable != null) { - if (o1 != null) { - h1 = o1.getHost() + ":" + o1.getPort(); - } + if (throwable instanceof RedisConnectionException) { + if (logger.isDebugEnabled()) { + logger.debug(throwable.getMessage(), throwable); + } else { + logger.warn(throwable.getMessage()); + } + } else { + logger.warn(message, throwable); + } - if (o2 != null) { - h2 = o2.getHost() + ":" + o2.getPort(); - } + sync.completeExceptionally(new RedisConnectionException(message, throwable)); + } else { + connection.async().clientSetname("lettuce#MasterSlaveTopologyRefresh"); + sync.complete(connection); + } + }); - return h1.compareToIgnoreCase(h2); - } - } - - /** - * Timed command that records the time at which the command was encoded and completed. - * - * @param Key type - * @param Value type - * @param Result type - */ - static class TimedAsyncCommand extends AsyncCommand { - - long encodedAtNs = -1; - long completedAtNs = -1; - - public TimedAsyncCommand(RedisCommand command) { - super(command); - } - - @Override - public void encode(ByteBuf buf) { - completedAtNs = -1; - encodedAtNs = -1; - - super.encode(buf); - encodedAtNs = System.nanoTime(); - } - - @Override - public void complete() { - completedAtNs = System.nanoTime(); - super.complete(); - } - - public long duration() { - if (completedAtNs == -1 || encodedAtNs == -1) { - return -1; + connections.addConnection(redisURI, sync); + } catch (RuntimeException e) { + logger.warn(String.format(message, redisURI), e); } - return completedAtNs - encodedAtNs; } - } - - static class LatencyComparator implements Comparator { - - private final Map latencies; - - public LatencyComparator(Map latencies) { - this.latencies = latencies; - } - - @Override - public int compare(RedisNodeDescription o1, RedisNodeDescription o2) { - Long latency1 = latencies.get(o1); - Long latency2 = latencies.get(o2); - - if (latency1 != null && latency2 != null) { - return latency1.compareTo(latency2); - } - - if (latency1 != null && latency2 == null) { - return -1; - } - - if (latency1 == null && latency2 != null) { - return 1; - } - - return 0; - } + return connections; } } diff --git a/src/main/java/com/lambdaworks/redis/masterslave/MasterSlaveUtils.java b/src/main/java/com/lambdaworks/redis/masterslave/MasterSlaveUtils.java index 39004c084c..df345b7c79 100644 --- a/src/main/java/com/lambdaworks/redis/masterslave/MasterSlaveUtils.java +++ b/src/main/java/com/lambdaworks/redis/masterslave/MasterSlaveUtils.java @@ -16,6 +16,7 @@ package com.lambdaworks.redis.masterslave; import java.util.Collection; +import java.util.Comparator; import com.lambdaworks.redis.RedisURI; import com.lambdaworks.redis.codec.Utf8StringCodec; @@ -102,4 +103,28 @@ static boolean essentiallyEqualsTo(RedisNodeDescription o1, RedisNodeDescription return true; } + /** + * Compare {@link RedisURI} based on their host and port representation. + */ + enum RedisURIComparator implements Comparator { + + INSTANCE; + + @Override + public int compare(RedisURI o1, RedisURI o2) { + String h1 = ""; + String h2 = ""; + + if (o1 != null) { + h1 = o1.getHost() + ":" + o1.getPort(); + } + + if (o2 != null) { + h2 = o2.getHost() + ":" + o2.getPort(); + } + + return h1.compareToIgnoreCase(h2); + } + } + } diff --git a/src/main/java/com/lambdaworks/redis/masterslave/NodeConnectionFactory.java b/src/main/java/com/lambdaworks/redis/masterslave/NodeConnectionFactory.java new file mode 100644 index 0000000000..dc6b608f41 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/masterslave/NodeConnectionFactory.java @@ -0,0 +1,43 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.lambdaworks.redis.masterslave; + +import java.net.SocketAddress; +import java.util.concurrent.CompletableFuture; + +import com.lambdaworks.redis.RedisURI; +import com.lambdaworks.redis.api.StatefulRedisConnection; +import com.lambdaworks.redis.codec.RedisCodec; + +/** + * Factory interface to obtain {@link StatefulRedisConnection connections} to Redis nodes. + * + * @author Mark Paluch + * @since 4.4 + */ +public interface NodeConnectionFactory { + + /** + * Connects to a {@link SocketAddress} with the given {@link RedisCodec} asynchronously. + * + * @param codec must not be {@literal null}. + * @param redisURI must not be {@literal null}. + * @param Key type. + * @param Value type. + * @return a new {@link StatefulRedisConnection} + */ + CompletableFuture> connectToNodeAsync(RedisCodec codec, RedisURI redisURI); +} diff --git a/src/main/java/com/lambdaworks/redis/masterslave/ReflectiveNodeConnectionFactory.java b/src/main/java/com/lambdaworks/redis/masterslave/ReflectiveNodeConnectionFactory.java new file mode 100644 index 0000000000..994cf8327c --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/masterslave/ReflectiveNodeConnectionFactory.java @@ -0,0 +1,67 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.lambdaworks.redis.masterslave; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.concurrent.CompletableFuture; + +import com.lambdaworks.redis.RedisClient; +import com.lambdaworks.redis.RedisURI; +import com.lambdaworks.redis.api.StatefulRedisConnection; +import com.lambdaworks.redis.codec.RedisCodec; + +/** + * {@link NodeConnectionFactory} implementation that operates via reflection on {@link RedisClient}. Using reflection does not + * require utility methods to leak on the API. + * + * @author Mark Paluch + */ +@SuppressWarnings("unchecked") +class ReflectiveNodeConnectionFactory implements NodeConnectionFactory { + + private final Method connectToNodeAsync; + private final RedisClient client; + + protected ReflectiveNodeConnectionFactory(RedisClient client) { + + this.client = client; + + try { + connectToNodeAsync = RedisClient.class.getDeclaredMethod("connectStandaloneAsync", RedisCodec.class, + RedisURI.class); + connectToNodeAsync.setAccessible(true); + } catch (NoSuchMethodException e) { + throw new IllegalStateException(e); + } + } + + @Override + public CompletableFuture> connectToNodeAsync(RedisCodec codec, + RedisURI redisURI) { + try { + return (CompletableFuture>) connectToNodeAsync.invoke(client, codec, redisURI); + } catch (IllegalAccessException e) { + throw new IllegalStateException(e); + } catch (InvocationTargetException e) { + + if (e.getCause() instanceof RuntimeException) { + throw (RuntimeException) e.getCause(); + } + throw new IllegalStateException(e.getCause()); + } + } +} diff --git a/src/main/java/com/lambdaworks/redis/masterslave/RefreshFutures.java b/src/main/java/com/lambdaworks/redis/masterslave/RefreshFutures.java new file mode 100644 index 0000000000..679712a5bf --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/masterslave/RefreshFutures.java @@ -0,0 +1,64 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.lambdaworks.redis.masterslave; + +import java.util.Collection; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; + +/** + * @author Mark Paluch + */ +class RefreshFutures { + + /** + * Await for either future completion or to reach the timeout. Successful/exceptional future completion is not substantial. + * + * @param timeout the timeout value. + * @param timeUnit timeout unit. + * @param futures {@link Collection} of {@literal Future}s. + * @return time awaited in {@link TimeUnit#NANOSECONDS}. + * @throws InterruptedException + */ + static long awaitAll(long timeout, TimeUnit timeUnit, Collection> futures) throws InterruptedException { + + long waitTime = 0; + + for (Future future : futures) { + + long timeoutLeft = timeUnit.toNanos(timeout) - waitTime; + + if (timeoutLeft <= 0) { + break; + } + + long startWait = System.nanoTime(); + + try { + future.get(timeoutLeft, TimeUnit.NANOSECONDS); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw e; + } catch (Exception e) { + continue; + } finally { + waitTime += System.nanoTime() - startWait; + } + + } + return waitTime; + } +} diff --git a/src/main/java/com/lambdaworks/redis/masterslave/Requests.java b/src/main/java/com/lambdaworks/redis/masterslave/Requests.java new file mode 100644 index 0000000000..e9a20b13b2 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/masterslave/Requests.java @@ -0,0 +1,53 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.lambdaworks.redis.masterslave; + +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; +import java.util.concurrent.TimeUnit; + +import com.lambdaworks.redis.RedisURI; + +/** + * Encapsulates asynchronously executed commands to multiple {@link RedisURI nodes}. + * + * @author Mark Paluch + */ +class Requests { + + private final Map> rawViews = new TreeMap<>( + MasterSlaveUtils.RedisURIComparator.INSTANCE); + + public Requests() { + } + + protected void addRequest(RedisURI redisURI, TimedAsyncCommand command) { + rawViews.put(redisURI, command); + } + + protected long await(long timeout, TimeUnit timeUnit) throws InterruptedException { + return RefreshFutures.awaitAll(timeout, timeUnit, rawViews.values()); + } + + protected Set nodes() { + return rawViews.keySet(); + } + + protected TimedAsyncCommand getRequest(RedisURI redisURI) { + return rawViews.get(redisURI); + } +} diff --git a/src/main/java/com/lambdaworks/redis/masterslave/SentinelTopologyRefresh.java b/src/main/java/com/lambdaworks/redis/masterslave/SentinelTopologyRefresh.java index 2dd728f4c3..c87813fb78 100644 --- a/src/main/java/com/lambdaworks/redis/masterslave/SentinelTopologyRefresh.java +++ b/src/main/java/com/lambdaworks/redis/masterslave/SentinelTopologyRefresh.java @@ -145,7 +145,7 @@ private void initializeSentinels() { private void processMessage(String pattern, String channel, String message) { topologyRefresh.processMessage(channel, message, () -> { - LOG.debug("Received topology changed signal from Redis Sentinel, scheduling topology update"); + LOG.debug("Received topology changed signal from Redis Sentinel ({}), scheduling topology update", channel); return () -> refreshRunnables.forEach(Runnable::run); }); diff --git a/src/main/java/com/lambdaworks/redis/masterslave/TimedAsyncCommand.java b/src/main/java/com/lambdaworks/redis/masterslave/TimedAsyncCommand.java new file mode 100644 index 0000000000..f595f9cefe --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/masterslave/TimedAsyncCommand.java @@ -0,0 +1,61 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.lambdaworks.redis.masterslave; + +import com.lambdaworks.redis.protocol.AsyncCommand; +import com.lambdaworks.redis.protocol.RedisCommand; + +import io.netty.buffer.ByteBuf; + +/** + * Timed command that records the time at which the command was encoded and completed. + * + * @param Key type + * @param Value type + * @param Result type + * @author Mark Paluch + */ +class TimedAsyncCommand extends AsyncCommand { + + long encodedAtNs = -1; + long completedAtNs = -1; + + public TimedAsyncCommand(RedisCommand command) { + super(command); + } + + @Override + public void encode(ByteBuf buf) { + completedAtNs = -1; + encodedAtNs = -1; + + super.encode(buf); + encodedAtNs = System.nanoTime(); + } + + @Override + public void complete() { + completedAtNs = System.nanoTime(); + super.complete(); + } + + public long duration() { + if (completedAtNs == -1 || encodedAtNs == -1) { + return -1; + } + return completedAtNs - encodedAtNs; + } +} diff --git a/src/main/java/com/lambdaworks/redis/masterslave/TopologyComparators.java b/src/main/java/com/lambdaworks/redis/masterslave/TopologyComparators.java new file mode 100644 index 0000000000..be98fbba0f --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/masterslave/TopologyComparators.java @@ -0,0 +1,87 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.lambdaworks.redis.masterslave; + +import java.util.Comparator; +import java.util.Map; + +import com.lambdaworks.redis.RedisURI; +import com.lambdaworks.redis.models.role.RedisNodeDescription; + +/** + * Comparators for {@link RedisNodeDescription} and {@link RedisURI}. + * + * @author Mark Paluch + */ +class TopologyComparators { + + /** + * Compare {@link RedisNodeDescription} based on their latency. Lowest comes first. + */ + static class LatencyComparator implements Comparator { + + private final Map latencies; + + public LatencyComparator(Map latencies) { + this.latencies = latencies; + } + + @Override + public int compare(RedisNodeDescription o1, RedisNodeDescription o2) { + + Long latency1 = latencies.get(o1); + Long latency2 = latencies.get(o2); + + if (latency1 != null && latency2 != null) { + return latency1.compareTo(latency2); + } + + if (latency1 != null) { + return -1; + } + + if (latency2 != null) { + return 1; + } + + return 0; + } + } + + /** + * Compare {@link RedisURI} based on their host and port representation. + */ + enum RedisURIComparator implements Comparator { + + INSTANCE; + + @Override + public int compare(RedisURI o1, RedisURI o2) { + String h1 = ""; + String h2 = ""; + + if (o1 != null) { + h1 = o1.getHost() + ":" + o1.getPort(); + } + + if (o2 != null) { + h2 = o2.getHost() + ":" + o2.getPort(); + } + + return h1.compareToIgnoreCase(h2); + } + } +} diff --git a/src/test/java/com/lambdaworks/redis/cluster/topology/ClusterTopologyRefreshTest.java b/src/test/java/com/lambdaworks/redis/cluster/topology/ClusterTopologyRefreshTest.java index d2addc8b78..831ebc5675 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/topology/ClusterTopologyRefreshTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/topology/ClusterTopologyRefreshTest.java @@ -30,7 +30,6 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; -import io.netty.util.concurrent.ImmediateEventExecutor; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -49,6 +48,8 @@ import com.lambdaworks.redis.resource.ClientResources; import com.lambdaworks.redis.resource.DnsResolvers; +import io.netty.util.concurrent.ImmediateEventExecutor; + /** * @author Mark Paluch */ @@ -376,7 +377,7 @@ protected Requests createClusterNodesRequests(int duration, String nodes) { connections.addConnection(redisURI, connection); Requests requests = connections.requestTopology(); - TimedAsyncCommand command = requests.rawViews.get(redisURI); + TimedAsyncCommand command = requests.getRequest(redisURI); command.getOutput().set(ByteBuffer.wrap(nodes.getBytes())); command.complete(); @@ -393,7 +394,7 @@ protected Requests createClientListRequests(int duration, String response) { connections.addConnection(redisURI, connection); Requests requests = connections.requestTopology(); - TimedAsyncCommand command = requests.rawViews.get(redisURI); + TimedAsyncCommand command = requests.getRequest(redisURI); command.getOutput().set(ByteBuffer.wrap(response.getBytes())); command.complete(); From c7406ca1d39bee3ba0ddd86d7035089cbe94dc89 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Wed, 21 Dec 2016 12:13:28 +0100 Subject: [PATCH 104/808] Polishing --- .../topology/ClusterTopologyRefresh.java | 4 ++-- .../redis/cluster/topology/Connections.java | 17 ++++++++-------- .../cluster/topology/RefreshFutures.java | 9 +++++++++ .../redis/cluster/topology/Requests.java | 20 ++++++++++--------- 4 files changed, 31 insertions(+), 19 deletions(-) diff --git a/src/main/java/com/lambdaworks/redis/cluster/topology/ClusterTopologyRefresh.java b/src/main/java/com/lambdaworks/redis/cluster/topology/ClusterTopologyRefresh.java index 0629106d68..4e5ae11dfb 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/topology/ClusterTopologyRefresh.java +++ b/src/main/java/com/lambdaworks/redis/cluster/topology/ClusterTopologyRefresh.java @@ -171,7 +171,7 @@ NodeTopologyViews getNodeSpecificViews(Requests requestedTopology, Requests requ } for (NodeTopologyView view : views) { - Collections.sort(view.getPartitions().getPartitions(), TopologyComparators.LatencyComparator.INSTANCE); + view.getPartitions().getPartitions().sort(TopologyComparators.LatencyComparator.INSTANCE); view.getPartitions().updateCache(); } @@ -236,7 +236,7 @@ private AsyncConnections getConnections(Iterable redisURIs) throws Int connections.addConnection(redisURI, sync); } catch (RuntimeException e) { - logger.warn(String.format("Cannot connect to %s", redisURI), e); + logger.warn(String.format("Unable to connect to %s", redisURI), e); } } diff --git a/src/main/java/com/lambdaworks/redis/cluster/topology/Connections.java b/src/main/java/com/lambdaworks/redis/cluster/topology/Connections.java index 60e43e8022..f23c045662 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/topology/Connections.java +++ b/src/main/java/com/lambdaworks/redis/cluster/topology/Connections.java @@ -20,6 +20,7 @@ import com.lambdaworks.redis.RedisURI; import com.lambdaworks.redis.api.StatefulRedisConnection; +import com.lambdaworks.redis.codec.StringCodec; import com.lambdaworks.redis.output.StatusOutput; import com.lambdaworks.redis.protocol.Command; import com.lambdaworks.redis.protocol.CommandArgs; @@ -31,10 +32,10 @@ */ class Connections { - private Map> connections = new TreeMap<>( - TopologyComparators.RedisURIComparator.INSTANCE); + private final Map> connections; public Connections() { + connections = new TreeMap<>(TopologyComparators.RedisURIComparator.INSTANCE); } private Connections(Map> connections) { @@ -73,9 +74,9 @@ public Requests requestTopology() { for (Map.Entry> entry : connections.entrySet()) { - CommandArgs args = new CommandArgs<>(ClusterTopologyRefresh.CODEC).add(CommandKeyword.NODES); - Command command = new Command<>(CommandType.CLUSTER, - new StatusOutput<>(ClusterTopologyRefresh.CODEC), args); + CommandArgs args = new CommandArgs<>(StringCodec.UTF8).add(CommandKeyword.NODES); + Command command = new Command<>(CommandType.CLUSTER, new StatusOutput<>(StringCodec.UTF8), + args); TimedAsyncCommand timedCommand = new TimedAsyncCommand<>(command); entry.getValue().dispatch(timedCommand); @@ -96,9 +97,9 @@ public Requests requestClients() { for (Map.Entry> entry : connections.entrySet()) { - CommandArgs args = new CommandArgs<>(ClusterTopologyRefresh.CODEC).add(CommandKeyword.LIST); - Command command = new Command<>(CommandType.CLIENT, - new StatusOutput<>(ClusterTopologyRefresh.CODEC), args); + CommandArgs args = new CommandArgs<>(StringCodec.UTF8).add(CommandKeyword.LIST); + Command command = new Command<>(CommandType.CLIENT, new StatusOutput<>(StringCodec.UTF8), + args); TimedAsyncCommand timedCommand = new TimedAsyncCommand<>(command); entry.getValue().dispatch(timedCommand); diff --git a/src/main/java/com/lambdaworks/redis/cluster/topology/RefreshFutures.java b/src/main/java/com/lambdaworks/redis/cluster/topology/RefreshFutures.java index 3a8463e427..57d03fdb59 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/topology/RefreshFutures.java +++ b/src/main/java/com/lambdaworks/redis/cluster/topology/RefreshFutures.java @@ -24,6 +24,15 @@ */ class RefreshFutures { + /** + * Await for either future completion or to reach the timeout. Successful/exceptional future completion is not substantial. + * + * @param timeout the timeout value. + * @param timeUnit timeout unit. + * @param futures {@link Collection} of {@literal Future}s. + * @return time awaited in {@link TimeUnit#NANOSECONDS}. + * @throws InterruptedException + */ static long awaitAll(long timeout, TimeUnit timeUnit, Collection> futures) throws InterruptedException { long waitTime = 0; diff --git a/src/main/java/com/lambdaworks/redis/cluster/topology/Requests.java b/src/main/java/com/lambdaworks/redis/cluster/topology/Requests.java index 58fb8fcf3e..bf3a555fe7 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/topology/Requests.java +++ b/src/main/java/com/lambdaworks/redis/cluster/topology/Requests.java @@ -23,37 +23,39 @@ import com.lambdaworks.redis.RedisURI; /** + * Encapsulates asynchronously executed commands to multiple {@link RedisURI nodes}. + * * @author Mark Paluch */ class Requests { - Map> rawViews = new TreeMap<>( - TopologyComparators.RedisURIComparator.INSTANCE); + private final Map> rawViews; - Requests() { + protected Requests() { + rawViews = new TreeMap<>(TopologyComparators.RedisURIComparator.INSTANCE); } - Requests(Map> rawViews) { + private Requests(Map> rawViews) { this.rawViews = rawViews; } - void addRequest(RedisURI redisURI, TimedAsyncCommand command) { + protected void addRequest(RedisURI redisURI, TimedAsyncCommand command) { rawViews.put(redisURI, command); } - long await(long timeout, TimeUnit timeUnit) throws InterruptedException { + protected long await(long timeout, TimeUnit timeUnit) throws InterruptedException { return RefreshFutures.awaitAll(timeout, timeUnit, rawViews.values()); } - Set nodes() { + protected Set nodes() { return rawViews.keySet(); } - TimedAsyncCommand getRequest(RedisURI redisURI) { + protected TimedAsyncCommand getRequest(RedisURI redisURI) { return rawViews.get(redisURI); } - Requests mergeWith(Requests requests) { + protected Requests mergeWith(Requests requests) { Map> result = new TreeMap<>( TopologyComparators.RedisURIComparator.INSTANCE); From 28d8eeed43bc3ce1ee8d867c344bd5ca4566ce3c Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Wed, 21 Dec 2016 13:27:00 +0100 Subject: [PATCH 105/808] Adopt fixed GEODIST/GEOHASH behavior in tests #362 --- .../java/com/lambdaworks/redis/commands/GeoCommandTest.java | 6 +++--- .../redis/commands/reactive/GeoReactiveCommandTest.java | 5 ----- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/src/test/java/com/lambdaworks/redis/commands/GeoCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/GeoCommandTest.java index c7ce5e06b4..5e3ceec851 100644 --- a/src/test/java/com/lambdaworks/redis/commands/GeoCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/GeoCommandTest.java @@ -118,8 +118,7 @@ public void geodist() throws Exception { assertThat(result).isGreaterThan(2.5).isLessThan(2.9); } - // See https://github.com/antirez/redis/issues/3512 and https://github.com/mp911de/lettuce/issues/362 - @Test(expected = RedisException.class) + @Test public void geodistMissingElements() throws Exception { prepareGeo(); @@ -256,7 +255,8 @@ public void geohashUnknownKey() throws Exception { List> geohash = redis.geohash("dunno", "member"); - assertThat(geohash).isEmpty(); + assertThat(geohash).hasSize(1); + assertThat(geohash.get(0)).isIn(null, Value.empty()); } @Test diff --git a/src/test/java/com/lambdaworks/redis/commands/reactive/GeoReactiveCommandTest.java b/src/test/java/com/lambdaworks/redis/commands/reactive/GeoReactiveCommandTest.java index 1291adece4..e497ce2e0a 100644 --- a/src/test/java/com/lambdaworks/redis/commands/reactive/GeoReactiveCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/commands/reactive/GeoReactiveCommandTest.java @@ -61,9 +61,4 @@ public void geopos() throws Exception { @Override public void geoposWithTransaction() throws Exception { } - - @Test(expected = NumberFormatException.class) - public void geodistMissingElements() throws Exception { - super.geodistMissingElements(); - } } From edf27eee6c84cfd9a4de3af7843b95fe8572ccc1 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Wed, 21 Dec 2016 17:25:14 +0100 Subject: [PATCH 106/808] Extend RedisConnectionStateListener.onRedisConnected by adding SocketAddress #419 --- .../redis/ConnectionEventTrigger.java | 2 +- .../lambdaworks/redis/ConnectionEvents.java | 9 +- .../redis/RedisConnectionStateAdapter.java | 42 ++++++ .../redis/RedisConnectionStateListener.java | 19 ++- .../com/lambdaworks/redis/ClientTest.java | 94 +----------- .../redis/RedisClientListenerTest.java | 134 ++++++++++++++++++ 6 files changed, 201 insertions(+), 99 deletions(-) create mode 100644 src/main/java/com/lambdaworks/redis/RedisConnectionStateAdapter.java create mode 100644 src/test/java/com/lambdaworks/redis/RedisClientListenerTest.java diff --git a/src/main/java/com/lambdaworks/redis/ConnectionEventTrigger.java b/src/main/java/com/lambdaworks/redis/ConnectionEventTrigger.java index 2178838e16..dc90d6846b 100644 --- a/src/main/java/com/lambdaworks/redis/ConnectionEventTrigger.java +++ b/src/main/java/com/lambdaworks/redis/ConnectionEventTrigger.java @@ -44,7 +44,7 @@ class ConnectionEventTrigger extends ChannelInboundHandlerAdapter { @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { - connectionEvents.fireEventRedisConnected(connection); + connectionEvents.fireEventRedisConnected(connection, ctx.channel().remoteAddress()); super.channelActive(ctx); } diff --git a/src/main/java/com/lambdaworks/redis/ConnectionEvents.java b/src/main/java/com/lambdaworks/redis/ConnectionEvents.java index 64bd6839bb..efe5636819 100644 --- a/src/main/java/com/lambdaworks/redis/ConnectionEvents.java +++ b/src/main/java/com/lambdaworks/redis/ConnectionEvents.java @@ -15,6 +15,7 @@ */ package com.lambdaworks.redis; +import java.net.SocketAddress; import java.util.Set; import java.util.concurrent.CompletableFuture; @@ -30,19 +31,19 @@ public class ConnectionEvents { private final Set listeners = new ConcurrentSet<>(); - protected void fireEventRedisConnected(RedisChannelHandler connection) { + void fireEventRedisConnected(RedisChannelHandler connection, SocketAddress socketAddress) { for (RedisConnectionStateListener listener : listeners) { - listener.onRedisConnected(connection); + listener.onRedisConnected(connection, socketAddress); } } - protected void fireEventRedisDisconnected(RedisChannelHandler connection) { + void fireEventRedisDisconnected(RedisChannelHandler connection) { for (RedisConnectionStateListener listener : listeners) { listener.onRedisDisconnected(connection); } } - protected void fireEventRedisExceptionCaught(RedisChannelHandler connection, Throwable cause) { + void fireEventRedisExceptionCaught(RedisChannelHandler connection, Throwable cause) { for (RedisConnectionStateListener listener : listeners) { listener.onRedisExceptionCaught(connection, cause); } diff --git a/src/main/java/com/lambdaworks/redis/RedisConnectionStateAdapter.java b/src/main/java/com/lambdaworks/redis/RedisConnectionStateAdapter.java new file mode 100644 index 0000000000..cda5404118 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/RedisConnectionStateAdapter.java @@ -0,0 +1,42 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.lambdaworks.redis; + +import java.net.SocketAddress; + +/** + * Convenience adapter with an empty implementation of all {@link RedisConnectionStateListener} callback methods. + * + * @author Mark Paluch + * @since 4.4 + */ +public class RedisConnectionStateAdapter implements RedisConnectionStateListener { + + @Override + public void onRedisConnected(RedisChannelHandler connection, SocketAddress socketAddress) { + // empty adapter method + } + + @Override + public void onRedisDisconnected(RedisChannelHandler connection) { + // empty adapter method + } + + @Override + public void onRedisExceptionCaught(RedisChannelHandler connection, Throwable cause) { + // empty adapter method + } +} diff --git a/src/main/java/com/lambdaworks/redis/RedisConnectionStateListener.java b/src/main/java/com/lambdaworks/redis/RedisConnectionStateListener.java index 9c1f199ee3..5d461a1513 100644 --- a/src/main/java/com/lambdaworks/redis/RedisConnectionStateListener.java +++ b/src/main/java/com/lambdaworks/redis/RedisConnectionStateListener.java @@ -15,10 +15,13 @@ */ package com.lambdaworks.redis; +import java.net.SocketAddress; + /** * Simple interface for Redis connection state monitoring. * * @author ze + * @author Mark Paluch */ public interface RedisConnectionStateListener { @@ -26,8 +29,22 @@ public interface RedisConnectionStateListener { * Event handler for successful connection event. * * @param connection Source connection. + * @deprecated since 4.4, use {@link RedisConnectionStateListener#onRedisConnected(RedisChannelHandler, SocketAddress)}. + */ + @Deprecated + default void onRedisConnected(RedisChannelHandler connection) { + } + + /** + * Event handler for successful connection event. Delegates by default to {@link #onRedisConnected(RedisChannelHandler)}. + * + * @param connection Source connection. + * @param socketAddress remote {@link SocketAddress}. + * @since 4.4 */ - void onRedisConnected(RedisChannelHandler connection); + default void onRedisConnected(RedisChannelHandler connection, SocketAddress socketAddress) { + onRedisConnected(connection); + } /** * Event handler for disconnection event. diff --git a/src/test/java/com/lambdaworks/redis/ClientTest.java b/src/test/java/com/lambdaworks/redis/ClientTest.java index f1873dd64d..a4859c5182 100644 --- a/src/test/java/com/lambdaworks/redis/ClientTest.java +++ b/src/test/java/com/lambdaworks/redis/ClientTest.java @@ -15,21 +15,17 @@ */ package com.lambdaworks.redis; -import static com.google.code.tempusfugit.temporal.Duration.seconds; -import static com.google.code.tempusfugit.temporal.WaitFor.waitOrTimeout; import static org.assertj.core.api.Assertions.assertThat; import java.util.concurrent.TimeUnit; -import com.lambdaworks.TestClientResources; import org.junit.FixMethodOrder; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.junit.runners.MethodSorters; -import com.google.code.tempusfugit.temporal.Condition; -import com.google.code.tempusfugit.temporal.Timeout; +import com.lambdaworks.TestClientResources; import com.lambdaworks.redis.api.StatefulRedisConnection; import com.lambdaworks.redis.api.async.RedisAsyncCommands; @@ -78,71 +74,6 @@ public void statefulConnectionFromReactive() throws Exception { async.getStatefulConnection().close(); } - @Test - public void listenerTest() throws Exception { - - final TestConnectionListener listener = new TestConnectionListener(); - - RedisClient client = RedisClient.create(RedisURI.Builder.redis(host, port).build()); - - client.addListener(listener); - - assertThat(listener.onConnected).isNull(); - assertThat(listener.onDisconnected).isNull(); - assertThat(listener.onException).isNull(); - - RedisAsyncCommands connection = client.connect().async(); - - StatefulRedisConnection statefulRedisConnection = connection.getStatefulConnection(); - - waitOrTimeout(() -> listener.onConnected != null, Timeout.timeout(seconds(2))); - - assertThat(listener.onConnected).isEqualTo(statefulRedisConnection); - assertThat(listener.onDisconnected).isNull(); - - connection.set(key, value).get(); - connection.getStatefulConnection().close(); - - waitOrTimeout(new Condition() { - - @Override - public boolean isSatisfied() { - return listener.onDisconnected != null; - } - }, Timeout.timeout(seconds(2))); - - assertThat(listener.onConnected).isEqualTo(statefulRedisConnection); - assertThat(listener.onDisconnected).isEqualTo(statefulRedisConnection); - - FastShutdown.shutdown(client); - } - - @Test - public void listenerTestWithRemoval() throws Exception { - - final TestConnectionListener removedListener = new TestConnectionListener(); - final TestConnectionListener retainedListener = new TestConnectionListener(); - - RedisClient client = RedisClient.create(RedisURI.Builder.redis(host, port).build()); - client.addListener(removedListener); - client.addListener(retainedListener); - client.removeListener(removedListener); - - // that's the sut call - client.connect().async(); - - waitOrTimeout(() -> retainedListener.onConnected != null, Timeout.timeout(seconds(2))); - - assertThat(retainedListener.onConnected).isNotNull(); - - assertThat(removedListener.onConnected).isNull(); - assertThat(removedListener.onDisconnected).isNull(); - assertThat(removedListener.onException).isNull(); - - FastShutdown.shutdown(client); - - } - @Test(expected = RedisException.class) public void timeout() throws Exception { redis.setTimeout(0, TimeUnit.MICROSECONDS); @@ -189,29 +120,6 @@ public void connectPubSubFailure() throws Exception { FastShutdown.shutdown(client); } - private class TestConnectionListener implements RedisConnectionStateListener { - - public RedisChannelHandler onConnected; - public RedisChannelHandler onDisconnected; - public RedisChannelHandler onException; - - @Override - public void onRedisConnected(RedisChannelHandler connection) { - onConnected = connection; - } - - @Override - public void onRedisDisconnected(RedisChannelHandler connection) { - onDisconnected = connection; - } - - @Override - public void onRedisExceptionCaught(RedisChannelHandler connection, Throwable cause) { - onException = connection; - - } - } - @Test public void emptyClient() throws Exception { diff --git a/src/test/java/com/lambdaworks/redis/RedisClientListenerTest.java b/src/test/java/com/lambdaworks/redis/RedisClientListenerTest.java new file mode 100644 index 0000000000..76f70bb341 --- /dev/null +++ b/src/test/java/com/lambdaworks/redis/RedisClientListenerTest.java @@ -0,0 +1,134 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.lambdaworks.redis; + +import static com.google.code.tempusfugit.temporal.Duration.seconds; +import static com.google.code.tempusfugit.temporal.WaitFor.waitOrTimeout; +import static org.assertj.core.api.Assertions.assertThat; + +import java.net.SocketAddress; +import java.util.concurrent.TimeUnit; + +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +import com.google.code.tempusfugit.temporal.Timeout; +import com.lambdaworks.TestClientResources; +import com.lambdaworks.redis.api.StatefulRedisConnection; +import com.lambdaworks.redis.resource.ClientResources; + +/** + * Integration tests for {@link RedisConnectionStateListener} via {@link RedisClient}. + * + * @author Mark Paluch + */ +public class RedisClientListenerTest extends AbstractTest { + + private static ClientResources DEFAULT_RESOURCES; + + @BeforeClass + public static void beforeClass() throws Exception { + DEFAULT_RESOURCES = TestClientResources.create(); + } + + @AfterClass + public static void afterClass() throws Exception { + DEFAULT_RESOURCES.shutdown(100, 100, TimeUnit.MILLISECONDS).get(); + } + + @Test + public void shouldNotifyListener() throws Exception { + + final TestConnectionListener listener = new TestConnectionListener(); + + RedisClient client = RedisClient.create(DEFAULT_RESOURCES, RedisURI.Builder.redis(host, port).build()); + + client.addListener(listener); + + assertThat(listener.onConnected).isNull(); + assertThat(listener.onDisconnected).isNull(); + assertThat(listener.onException).isNull(); + + StatefulRedisConnection connection = client.connect(); + + waitOrTimeout(() -> listener.onConnected != null, Timeout.timeout(seconds(2))); + assertThat(listener.onConnectedSocketAddress).isNotNull(); + + assertThat(listener.onConnected).isEqualTo(connection); + assertThat(listener.onDisconnected).isNull(); + + connection.sync().set(key, value); + connection.close(); + + waitOrTimeout(() -> listener.onDisconnected != null, Timeout.timeout(seconds(2))); + + assertThat(listener.onConnected).isEqualTo(connection); + assertThat(listener.onDisconnected).isEqualTo(connection); + + FastShutdown.shutdown(client); + } + + @Test + public void shouldNotNotifyListenerAfterRemoval() throws Exception { + + final TestConnectionListener removedListener = new TestConnectionListener(); + final TestConnectionListener retainedListener = new TestConnectionListener(); + + RedisClient client = RedisClient.create(DEFAULT_RESOURCES, RedisURI.Builder.redis(host, port).build()); + client.addListener(removedListener); + client.addListener(retainedListener); + client.removeListener(removedListener); + + // that's the sut call + client.connect().close(); + + waitOrTimeout(() -> retainedListener.onConnected != null, Timeout.timeout(seconds(2))); + + assertThat(retainedListener.onConnected).isNotNull(); + + assertThat(removedListener.onConnected).isNull(); + assertThat(removedListener.onConnectedSocketAddress).isNull(); + assertThat(removedListener.onDisconnected).isNull(); + assertThat(removedListener.onException).isNull(); + + FastShutdown.shutdown(client); + } + + private class TestConnectionListener implements RedisConnectionStateListener { + + volatile SocketAddress onConnectedSocketAddress; + volatile RedisChannelHandler onConnected; + volatile RedisChannelHandler onDisconnected; + volatile RedisChannelHandler onException; + + @Override + public void onRedisConnected(RedisChannelHandler connection, SocketAddress socketAddress) { + onConnected = connection; + onConnectedSocketAddress = socketAddress; + } + + @Override + public void onRedisDisconnected(RedisChannelHandler connection) { + onDisconnected = connection; + } + + @Override + public void onRedisExceptionCaught(RedisChannelHandler connection, Throwable cause) { + onException = connection; + } + } +} From f7fabffb004d1fa0a2f135c98ad0eb6e99fe7468 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Fri, 23 Dec 2016 10:59:05 +0100 Subject: [PATCH 107/808] Consider Wildcard types in type information and assignability #431 --- .../support/GenericArrayTypeInformation.java | 2 +- .../support/ParametrizedTypeInformation.java | 22 ++- .../redis/dynamic/support/TypeDiscoverer.java | 40 ++--- .../support/TypeVariableTypeInformation.java | 24 ++- .../support/WildcardTypeInformation.java | 79 ++++++++++ .../ParametrizedTypeInformationTest.java | 141 ++++++++++++++++++ .../support/WildcardTypeInformationTest.java | 130 ++++++++++++++++ 7 files changed, 411 insertions(+), 27 deletions(-) create mode 100644 src/main/java/com/lambdaworks/redis/dynamic/support/WildcardTypeInformation.java create mode 100644 src/test/java/com/lambdaworks/redis/dynamic/support/ParametrizedTypeInformationTest.java create mode 100644 src/test/java/com/lambdaworks/redis/dynamic/support/WildcardTypeInformationTest.java diff --git a/src/main/java/com/lambdaworks/redis/dynamic/support/GenericArrayTypeInformation.java b/src/main/java/com/lambdaworks/redis/dynamic/support/GenericArrayTypeInformation.java index cc67c7743f..26bad0ac3c 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/support/GenericArrayTypeInformation.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/support/GenericArrayTypeInformation.java @@ -46,7 +46,7 @@ protected GenericArrayTypeInformation(GenericArrayType type, TypeDiscoverer p @Override @SuppressWarnings("unchecked") public Class getType() { - return (Class) Array.newInstance(resolveType(type.getGenericComponentType()), 0).getClass(); + return (Class) Array.newInstance(resolveClass(type.getGenericComponentType()), 0).getClass(); } @Override diff --git a/src/main/java/com/lambdaworks/redis/dynamic/support/ParametrizedTypeInformation.java b/src/main/java/com/lambdaworks/redis/dynamic/support/ParametrizedTypeInformation.java index 014cb1dc4a..d5b115887d 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/support/ParametrizedTypeInformation.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/support/ParametrizedTypeInformation.java @@ -64,7 +64,7 @@ protected TypeInformation doGetMapValueType() { for (Type supertype : supertypes) { - Class rawSuperType = resolveType(supertype); + Class rawSuperType = resolveClass(supertype); if (Map.class.isAssignableFrom(rawSuperType)) { @@ -74,13 +74,13 @@ protected TypeInformation doGetMapValueType() { } } - return super.getMapValueType(); + return super.doGetMapValueType(); } @Override public List> getTypeArguments() { - List> result = new ArrayList>(); + List> result = new ArrayList<>(); for (Type argument : type.getActualTypeArguments()) { result.add(createInfo(argument)); @@ -114,9 +114,21 @@ public boolean isAssignableFrom(TypeInformation target) { } for (int i = 0; i < myParameters.size(); i++) { - if (!myParameters.get(i).isAssignableFrom(typeParameters.get(i))) { - return false; + + if (myParameters.get(i) instanceof WildcardTypeInformation) { + if (!myParameters.get(i).isAssignableFrom(typeParameters.get(i))) { + return false; + } + } else { + if (!myParameters.get(i).getType().equals(typeParameters.get(i).getType())) { + return false; + } + + if (!myParameters.get(i).isAssignableFrom(typeParameters.get(i))) { + return false; + } } + } return true; diff --git a/src/main/java/com/lambdaworks/redis/dynamic/support/TypeDiscoverer.java b/src/main/java/com/lambdaworks/redis/dynamic/support/TypeDiscoverer.java index d3b16a66e2..e4bbf4f3b6 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/support/TypeDiscoverer.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/support/TypeDiscoverer.java @@ -17,7 +17,6 @@ import java.lang.reflect.*; import java.util.*; -import java.util.concurrent.ConcurrentHashMap; import com.lambdaworks.redis.internal.LettuceAssert; @@ -28,7 +27,6 @@ class TypeDiscoverer implements TypeInformation { private final Type type; private final Map, Type> typeVariableMap; - private final Map> fieldTypes = new ConcurrentHashMap>(); private final int hashCode; private boolean componentTypeResolved = false; @@ -40,7 +38,7 @@ class TypeDiscoverer implements TypeInformation { private Class resolvedType; /** - * Creates a ne {@link TypeDiscoverer} for the given type, type variable map and parent. + * Creates a new {@link TypeDiscoverer} for the given type and type variable map. * * @param type must not be {@literal null}. * @param typeVariableMap must not be {@literal null}. @@ -48,6 +46,7 @@ class TypeDiscoverer implements TypeInformation { protected TypeDiscoverer(Type type, Map, Type> typeVariableMap) { LettuceAssert.notNull(type, "Type must not be null"); + LettuceAssert.notNull(typeVariableMap, "TypeVariableMap must not be null"); this.type = type; this.typeVariableMap = typeVariableMap; @@ -80,7 +79,7 @@ protected TypeInformation createInfo(Type fieldType) { return new ClassTypeInformation((Class) fieldType); } - Class resolveType = resolveType(fieldType); + Class resolveType = resolveClass(fieldType); Map variableMap = new HashMap(); variableMap.putAll(GenericTypeResolver.getTypeVariableMap(resolveType)); @@ -110,17 +109,7 @@ protected TypeInformation createInfo(Type fieldType) { if (fieldType instanceof WildcardType) { WildcardType wildcardType = (WildcardType) fieldType; - Type[] bounds = wildcardType.getLowerBounds(); - - if (bounds.length > 0) { - return createInfo(bounds[0]); - } - - bounds = wildcardType.getUpperBounds(); - - if (bounds.length > 0) { - return createInfo(bounds[0]); - } + return new WildcardTypeInformation(wildcardType, variableMap); } throw new IllegalArgumentException(); @@ -132,8 +121,8 @@ protected TypeInformation createInfo(Type fieldType) { * @param type * @return */ - @SuppressWarnings({ "unchecked", "rawtypes", "deprecation" }) - protected Class resolveType(Type type) { + @SuppressWarnings({ "unchecked", "rawtypes" }) + protected Class resolveClass(Type type) { Map map = new HashMap(); map.putAll(getTypeVariableMap()); @@ -141,6 +130,21 @@ protected Class resolveType(Type type) { return (Class) ResolvableType.forType(type, new TypeVariableMapVariableResolver(map)).resolve(Object.class); } + /** + * Resolves the given type into a {@link Type}. + * + * @param type + * @return + */ + @SuppressWarnings({ "unchecked", "rawtypes" }) + protected Type resolveType(Type type) { + + Map map = new HashMap<>(); + map.putAll(getTypeVariableMap()); + + return ResolvableType.forType(type, new TypeVariableMapVariableResolver(map)).resolveType().getType(); + } + public List> getParameterTypes(Constructor constructor) { LettuceAssert.notNull(constructor, "Constructor must not be null!"); @@ -158,7 +162,7 @@ public List> getParameterTypes(Constructor constructor) { public Class getType() { if (resolvedType == null) { - this.resolvedType = resolveType(type); + this.resolvedType = resolveClass(type); } return this.resolvedType; diff --git a/src/main/java/com/lambdaworks/redis/dynamic/support/TypeVariableTypeInformation.java b/src/main/java/com/lambdaworks/redis/dynamic/support/TypeVariableTypeInformation.java index 8d94a71bdd..3d0ffae9fa 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/support/TypeVariableTypeInformation.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/support/TypeVariableTypeInformation.java @@ -18,6 +18,8 @@ import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.lang.reflect.TypeVariable; +import java.util.ArrayList; +import java.util.List; import java.util.Map; import com.lambdaworks.redis.internal.LettuceAssert; @@ -57,10 +59,10 @@ public Class getType() { if (owningType instanceof ParameterizedType && index != -1) { Type fieldType = ((ParameterizedType) owningType).getActualTypeArguments()[index]; - return resolveType(fieldType); + return resolveClass(fieldType); } - return resolveType(variable); + return resolveClass(variable); } /** @@ -71,7 +73,7 @@ public Class getType() { */ private int getIndex(TypeVariable variable) { - Class rawType = resolveType(owningType); + Class rawType = resolveClass(owningType); TypeVariable[] typeParameters = rawType.getTypeParameters(); for (int i = 0; i < typeParameters.length; i++) { @@ -83,6 +85,22 @@ private int getIndex(TypeVariable variable) { return -1; } + @Override + public List> getTypeArguments() { + + List> result = new ArrayList<>(); + + Type type = resolveType(variable); + if (type instanceof ParameterizedType) { + + for (Type typeArgument : ((ParameterizedType) type).getActualTypeArguments()) { + result.add(createInfo(typeArgument)); + } + } + + return result; + } + @Override public boolean equals(Object obj) { diff --git a/src/main/java/com/lambdaworks/redis/dynamic/support/WildcardTypeInformation.java b/src/main/java/com/lambdaworks/redis/dynamic/support/WildcardTypeInformation.java new file mode 100644 index 0000000000..47680f3530 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/dynamic/support/WildcardTypeInformation.java @@ -0,0 +1,79 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.lambdaworks.redis.dynamic.support; + +import java.lang.reflect.Type; +import java.lang.reflect.TypeVariable; +import java.lang.reflect.WildcardType; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +/** + * {@link TypeInformation} for a {@link WildcardType}. + */ +class WildcardTypeInformation extends TypeDiscoverer { + + private final WildcardType type; + + /** + * Creates a new {@link WildcardTypeInformation} for the given type, type variable map. + * + * @param type must not be {@literal null}. + * @param typeVariableMap must not be {@literal null}. + */ + protected WildcardTypeInformation(WildcardType type, Map, Type> typeVariableMap) { + + super(type, typeVariableMap); + this.type = type; + } + + @Override + public boolean isAssignableFrom(TypeInformation target) { + + for (TypeInformation lowerBound : getLowerBounds()) { + if (!target.isAssignableFrom(lowerBound)) { + return false; + } + } + + for (TypeInformation upperBound : getUpperBounds()) { + if (!upperBound.isAssignableFrom(target)) { + return false; + } + } + + return true; + } + + public List> getUpperBounds() { + return getBounds(type.getUpperBounds()); + } + + public List> getLowerBounds() { + return getBounds(type.getLowerBounds()); + } + + private List> getBounds(Type[] bounds) { + + List> typeInformations = new ArrayList<>(bounds.length); + + Arrays.stream(bounds).map(this::createInfo).forEach(typeInformations::add); + + return typeInformations; + } +} diff --git a/src/test/java/com/lambdaworks/redis/dynamic/support/ParametrizedTypeInformationTest.java b/src/test/java/com/lambdaworks/redis/dynamic/support/ParametrizedTypeInformationTest.java new file mode 100644 index 0000000000..d5c05cbf05 --- /dev/null +++ b/src/test/java/com/lambdaworks/redis/dynamic/support/ParametrizedTypeInformationTest.java @@ -0,0 +1,141 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.lambdaworks.redis.dynamic.support; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Collection; +import java.util.List; +import java.util.Set; + +import org.junit.Test; + +/** + * @author Mark Paluch + */ +public class ParametrizedTypeInformationTest { + + @Test + public void isAssignableShouldConsiderExactType() throws Exception { + + TypeInformation target = ClassTypeInformation + .fromReturnTypeOf(ReflectionUtils.findMethod(TestType.class, "exactNumber")); + + assertThat(target.isAssignableFrom(ClassTypeInformation.from(ListOfNumber.class))).isTrue(); + assertThat(target.isAssignableFrom(ClassTypeInformation.from(ListOfInteger.class))).isFalse(); + assertThat(target.isAssignableFrom(ClassTypeInformation.from(ListOfString.class))).isFalse(); + } + + @Test + public void isAssignableShouldConsiderCompatibleType() throws Exception { + + TypeInformation target = ClassTypeInformation + .fromReturnTypeOf(ReflectionUtils.findMethod(TestType.class, "collectionOfNumber")); + + assertThat(target.isAssignableFrom(ClassTypeInformation.from(ListOfNumber.class))).isTrue(); + assertThat(target.isAssignableFrom(ClassTypeInformation.from(ListOfInteger.class))).isFalse(); + assertThat(target.isAssignableFrom(ClassTypeInformation.from(ListOfString.class))).isFalse(); + } + + @Test + public void isAssignableShouldConsiderWildcardOfNumberType() throws Exception { + + TypeInformation target = ClassTypeInformation + .fromReturnTypeOf(ReflectionUtils.findMethod(TestType.class, "numberOrSubtype")); + + assertThat(target.isAssignableFrom(ClassTypeInformation.from(ListOfNumber.class))).isTrue(); + assertThat(target.isAssignableFrom(ClassTypeInformation.from(ListOfInteger.class))).isTrue(); + assertThat(target.isAssignableFrom(ClassTypeInformation.from(ListOfString.class))).isFalse(); + } + + @Test + public void isAssignableShouldConsiderWildcard() throws Exception { + + TypeInformation target = ClassTypeInformation + .fromReturnTypeOf(ReflectionUtils.findMethod(TestType.class, "anything")); + + assertThat(target.isAssignableFrom(ClassTypeInformation.from(ListOfNumber.class))).isTrue(); + assertThat(target.isAssignableFrom(ClassTypeInformation.from(ListOfInteger.class))).isTrue(); + assertThat(target.isAssignableFrom(ClassTypeInformation.from(ListOfString.class))).isTrue(); + } + + @Test + public void returnsNullMapValueTypeForNonMapProperties() { + + TypeInformation valueType = ClassTypeInformation.from(Bar.class).getSuperTypeInformation(List.class); + TypeInformation mapValueType = valueType.getMapValueType(); + + assertThat(valueType).isInstanceOf(ParametrizedTypeInformation.class); + assertThat(mapValueType).isNull(); + } + + @Test + public void isAssignableShouldConsiderNestedParameterTypes() throws Exception { + + TypeInformation target = ClassTypeInformation + .fromReturnTypeOf(ReflectionUtils.findMethod(TestType.class, "collectionOfIterableOfNumber")); + + assertThat(target.isAssignableFrom(ClassTypeInformation.from(ListOfIterableOfNumber.class))).isTrue(); + assertThat(target.isAssignableFrom(ClassTypeInformation.from(ListOfIterableOfInteger.class))).isFalse(); + assertThat(target.isAssignableFrom(ClassTypeInformation.from(ListOfListOfNumber.class))).isFalse(); + assertThat(target.isAssignableFrom(ClassTypeInformation.from(ListOfSetOfNumber.class))).isFalse(); + } + + interface Bar extends List { + + } + + static interface TestType { + + Collection collectionOfNumber(); + + Collection> collectionOfIterableOfNumber(); + + List exactNumber(); + + List anything(); + + List numberOrSubtype(); + } + + static interface ListOfNumber extends List { + + } + + static interface ListOfIterableOfNumber extends List> { + + } + + static interface ListOfSetOfNumber extends List> { + + } + + static interface ListOfIterableOfInteger extends List> { + + } + + static interface ListOfListOfNumber extends List> { + + } + + static interface ListOfString extends List { + + } + + static interface ListOfInteger extends List { + + } +} \ No newline at end of file diff --git a/src/test/java/com/lambdaworks/redis/dynamic/support/WildcardTypeInformationTest.java b/src/test/java/com/lambdaworks/redis/dynamic/support/WildcardTypeInformationTest.java new file mode 100644 index 0000000000..a3b0825aea --- /dev/null +++ b/src/test/java/com/lambdaworks/redis/dynamic/support/WildcardTypeInformationTest.java @@ -0,0 +1,130 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.lambdaworks.redis.dynamic.support; + +import static com.lambdaworks.redis.dynamic.support.ClassTypeInformation.from; +import static org.assertj.core.api.Assertions.assertThat; + +import java.lang.reflect.Method; +import java.util.Collection; +import java.util.List; + +import org.junit.Ignore; +import org.junit.Test; + +/** + * @author Mark Paluch + */ +public class WildcardTypeInformationTest { + + @Test + public void shouldResolveWildcardType() { + + TypeInformation information = ClassTypeInformation.fromReturnTypeOf(methodOf("listOfAnything")); + + assertThat(information.getComponentType()).isInstanceOf(WildcardTypeInformation.class); + } + + @Test + public void isAssignableFromExactType() { + + TypeInformation information = ClassTypeInformation.fromReturnTypeOf(methodOf("listOfAnything")); + TypeInformation compatible = ClassTypeInformation.fromReturnTypeOf(methodOf("anotherListOfAnything")); + + assertThat(information.isAssignableFrom(compatible)).isTrue(); + } + + @Test + public void isAssignableFromCompatibleFirstLevelType() { + + TypeInformation target = ClassTypeInformation.fromReturnTypeOf(methodOf("collectionOfAnything")); + TypeInformation source = ClassTypeInformation.fromReturnTypeOf(methodOf("anotherListOfAnything")); + + assertThat(target.isAssignableFrom(source)).isTrue(); + } + + @Test + public void isAssignableFromCompatibleComponentType() { + + TypeInformation target = ClassTypeInformation.fromReturnTypeOf(methodOf("listOfAnything")); + TypeInformation source = ClassTypeInformation.fromReturnTypeOf(methodOf("exactNumber")); + + assertThat(target.isAssignableFrom(source)).isTrue(); + assertThat(target.isAssignableFrom(ClassTypeInformation.SET)).isFalse(); + } + + @Test + public void isAssignableFromUpperBoundComponentType() { + + TypeInformation target = componentTypeOf("atMostInteger"); + + assertThat(target.isAssignableFrom(from(Integer.class))).isTrue(); + assertThat(target.isAssignableFrom(from(Number.class))).isTrue(); + assertThat(target.isAssignableFrom(from(Float.class))).isFalse(); + } + + @Test + public void isAssignableFromLowerBoundComponentType() { + + TypeInformation target = componentTypeOf("atLeastNumber"); + + assertThat(target.isAssignableFrom(from(Integer.class))).isTrue(); + assertThat(target.isAssignableFrom(from(Number.class))).isTrue(); + assertThat(target.isAssignableFrom(from(Float.class))).isTrue(); + assertThat(target.isAssignableFrom(from(String.class))).isFalse(); + assertThat(target.isAssignableFrom(from(Object.class))).isFalse(); + } + + @Test + @Ignore("Method-level variables not supported") + public void isAssignableFromParametrizedWildcardType() { + + TypeInformation target = componentTypeOf("numberOrSubtype"); + + assertThat(target.isAssignableFrom(from(Integer.class))).isTrue(); + assertThat(target.isAssignableFrom(from(Number.class))).isTrue(); + assertThat(target.isAssignableFrom(from(Float.class))).isTrue(); + assertThat(target.isAssignableFrom(from(String.class))).isFalse(); + assertThat(target.isAssignableFrom(from(Object.class))).isFalse(); + } + + protected TypeInformation componentTypeOf(String name) { + return ClassTypeInformation.fromReturnTypeOf(methodOf(name)).getComponentType(); + } + + protected Method methodOf(String name) { + return ReflectionUtils.findMethod(GenericReturnTypes.class, name); + } + + static interface GenericReturnTypes { + + List exactNumber(); + + List listOfAnything(); + + List anotherListOfAnything(); + + Collection collectionOfAnything(); + + List atMostInteger(); + + List exactFloat(); + + List atLeastNumber(); + + List numberOrSubtype(); + } +} \ No newline at end of file From 7f80a1d80046a9a8a30f3f1172a548a18e295227 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Fri, 23 Dec 2016 20:43:28 +0100 Subject: [PATCH 108/808] Use ResolvableType for type resolution #426 ResolvableType correctly determines assignability considering wildcards and parametrized assignability. OutputRegistryCommandOutputFactoryResolver now uses a List to retain OutputRegistry ordering. --- .../redis/dynamic/CommandMethod.java | 30 +++--- .../dynamic/CommandSegmentCommandFactory.java | 2 +- .../CodecAwareOutputFactoryResolver.java | 56 +---------- .../output/CommandOutputResolverSupport.java | 50 +--------- .../redis/dynamic/output/OutputRegistry.java | 95 ++++++++++++++----- ...tRegistryCommandOutputFactoryResolver.java | 11 +-- .../redis/dynamic/output/OutputSelector.java | 93 +++++------------- .../redis/dynamic/output/OutputType.java | 24 ++--- .../dynamic/support/ClassTypeInformation.java | 2 +- .../redis/dynamic/support/ResolvableType.java | 8 +- .../redis/dynamic/support/TypeDiscoverer.java | 9 +- .../dynamic/support/TypeInformation.java | 7 ++ .../redis/dynamic/CommandMethodTest.java | 8 +- .../output/CodecAwareOutputResolverTest.java | 20 +--- ...istryCommandOutputFactoryResolverTest.java | 59 ++++++++++-- .../dynamic/output/OutputRegistryTest.java | 88 ++++++++++++----- .../ParametrizedTypeInformationTest.java | 1 - .../support/WildcardTypeInformationTest.java | 16 ---- 18 files changed, 272 insertions(+), 307 deletions(-) diff --git a/src/main/java/com/lambdaworks/redis/dynamic/CommandMethod.java b/src/main/java/com/lambdaworks/redis/dynamic/CommandMethod.java index f2585aa281..c0fcbd28cc 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/CommandMethod.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/CommandMethod.java @@ -27,7 +27,7 @@ import com.lambdaworks.redis.dynamic.parameter.ExecutionSpecificParameters; import com.lambdaworks.redis.dynamic.parameter.Parameter; import com.lambdaworks.redis.dynamic.parameter.Parameters; -import com.lambdaworks.redis.dynamic.support.ClassTypeInformation; +import com.lambdaworks.redis.dynamic.support.ResolvableType; import com.lambdaworks.redis.dynamic.support.TypeInformation; import com.lambdaworks.redis.internal.LettuceAssert; @@ -41,10 +41,10 @@ public class CommandMethod { private final Method method; - private final TypeInformation returnType; + private final ResolvableType returnType; private final List> arguments = new ArrayList<>(); private final Parameters parameters; - private final TypeInformation actualReturnType; + private final ResolvableType actualReturnType; /** * Create a new {@link CommandMethod} given a {@link Method}. @@ -67,15 +67,21 @@ public CommandMethod(Method method, Parameters parameters) { LettuceAssert.notNull(parameters, "Parameters must not be null"); this.method = method; - this.returnType = ClassTypeInformation.fromReturnTypeOf(method); + this.returnType = ResolvableType.forMethodReturnType(method); this.parameters = parameters; Collections.addAll(arguments, method.getParameterTypes()); - TypeInformation actualReturnType = this.returnType; + ResolvableType actualReturnType = this.returnType; - while (Future.class.isAssignableFrom(actualReturnType.getType()) - || ReactiveTypes.supports(actualReturnType.getType())) { - actualReturnType = actualReturnType.getComponentType(); + while (Future.class.isAssignableFrom(actualReturnType.getRawClass()) + || ReactiveTypes.supports(actualReturnType.getRawClass())) { + ResolvableType[] generics = actualReturnType.getGenerics(); + + if (generics.length != 1) { + break; + } + + actualReturnType = generics[0]; } this.actualReturnType = actualReturnType; @@ -101,7 +107,7 @@ public Method getMethod() { * * @return declared {@link Method} return {@link TypeInformation}. */ - public TypeInformation getReturnType() { + public ResolvableType getReturnType() { return returnType; } @@ -109,7 +115,7 @@ public TypeInformation getReturnType() { * * @return the actual {@link Method} return {@link TypeInformation} after unwrapping. */ - public TypeInformation getActualReturnType() { + public ResolvableType getActualReturnType() { return actualReturnType; } @@ -145,7 +151,7 @@ public String getName() { * @return {@literal true} if the method uses asynchronous execution declaring {@link Future} as result type. */ public boolean isFutureExecution() { - return Future.class.isAssignableFrom(getReturnType().getType()); + return Future.class.isAssignableFrom(getReturnType().getRawClass()); } /** @@ -153,7 +159,7 @@ public boolean isFutureExecution() { * @return {@literal true} if the method uses reactive execution declaring {@link Publisher} as result type. */ public boolean isReactiveExecution() { - return ReactiveTypes.supports(getReturnType().getType()); + return ReactiveTypes.supports(getReturnType().getRawClass()); } @Override diff --git a/src/main/java/com/lambdaworks/redis/dynamic/CommandSegmentCommandFactory.java b/src/main/java/com/lambdaworks/redis/dynamic/CommandSegmentCommandFactory.java index b8df2b3987..f96b90c216 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/CommandSegmentCommandFactory.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/CommandSegmentCommandFactory.java @@ -48,7 +48,7 @@ public CommandSegmentCommandFactory(CommandSegments commandSegments, CommandMeth this.redisCodec = redisCodec; this.outputResolver = outputResolver; - OutputSelector outputSelector = new OutputSelector(commandMethod.getActualReturnType()); + OutputSelector outputSelector = new OutputSelector(commandMethod.getActualReturnType(), redisCodec); CommandOutputFactory factory = resolveCommandOutputFactory(outputSelector); if (factory == null) { diff --git a/src/main/java/com/lambdaworks/redis/dynamic/output/CodecAwareOutputFactoryResolver.java b/src/main/java/com/lambdaworks/redis/dynamic/output/CodecAwareOutputFactoryResolver.java index 96d322686a..eab6e4e17b 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/output/CodecAwareOutputFactoryResolver.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/output/CodecAwareOutputFactoryResolver.java @@ -15,13 +15,7 @@ */ package com.lambdaworks.redis.dynamic.output; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - import com.lambdaworks.redis.codec.RedisCodec; -import com.lambdaworks.redis.dynamic.support.ClassTypeInformation; -import com.lambdaworks.redis.dynamic.support.TypeInformation; import com.lambdaworks.redis.internal.LettuceAssert; /** @@ -34,9 +28,7 @@ public class CodecAwareOutputFactoryResolver implements CommandOutputFactoryResolver { private final CommandOutputFactoryResolver delegate; - private final TypeInformation keyType; - private final TypeInformation valueType; - private final Map> typeVariables = new HashMap<>(); + private final RedisCodec redisCodec; /** * Create a new {@link CodecAwareOutputFactoryResolver} given {@link CommandOutputFactoryResolver} and {@link RedisCodec}. @@ -50,56 +42,16 @@ public CodecAwareOutputFactoryResolver(CommandOutputFactoryResolver delegate, Re LettuceAssert.notNull(redisCodec, "RedisCodec must not be null"); this.delegate = delegate; - - ClassTypeInformation typeInformation = ClassTypeInformation.from(redisCodec.getClass()); - TypeInformation superTypeInformation = typeInformation.getSuperTypeInformation(RedisCodec.class); - List> typeArguments = superTypeInformation.getTypeArguments(); - - this.keyType = typeArguments.get(0); - this.valueType = typeArguments.get(1); - - this.typeVariables.put("K", keyType); - this.typeVariables.put("V", valueType); + this.redisCodec = redisCodec; } @Override public CommandOutputFactory resolveCommandOutput(OutputSelector outputSelector) { - - Map> typeVariables = new HashMap<>(outputSelector.getTypeVariables()); - typeVariables.putAll(this.typeVariables); - - return delegate.resolveCommandOutput( - new OutputSelector(outputSelector.getTypeInformation(), isKeyType(outputSelector.getTypeInformation()), - isValueType(outputSelector.getTypeInformation()), typeVariables)); + return delegate.resolveCommandOutput(new OutputSelector(outputSelector.getOutputType(), redisCodec)); } @Override public CommandOutputFactory resolveStreamingCommandOutput(OutputSelector outputSelector) { - - Map> typeVariables = new HashMap<>(outputSelector.getTypeVariables()); - typeVariables.putAll(this.typeVariables); - - return delegate.resolveStreamingCommandOutput( - new OutputSelector(outputSelector.getTypeInformation(), isKeyType(outputSelector.getTypeInformation()), - isValueType(outputSelector.getTypeInformation()), typeVariables)); - } - - protected boolean isKeyType(TypeInformation typeInformation) { - return walkComponentTypeAssignability(typeInformation, keyType); - } - - protected boolean isValueType(TypeInformation typeInformation) { - return walkComponentTypeAssignability(typeInformation, valueType); - } - - private boolean walkComponentTypeAssignability(TypeInformation typeInformation, TypeInformation sourceType) { - - do { - if (typeInformation.isAssignableFrom(sourceType)) { - return true; - } - typeInformation = typeInformation.getComponentType(); - } while (typeInformation != null); - return false; + return delegate.resolveStreamingCommandOutput(new OutputSelector(outputSelector.getOutputType(), redisCodec)); } } diff --git a/src/main/java/com/lambdaworks/redis/dynamic/output/CommandOutputResolverSupport.java b/src/main/java/com/lambdaworks/redis/dynamic/output/CommandOutputResolverSupport.java index ac42786ddb..71a9caf860 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/output/CommandOutputResolverSupport.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/output/CommandOutputResolverSupport.java @@ -15,9 +15,7 @@ */ package com.lambdaworks.redis.dynamic.output; -import com.lambdaworks.redis.dynamic.support.TypeInformation; -import com.lambdaworks.redis.dynamic.support.TypeVariableTypeInformation; -import com.lambdaworks.redis.internal.LettuceClassUtils; +import com.lambdaworks.redis.dynamic.support.ResolvableType; /** * Base class for {@link CommandOutputFactory} resolution such as {@link OutputRegistryCommandOutputFactoryResolver}. @@ -40,49 +38,9 @@ public abstract class CommandOutputResolverSupport { */ protected boolean isAssignableFrom(OutputSelector selector, OutputType provider) { - TypeInformation outputTypeInformation = provider.getTypeInformation(); - TypeInformation selectorTypeInformation = selector.getTypeInformation(); + ResolvableType selectorType = selector.getOutputType(); + ResolvableType resolvableType = provider.withCodec(selector.getRedisCodec()); - do { - - if (outputTypeInformation instanceof TypeVariableTypeInformation) { - if (selector.containsTypeVariable(outputTypeInformation.toString())) { - outputTypeInformation = selector.getTypeVariable(outputTypeInformation.toString()); - } - } - - if (outputTypeInformation.getType() == Object.class && selectorTypeInformation.getComponentType() != null) { - - if (provider.getPrimaryType() == OutputRegistry.KeySurrogate.class) { - return selector.isKey(); - } - - if (provider.getPrimaryType() == OutputRegistry.ValueSurrogate.class) { - return selector.isValue(); - } - } - - if (!isAssignableFrom(selectorTypeInformation, outputTypeInformation)) { - return false; - } - - outputTypeInformation = outputTypeInformation.getComponentType(); - selectorTypeInformation = selectorTypeInformation.getComponentType(); - - } while (outputTypeInformation != null && outputTypeInformation.getComponentType() != outputTypeInformation - && selectorTypeInformation != null && selectorTypeInformation.getComponentType() != selectorTypeInformation); - return true; - } - - /** - * Overridable hook to check whether {@code selector} can be assigned from the provider type {@code provider}. - * - * @param selector must not be {@literal null}. - * @param provider must not be {@literal null}. - * @return {@literal true} if selector can be assigned from its provider type. - */ - protected boolean isAssignableFrom(TypeInformation selector, TypeInformation provider) { - - return selector.isAssignableFrom(provider) || LettuceClassUtils.isAssignable(selector.getType(), provider.getType()); + return selectorType.isAssignableFrom(resolvableType); } } diff --git a/src/main/java/com/lambdaworks/redis/dynamic/output/OutputRegistry.java b/src/main/java/com/lambdaworks/redis/dynamic/output/OutputRegistry.java index 9db55512bf..cf2e2ff4dc 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/output/OutputRegistry.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/output/OutputRegistry.java @@ -15,12 +15,16 @@ */ package com.lambdaworks.redis.dynamic.output; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; +import java.lang.reflect.TypeVariable; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import com.lambdaworks.redis.codec.RedisCodec; import com.lambdaworks.redis.dynamic.support.ClassTypeInformation; +import com.lambdaworks.redis.dynamic.support.ResolvableType; import com.lambdaworks.redis.dynamic.support.TypeInformation; -import com.lambdaworks.redis.dynamic.support.TypeVariableTypeInformation; import com.lambdaworks.redis.internal.LettuceAssert; import com.lambdaworks.redis.output.*; @@ -59,8 +63,8 @@ public class OutputRegistry { register(registry, GeoCoordinatesListOutput.class, GeoCoordinatesListOutput::new); register(registry, GeoCoordinatesValueListOutput.class, GeoCoordinatesValueListOutput::new); register(registry, ScoredValueListOutput.class, ScoredValueListOutput::new); - register(registry, StringValueListOutput.class, StringValueListOutput::new); register(registry, ValueValueListOutput.class, ValueValueListOutput::new); + register(registry, StringValueListOutput.class, StringValueListOutput::new); register(registry, StringListOutput.class, StringListOutput::new); register(registry, VoidOutput.class, VoidOutput::new); @@ -155,9 +159,33 @@ static OutputType getStreamingType(Class commandOutputC } List> typeArguments = superTypeInformation.getTypeArguments(); - Class primaryType = getPrimaryType(typeArguments.get(0)); - return new OutputType(primaryType, commandOutputClass, typeArguments.get(0), true); + return new OutputType(commandOutputClass, typeArguments.get(0), true) { + + @Override + public ResolvableType withCodec(RedisCodec codec) { + + TypeInformation typeInformation = ClassTypeInformation.from(codec.getClass()); + + ResolvableType resolvableType = ResolvableType.forType(commandOutputClass, + new CodecVariableTypeResolver(typeInformation)); + + while (resolvableType != ResolvableType.NONE) { + + ResolvableType[] interfaces = resolvableType.getInterfaces(); + for (ResolvableType resolvableInterface : interfaces) { + + if (resolvableInterface.getRawClass().equals(StreamingOutput.class)) { + return resolvableInterface.getGeneric(0); + } + } + + resolvableType = resolvableType.getSuperType(); + } + + throw new IllegalStateException(); + } + }; } /** @@ -177,36 +205,53 @@ static OutputType getOutputComponentType(Class commandO } List> typeArguments = superTypeInformation.getTypeArguments(); - Class primaryType = getPrimaryType(typeArguments.get(2)); - return new OutputType(primaryType, commandOutputClass, typeArguments.get(2), false); + return new OutputType(commandOutputClass, typeArguments.get(2), false) { + @Override + public ResolvableType withCodec(RedisCodec codec) { + + TypeInformation typeInformation = ClassTypeInformation.from(codec.getClass()); + + ResolvableType resolvableType = ResolvableType.forType(commandOutputClass, + new CodecVariableTypeResolver(typeInformation)); + + while (!resolvableType.getRawClass().equals(CommandOutput.class)) { + resolvableType = resolvableType.getSuperType(); + } + + return resolvableType.getGeneric(2); + } + }; } - private static Class getPrimaryType(TypeInformation typeInformation) { + static class CodecVariableTypeResolver implements ResolvableType.VariableResolver { + + private final TypeInformation codecType; + private final List> typeArguments; + + public CodecVariableTypeResolver(TypeInformation codecType) { + + this.codecType = codecType.getSuperTypeInformation(RedisCodec.class); + this.typeArguments = this.codecType.getTypeArguments(); + } - Class primaryType = typeInformation.getType(); - while (typeInformation.isCollectionLike() && typeInformation != typeInformation.getComponentType()) { - typeInformation = typeInformation.getComponentType(); + @Override + public Object getSource() { + return codecType; } - if (typeInformation instanceof TypeVariableTypeInformation) { + @Override + public ResolvableType resolveVariable(TypeVariable variable) { - // TODO: Requires maybe a more sophisticated resolution. - if (typeInformation.toString().equals("K")) { - primaryType = KeySurrogate.class; + if (variable.getName().equals("K")) { + return ResolvableType.forClass(typeArguments.get(0).getType()); } - if (typeInformation.toString().equals("V")) { - primaryType = ValueSurrogate.class; + if (variable.getName().equals("V")) { + return ResolvableType.forClass(typeArguments.get(1).getType()); } + return null; } - return primaryType; - } - - static class KeySurrogate { - } - - static class ValueSurrogate { } } diff --git a/src/main/java/com/lambdaworks/redis/dynamic/output/OutputRegistryCommandOutputFactoryResolver.java b/src/main/java/com/lambdaworks/redis/dynamic/output/OutputRegistryCommandOutputFactoryResolver.java index eac5f588a0..f15df526aa 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/output/OutputRegistryCommandOutputFactoryResolver.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/output/OutputRegistryCommandOutputFactoryResolver.java @@ -18,7 +18,6 @@ import java.util.Collection; import java.util.List; import java.util.Map; -import java.util.Set; import java.util.stream.Collectors; import com.lambdaworks.redis.dynamic.support.ClassTypeInformation; @@ -59,8 +58,8 @@ public CommandOutputFactory resolveCommandOutput(OutputSelector outputSelector) Map registry = outputRegistry.getRegistry(); - Set outputTypes = registry.keySet().stream().filter((outputType) -> !outputType.isStreaming()) - .collect(Collectors.toSet()); + List outputTypes = registry.keySet().stream().filter((outputType) -> !outputType.isStreaming()) + .collect(Collectors.toList()); List candidates = getCandidates(outputTypes, outputSelector); @@ -76,7 +75,7 @@ public CommandOutputFactory resolveStreamingCommandOutput(OutputSelector outputS Map registry = outputRegistry.getRegistry(); - Set outputTypes = registry.keySet().stream().filter(OutputType::isStreaming).collect(Collectors.toSet()); + List outputTypes = registry.keySet().stream().filter(OutputType::isStreaming).collect(Collectors.toList()); List candidates = getCandidates(outputTypes, outputSelector); @@ -91,9 +90,9 @@ private List getCandidates(Collection outputTypes, Outpu return outputTypes.stream().filter(outputType -> { - if (COMMAND_OUTPUT.getType().isAssignableFrom(outputSelector.getTypeInformation().getType())) { + if (COMMAND_OUTPUT.getType().isAssignableFrom(outputSelector.getOutputType().getRawClass())) { - if (outputSelector.getTypeInformation().getType().isAssignableFrom(outputType.getCommandOutputClass())) { + if (outputSelector.getOutputType().getRawClass().isAssignableFrom(outputType.getCommandOutputClass())) { return true; } } diff --git a/src/main/java/com/lambdaworks/redis/dynamic/output/OutputSelector.java b/src/main/java/com/lambdaworks/redis/dynamic/output/OutputSelector.java index 528a399fdb..04d60b5ac0 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/output/OutputSelector.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/output/OutputSelector.java @@ -15,100 +15,51 @@ */ package com.lambdaworks.redis.dynamic.output; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -import com.lambdaworks.redis.dynamic.support.TypeInformation; +import com.lambdaworks.redis.codec.RedisCodec; +import com.lambdaworks.redis.dynamic.support.ResolvableType; import com.lambdaworks.redis.internal.LettuceAssert; /** * Selector {@link CommandOutputFactory} resolution. *

    - * A {@link OutputSelector} is based on the result {@link TypeInformation} and can supply additionaly whether the type is a key - * or value type. An optional {@link Map} with type variables (usually {@link com.lambdaworks.redis.codec.RedisCodec} type - * variables) can be supplied to resolve type variables inside of {@link com.lambdaworks.redis.output.CommandOutput}. + * A {@link OutputSelector} is based on the result {@link ResolvableType} and {@link com.lambdaworks.redis.codec.RedisCodec}. + * The codec supplies types for generics resolution of {@link com.lambdaworks.redis.output.CommandOutput}. * * @author Mark Paluch * @since 5.0 */ public class OutputSelector { - private final TypeInformation typeInformation; - private final boolean key; - private final boolean value; - private final Map> typeVariables; - - /** - * Create a new {@link OutputSelector} given {@link TypeInformation}. - * - * @param typeInformation must not be {@literal null}. - */ - public OutputSelector(TypeInformation typeInformation) { - this(typeInformation, false, false, Collections.emptyMap()); - } - - /** - * Create a new {@link OutputSelector} given {@link TypeInformation}, key/value flags and {@link Map} of type variables. - * - * @param typeInformation must not be {@literal null}. - * @param key - * @param value - * @param typeVariables must not be {@literal null}. - */ - public OutputSelector(TypeInformation typeInformation, boolean key, boolean value, - Map> typeVariables) { - - LettuceAssert.notNull(typeInformation, "Result TypeInformation must not be null"); - LettuceAssert.notNull(typeVariables, "Map of type variables must not be null"); - - this.typeInformation = typeInformation; - this.key = key; - this.value = value; - this.typeVariables = Collections.unmodifiableMap(new HashMap<>(typeVariables)); - } - - /** - * @param typeVariableName - * @return {@literal true} if the {@code typeVariableName} is provided. - */ - public boolean containsTypeVariable(String typeVariableName) { - return typeVariables.containsKey(typeVariableName); - } + private final ResolvableType outputType; + private final RedisCodec redisCodec; /** - * @param typeInformation - * @return the {@link TypeInformation} for a type variable. + * Creates a new {@link OutputSelector} given {@link ResolvableType} and {@link RedisCodec}. + * + * @param outputType must not be {@literal null}. + * @param redisCodec must not be {@literal null}. */ - public TypeInformation getTypeVariable(String typeInformation) { - return typeVariables.get(typeInformation); - } + public OutputSelector(ResolvableType outputType, RedisCodec redisCodec) { - /** - * @return the resulting {@link TypeInformation}. - */ - public TypeInformation getTypeInformation() { - return typeInformation; - } + LettuceAssert.notNull(outputType, "Output type must not be null!"); + LettuceAssert.notNull(redisCodec, "RedisCodec must not be null!"); - /** - * @return {@link Map} of type variables. - */ - public Map> getTypeVariables() { - return Collections.unmodifiableMap(typeVariables); + this.outputType = outputType; + this.redisCodec = redisCodec; } /** - * @return {@literal true} if the {@link #getTypeInformation()} is a key-type. + * @return the output type. */ - public boolean isKey() { - return key; + public ResolvableType getOutputType() { + return outputType; } /** - * @return {@literal true} if the {@link #getTypeInformation()} is a value-type. + * + * @return the associated codec. */ - public boolean isValue() { - return value; + public RedisCodec getRedisCodec() { + return redisCodec; } } diff --git a/src/main/java/com/lambdaworks/redis/dynamic/output/OutputType.java b/src/main/java/com/lambdaworks/redis/dynamic/output/OutputType.java index 1a90bb556f..22f9a2cb9e 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/output/OutputType.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/output/OutputType.java @@ -15,6 +15,8 @@ */ package com.lambdaworks.redis.dynamic.output; +import com.lambdaworks.redis.codec.RedisCodec; +import com.lambdaworks.redis.dynamic.support.ResolvableType; import com.lambdaworks.redis.dynamic.support.TypeInformation; import com.lambdaworks.redis.internal.LettuceAssert; import com.lambdaworks.redis.output.CommandOutput; @@ -34,7 +36,6 @@ */ public class OutputType { - private final Class primaryType; private final Class commandOutputClass; private final TypeInformation typeInformation; private final boolean streaming; @@ -43,32 +44,20 @@ public class OutputType { * Create a new {@link OutputType} given {@code primaryType}, the {@code commandOutputClass}, {@link TypeInformation} and * whether the {@link OutputType} is for a {@link com.lambdaworks.redis.output.StreamingOutput}. * - * @param primaryType must not be {@literal null}. * @param commandOutputClass must not be {@literal null}. * @param typeInformation must not be {@literal null}. * @param streaming {@literal true} if the type descriptor concerns the {@link com.lambdaworks.redis.output.StreamingOutput} - * result type. */ - public OutputType(Class primaryType, Class commandOutputClass, - TypeInformation typeInformation, boolean streaming) { + OutputType(Class commandOutputClass, TypeInformation typeInformation, boolean streaming) { - LettuceAssert.notNull(primaryType, "Primary type must not be null"); LettuceAssert.notNull(commandOutputClass, "CommandOutput class must not be null"); LettuceAssert.notNull(typeInformation, "TypeInformation must not be null"); - this.primaryType = primaryType; this.commandOutputClass = commandOutputClass; this.typeInformation = typeInformation; this.streaming = streaming; } - /** - * @return - */ - public Class getPrimaryType() { - return primaryType; - } - /** * @return */ @@ -83,6 +72,10 @@ public boolean isStreaming() { return streaming; } + public ResolvableType withCodec(RedisCodec codec) { + return ResolvableType.forClass(typeInformation.getType()); + } + /** * @return */ @@ -95,8 +88,7 @@ public String toString() { StringBuilder sb = new StringBuilder(); sb.append(getClass().getSimpleName()); - sb.append(" [primaryType=").append(primaryType); - sb.append(", commandOutputClass=").append(commandOutputClass); + sb.append(" [commandOutputClass=").append(commandOutputClass); sb.append(", typeInformation=").append(typeInformation); sb.append(", streaming=").append(streaming); sb.append(']'); diff --git a/src/main/java/com/lambdaworks/redis/dynamic/support/ClassTypeInformation.java b/src/main/java/com/lambdaworks/redis/dynamic/support/ClassTypeInformation.java index b61bd415db..729f0c5921 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/support/ClassTypeInformation.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/support/ClassTypeInformation.java @@ -43,7 +43,7 @@ public class ClassTypeInformation extends TypeDiscoverer { static { for (ClassTypeInformation info : Arrays.asList(COLLECTION, LIST, SET, MAP, OBJECT)) { - CACHE.put(info.getType(), new WeakReference>(info)); + CACHE.put(info.getType(), new WeakReference<>(info)); } } diff --git a/src/main/java/com/lambdaworks/redis/dynamic/support/ResolvableType.java b/src/main/java/com/lambdaworks/redis/dynamic/support/ResolvableType.java index cdf77b954e..bbaaae8f08 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/support/ResolvableType.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/support/ResolvableType.java @@ -34,7 +34,7 @@ * {@link #resolve() resolve} to a {@link java.lang.Class}. */ @SuppressWarnings("serial") -class ResolvableType implements Serializable { +public class ResolvableType implements Serializable { /** * {@code ResolvableType} returned when no value is available. {@code NONE} is used in preference to {@code null} so that @@ -685,7 +685,7 @@ private Class resolveClass() { *

    * Note: The returned {@link ResolvableType} should only be used as an intermediary as it cannot be serialized. */ - ResolvableType resolveType() { + public ResolvableType resolveType() { if (this.type instanceof ParameterizedType) { return forType(((ParameterizedType) this.type).getRawType(), this.variableResolver); } @@ -1084,7 +1084,7 @@ public static ResolvableType forType(Type type, ResolvableType owner) { * @param variableResolver the variable resolver or {@code null} * @return a {@link ResolvableType} for the specified {@link Type} and {@link VariableResolver} */ - static ResolvableType forType(Type type, VariableResolver variableResolver) { + public static ResolvableType forType(Type type, VariableResolver variableResolver) { return forType(type, null, variableResolver); } @@ -1116,7 +1116,7 @@ static ResolvableType forType(Type type, TypeProvider typeProvider, VariableReso /** * Strategy interface used to resolve {@link TypeVariable}s. */ - interface VariableResolver extends Serializable { + public interface VariableResolver extends Serializable { /** * Return the source of the resolver (used for hashCode and equals). diff --git a/src/main/java/com/lambdaworks/redis/dynamic/support/TypeDiscoverer.java b/src/main/java/com/lambdaworks/redis/dynamic/support/TypeDiscoverer.java index e4bbf4f3b6..b0e71adeb0 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/support/TypeDiscoverer.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/support/TypeDiscoverer.java @@ -58,7 +58,7 @@ protected TypeDiscoverer(Type type, Map, Type> typeVariableMap) * * @return */ - protected Map, Type> getTypeVariableMap() { + public Map, Type> getTypeVariableMap() { return typeVariableMap; } @@ -142,7 +142,7 @@ protected Type resolveType(Type type) { Map map = new HashMap<>(); map.putAll(getTypeVariableMap()); - return ResolvableType.forType(type, new TypeVariableMapVariableResolver(map)).resolveType().getType(); + return ResolvableType.forType(type, new TypeVariableMapVariableResolver(map)).getType(); } public List> getParameterTypes(Constructor constructor) { @@ -168,6 +168,11 @@ public Class getType() { return this.resolvedType; } + @Override + public Type getGenericType() { + return resolveType(type); + } + @Override public ClassTypeInformation getRawTypeInformation() { return ClassTypeInformation.from(getType()).getRawTypeInformation(); diff --git a/src/main/java/com/lambdaworks/redis/dynamic/support/TypeInformation.java b/src/main/java/com/lambdaworks/redis/dynamic/support/TypeInformation.java index bd615bd4a5..167a92c7b0 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/support/TypeInformation.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/support/TypeInformation.java @@ -17,13 +17,18 @@ import java.lang.reflect.Constructor; import java.lang.reflect.Method; +import java.lang.reflect.Type; +import java.lang.reflect.TypeVariable; import java.util.List; +import java.util.Map; /** * Interface to access types and resolving generics on the way. */ public interface TypeInformation { + Type getGenericType(); + /** * Returns the {@link TypeInformation}s for the parameters of the given {@link Constructor}. * @@ -127,4 +132,6 @@ public interface TypeInformation { * @return */ List> getTypeArguments(); + + Map, Type> getTypeVariableMap(); } diff --git a/src/test/java/com/lambdaworks/redis/dynamic/CommandMethodTest.java b/src/test/java/com/lambdaworks/redis/dynamic/CommandMethodTest.java index eda6b87a85..cade02bc86 100644 --- a/src/test/java/com/lambdaworks/redis/dynamic/CommandMethodTest.java +++ b/src/test/java/com/lambdaworks/redis/dynamic/CommandMethodTest.java @@ -43,8 +43,8 @@ public void shouldResolveFutureComponentType() throws Exception { CommandMethod commandMethod = new CommandMethod(getMethod("getFuture")); - assertThat(commandMethod.getActualReturnType().getType()).isEqualTo(String.class); - assertThat(commandMethod.getReturnType().getType()).isEqualTo(Future.class); + assertThat(commandMethod.getActualReturnType().getRawClass()).isEqualTo(String.class); + assertThat(commandMethod.getReturnType().getRawClass()).isEqualTo(Future.class); } @Test @@ -52,8 +52,8 @@ public void shouldResolveFluxComponentType() throws Exception { CommandMethod commandMethod = new CommandMethod(getMethod("getFlux")); - assertThat(commandMethod.getActualReturnType().getType()).isEqualTo(String.class); - assertThat(commandMethod.getReturnType().getType()).isEqualTo(Flux.class); + assertThat(commandMethod.getActualReturnType().getRawClass()).isEqualTo(String.class); + assertThat(commandMethod.getReturnType().getRawClass()).isEqualTo(Flux.class); } private Method getMethod(String name) throws NoSuchMethodException { diff --git a/src/test/java/com/lambdaworks/redis/dynamic/output/CodecAwareOutputResolverTest.java b/src/test/java/com/lambdaworks/redis/dynamic/output/CodecAwareOutputResolverTest.java index a5a19dc7df..00fe34db28 100644 --- a/src/test/java/com/lambdaworks/redis/dynamic/output/CodecAwareOutputResolverTest.java +++ b/src/test/java/com/lambdaworks/redis/dynamic/output/CodecAwareOutputResolverTest.java @@ -26,7 +26,6 @@ import com.lambdaworks.redis.codec.RedisCodec; import com.lambdaworks.redis.dynamic.CommandMethod; -import com.lambdaworks.redis.dynamic.support.ClassTypeInformation; import com.lambdaworks.redis.dynamic.support.ReflectionUtils; import com.lambdaworks.redis.output.*; @@ -46,20 +45,6 @@ public void shouldResolveValueOutput() { assertThat(commandOutput).isInstanceOf(ValueOutput.class); } - @Test - public void shouldDetermineKeyType() { - - assertThat(resolver.isKeyType(ClassTypeInformation.from(String.class))).isFalse(); - assertThat(resolver.isKeyType(ClassTypeInformation.from(ByteBuffer.class))).isTrue(); - } - - @Test - public void shouldDetermineValueType() { - - assertThat(resolver.isValueType(ClassTypeInformation.from(String.class))).isTrue(); - assertThat(resolver.isValueType(ClassTypeInformation.from(ByteBuffer.class))).isFalse(); - } - @Test public void shouldResolveValueListOutput() { @@ -104,7 +89,8 @@ public void shouldResolveMapsOutput() { Method method = ReflectionUtils.findMethod(CommandMethods.class, methodName); CommandMethod commandMethod = new CommandMethod(method); - CommandOutputFactory factory = resolver.resolveCommandOutput(new OutputSelector(commandMethod.getActualReturnType())); + CommandOutputFactory factory = resolver + .resolveCommandOutput(new OutputSelector(commandMethod.getReturnType(), new ByteBufferAndStringCodec())); return factory.create(new ByteBufferAndStringCodec()); } @@ -113,7 +99,7 @@ private static interface CommandMethods { List stringList(); - List charSequenceList(); + List charSequenceList(); List byteBufferList(); diff --git a/src/test/java/com/lambdaworks/redis/dynamic/output/OutputRegistryCommandOutputFactoryResolverTest.java b/src/test/java/com/lambdaworks/redis/dynamic/output/OutputRegistryCommandOutputFactoryResolverTest.java index 133a48a10c..602cad95bd 100644 --- a/src/test/java/com/lambdaworks/redis/dynamic/output/OutputRegistryCommandOutputFactoryResolverTest.java +++ b/src/test/java/com/lambdaworks/redis/dynamic/output/OutputRegistryCommandOutputFactoryResolverTest.java @@ -18,11 +18,13 @@ import static org.assertj.core.api.Assertions.assertThat; import java.lang.reflect.Method; +import java.util.Collection; import java.util.List; import org.junit.Test; import com.lambdaworks.redis.GeoCoordinates; +import com.lambdaworks.redis.ScoredValue; import com.lambdaworks.redis.Value; import com.lambdaworks.redis.codec.StringCodec; import com.lambdaworks.redis.dynamic.CommandMethod; @@ -40,8 +42,8 @@ public class OutputRegistryCommandOutputFactoryResolverTest { @Test public void shouldResolveStringListOutput() { - assertThat(getCommandOutput("stringList")).isInstanceOf(StringListOutput.class); - assertThat(getCommandOutput("stringIterable")).isInstanceOf(StringListOutput.class); + assertThat(getCommandOutput("stringList")).isInstanceOf(KeyListOutput.class); + assertThat(getCommandOutput("stringIterable")).isInstanceOf(KeyListOutput.class); } @Test @@ -54,9 +56,17 @@ public void shouldResolveVoidOutput() { @Test public void shouldResolveStringValueListOutput() { - CommandOutput commandOutput = getCommandOutput("stringValueList"); + CommandOutput commandOutput = getCommandOutput("stringValueCollection"); - assertThat(commandOutput).isInstanceOf(StringValueListOutput.class); + assertThat(commandOutput).isInstanceOf(ValueValueListOutput.class); + } + + @Test + public void shouldResolveStringScoredValueListOutput() { + + CommandOutput commandOutput = getCommandOutput("stringScoredValueList"); + + assertThat(commandOutput).isInstanceOf(ScoredValueListOutput.class); } @Test @@ -107,23 +117,54 @@ public void shouldResolveListOfMapsOutput() { assertThat(commandOutput).isInstanceOf(ListOfMapsOutput.class); } - protected CommandOutput getCommandOutput(String methodName) { + @Test + public void stringValueCollectionIsAssignableFromStringValueListOutput() { - Method method = ReflectionUtils.findMethod(CommandMethods.class, methodName); - CommandMethod commandMethod = new CommandMethod(method); + OutputSelector selector = getOutputSelector("stringValueCollection"); + + boolean assignable = resolver.isAssignableFrom(selector, + OutputRegistry.getOutputComponentType(StringValueListOutput.class)); + assertThat(assignable).isTrue(); + } + + @Test + public void stringWildcardValueCollectionIsAssignableFromOutputs() { + + OutputSelector selector = getOutputSelector("stringValueCollection"); - CommandOutputFactory factory = resolver.resolveCommandOutput(new OutputSelector(commandMethod.getActualReturnType())); + assertThat(resolver.isAssignableFrom(selector, OutputRegistry.getOutputComponentType(ScoredValueListOutput.class))) + .isFalse(); + + assertThat(resolver.isAssignableFrom(selector, OutputRegistry.getOutputComponentType(StringValueListOutput.class))) + .isTrue(); + + } + + protected CommandOutput getCommandOutput(String methodName) { + + OutputSelector outputSelector = getOutputSelector(methodName); + CommandOutputFactory factory = resolver.resolveCommandOutput(outputSelector); return factory.create(new StringCodec()); } + private OutputSelector getOutputSelector(String methodName) { + + Method method = ReflectionUtils.findMethod(CommandMethods.class, methodName); + return new OutputSelector(new CommandMethod(method).getActualReturnType(), StringCodec.UTF8); + } + private static interface CommandMethods { List stringList(); Iterable stringIterable(); - List> stringValueList(); + Collection> stringValueCollection(); + + Collection> stringWildcardValueCollection(); + + List> stringScoredValueList(); List> geoCoordinatesValueList(); diff --git a/src/test/java/com/lambdaworks/redis/dynamic/output/OutputRegistryTest.java b/src/test/java/com/lambdaworks/redis/dynamic/output/OutputRegistryTest.java index cfd9bcae8f..e3d13e5a21 100644 --- a/src/test/java/com/lambdaworks/redis/dynamic/output/OutputRegistryTest.java +++ b/src/test/java/com/lambdaworks/redis/dynamic/output/OutputRegistryTest.java @@ -17,16 +17,18 @@ import static org.assertj.core.api.Assertions.assertThat; +import java.nio.ByteBuffer; import java.util.List; -import com.lambdaworks.redis.dynamic.support.ClassTypeInformation; import org.junit.Test; -import com.lambdaworks.redis.Value; -import com.lambdaworks.redis.dynamic.output.OutputRegistry.KeySurrogate; -import com.lambdaworks.redis.output.GeoCoordinatesValueListOutput; -import com.lambdaworks.redis.output.KeyListOutput; -import com.lambdaworks.redis.output.StringListOutput; +import com.lambdaworks.redis.ScoredValue; +import com.lambdaworks.redis.codec.ByteArrayCodec; +import com.lambdaworks.redis.codec.RedisCodec; +import com.lambdaworks.redis.codec.StringCodec; +import com.lambdaworks.redis.dynamic.support.ClassTypeInformation; +import com.lambdaworks.redis.dynamic.support.ResolvableType; +import com.lambdaworks.redis.output.*; /** * @author Mark Paluch @@ -34,46 +36,84 @@ public class OutputRegistryTest { @Test - public void getStreamingType() throws Exception { + public void getKeyOutputType() throws Exception { - OutputType streamingType = OutputRegistry.getStreamingType(GeoCoordinatesValueListOutput.class); + OutputType outputComponentType = OutputRegistry.getOutputComponentType(KeyListOutput.class); - assertThat(streamingType.getPrimaryType()).isEqualTo(Value.class); + assertThat(outputComponentType.getTypeInformation().getComponentType().getType()).isEqualTo(Object.class); } @Test - public void getOutputComponentType() throws Exception { + public void getStringListOutputType() throws Exception { - OutputType outputComponentType = OutputRegistry.getOutputComponentType(GeoCoordinatesValueListOutput.class); + OutputType outputComponentType = OutputRegistry.getOutputComponentType(StringListOutput.class); - assertThat(outputComponentType.getPrimaryType()).isEqualTo(List.class); + assertThat(outputComponentType.getTypeInformation().getComponentType()) + .isEqualTo(ClassTypeInformation.from(String.class)); } @Test - public void getKeyStreamingType() throws Exception { + public void componentTypeOfKeyOuputWithCodecIsAssignableFromString() throws Exception { - OutputRegistry.getStreamingType(KeyListOutput.class); - OutputType streamingType = OutputRegistry.getStreamingType(KeyListOutput.class); + OutputType outputComponentType = OutputRegistry.getOutputComponentType(KeyOutput.class); - assertThat(streamingType.getPrimaryType()).isEqualTo(KeySurrogate.class); + ResolvableType resolvableType = outputComponentType.withCodec(new StringCodec()); + + assertThat(resolvableType.isAssignableFrom(String.class)).isTrue(); } @Test - public void getKeyOutputType() throws Exception { + public void componentTypeOfKeyListOuputWithCodecIsAssignableFromListOfString() throws Exception { OutputType outputComponentType = OutputRegistry.getOutputComponentType(KeyListOutput.class); - assertThat(outputComponentType.getPrimaryType()).isEqualTo(KeySurrogate.class); - assertThat(outputComponentType.getTypeInformation().getComponentType().getType()).isEqualTo(Object.class); + ResolvableType resolvableType = outputComponentType.withCodec(new StringCodec()); + + assertThat(resolvableType.isAssignableFrom(ResolvableType.forClassWithGenerics(List.class, String.class))).isTrue(); } @Test - public void getStringListOutputType() throws Exception { + public void streamingTypeOfKeyOuputWithCodecIsAssignableFromString() throws Exception { - OutputType outputComponentType = OutputRegistry.getOutputComponentType(StringListOutput.class); + OutputType outputComponentType = OutputRegistry.getStreamingType(KeyListOutput.class); - assertThat(outputComponentType.getPrimaryType()).isEqualTo(List.class); - assertThat(outputComponentType.getTypeInformation().getComponentType()) - .isEqualTo(ClassTypeInformation.from(String.class)); + ResolvableType resolvableType = outputComponentType.withCodec(new StringCodec()); + + assertThat(resolvableType.isAssignableFrom(ResolvableType.forClass(String.class))).isTrue(); + } + + @Test + public void streamingTypeOfKeyListOuputWithCodecIsAssignableFromListOfString() throws Exception { + + OutputType outputComponentType = OutputRegistry.getStreamingType(ScoredValueListOutput.class); + + ResolvableType resolvableType = outputComponentType.withCodec(new StringCodec()); + + assertThat(resolvableType.isAssignableFrom(ResolvableType.forClassWithGenerics(ScoredValue.class, String.class))) + .isTrue(); + } + + @Test + public void customizedValueOutput() throws Exception { + + OutputType outputComponentType = OutputRegistry.getOutputComponentType(KeyTypedOutput.class); + + ResolvableType resolvableType = outputComponentType.withCodec(ByteArrayCodec.INSTANCE); + + assertThat(resolvableType.isAssignableFrom(ResolvableType.forClass(byte[].class))).isTrue(); + } + + private static abstract class IntermediateOutput extends CommandOutput { + + public IntermediateOutput(RedisCodec codec, V1 output) { + super(codec, null); + } + } + + private static class KeyTypedOutput extends IntermediateOutput { + + public KeyTypedOutput(RedisCodec codec) { + super(codec, null); + } } } diff --git a/src/test/java/com/lambdaworks/redis/dynamic/support/ParametrizedTypeInformationTest.java b/src/test/java/com/lambdaworks/redis/dynamic/support/ParametrizedTypeInformationTest.java index d5c05cbf05..6522b120f6 100644 --- a/src/test/java/com/lambdaworks/redis/dynamic/support/ParametrizedTypeInformationTest.java +++ b/src/test/java/com/lambdaworks/redis/dynamic/support/ParametrizedTypeInformationTest.java @@ -88,7 +88,6 @@ public void isAssignableShouldConsiderNestedParameterTypes() throws Exception { TypeInformation target = ClassTypeInformation .fromReturnTypeOf(ReflectionUtils.findMethod(TestType.class, "collectionOfIterableOfNumber")); - assertThat(target.isAssignableFrom(ClassTypeInformation.from(ListOfIterableOfNumber.class))).isTrue(); assertThat(target.isAssignableFrom(ClassTypeInformation.from(ListOfIterableOfInteger.class))).isFalse(); assertThat(target.isAssignableFrom(ClassTypeInformation.from(ListOfListOfNumber.class))).isFalse(); assertThat(target.isAssignableFrom(ClassTypeInformation.from(ListOfSetOfNumber.class))).isFalse(); diff --git a/src/test/java/com/lambdaworks/redis/dynamic/support/WildcardTypeInformationTest.java b/src/test/java/com/lambdaworks/redis/dynamic/support/WildcardTypeInformationTest.java index a3b0825aea..29d4874c56 100644 --- a/src/test/java/com/lambdaworks/redis/dynamic/support/WildcardTypeInformationTest.java +++ b/src/test/java/com/lambdaworks/redis/dynamic/support/WildcardTypeInformationTest.java @@ -22,7 +22,6 @@ import java.util.Collection; import java.util.List; -import org.junit.Ignore; import org.junit.Test; /** @@ -88,19 +87,6 @@ public void isAssignableFromLowerBoundComponentType() { assertThat(target.isAssignableFrom(from(Object.class))).isFalse(); } - @Test - @Ignore("Method-level variables not supported") - public void isAssignableFromParametrizedWildcardType() { - - TypeInformation target = componentTypeOf("numberOrSubtype"); - - assertThat(target.isAssignableFrom(from(Integer.class))).isTrue(); - assertThat(target.isAssignableFrom(from(Number.class))).isTrue(); - assertThat(target.isAssignableFrom(from(Float.class))).isTrue(); - assertThat(target.isAssignableFrom(from(String.class))).isFalse(); - assertThat(target.isAssignableFrom(from(Object.class))).isFalse(); - } - protected TypeInformation componentTypeOf(String name) { return ClassTypeInformation.fromReturnTypeOf(methodOf(name)).getComponentType(); } @@ -124,7 +110,5 @@ static interface GenericReturnTypes { List exactFloat(); List atLeastNumber(); - - List numberOrSubtype(); } } \ No newline at end of file From 41fa6be0857ba830daef6a88da2db7b6a8027af0 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Sun, 8 Jan 2017 21:52:46 +0100 Subject: [PATCH 109/808] Remove own BackpressureUtils class #394 Switch to Reactor Core's Operators class to update wip (demand). Remove superflous allDataRead since it was never used. allDataRead is set by the onAllDataRead event handling inside the state transitions. --- .../lambdaworks/redis/BackpressureUtils.java | 57 ------------------- .../com/lambdaworks/redis/RedisPublisher.java | 35 +++++++----- 2 files changed, 22 insertions(+), 70 deletions(-) delete mode 100644 src/main/java/com/lambdaworks/redis/BackpressureUtils.java diff --git a/src/main/java/com/lambdaworks/redis/BackpressureUtils.java b/src/main/java/com/lambdaworks/redis/BackpressureUtils.java deleted file mode 100644 index 227879d205..0000000000 --- a/src/main/java/com/lambdaworks/redis/BackpressureUtils.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2011-2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.lambdaworks.redis; - -import java.util.concurrent.atomic.AtomicLong; - -enum BackpressureUtils { - ; - - /** - * Cap a substraction to 0 - * - * @param a left operand - * @param b right operand - * @return Subscription result or 0 if overflow - */ - public static long subOrZero(long a, long b) { - long res = a - b; - if (res < 0L) { - return 0; - } - return res; - } - - /** - * Concurrent substraction bound to 0 and Long.MAX_VALUE. Any concurrent write will "happen" before this operation. - * - * @param sequence current atomic to update - * @param toSub delta to sub - * @return value before subscription, 0 or Long.MAX_VALUE - */ - public static long getAndSub(AtomicLong sequence, long toSub) { - long r, u; - do { - r = sequence.get(); - if (r == 0 || r == Long.MAX_VALUE) { - return r; - } - u = subOrZero(r, toSub); - } while (!sequence.compareAndSet(r, u)); - - return r; - } -} diff --git a/src/main/java/com/lambdaworks/redis/RedisPublisher.java b/src/main/java/com/lambdaworks/redis/RedisPublisher.java index c78cd2fa11..1528f5f0f3 100644 --- a/src/main/java/com/lambdaworks/redis/RedisPublisher.java +++ b/src/main/java/com/lambdaworks/redis/RedisPublisher.java @@ -30,6 +30,8 @@ import org.reactivestreams.Subscriber; import org.reactivestreams.Subscription; +import reactor.core.publisher.Operators; + import com.lambdaworks.redis.api.StatefulConnection; import com.lambdaworks.redis.api.StatefulRedisConnection; import com.lambdaworks.redis.internal.LettuceAssert; @@ -39,7 +41,6 @@ import io.netty.util.internal.logging.InternalLogger; import io.netty.util.internal.logging.InternalLoggerFactory; -import reactor.core.publisher.Operators; /** * Reactive command {@link Publisher} using ReactiveStreams. @@ -83,8 +84,7 @@ public RedisPublisher(RedisCommand staticCommand, StatefulConnection> commandSupplier, StatefulConnection connection, - boolean dissolve) { + public RedisPublisher(Supplier> commandSupplier, StatefulConnection connection, boolean dissolve) { LettuceAssert.notNull(commandSupplier, "CommandSupplier must not be null"); LettuceAssert.notNull(connection, "StatefulConnection must not be null"); @@ -164,7 +164,7 @@ void subscribe(Subscriber subscriber) { } if (traceEnabled) { - LOG.trace("{} subscribe: {}@{}", state(), subscriber.getClass().getName(), Objects.hashCode(subscriber)); + LOG.trace("{} subscribe: {}@{}", state(), subscriber.getClass().getName(), subscriber.hashCode()); } state().subscribe(this, subscriber); @@ -239,7 +239,6 @@ final void onAllDataRead() { LOG.trace("{} onAllDataRead()", state()); } - allDataRead = true; this.state.get().onAllDataRead(this); } @@ -253,6 +252,7 @@ final void onError(Throwable t) { if (LOG.isErrorEnabled()) { LOG.trace("{} onError(): {}", state(), t.toString(), t); } + this.state.get().onError(this, t); } @@ -260,20 +260,26 @@ final void onError(Throwable t) { * Reads and publishes data from the input. Continues until either there is no more demand, or until there is no more * data to be read. * - * @return {@literal true} if there is more demand, {@literal false} otherwise + * @return {@literal true} if there is more demand, {@literal false} otherwise. */ private boolean readAndPublish() throws IOException { while (hasDemand()) { + T data = read(); if (data != null) { - BackpressureUtils.getAndSub(this.demand, 1L); + this.subscriber.onNext(data); + + if (Operators.addAndGet(this.demand, -1) == 0) { + return false; + } } else { return true; } } + return false; } @@ -301,14 +307,15 @@ void checkCommandDispatch() { } } - @SuppressWarnings({"unchecked", "rawtypes"}) - private void dispatchCommand() { + @SuppressWarnings({ "unchecked", "rawtypes" }) + void dispatchCommand() { + if (command.getOutput() instanceof StreamingOutput) { StreamingOutput streamingOutput = (StreamingOutput) command.getOutput(); if (connection instanceof StatefulRedisConnection && ((StatefulRedisConnection) connection).isMulti()) { - streamingOutput - .setSubscriber(new CompositeSubscriber(Arrays.asList(this, streamingOutput.getSubscriber()))); + streamingOutput.setSubscriber(new CompositeSubscriber(Arrays.asList(this, + streamingOutput.getSubscriber()))); } else { streamingOutput.setSubscriber(this); } @@ -376,9 +383,11 @@ void subscribe(RedisSubscription subscription, Subscriber subscriber) { void request(RedisSubscription subscription, long n) { if (Operators.checkRequest(n, subscription.subscriber)) { + Operators.addAndGet(subscription.demand, n); if (subscription.changeState(this, DEMAND)) { + try { subscription.checkCommandDispatch(); } catch (Exception ex) { @@ -407,14 +416,14 @@ void onDataAvailable(RedisSubscription subscription) { subscription.checkOnDataAvailable(); } else { - if (subscription.allDataRead && subscription.data.isEmpty()) { + if (subscription.data.isEmpty() && subscription.allDataRead) { subscription.onAllDataRead(); } else { subscription.changeState(READING, NO_DEMAND); } } } catch (IOException ex) { - subscription.onError(ex); + onError(subscription, ex); } } } From 48e54b63ee9ef12ce3c37344eac811a7529237d0 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Sun, 8 Jan 2017 21:54:51 +0100 Subject: [PATCH 110/808] Guard data queue against overflow #394 Check for the outcome when offering an element to the data queue. Send an error signal to the subscriber if the element cannot be added to the queue. --- src/main/java/com/lambdaworks/redis/RedisPublisher.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/lambdaworks/redis/RedisPublisher.java b/src/main/java/com/lambdaworks/redis/RedisPublisher.java index 1528f5f0f3..eda77ceae8 100644 --- a/src/main/java/com/lambdaworks/redis/RedisPublisher.java +++ b/src/main/java/com/lambdaworks/redis/RedisPublisher.java @@ -30,6 +30,7 @@ import org.reactivestreams.Subscriber; import org.reactivestreams.Subscription; +import reactor.core.Exceptions; import reactor.core.publisher.Operators; import com.lambdaworks.redis.api.StatefulConnection; @@ -212,7 +213,13 @@ public void onNext(T t) { LettuceAssert.notNull(t, "Data must not be null"); - data.add(t); + if (!data.offer(t)) { + + Throwable e = Operators.onOperatorError(this, Exceptions.failWithOverflow(), t); + onError(e); + return; + } + onDataAvailable(); } From 832b5c8b92af245e9f445e56ba6a54d5272195cf Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Sun, 8 Jan 2017 22:02:21 +0100 Subject: [PATCH 111/808] Optimize field access #394 Increase field visibility to package level to prevent synthetic accessors. Use AtomicLongFieldUpdater for demand updating that was previously an AtomicLong to reduce memory footprint. Use CommandDispatch state to perform command dispatching. That change prevents conditional code to be executed if data is requested (no demand -> demand) while command execution is allowed to happen only once. --- .../com/lambdaworks/redis/RedisPublisher.java | 88 +++++++++++++------ 1 file changed, 61 insertions(+), 27 deletions(-) diff --git a/src/main/java/com/lambdaworks/redis/RedisPublisher.java b/src/main/java/com/lambdaworks/redis/RedisPublisher.java index eda77ceae8..38cb759df7 100644 --- a/src/main/java/com/lambdaworks/redis/RedisPublisher.java +++ b/src/main/java/com/lambdaworks/redis/RedisPublisher.java @@ -20,9 +20,7 @@ import java.util.Collection; import java.util.Objects; import java.util.Queue; -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicLongFieldUpdater; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Supplier; @@ -32,6 +30,7 @@ import reactor.core.Exceptions; import reactor.core.publisher.Operators; +import reactor.util.concurrent.QueueSupplier; import com.lambdaworks.redis.api.StatefulConnection; import com.lambdaworks.redis.api.StatefulRedisConnection; @@ -125,23 +124,26 @@ public void subscribe(Subscriber subscriber) { * * @param data element type */ - private static class RedisSubscription implements Subscription, StreamingOutput.Subscriber { + static class RedisSubscription implements Subscription, StreamingOutput.Subscriber { - private static final InternalLogger LOG = InternalLoggerFactory.getInstance(RedisPublisher.class); - private final boolean traceEnabled = LOG.isTraceEnabled(); + static final InternalLogger LOG = InternalLoggerFactory.getInstance(RedisPublisher.class); - private final AtomicLong demand = new AtomicLong(); - private final Queue data = new ConcurrentLinkedQueue(); - private final AtomicBoolean dispatched = new AtomicBoolean(); - private volatile boolean allDataRead = false; + static final AtomicLongFieldUpdater DEMAND = AtomicLongFieldUpdater.newUpdater( + RedisSubscription.class, "demand"); - private final StatefulConnection connection; - private final RedisCommand command; - private final boolean dissolve; + final boolean traceEnabled = LOG.isTraceEnabled(); + + final Queue data = QueueSupplier. unbounded().get(); + final StatefulConnection connection; + final RedisCommand command; + final boolean dissolve; + final AtomicReference state = new AtomicReference<>(State.UNSUBSCRIBED); + final AtomicReference commandDispatch = new AtomicReference<>(CommandDispatch.UNDISPATCHED); - private Subscriber subscriber; + volatile long demand; + volatile boolean allDataRead = false; - private final AtomicReference state = new AtomicReference<>(State.UNSUBSCRIBED); + Subscriber subscriber; RedisSubscription(StatefulConnection connection, RedisCommand command, boolean dissolve) { @@ -279,7 +281,7 @@ private boolean readAndPublish() throws IOException { this.subscriber.onNext(data); - if (Operators.addAndGet(this.demand, -1) == 0) { + if (Operators.addAndGet(DEMAND, this, -1) == 0) { return false; } } else { @@ -292,7 +294,7 @@ private boolean readAndPublish() throws IOException { /** * Reads data from the input, if possible. - * + * * @return the data that was read or {@literal null} */ protected T read() { @@ -300,7 +302,7 @@ protected T read() { } private boolean hasDemand() { - return this.demand.get() > 0; + return this.demand > 0; } private boolean changeState(State oldState, State newState) { @@ -308,10 +310,7 @@ private boolean changeState(State oldState, State newState) { } void checkCommandDispatch() { - - if (!dispatched.get() && dispatched.compareAndSet(false, true)) { - dispatchCommand(); - } + commandDispatch.get().dispatch(this); } @SuppressWarnings({ "unchecked", "rawtypes" }) @@ -340,7 +339,42 @@ void checkOnDataAvailable() { } /** - * Represents a state for the {@link Subscription} to be in. The following figure indicate the four different states that + * Represents a state for command dispatch of the {@link Subscription}. The following figure indicates the two different + * states that exist, and the relationships between them. + * + *
    +     *   UNDISPATCHED
    +     *        |
    +     *        v
    +     *   DISPATCHED
    +     * 
    + * + * Refer to the individual states for more information. + */ + private enum CommandDispatch { + + /** + * Initial state. Will respond to {@link #dispatch(RedisSubscription)} by changing the state to {@link #DISPATCHED} and + * dispatch the command. + */ + UNDISPATCHED { + + @Override + void dispatch(RedisSubscription redisSubscription) { + + if (redisSubscription.commandDispatch.compareAndSet(this, DISPATCHED)) { + redisSubscription.dispatchCommand(); + } + } + }, + DISPATCHED; + + void dispatch(RedisSubscription redisSubscription) { + } + } + + /** + * Represents a state for the {@link Subscription} to be in. The following figure indicates the four different states that * exist, and the relationships between them. * *
    @@ -355,7 +389,7 @@ void checkOnDataAvailable() {
          *    |                 v              |
          *    ------------> COMPLETED <---------
          * 
    - * + * * Refer to the individual states for more information. */ private enum State { @@ -391,7 +425,7 @@ void request(RedisSubscription subscription, long n) { if (Operators.checkRequest(n, subscription.subscriber)) { - Operators.addAndGet(subscription.demand, n); + Operators.getAndAddCap(subscription.DEMAND, subscription, n); if (subscription.changeState(this, DEMAND)) { @@ -439,7 +473,7 @@ void onDataAvailable(RedisSubscription subscription) { void request(RedisSubscription subscription, long n) { if (Operators.checkRequest(n, subscription.subscriber)) { - Operators.addAndGet(subscription.demand, n); + Operators.getAndAddCap(subscription.DEMAND, subscription, n); } } @@ -450,7 +484,7 @@ void request(RedisSubscription subscription, long n) { void request(RedisSubscription subscription, long n) { if (Operators.checkRequest(n, subscription.subscriber)) { - Operators.addAndGet(subscription.demand, n); + Operators.getAndAddCap(subscription.DEMAND, subscription, n); } } }, From dc531035a6cf51c07194f9d3c2f5c793492a065d Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Sat, 14 Jan 2017 19:40:14 +0100 Subject: [PATCH 112/808] Upgrade to netty 4.1.7 #436 --- pom.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index eae715420e..1f17085b2d 100644 --- a/pom.xml +++ b/pom.xml @@ -57,7 +57,7 @@ true 4.2.2.Final 3.5.0.Final - 4.1.6.Final + 4.1.7.Final @@ -111,7 +111,7 @@ io.netty netty-tcnative - 1.1.33.Fork21 + 1.1.33.Fork25 ${os.detected.classifier} provided true @@ -309,7 +309,7 @@ netty-40 - 4.0.42.Final + 4.0.43.Final From d6107049c48c745b5bf39bc1fd2d76999037bcab Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Thu, 19 Jan 2017 07:15:10 +0100 Subject: [PATCH 113/808] Expose a protected default constructor for RedisClusterClient #438 RedisClusterClient exposes now a protected default constructor so frameworks like CDI can create proxy instances. Previously, RedisClusterClient provided a private default constructor that prevents proxying as CDI cannot proxy beans (in normalscoped Scopes) without a non-private no-args constructor. --- .../java/com/lambdaworks/redis/RedisClient.java | 17 +++++++++-------- .../redis/cluster/RedisClusterClient.java | 5 ++++- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/lambdaworks/redis/RedisClient.java b/src/main/java/com/lambdaworks/redis/RedisClient.java index 450bc1abaf..1b086ee106 100644 --- a/src/main/java/com/lambdaworks/redis/RedisClient.java +++ b/src/main/java/com/lambdaworks/redis/RedisClient.java @@ -67,6 +67,7 @@ protected RedisClient(ClientResources clientResources, RedisURI redisURI) { /** * Creates a uri-less RedisClient. You can connect to different Redis servers but you must supply a {@link RedisURI} on * connecting. Methods without having a {@link RedisURI} will fail with a {@link java.lang.IllegalStateException}. + * Non-private constructor to make {@link RedisClient} proxyable. */ protected RedisClient() { this(null, EMPTY_URI); @@ -336,8 +337,7 @@ public StatefulRedisPubSubConnection connectPubSub(RedisCodec return connectPubSub(codec, redisURI, Timeout.from(redisURI)); } - private StatefulRedisPubSubConnection connectPubSub(RedisCodec codec, RedisURI redisURI, - Timeout timeout) { + private StatefulRedisPubSubConnection connectPubSub(RedisCodec codec, RedisURI redisURI, Timeout timeout) { assertNotNull(codec); checkValidRedisURI(redisURI); @@ -572,8 +572,8 @@ protected StatefulRedisConnectionImpl newStatefulRedisConnection(Re * @see RedisURI#getSentinels() * @see RedisURI#getSentinelMasterId() */ - protected SocketAddress getSocketAddress(RedisURI redisURI) - throws InterruptedException, TimeoutException, ExecutionException { + protected SocketAddress getSocketAddress(RedisURI redisURI) throws InterruptedException, TimeoutException, + ExecutionException { SocketAddress redisAddress; if (redisURI.getSentinelMasterId() != null && !redisURI.getSentinels().isEmpty()) { @@ -582,8 +582,8 @@ protected SocketAddress getSocketAddress(RedisURI redisURI) redisAddress = lookupRedis(redisURI); if (redisAddress == null) { - throw new RedisConnectionException( - "Cannot provide redisAddress using sentinel for masterId " + redisURI.getSentinelMasterId()); + throw new RedisConnectionException("Cannot provide redisAddress using sentinel for masterId " + + redisURI.getSentinelMasterId()); } } else { @@ -675,8 +675,9 @@ private static void assertNotNull(ClientResources clientResources) { } private void checkForRedisURI() { - LettuceAssert.assertState(this.redisURI != EMPTY_URI, - "RedisURI is not available. Use RedisClient(Host), RedisClient(Host, Port) or RedisClient(RedisURI) to construct your client."); + LettuceAssert + .assertState(this.redisURI != EMPTY_URI, + "RedisURI is not available. Use RedisClient(Host), RedisClient(Host, Port) or RedisClient(RedisURI) to construct your client."); checkValidRedisURI(this.redisURI); } diff --git a/src/main/java/com/lambdaworks/redis/cluster/RedisClusterClient.java b/src/main/java/com/lambdaworks/redis/cluster/RedisClusterClient.java index 2d142bcb38..ab6f4d06a5 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/RedisClusterClient.java +++ b/src/main/java/com/lambdaworks/redis/cluster/RedisClusterClient.java @@ -141,7 +141,10 @@ public class RedisClusterClient extends AbstractRedisClient { private Partitions partitions; - private RedisClusterClient() { + /** + * Non-private constructor to make {@link RedisClusterClient} proxyable. + */ + protected RedisClusterClient() { super(null); From af27880eb5449888763e0f1e9180e6f27502f471 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Fri, 20 Jan 2017 22:41:24 +0100 Subject: [PATCH 114/808] Propagate backpressure to the transport channel #394 Backpressure of reactive commands, more specific the missing demand, is propagated to the channel. Reactive commands receive a batch of data and are queried whether they still have a demand for data or whether their demand is satisfied (because of no demand/saturated demand). A command without demand will disable further channel reads until the command is completed/canceled or signals further demand. A significant amount of unread data will eventually cause the TCP receive buffer to overflow. This change moves the buffer responsibility away from the application into the operating system layer which requires then appropriate receive buffer sizing. On the other side, the application is protected against buffer overflows inside the application and reduces the memory footprint because of a reduced amount of data that is held inside the application. --- .../com/lambdaworks/redis/RedisPublisher.java | 149 ++++++++----- .../redis/protocol/CommandHandler.java | 55 +++-- .../redis/protocol/DefaultEndpoint.java | 9 +- .../redis/protocol/DemandAware.java | 72 +++++++ .../lambdaworks/redis/protocol/Endpoint.java | 2 +- .../redis/protocol/HasQueuedCommands.java | 2 +- .../ReactiveBackpressurePropagationTest.java | 196 ++++++++++++++++++ .../redis/ReactiveConnectionTest.java | 22 +- 8 files changed, 430 insertions(+), 77 deletions(-) create mode 100644 src/main/java/com/lambdaworks/redis/protocol/DemandAware.java create mode 100644 src/test/java/com/lambdaworks/redis/ReactiveBackpressurePropagationTest.java diff --git a/src/main/java/com/lambdaworks/redis/RedisPublisher.java b/src/main/java/com/lambdaworks/redis/RedisPublisher.java index 38cb759df7..62a7b0e9cf 100644 --- a/src/main/java/com/lambdaworks/redis/RedisPublisher.java +++ b/src/main/java/com/lambdaworks/redis/RedisPublisher.java @@ -37,6 +37,7 @@ import com.lambdaworks.redis.internal.LettuceAssert; import com.lambdaworks.redis.output.StreamingOutput; import com.lambdaworks.redis.protocol.CommandWrapper; +import com.lambdaworks.redis.protocol.DemandAware; import com.lambdaworks.redis.protocol.RedisCommand; import io.netty.util.internal.logging.InternalLogger; @@ -131,7 +132,8 @@ static class RedisSubscription implements Subscription, StreamingOutput.Subsc static final AtomicLongFieldUpdater DEMAND = AtomicLongFieldUpdater.newUpdater( RedisSubscription.class, "demand"); - final boolean traceEnabled = LOG.isTraceEnabled(); + private final SubscriptionCommand subscriptionCommand; + private final boolean traceEnabled = LOG.isTraceEnabled(); final Queue data = QueueSupplier. unbounded().get(); final StatefulConnection connection; @@ -145,6 +147,7 @@ static class RedisSubscription implements Subscription, StreamingOutput.Subsc Subscriber subscriber; + @SuppressWarnings("unchecked") RedisSubscription(StatefulConnection connection, RedisCommand command, boolean dissolve) { LettuceAssert.notNull(connection, "Connection must not be null"); @@ -153,6 +156,19 @@ static class RedisSubscription implements Subscription, StreamingOutput.Subsc this.connection = connection; this.command = command; this.dissolve = dissolve; + + if (command.getOutput() instanceof StreamingOutput) { + StreamingOutput streamingOutput = (StreamingOutput) command.getOutput(); + + if (connection instanceof StatefulRedisConnection && ((StatefulRedisConnection) connection).isMulti()) { + streamingOutput.setSubscriber(new CompositeSubscriber<>( + Arrays.asList(this, streamingOutput.getSubscriber()))); + } else { + streamingOutput.setSubscriber(this); + } + } + + this.subscriptionCommand = new SubscriptionCommand<>(command, this, dissolve); } /** @@ -201,10 +217,6 @@ public final void cancel() { state().cancel(this); } - private RedisPublisher.State state() { - return this.state.get(); - } - /** * Called by {@link StreamingOutput} to dispatch data (push). * @@ -215,6 +227,10 @@ public void onNext(T t) { LettuceAssert.notNull(t, "Data must not be null"); + if (state() == State.COMPLETED) { + return; + } + if (!data.offer(t)) { Throwable e = Operators.onOperatorError(this, Exceptions.failWithOverflow(), t); @@ -235,7 +251,7 @@ final void onDataAvailable() { LOG.trace("{} onDataAvailable()", state()); } - this.state.get().onDataAvailable(this); + state().onDataAvailable(this); } /** @@ -248,7 +264,7 @@ final void onAllDataRead() { LOG.trace("{} onAllDataRead()", state()); } - this.state.get().onAllDataRead(this); + state().onAllDataRead(this); } /** @@ -262,34 +278,7 @@ final void onError(Throwable t) { LOG.trace("{} onError(): {}", state(), t.toString(), t); } - this.state.get().onError(this, t); - } - - /** - * Reads and publishes data from the input. Continues until either there is no more demand, or until there is no more - * data to be read. - * - * @return {@literal true} if there is more demand, {@literal false} otherwise. - */ - private boolean readAndPublish() throws IOException { - - while (hasDemand()) { - - T data = read(); - - if (data != null) { - - this.subscriber.onNext(data); - - if (Operators.addAndGet(DEMAND, this, -1) == 0) { - return false; - } - } else { - return true; - } - } - - return false; + state().onError(this, t); } /** @@ -315,26 +304,51 @@ void checkCommandDispatch() { @SuppressWarnings({ "unchecked", "rawtypes" }) void dispatchCommand() { + connection.dispatch((RedisCommand) subscriptionCommand); + } - if (command.getOutput() instanceof StreamingOutput) { - StreamingOutput streamingOutput = (StreamingOutput) command.getOutput(); + void checkOnDataAvailable() { - if (connection instanceof StatefulRedisConnection && ((StatefulRedisConnection) connection).isMulti()) { - streamingOutput.setSubscriber(new CompositeSubscriber(Arrays.asList(this, - streamingOutput.getSubscriber()))); - } else { - streamingOutput.setSubscriber(this); + if (data.isEmpty()) { + if (hasDemand()) { + state().readData(this); } } - connection.dispatch(new SubscriptionCommand(command, this, dissolve)); + if (!data.isEmpty()) { + onDataAvailable(); + } } - void checkOnDataAvailable() { + /** + * Reads and publishes data from the input. Continues until either there is no more demand, or until there is no more + * data to be read. + * + * @return {@literal true} if there is more demand, {@literal false} otherwise. + */ + private boolean readAndPublish() throws IOException { - if (!data.isEmpty()) { - onDataAvailable(); + while (hasDemand()) { + + T data = read(); + + if (data != null) { + + this.subscriber.onNext(data); + + if (Operators.addAndGet(DEMAND, this, -1) == 0) { + return false; + } + } else { + return true; + } } + + return false; + } + + RedisPublisher.State state() { + return this.state.get(); } } @@ -425,7 +439,7 @@ void request(RedisSubscription subscription, long n) { if (Operators.checkRequest(n, subscription.subscriber)) { - Operators.getAndAddCap(subscription.DEMAND, subscription, n); + Operators.getAndAddCap(RedisSubscription.DEMAND, subscription, n); if (subscription.changeState(this, DEMAND)) { @@ -473,7 +487,7 @@ void onDataAvailable(RedisSubscription subscription) { void request(RedisSubscription subscription, long n) { if (Operators.checkRequest(n, subscription.subscriber)) { - Operators.getAndAddCap(subscription.DEMAND, subscription, n); + Operators.getAndAddCap(RedisSubscription.DEMAND, subscription, n); } } @@ -484,7 +498,7 @@ void request(RedisSubscription subscription, long n) { void request(RedisSubscription subscription, long n) { if (Operators.checkRequest(n, subscription.subscriber)) { - Operators.getAndAddCap(subscription.DEMAND, subscription, n); + Operators.getAndAddCap(RedisSubscription.DEMAND, subscription, n); } } }, @@ -526,7 +540,16 @@ void request(RedisSubscription subscription, long n) { void cancel(RedisSubscription subscription) { subscription.command.cancel(); - subscription.changeState(this, COMPLETED); + if (subscription.changeState(this, COMPLETED)) { + readData(subscription); + } + } + + void readData(RedisSubscription subscription) { + DemandAware.Source source = subscription.subscriptionCommand.source; + if (source != null) { + source.requestMore(); + } } void onDataAvailable(RedisSubscription subscription) { @@ -538,6 +561,7 @@ void onAllDataRead(RedisSubscription subscription) { subscription.allDataRead = true; if (subscription.data.isEmpty() && subscription.changeState(this, COMPLETED)) { + readData(subscription); if (subscription.subscriber != null) { subscription.subscriber.onComplete(); } @@ -547,6 +571,7 @@ void onAllDataRead(RedisSubscription subscription) { void onError(RedisSubscription subscription, Throwable t) { if (subscription.changeState(this, COMPLETED)) { + readData(subscription); if (subscription.subscriber != null) { subscription.subscriber.onError(t); } @@ -561,11 +586,12 @@ void onError(RedisSubscription subscription, Throwable t) { * @param value type * @param response type */ - private static class SubscriptionCommand extends CommandWrapper { + private static class SubscriptionCommand extends CommandWrapper implements DemandAware.Sink { private final boolean dissolve; private final RedisSubscription subscription; - private boolean completed = false; + private volatile boolean completed = false; + private volatile DemandAware.Source source; public SubscriptionCommand(RedisCommand command, RedisSubscription subscription, boolean dissolve) { @@ -575,6 +601,13 @@ public SubscriptionCommand(RedisCommand command, RedisSubscription s this.dissolve = dissolve; } + @Override + public boolean hasDemand() { + + // signal demand as completed commands just no-op on incoming data. + return completed || subscription.state() == State.COMPLETED || subscription.demand > subscription.data.size(); + } + @Override @SuppressWarnings("unchecked") public void complete() { @@ -598,7 +631,9 @@ public void complete() { if (!(getOutput() instanceof StreamingOutput) && result != null) { if (dissolve && result instanceof Collection) { + Collection collection = (Collection) result; + for (T t : collection) { if (t != null) { subscription.onNext(t); @@ -617,6 +652,16 @@ public void complete() { } } + @Override + public void setSource(DemandAware.Source source) { + this.source = source; + } + + @Override + public void removeSource() { + this.source = null; + } + @Override public void cancel() { diff --git a/src/main/java/com/lambdaworks/redis/protocol/CommandHandler.java b/src/main/java/com/lambdaworks/redis/protocol/CommandHandler.java index 8a8533a040..61dc9acc16 100644 --- a/src/main/java/com/lambdaworks/redis/protocol/CommandHandler.java +++ b/src/main/java/com/lambdaworks/redis/protocol/CommandHandler.java @@ -62,11 +62,12 @@ public class CommandHandler extends ChannelDuplexHandler implements HasQueuedCom private final RedisStateMachine rsm = new RedisStateMachine(); private final boolean traceEnabled = logger.isTraceEnabled(); private final boolean debugEnabled = logger.isDebugEnabled(); + private final BackpressureSource backpressureSource = new BackpressureSource(); private final ClientResources clientResources; private final Endpoint endpoint; - private Channel channel; + Channel channel; private ByteBuf buffer; private LifecycleState lifecycleState = LifecycleState.NOT_CONNECTED; private String logPrefix; @@ -196,13 +197,10 @@ public void channelActive(ChannelHandlerContext ctx) throws Exception { endpoint.notifyChannelActive(ctx.channel()); super.channelActive(ctx); + if (channel != null) { - channel.eventLoop().submit(new Runnable() { - @Override - public void run() { - channel.pipeline().fireUserEventTriggered(new ConnectionEvents.Activated()); - } - }); + channel.eventLoop().submit( + (Runnable) () -> channel.pipeline().fireUserEventTriggered(new ConnectionEvents.Activated())); } if (debugEnabled) { @@ -227,8 +225,8 @@ public void channelInactive(ChannelHandlerContext ctx) throws Exception { } setState(LifecycleState.DISCONNECTED); - setState(LifecycleState.DEACTIVATING); + endpoint.notifyChannelInactive(ctx.channel()); endpoint.notifyDrainQueuedCommands(this); @@ -316,9 +314,24 @@ protected void decode(ChannelHandlerContext ctx, ByteBuf buffer) throws Interrup WithLatency withLatency = getWithLatency(command); if (!rsm.decode(buffer, command, command.getOutput())) { + + if (command instanceof DemandAware.Sink) { + + DemandAware.Sink sink = (DemandAware.Sink) command; + sink.setSource(backpressureSource); + + if (!sink.hasDemand()) { + ctx.channel().config().setAutoRead(false); + } + } + return; } + if (!ctx.channel().config().isAutoRead()) { + ctx.channel().config().setAutoRead(true); + } + recordLatency(withLatency, command.getType()); queue.poll(); @@ -336,12 +349,17 @@ protected void decode(ChannelHandlerContext ctx, ByteBuf buffer) throws Interrup } private WithLatency getWithLatency(RedisCommand command) { + WithLatency withLatency = null; if (clientResources.commandLatencyCollector().isEnabled()) { + RedisCommand unwrappedCommand = CommandWrapper.unwrap(command); + if (unwrappedCommand instanceof WithLatency) { + withLatency = (WithLatency) unwrappedCommand; + if (withLatency.getFirstResponse() == -1) { withLatency.firstResponse(nanoTime()); } @@ -357,14 +375,13 @@ protected boolean decode(ByteBuf buffer, CommandOutput output) { private void recordLatency(WithLatency withLatency, ProtocolKeyword commandType) { - if (withLatency != null && clientResources.commandLatencyCollector().isEnabled() && channel != null - && remote() != null) { + if (withLatency != null && clientResources.commandLatencyCollector().isEnabled() && channel != null && remote() != null) { long firstResponseLatency = nanoTime() - withLatency.getFirstResponse(); long completionLatency = nanoTime() - withLatency.getSent(); - clientResources.commandLatencyCollector().recordCommandLatency(local(), remote(), commandType, firstResponseLatency, - completionLatency); + clientResources.commandLatencyCollector().recordCommandLatency(local(), remote(), commandType, + firstResponseLatency, completionLatency); } } @@ -516,4 +533,18 @@ protected String logPrefix() { public enum LifecycleState { NOT_CONNECTED, REGISTERED, CONNECTED, ACTIVATING, ACTIVE, DISCONNECTED, DEACTIVATING, DEACTIVATED, CLOSED, } + + /** + * Source for backpressure. + */ + class BackpressureSource implements DemandAware.Source { + + @Override + public void requestMore() { + + if (isConnected() && !isClosed() && !channel.config().isAutoRead()) { + channel.config().setAutoRead(true); + } + } + } } diff --git a/src/main/java/com/lambdaworks/redis/protocol/DefaultEndpoint.java b/src/main/java/com/lambdaworks/redis/protocol/DefaultEndpoint.java index d03091b20f..1e26d9e8f5 100644 --- a/src/main/java/com/lambdaworks/redis/protocol/DefaultEndpoint.java +++ b/src/main/java/com/lambdaworks/redis/protocol/DefaultEndpoint.java @@ -60,7 +60,6 @@ public class DefaultEndpoint implements RedisChannelWriter, Endpoint, HasQueuedC private final ClientOptions clientOptions; private final QueuedCommands queuedCommands = new QueuedCommands(); - private final boolean traceEnabled = logger.isTraceEnabled(); private final boolean debugEnabled = logger.isDebugEnabled(); protected volatile Channel channel; @@ -418,6 +417,14 @@ public void notifyDrainQueuedCommands(HasQueuedCommands queuedCommands) { sharedLock.doExclusive(() -> { List> commands = drainCommands(queuedCommands.getQueue()); + + for (RedisCommand command : commands) { + + if (command instanceof DemandAware.Sink) { + ((DemandAware.Sink) command).removeSource(); + } + } + Collections.reverse(commands); logger.debug("{} notifyQueuedCommands {} command(s) added to buffer", logPrefix(), commands.size()); diff --git a/src/main/java/com/lambdaworks/redis/protocol/DemandAware.java b/src/main/java/com/lambdaworks/redis/protocol/DemandAware.java new file mode 100644 index 0000000000..f713444d97 --- /dev/null +++ b/src/main/java/com/lambdaworks/redis/protocol/DemandAware.java @@ -0,0 +1,72 @@ +/* + * Copyright 2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.lambdaworks.redis.protocol; + +/** + * Interface for demand-aware components. + *

    + * A demand-aware component is aware of its demand for data that is read from the {@link Source} and possibly awaits processing. + * A {@link Sink} with demand is ready to process data. A {@link Sink} without demand signals that it's ability to keep up with + * the incoming data is no longer given and it wishes to receive no more data. Submitting more data could cause overload and + * exhaust buffer space. + * + * @author Mark Paluch + * @since 5.0 + */ +public interface DemandAware { + + /** + * A demand-aware {@link Sink} that accepts data. It can signal its {@link Source} demand/readiness to emit more data. + * Instances of implementing classes are required to be thread-safe as they are shared amongst multiple threads. + */ + interface Sink { + + /** + * Returns {@literal true} if the {@link Sink} has demand or {@literal false} if the source has no demand. + * {@literal false} means either the {@link Sink} has no demand in general because data is not needed or the current + * demand is saturated. + * + * @return {@literal true} if the {@link Sink} demands data. + */ + boolean hasDemand(); + + /** + * Sets the {@link Source} for a {@link Sink}. The {@link Sink} is notified by this {@link Source} if the source + * indicates new demand or the sink catches up so it's ready to receive more data. + * + * @param source the reference to the data {@link Source}, must not be {@literal null}. + */ + void setSource(Source source); + + /** + * Removes the {@link Source} reference from this {@link Sink}. Any previously set {@link Source} will no longer be + * asked for data. + */ + void removeSource(); + } + + /** + * A {@link Source} provides data to a {@link DemandAware} and can be notified to produce more input for the command. + * Instances of implementing classes are required to be thread-safe as they are shared amongst multiple threads. + */ + interface Source { + + /** + * Signals demand to the {@link Source} + */ + void requestMore(); + } +} diff --git a/src/main/java/com/lambdaworks/redis/protocol/Endpoint.java b/src/main/java/com/lambdaworks/redis/protocol/Endpoint.java index 0ac5736e15..e0d73b15f4 100644 --- a/src/main/java/com/lambdaworks/redis/protocol/Endpoint.java +++ b/src/main/java/com/lambdaworks/redis/protocol/Endpoint.java @@ -25,7 +25,7 @@ * * @author Mark Paluch */ -interface Endpoint { +public interface Endpoint { /** * Notify about channel activation. diff --git a/src/main/java/com/lambdaworks/redis/protocol/HasQueuedCommands.java b/src/main/java/com/lambdaworks/redis/protocol/HasQueuedCommands.java index 37beac56ab..b68e99b726 100644 --- a/src/main/java/com/lambdaworks/redis/protocol/HasQueuedCommands.java +++ b/src/main/java/com/lambdaworks/redis/protocol/HasQueuedCommands.java @@ -23,7 +23,7 @@ * * @author Mark Paluch */ -interface HasQueuedCommands { +public interface HasQueuedCommands { /** * The queue holding commands. diff --git a/src/test/java/com/lambdaworks/redis/ReactiveBackpressurePropagationTest.java b/src/test/java/com/lambdaworks/redis/ReactiveBackpressurePropagationTest.java new file mode 100644 index 0000000000..81f83e7738 --- /dev/null +++ b/src/test/java/com/lambdaworks/redis/ReactiveBackpressurePropagationTest.java @@ -0,0 +1,196 @@ +/* + * Copyright 2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.lambdaworks.redis; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.when; + +import java.util.List; +import java.util.concurrent.CountDownLatch; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; + +import reactor.core.Cancellation; +import reactor.core.publisher.Flux; +import reactor.core.scheduler.Schedulers; + +import com.lambdaworks.redis.api.StatefulConnection; +import com.lambdaworks.redis.codec.StringCodec; +import com.lambdaworks.redis.metrics.CommandLatencyCollector; +import com.lambdaworks.redis.output.ValueListOutput; +import com.lambdaworks.redis.protocol.*; +import com.lambdaworks.redis.resource.ClientResources; + +import io.netty.buffer.Unpooled; +import io.netty.channel.embedded.EmbeddedChannel; +import io.netty.channel.local.LocalAddress; + +/** + * @author Mark Paluch + */ +@RunWith(MockitoJUnitRunner.class) +public class ReactiveBackpressurePropagationTest { + + private CommandHandler commandHandler; + private EmbeddedChannel embeddedChannel; + + @Mock + private Endpoint endpoint; + + @Mock + private ClientResources clientResources; + + @Mock + private CommandLatencyCollector latencyCollector; + + @Mock + private StatefulConnection statefulConnection; + + @Before + public void before() throws Exception { + + commandHandler = new CommandHandler(clientResources, endpoint); + + when(clientResources.commandLatencyCollector()).thenReturn(latencyCollector); + when(statefulConnection.dispatch(any())).thenAnswer(invocation -> { + + RedisCommand command = (RedisCommand) invocation.getArguments()[0]; + embeddedChannel.writeOutbound(command); + return command; + }); + + embeddedChannel = new EmbeddedChannel(commandHandler); + embeddedChannel.connect(new LocalAddress("remote")); + } + + @Test + public void writeCommand() throws Exception { + + Command> lrange = new Command<>(CommandType.LRANGE, + new ValueListOutput<>(StringCodec.UTF8)); + RedisPublisher publisher = new RedisPublisher<>((Command) lrange, statefulConnection, true); + + CountDownLatch pressureArrived = new CountDownLatch(1); + CountDownLatch buildPressure = new CountDownLatch(1); + CountDownLatch waitForPressureReduced = new CountDownLatch(2); + CountDownLatch waitForWorkCompleted = new CountDownLatch(4); + + Flux.from(publisher).limitRate(2).publishOn(Schedulers.single()).doOnNext(s -> { + + try { + pressureArrived.countDown(); + buildPressure.await(); + } catch (InterruptedException e) { + } + + waitForPressureReduced.countDown(); + waitForWorkCompleted.countDown(); + + }).subscribe(); + + assertThat(embeddedChannel.config().isAutoRead()).isTrue(); + + // produce some back pressure + embeddedChannel.writeInbound(Unpooled.wrappedBuffer(RESP.arrayHeader(4))); + embeddedChannel.writeInbound(Unpooled.wrappedBuffer(RESP.bulkString("one"))); + pressureArrived.await(); + assertThat(embeddedChannel.config().isAutoRead()).isTrue(); + + embeddedChannel.writeInbound(Unpooled.wrappedBuffer(RESP.bulkString("two"))); + embeddedChannel.writeInbound(Unpooled.wrappedBuffer(RESP.bulkString("three"))); + assertThat(embeddedChannel.config().isAutoRead()).isFalse(); + + // allow processing + buildPressure.countDown(); + + // wait until processing caught up + waitForPressureReduced.await(); + assertThat(embeddedChannel.config().isAutoRead()).isTrue(); + + // emit the last item + embeddedChannel.writeInbound(Unpooled.wrappedBuffer(RESP.bulkString("four"))); + + // done + waitForWorkCompleted.await(); + assertThat(embeddedChannel.config().isAutoRead()).isTrue(); + } + + @Test + public void writeCommandAndCancelInTheMiddle() throws Exception { + + Command> lrange = new Command<>(CommandType.LRANGE, + new ValueListOutput<>(StringCodec.UTF8)); + RedisPublisher publisher = new RedisPublisher<>((Command) lrange, statefulConnection, true); + + CountDownLatch pressureArrived = new CountDownLatch(1); + CountDownLatch buildPressure = new CountDownLatch(1); + CountDownLatch waitForPressureReduced = new CountDownLatch(2); + + Cancellation cancellation = Flux.from(publisher).limitRate(2).publishOn(Schedulers.single()).doOnNext(s -> { + + try { + pressureArrived.countDown(); + buildPressure.await(); + } catch (InterruptedException e) { + } + + waitForPressureReduced.countDown(); + + }).subscribe(); + + assertThat(embeddedChannel.config().isAutoRead()).isTrue(); + + // produce some back pressure + embeddedChannel.writeInbound(Unpooled.wrappedBuffer(RESP.arrayHeader(4))); + embeddedChannel.writeInbound(Unpooled.wrappedBuffer(RESP.bulkString("one"))); + pressureArrived.await(); + assertThat(embeddedChannel.config().isAutoRead()).isTrue(); + + embeddedChannel.writeInbound(Unpooled.wrappedBuffer(RESP.bulkString("two"))); + embeddedChannel.writeInbound(Unpooled.wrappedBuffer(RESP.bulkString("three"))); + assertThat(embeddedChannel.config().isAutoRead()).isFalse(); + + cancellation.dispose(); + + assertThat(embeddedChannel.config().isAutoRead()).isTrue(); + + // allow processing + buildPressure.countDown(); + + // emit the last item + embeddedChannel.writeInbound(Unpooled.wrappedBuffer(RESP.bulkString("four"))); + + // done + assertThat(embeddedChannel.config().isAutoRead()).isTrue(); + } + + static class RESP { + + static byte[] arrayHeader(int count) { + return String.format("*%d\r\n", count).getBytes(); + } + + static byte[] bulkString(String string) { + return String.format("$%d\r\n%s\r\n", string.getBytes().length, string).getBytes(); + } + } + +} diff --git a/src/test/java/com/lambdaworks/redis/ReactiveConnectionTest.java b/src/test/java/com/lambdaworks/redis/ReactiveConnectionTest.java index c95498c5e3..23faab5a1f 100644 --- a/src/test/java/com/lambdaworks/redis/ReactiveConnectionTest.java +++ b/src/test/java/com/lambdaworks/redis/ReactiveConnectionTest.java @@ -34,16 +34,16 @@ import org.reactivestreams.Subscriber; import org.reactivestreams.Subscription; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import reactor.core.scheduler.Schedulers; + import com.lambdaworks.Delay; import com.lambdaworks.Wait; import com.lambdaworks.redis.api.StatefulRedisConnection; import com.lambdaworks.redis.api.reactive.RedisReactiveCommands; import com.lambdaworks.redis.reactive.TestSubscriber; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; -import reactor.core.scheduler.Schedulers; - public class ReactiveConnectionTest extends AbstractRedisClientTest { private RedisReactiveCommands reactive; @@ -187,8 +187,8 @@ public void reactiveChain() throws Exception { reactive.mset(map).block(); - List values = reactive.keys("*").flatMap(s -> reactive.get(s)).collectList().subscribeOn(Schedulers.immediate()) - .block(); + List values = reactive.keys("*").flatMap(s -> reactive.get(s)).collectList() + .subscribeOn(Schedulers.immediate()).block(); assertThat(values).hasSize(2).contains(value, "value1"); } @@ -225,12 +225,14 @@ public void subscribeWithDisconnectedClient() throws Exception { Mono ping = connection.reactive().ping(); - ping.subscribeWith(TestSubscriber.create()).assertErrorWith(throwable -> { + ping.subscribeWith(TestSubscriber.create()) + .assertErrorWith( + throwable -> { - assertThat(throwable).isInstanceOf(RedisException.class) - .hasMessageContaining("not connected. Commands are rejected"); + assertThat(throwable).isInstanceOf(RedisException.class).hasMessageContaining( + "not connected. Commands are rejected"); - }).await(); + }).await(); } } From 866781a267c57db63bb0e604f1fd2391b1b06427 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Sat, 21 Jan 2017 22:34:02 +0100 Subject: [PATCH 115/808] =?UTF-8?q?Fix=20Partitions.addPartition(=E2=80=A6?= =?UTF-8?q?)=20and=20Partitions.reload(=E2=80=A6)=20synchronization=20#442?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Partitions.addPartition(…) and Partitions.reload(…) are now correctly synchronized by using the correct mutex, the mutable partitions collection that is used as well by other methods. Wrong synchronization could lead to concurrent modifications that are terminated with a ConcurrentModificationException so topology updates could fail. This race can be caused if topology updates are executed by two updates that are executed at the same time because of network congestion/slow updating or a a concurrent update by the background updater and an update outside the client. --- .../redis/cluster/models/partitions/Partitions.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/lambdaworks/redis/cluster/models/partitions/Partitions.java b/src/main/java/com/lambdaworks/redis/cluster/models/partitions/Partitions.java index bfe97eaf48..d2a9a7be6e 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/models/partitions/Partitions.java +++ b/src/main/java/com/lambdaworks/redis/cluster/models/partitions/Partitions.java @@ -146,7 +146,7 @@ public void addPartition(RedisClusterNode partition) { LettuceAssert.notNull(partition, "Partition must not be null"); - synchronized (this) { + synchronized (partitions) { slotCache = EMPTY; partitions.add(partition); } @@ -179,7 +179,7 @@ public void reload(List partitions) { LettuceAssert.noNullElements(partitions, "Partitions must not contain null elements"); - synchronized (partitions) { + synchronized (this.partitions) { this.partitions.clear(); this.partitions.addAll(partitions); updateCache(); From d51b44299e782de1c8939df8dfe8719e0dad1523 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Sat, 21 Jan 2017 22:36:02 +0100 Subject: [PATCH 116/808] Reuse stale connections collection when closing stale connections #443 Stale connections expiry now uses the same collection of connections to prevent stale expiry preparation and the actual closing to use different connections. --- .../PooledClusterConnectionProvider.java | 33 ++++++++++++++++--- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/lambdaworks/redis/cluster/PooledClusterConnectionProvider.java b/src/main/java/com/lambdaworks/redis/cluster/PooledClusterConnectionProvider.java index 9705677c4c..a1e2c53023 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/PooledClusterConnectionProvider.java +++ b/src/main/java/com/lambdaworks/redis/cluster/PooledClusterConnectionProvider.java @@ -306,7 +306,7 @@ private void reconfigurePartitions() { } resetFastConnectionCache(); - closeStaleConnections(); + closeStaleConnections(staleConnections); } /** @@ -314,9 +314,14 @@ private void reconfigurePartitions() { */ @Override public void closeStaleConnections() { - logger.debug("closeStaleConnections() count before expiring: {}", getConnectionCount()); Set stale = getStaleConnectionKeys(); + closeStaleConnections(stale); + } + + protected void closeStaleConnections(Set stale) { + + logger.debug("closeStaleConnections() count before expiring: {}", getConnectionCount()); for (ConnectionKey connectionKey : stale) { StatefulRedisConnection connection = connections.get(connectionKey); @@ -360,6 +365,7 @@ private Set getStaleConnectionKeys() { */ @Override public void setAutoFlushCommands(boolean autoFlush) { + synchronized (stateLock) { this.autoFlushCommands = autoFlush; } @@ -378,6 +384,7 @@ public void flushCommands() { @Override public void setReadFrom(ReadFrom readFrom) { + synchronized (stateLock) { this.readFrom = readFrom; Arrays.fill(readers, null); @@ -404,10 +411,10 @@ long getConnectionCount() { * Synchronize on {@code stateLock} to initiate a happens-before relation and clear the thread caches of other threads. */ private void resetFastConnectionCache() { + synchronized (stateLock) { Arrays.fill(writers, null); Arrays.fill(readers, null); - } } @@ -417,12 +424,15 @@ private static RuntimeException invalidConnectionPoint(String message) { } Supplier getSocketAddressSupplier(final ConnectionKey connectionKey) { + return () -> { + if (connectionKey.nodeId != null) { SocketAddress socketAddress = getSocketAddress(connectionKey.nodeId); logger.debug("Resolved SocketAddress {} using for Cluster node {}", socketAddress, connectionKey.nodeId); return socketAddress; } + SocketAddress socketAddress = new InetSocketAddress(connectionKey.host, connectionKey.port); logger.debug("Resolved SocketAddress {} using for Cluster node at {}:{}", socketAddress, connectionKey.host, connectionKey.port); @@ -431,6 +441,7 @@ Supplier getSocketAddressSupplier(final ConnectionKey connectionK } private SocketAddress getSocketAddress(String nodeId) { + for (RedisClusterNode partition : partitions) { if (partition.getNodeId().equals(nodeId)) { return SocketAddressResolver.resolve(partition.getUri(), redisClusterClient.getResources().dnsResolver()); @@ -465,6 +476,7 @@ public ConnectionKey(Intent intent, String host, int port) { @Override public boolean equals(Object o) { + if (this == o) return true; if (!(o instanceof ConnectionKey)) @@ -483,12 +495,26 @@ public boolean equals(Object o) { @Override public int hashCode() { + int result = intent != null ? intent.name().hashCode() : 0; result = 31 * result + (nodeId != null ? nodeId.hashCode() : 0); result = 31 * result + (host != null ? host.hashCode() : 0); result = 31 * result + port; return result; } + + @Override + public String toString() { + + StringBuffer sb = new StringBuffer(); + sb.append(getClass().getSimpleName()); + sb.append(" [intent=").append(intent); + sb.append(", nodeId='").append(nodeId).append('\''); + sb.append(", host='").append(host).append('\''); + sb.append(", port=").append(port); + sb.append(']'); + return sb.toString(); + } } boolean validateClusterNodeMembership() { @@ -588,6 +614,5 @@ public StatefulRedisConnection apply(ConnectionKey key) { } interface ClusterNodeConnectionFactory extends Function> { - } } From 7df2d0ff2fec069a223557f2d10c69af58a1d775 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Sat, 21 Jan 2017 22:36:24 +0100 Subject: [PATCH 117/808] Polishing --- .../com/lambdaworks/redis/dynamic/segment/CommandSegment.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/lambdaworks/redis/dynamic/segment/CommandSegment.java b/src/main/java/com/lambdaworks/redis/dynamic/segment/CommandSegment.java index 9559682c62..bb7dcea60b 100644 --- a/src/main/java/com/lambdaworks/redis/dynamic/segment/CommandSegment.java +++ b/src/main/java/com/lambdaworks/redis/dynamic/segment/CommandSegment.java @@ -67,7 +67,8 @@ public static CommandSegment indexedParameter(int index) { @Override public String toString() { - final StringBuffer sb = new StringBuffer(); + + StringBuffer sb = new StringBuffer(); sb.append(getClass().getSimpleName()); sb.append(" ").append(asString()); return sb.toString(); From 9fdd5970952b30ac8ebe83ec1da168c9f00d328b Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Mon, 23 Jan 2017 20:35:58 +0100 Subject: [PATCH 118/808] Ensure RoundRobinSocketAddressSupplier consistency before returning a SocketAddress #440 RoundRobinSocketAddressSupplier now checks whether its partition collection reference contains all nodes before returning a SocketAddress. In case of an inconsistency, RoundRobinSocketAddressSupplier is refreshed with the current cluster nodes and round-robin is re-initialized starting with the first node. Previously, Partitions could contain less nodes so stale nodes remained active. In case of a topology update, Partitions contains less nodes (e.g. because a cluster node was removed) but the cluster node was still references by RoundRobinSocketAddressSupplier. This caused a reconnect attempt to a node which was no longer part of the cluster. --- .../RoundRobinSocketAddressSupplier.java | 5 +++- .../RoundRobinSocketAddressSupplierTest.java | 28 +++++++++++++++---- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/lambdaworks/redis/cluster/RoundRobinSocketAddressSupplier.java b/src/main/java/com/lambdaworks/redis/cluster/RoundRobinSocketAddressSupplier.java index da553a8425..19a713d4bc 100644 --- a/src/main/java/com/lambdaworks/redis/cluster/RoundRobinSocketAddressSupplier.java +++ b/src/main/java/com/lambdaworks/redis/cluster/RoundRobinSocketAddressSupplier.java @@ -62,7 +62,8 @@ public RoundRobinSocketAddressSupplier(Collection partitions, @Override public SocketAddress get() { - if (!clusterNodes.containsAll(partitions)) { + + if (!clusterNodes.containsAll(partitions) || !partitions.containsAll(clusterNodes)) { resetRoundRobin(); } @@ -71,12 +72,14 @@ public SocketAddress get() { } protected void resetRoundRobin() { + clusterNodes.clear(); clusterNodes.addAll(sortFunction.apply(partitions)); roundRobin.offset = null; } protected SocketAddress getSocketAddress(RedisClusterNode redisClusterNode) { + SocketAddress resolvedAddress = SocketAddressResolver.resolve(redisClusterNode.getUri(), clientResources.dnsResolver()); logger.debug("Resolved SocketAddress {} using for Cluster node {}", resolvedAddress, redisClusterNode.getNodeId()); return resolvedAddress; diff --git a/src/test/java/com/lambdaworks/redis/cluster/RoundRobinSocketAddressSupplierTest.java b/src/test/java/com/lambdaworks/redis/cluster/RoundRobinSocketAddressSupplierTest.java index 410b7a0e51..7053d8b0c2 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/RoundRobinSocketAddressSupplierTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/RoundRobinSocketAddressSupplierTest.java @@ -22,18 +22,18 @@ import java.util.HashSet; import java.util.concurrent.TimeUnit; -import com.lambdaworks.redis.resource.ClientResources; -import com.lambdaworks.redis.resource.DnsResolvers; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; import com.lambdaworks.redis.RedisURI; import com.lambdaworks.redis.cluster.models.partitions.Partitions; import com.lambdaworks.redis.cluster.models.partitions.RedisClusterNode; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.runners.MockitoJUnitRunner; +import com.lambdaworks.redis.resource.ClientResources; +import com.lambdaworks.redis.resource.DnsResolvers; /** * @author Mark Paluch @@ -52,6 +52,7 @@ public class RoundRobinSocketAddressSupplierTest { @BeforeClass public static void beforeClass() throws Exception { + hap1.getResolvedAddress(); hap2.getResolvedAddress(); hap3.getResolvedAddress(); @@ -88,7 +89,7 @@ public void noOffset() throws Exception { } @Test - public void partitionTableChanges() throws Exception { + public void partitionTableChangesNewNode() throws Exception { RoundRobinSocketAddressSupplier sut = new RoundRobinSocketAddressSupplier(partitions, redisClusterNodes -> redisClusterNodes, clientResourcesMock); @@ -106,4 +107,19 @@ public void partitionTableChanges() throws Exception { assertThat(sut.get()).isEqualTo(hap1.getResolvedAddress()); } + @Test + public void partitionTableChangesNodeRemoved() throws Exception { + + RoundRobinSocketAddressSupplier sut = new RoundRobinSocketAddressSupplier(partitions, + redisClusterNodes -> redisClusterNodes, clientResourcesMock); + + assertThat(sut.get()).isEqualTo(hap1.getResolvedAddress()); + assertThat(sut.get()).isEqualTo(hap2.getResolvedAddress()); + + partitions.remove(partitions.getPartition(2)); + + assertThat(sut.get()).isEqualTo(hap1.getResolvedAddress()); + assertThat(sut.get()).isEqualTo(hap2.getResolvedAddress()); + assertThat(sut.get()).isEqualTo(hap1.getResolvedAddress()); + } } From 0826a09425648a22d33bea5700241770eb827eec Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Sun, 22 Jan 2017 20:57:14 +0100 Subject: [PATCH 119/808] Fix ClientResources usage in tests #445 --- .../java/com/lambdaworks/TestClientResources.java | 15 +++++++++++++-- .../redis/RedisClientListenerTest.java | 7 +------ .../redis/cluster/ClusterPartiallyDownTest.java | 9 ++++++++- .../redis/support/ConnectionPoolSupportTest.java | 2 +- 4 files changed, 23 insertions(+), 10 deletions(-) diff --git a/src/test/java/com/lambdaworks/TestClientResources.java b/src/test/java/com/lambdaworks/TestClientResources.java index 2acd2530db..58b102d60a 100644 --- a/src/test/java/com/lambdaworks/TestClientResources.java +++ b/src/test/java/com/lambdaworks/TestClientResources.java @@ -33,9 +33,16 @@ public class TestClientResources { private final static TestClientResources instance = new TestClientResources(); private ClientResources clientResources = create(); + /** + * Creates a new {@link ClientResources} instance and registers a shutdown hook to de-allocate the instance upon JVM + * shutdown. + * + * @return a new {@link ClientResources} instance. + */ public static ClientResources create() { - final DefaultClientResources resources = DefaultClientResources.builder().eventLoopGroupProvider( - new TestEventLoopGroupProvider()).build(); + + final DefaultClientResources resources = DefaultClientResources.builder() + .eventLoopGroupProvider(new TestEventLoopGroupProvider()).build(); Runtime.getRuntime().addShutdownHook(new Thread() { @Override @@ -51,6 +58,10 @@ public void run() { return resources; } + /** + * @return the default {@link ClientResources} instance used across multiple tests. The returned instance must not be shut + * down. + */ public static ClientResources get() { return instance.clientResources; } diff --git a/src/test/java/com/lambdaworks/redis/RedisClientListenerTest.java b/src/test/java/com/lambdaworks/redis/RedisClientListenerTest.java index 76f70bb341..786e1d76c1 100644 --- a/src/test/java/com/lambdaworks/redis/RedisClientListenerTest.java +++ b/src/test/java/com/lambdaworks/redis/RedisClientListenerTest.java @@ -42,12 +42,7 @@ public class RedisClientListenerTest extends AbstractTest { @BeforeClass public static void beforeClass() throws Exception { - DEFAULT_RESOURCES = TestClientResources.create(); - } - - @AfterClass - public static void afterClass() throws Exception { - DEFAULT_RESOURCES.shutdown(100, 100, TimeUnit.MILLISECONDS).get(); + DEFAULT_RESOURCES = TestClientResources.get(); } @Test diff --git a/src/test/java/com/lambdaworks/redis/cluster/ClusterPartiallyDownTest.java b/src/test/java/com/lambdaworks/redis/cluster/ClusterPartiallyDownTest.java index 1a98512dcf..24cb6666c3 100644 --- a/src/test/java/com/lambdaworks/redis/cluster/ClusterPartiallyDownTest.java +++ b/src/test/java/com/lambdaworks/redis/cluster/ClusterPartiallyDownTest.java @@ -25,6 +25,7 @@ import org.junit.After; import org.junit.Before; +import org.junit.BeforeClass; import org.junit.Test; import com.lambdaworks.TestClientResources; @@ -39,7 +40,8 @@ * @author Mark Paluch */ public class ClusterPartiallyDownTest extends AbstractTest { - private static ClientResources clientResources = TestClientResources.create(); + + private static ClientResources clientResources; private static int port1 = 7579; private static int port2 = 7580; @@ -53,6 +55,11 @@ public class ClusterPartiallyDownTest extends AbstractTest { private RedisClusterClient redisClusterClient; + @BeforeClass + public static void beforeClass() { + clientResources = TestClientResources.get(); + } + @Before public void before() throws Exception { diff --git a/src/test/java/com/lambdaworks/redis/support/ConnectionPoolSupportTest.java b/src/test/java/com/lambdaworks/redis/support/ConnectionPoolSupportTest.java index 2112e789d2..cb39a76ee1 100644 --- a/src/test/java/com/lambdaworks/redis/support/ConnectionPoolSupportTest.java +++ b/src/test/java/com/lambdaworks/redis/support/ConnectionPoolSupportTest.java @@ -184,7 +184,7 @@ public void wrappedMasterSlaveConnectionShouldUseWrappers() throws Exception { @Test public void wrappedClusterConnectionShouldUseWrappers() throws Exception { - RedisClusterClient redisClusterClient = RedisClusterClient.create(TestClientResources.create(), + RedisClusterClient redisClusterClient = RedisClusterClient.create(TestClientResources.get(), RedisURI.create(TestSettings.host(), 7379)); GenericObjectPool> pool = ConnectionPoolSupport From f0966e365fd5efcafbb99a1837f492d5f8add256 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Tue, 24 Jan 2017 20:08:47 +0100 Subject: [PATCH 120/808] Polishing Complete initialization future after triggering activation event. Improve test synchronization. Increase sentinel timeouts. --- Makefile | 4 ++-- .../com/lambdaworks/redis/PlainChannelInitializer.java | 2 +- .../redis/protocol/ConnectionFailureTest.java | 2 +- .../lambdaworks/redis/pubsub/PubSubCommandTest.java | 10 ++++++---- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/Makefile b/Makefile index a554424939..e176ee9f10 100644 --- a/Makefile +++ b/Makefile @@ -120,8 +120,8 @@ work/sentinel-%.conf: @echo logfile $(shell pwd)/work/redis-sentinel-$*.log >> $@ @echo sentinel monitor mymaster 127.0.0.1 6482 1 >> $@ - @echo sentinel down-after-milliseconds mymaster 100 >> $@ - @echo sentinel failover-timeout mymaster 100 >> $@ + @echo sentinel down-after-milliseconds mymaster 200 >> $@ + @echo sentinel failover-timeout mymaster 200 >> $@ @echo sentinel parallel-syncs mymaster 1 >> $@ @echo unixsocket $(ROOT_DIR)/work/socket-$* >> $@ @echo unixsocketperm 777 >> $@ diff --git a/src/main/java/com/lambdaworks/redis/PlainChannelInitializer.java b/src/main/java/com/lambdaworks/redis/PlainChannelInitializer.java index 5e9ee9d79e..57953f7d05 100644 --- a/src/main/java/com/lambdaworks/redis/PlainChannelInitializer.java +++ b/src/main/java/com/lambdaworks/redis/PlainChannelInitializer.java @@ -126,8 +126,8 @@ static void pingBeforeActivate(final AsyncCommand cmd, final Completabl final ChannelHandlerContext ctx) throws Exception { cmd.handle((o, throwable) -> { if (throwable == null) { - initializedFuture.complete(true); ctx.fireChannelActive(); + initializedFuture.complete(true); } else { initializedFuture.completeExceptionally(throwable); } diff --git a/src/test/java/com/lambdaworks/redis/protocol/ConnectionFailureTest.java b/src/test/java/com/lambdaworks/redis/protocol/ConnectionFailureTest.java index 1129c2ee9d..41e6a6a7f7 100644 --- a/src/test/java/com/lambdaworks/redis/protocol/ConnectionFailureTest.java +++ b/src/test/java/com/lambdaworks/redis/protocol/ConnectionFailureTest.java @@ -69,7 +69,7 @@ public void pingBeforeConnectFails() throws Exception { * * @throws Exception */ - @Test(timeout = 120000) + @Test(timeout = 12000) public void pingBeforeConnectFailOnReconnect() throws Exception { ClientOptions clientOptions = ClientOptions.builder().pingBeforeActivateConnection(true) diff --git a/src/test/java/com/lambdaworks/redis/pubsub/PubSubCommandTest.java b/src/test/java/com/lambdaworks/redis/pubsub/PubSubCommandTest.java index 60d8fd7c8d..e38cc32021 100644 --- a/src/test/java/com/lambdaworks/redis/pubsub/PubSubCommandTest.java +++ b/src/test/java/com/lambdaworks/redis/pubsub/PubSubCommandTest.java @@ -26,11 +26,11 @@ import java.util.concurrent.BlockingQueue; import java.util.concurrent.TimeUnit; -import com.lambdaworks.TestClientResources; import org.junit.After; import org.junit.Before; import org.junit.Test; +import com.lambdaworks.TestClientResources; import com.lambdaworks.Wait; import com.lambdaworks.redis.*; import com.lambdaworks.redis.api.async.RedisAsyncCommands; @@ -85,16 +85,18 @@ protected void run(RedisClient client) throws Exception { @Test public void authWithReconnect() throws Exception { + new WithPasswordRequired() { @Override protected void run(RedisClient client) throws Exception { + RedisPubSubAsyncCommands connection = client.connectPubSub().async(); connection.getStatefulConnection().addListener(PubSubCommandTest.this); connection.auth(passwd); connection.quit(); - Wait.untilTrue(() -> { - return !connection.isOpen(); - }).waitOrTimeout(); + + Thread.sleep(100); + Wait.untilTrue(connection::isOpen).waitOrTimeout(); connection.subscribe(channel); assertThat(channels.take()).isEqualTo(channel); From a24bf57247cca5adb0a3921e5f0a0f62579d7265 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Fri, 27 Jan 2017 17:07:03 +0100 Subject: [PATCH 121/808] Enable JMH tests on TravisCI #454 --- .travis.yml | 1 + pom.xml | 38 ++++++++++++++----- .../cluster/EmptyStatefulRedisConnection.java | 2 +- .../redis/protocol/CommandBenchmark.java | 17 +++------ .../redis/protocol/EmptyClientResources.java | 7 ++++ .../lambdaworks/redis/protocol/JmhMain.java | 20 +++++----- 6 files changed, 54 insertions(+), 31 deletions(-) diff --git a/.travis.yml b/.travis.yml index a6f794fe99..383ebf3c57 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,6 +5,7 @@ env: matrix: - PROFILE=netty-40 - PROFILE=netty-41 + - PROFILE=jmh sudo: false before_install: - if [[ ! -f stunnel.tar.gz ]]; then wget -O stunnel.tar.gz ftp://ftp.stunnel.org/stunnel/archive/5.x/stunnel-5.33.tar.gz; fi diff --git a/pom.xml b/pom.xml index 1f17085b2d..9325a22722 100644 --- a/pom.xml +++ b/pom.xml @@ -420,12 +420,20 @@ - - - src/test/resources - - + + maven-surefire-plugin + + true + + + + org.eluder.coveralls + coveralls-maven-plugin + + true + + org.codehaus.mojo build-helper-maven-plugin @@ -433,7 +441,7 @@ add-source - generate-sources + generate-test-sources add-test-source @@ -448,10 +456,11 @@ org.codehaus.mojo exec-maven-plugin + 1.5.0 run-benchmarks - process-test-resources + test exec @@ -459,10 +468,21 @@ java test + -Xmx2G -classpath org.openjdk.jmh.Main .* + -tu + ns + -f + 1 + -wi + 10 + -i + 10 + -bm + avgt @@ -479,7 +499,7 @@ kr.motd.maven os-maven-plugin - 1.4.0.Final + 1.5.0.Final @@ -488,7 +508,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.1 + 3.6.0 -Xlint:all,-deprecation,-unchecked -Xlint:none diff --git a/src/test/jmh/com/lambdaworks/redis/cluster/EmptyStatefulRedisConnection.java b/src/test/jmh/com/lambdaworks/redis/cluster/EmptyStatefulRedisConnection.java index 9d62892ba7..fe64e9b65a 100644 --- a/src/test/jmh/com/lambdaworks/redis/cluster/EmptyStatefulRedisConnection.java +++ b/src/test/jmh/com/lambdaworks/redis/cluster/EmptyStatefulRedisConnection.java @@ -18,7 +18,7 @@ import com.lambdaworks.redis.ClientOptions; import com.lambdaworks.redis.api.StatefulRedisConnection; import com.lambdaworks.redis.api.async.RedisAsyncCommands; -import com.lambdaworks.redis.api.rx.RedisReactiveCommands; +import com.lambdaworks.redis.api.reactive.RedisReactiveCommands; import com.lambdaworks.redis.api.sync.RedisCommands; import com.lambdaworks.redis.protocol.ConnectionFacade; import com.lambdaworks.redis.protocol.RedisCommand; diff --git a/src/test/jmh/com/lambdaworks/redis/protocol/CommandBenchmark.java b/src/test/jmh/com/lambdaworks/redis/protocol/CommandBenchmark.java index cb5c728c4a..594e27bff4 100644 --- a/src/test/jmh/com/lambdaworks/redis/protocol/CommandBenchmark.java +++ b/src/test/jmh/com/lambdaworks/redis/protocol/CommandBenchmark.java @@ -15,17 +15,18 @@ */ package com.lambdaworks.redis.protocol; -import com.lambdaworks.redis.codec.StringCodec; -import com.lambdaworks.redis.protocol.CommandArgs.ExperimentalByteArrayCodec; -import org.openjdk.jmh.annotations.*; +import java.nio.charset.StandardCharsets; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.State; import com.lambdaworks.redis.codec.ByteArrayCodec; import com.lambdaworks.redis.codec.RedisCodec; +import com.lambdaworks.redis.codec.StringCodec; import com.lambdaworks.redis.codec.Utf8StringCodec; import com.lambdaworks.redis.output.ValueOutput; -import java.nio.charset.StandardCharsets; - /** * Benchmark for {@link Command}. Test cases: *