From bad18b916bc9c30aa58edb4676c6d6c8f571ab63 Mon Sep 17 00:00:00 2001 From: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com> Date: Tue, 26 Mar 2024 12:48:17 +0600 Subject: [PATCH] Add Experimental, Internal and VisibleForTesting annotations (#3790) * Add Experimental, Internal and VisibleForTesting annotations * Use VisibleForTesting annotation * Use Internal annotation * Use Experimental annotation --- .../clients/jedis/JedisClusterInfoCache.java | 6 +++++- .../clients/jedis/MultiClusterClientConfig.java | 2 ++ .../java/redis/clients/jedis/UnifiedJedis.java | 2 ++ .../clients/jedis/annots/Experimental.java | 17 +++++++++++++++++ .../redis/clients/jedis/annots/Internal.java | 17 +++++++++++++++++ .../clients/jedis/annots/VisibleForTesting.java | 12 ++++++++++++ .../jedis/executors/ClusterCommandExecutor.java | 3 +++ .../executors/RetryableCommandExecutor.java | 3 +++ .../mcf/CircuitBreakerCommandExecutor.java | 2 ++ .../jedis/mcf/CircuitBreakerFailoverBase.java | 2 ++ ...ircuitBreakerFailoverConnectionProvider.java | 2 ++ .../clients/jedis/mcf/MultiClusterPipeline.java | 2 ++ .../jedis/mcf/MultiClusterTransaction.java | 2 ++ .../MultiClusterPooledConnectionProvider.java | 2 ++ 14 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 src/main/java/redis/clients/jedis/annots/Experimental.java create mode 100644 src/main/java/redis/clients/jedis/annots/Internal.java create mode 100644 src/main/java/redis/clients/jedis/annots/VisibleForTesting.java diff --git a/src/main/java/redis/clients/jedis/JedisClusterInfoCache.java b/src/main/java/redis/clients/jedis/JedisClusterInfoCache.java index bea4982fd4..da88462ef4 100644 --- a/src/main/java/redis/clients/jedis/JedisClusterInfoCache.java +++ b/src/main/java/redis/clients/jedis/JedisClusterInfoCache.java @@ -11,22 +11,26 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Set; + import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantReadWriteLock; -import org.apache.commons.pool2.impl.GenericObjectPoolConfig; +import org.apache.commons.pool2.impl.GenericObjectPoolConfig; import org.slf4j.Logger; import org.slf4j.LoggerFactory; + +import redis.clients.jedis.annots.Internal; import redis.clients.jedis.exceptions.JedisClusterOperationException; import redis.clients.jedis.exceptions.JedisException; import redis.clients.jedis.util.SafeEncoder; import static redis.clients.jedis.JedisCluster.INIT_NO_ERROR_PROPERTY; +@Internal public class JedisClusterInfoCache { private static final Logger logger = LoggerFactory.getLogger(JedisClusterInfoCache.class); diff --git a/src/main/java/redis/clients/jedis/MultiClusterClientConfig.java b/src/main/java/redis/clients/jedis/MultiClusterClientConfig.java index 15956ebed4..10dff9ef64 100644 --- a/src/main/java/redis/clients/jedis/MultiClusterClientConfig.java +++ b/src/main/java/redis/clients/jedis/MultiClusterClientConfig.java @@ -7,6 +7,7 @@ import java.util.Arrays; import java.util.List; +import redis.clients.jedis.annots.Experimental; import redis.clients.jedis.exceptions.JedisConnectionException; import redis.clients.jedis.exceptions.JedisValidationException; @@ -25,6 +26,7 @@ *

*/ // TODO: move +@Experimental public final class MultiClusterClientConfig { private static final int RETRY_MAX_ATTEMPTS_DEFAULT = 3; diff --git a/src/main/java/redis/clients/jedis/UnifiedJedis.java b/src/main/java/redis/clients/jedis/UnifiedJedis.java index 138300c451..b8137d3536 100644 --- a/src/main/java/redis/clients/jedis/UnifiedJedis.java +++ b/src/main/java/redis/clients/jedis/UnifiedJedis.java @@ -9,6 +9,7 @@ import org.apache.commons.pool2.impl.GenericObjectPoolConfig; import org.json.JSONArray; +import redis.clients.jedis.annots.Experimental; import redis.clients.jedis.args.*; import redis.clients.jedis.bloom.*; import redis.clients.jedis.commands.JedisCommands; @@ -192,6 +193,7 @@ public UnifiedJedis(ConnectionProvider provider, int maxAttempts, Duration maxTo * by using simple configuration which is passed through from Resilience4j - https://resilience4j.readme.io/docs *

*/ + @Experimental public UnifiedJedis(MultiClusterPooledConnectionProvider provider) { this(new CircuitBreakerCommandExecutor(provider), provider); } diff --git a/src/main/java/redis/clients/jedis/annots/Experimental.java b/src/main/java/redis/clients/jedis/annots/Experimental.java new file mode 100644 index 0000000000..e0c642e630 --- /dev/null +++ b/src/main/java/redis/clients/jedis/annots/Experimental.java @@ -0,0 +1,17 @@ +package redis.clients.jedis.annots; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Target; + +/** + * Annotation to mark classes for experimental development. + *

+ * Classes with this annotation may be renamed, changed or even removed in a future version. This + * annotation doesn't mean that the implementation has an 'experimental' quality. + *

+ * If a type is marked with this annotation, all its members are considered experimental. + */ +@Documented +@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.CONSTRUCTOR}) +public @interface Experimental { } diff --git a/src/main/java/redis/clients/jedis/annots/Internal.java b/src/main/java/redis/clients/jedis/annots/Internal.java new file mode 100644 index 0000000000..551460e834 --- /dev/null +++ b/src/main/java/redis/clients/jedis/annots/Internal.java @@ -0,0 +1,17 @@ +package redis.clients.jedis.annots; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Target; + +/** + * Annotation to mark classes or methods as an internal development API. It indicates that the + * annotated element must not be considered as a public API. + *

+ * Classes or methods with this annotation may change across releases. + *

+ * If a type is marked with this annotation, all its members are considered internal. + */ +@Documented +@Target({ElementType.TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.FIELD}) +public @interface Internal { } \ No newline at end of file diff --git a/src/main/java/redis/clients/jedis/annots/VisibleForTesting.java b/src/main/java/redis/clients/jedis/annots/VisibleForTesting.java new file mode 100644 index 0000000000..e9aac5c7b3 --- /dev/null +++ b/src/main/java/redis/clients/jedis/annots/VisibleForTesting.java @@ -0,0 +1,12 @@ +package redis.clients.jedis.annots; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Target; + +/** + * A member or type annotated with {@link VisibleForTesting} declares that it is only visible for testing purposes. + */ +@Documented +@Target({ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.TYPE}) +public @interface VisibleForTesting { } diff --git a/src/main/java/redis/clients/jedis/executors/ClusterCommandExecutor.java b/src/main/java/redis/clients/jedis/executors/ClusterCommandExecutor.java index 4cc25c42a9..375db99e14 100644 --- a/src/main/java/redis/clients/jedis/executors/ClusterCommandExecutor.java +++ b/src/main/java/redis/clients/jedis/executors/ClusterCommandExecutor.java @@ -13,6 +13,7 @@ import redis.clients.jedis.ConnectionPool; import redis.clients.jedis.HostAndPort; import redis.clients.jedis.Protocol; +import redis.clients.jedis.annots.VisibleForTesting; import redis.clients.jedis.exceptions.*; import redis.clients.jedis.providers.ClusterConnectionProvider; import redis.clients.jedis.util.IOUtils; @@ -135,6 +136,7 @@ public final T executeCommand(CommandObject commandObject) { * WARNING: This method is accessible for the purpose of testing. * This should not be used or overriden. */ + @VisibleForTesting protected T execute(Connection connection, CommandObject commandObject) { return connection.executeCommand(commandObject); } @@ -193,6 +195,7 @@ private static long getBackoffSleepMillis(int attemptsLeft, Instant deadline) { * WARNING: This method is accessible for the purpose of testing. * This should not be used or overriden. */ + @VisibleForTesting protected void sleep(long sleepMillis) { try { TimeUnit.MILLISECONDS.sleep(sleepMillis); diff --git a/src/main/java/redis/clients/jedis/executors/RetryableCommandExecutor.java b/src/main/java/redis/clients/jedis/executors/RetryableCommandExecutor.java index f4f9002539..4351f3fab4 100644 --- a/src/main/java/redis/clients/jedis/executors/RetryableCommandExecutor.java +++ b/src/main/java/redis/clients/jedis/executors/RetryableCommandExecutor.java @@ -8,6 +8,7 @@ import redis.clients.jedis.CommandObject; import redis.clients.jedis.Connection; +import redis.clients.jedis.annots.VisibleForTesting; import redis.clients.jedis.exceptions.JedisConnectionException; import redis.clients.jedis.exceptions.JedisException; import redis.clients.jedis.util.IOUtils; @@ -75,6 +76,7 @@ public final T executeCommand(CommandObject commandObject) { * WARNING: This method is accessible for the purpose of testing. * This should not be used or overriden. */ + @VisibleForTesting protected T execute(Connection connection, CommandObject commandObject) { return connection.executeCommand(commandObject); } @@ -115,6 +117,7 @@ private static long getBackoffSleepMillis(int attemptsLeft, Instant deadline) { * WARNING: This method is accessible for the purpose of testing. * This should not be used or overriden. */ + @VisibleForTesting protected void sleep(long sleepMillis) { try { TimeUnit.MILLISECONDS.sleep(sleepMillis); diff --git a/src/main/java/redis/clients/jedis/mcf/CircuitBreakerCommandExecutor.java b/src/main/java/redis/clients/jedis/mcf/CircuitBreakerCommandExecutor.java index 38b32bbad0..5d54b67d17 100644 --- a/src/main/java/redis/clients/jedis/mcf/CircuitBreakerCommandExecutor.java +++ b/src/main/java/redis/clients/jedis/mcf/CircuitBreakerCommandExecutor.java @@ -6,6 +6,7 @@ import redis.clients.jedis.CommandObject; import redis.clients.jedis.Connection; +import redis.clients.jedis.annots.Experimental; import redis.clients.jedis.executors.CommandExecutor; import redis.clients.jedis.providers.MultiClusterPooledConnectionProvider; import redis.clients.jedis.providers.MultiClusterPooledConnectionProvider.Cluster; @@ -18,6 +19,7 @@ * by using simple configuration which is passed through from Resilience4j - https://resilience4j.readme.io/docs *

*/ +@Experimental public class CircuitBreakerCommandExecutor extends CircuitBreakerFailoverBase implements CommandExecutor { public CircuitBreakerCommandExecutor(MultiClusterPooledConnectionProvider provider) { diff --git a/src/main/java/redis/clients/jedis/mcf/CircuitBreakerFailoverBase.java b/src/main/java/redis/clients/jedis/mcf/CircuitBreakerFailoverBase.java index b06d7b9604..4ef383e649 100644 --- a/src/main/java/redis/clients/jedis/mcf/CircuitBreakerFailoverBase.java +++ b/src/main/java/redis/clients/jedis/mcf/CircuitBreakerFailoverBase.java @@ -1,6 +1,7 @@ package redis.clients.jedis.mcf; import io.github.resilience4j.circuitbreaker.CircuitBreaker; +import redis.clients.jedis.annots.Experimental; import redis.clients.jedis.exceptions.JedisConnectionException; import redis.clients.jedis.providers.MultiClusterPooledConnectionProvider; import redis.clients.jedis.util.IOUtils; @@ -14,6 +15,7 @@ * Resilience4j - https://resilience4j.readme.io/docs *

*/ +@Experimental public class CircuitBreakerFailoverBase implements AutoCloseable { protected final MultiClusterPooledConnectionProvider provider; diff --git a/src/main/java/redis/clients/jedis/mcf/CircuitBreakerFailoverConnectionProvider.java b/src/main/java/redis/clients/jedis/mcf/CircuitBreakerFailoverConnectionProvider.java index 10a0823973..cd0e91015a 100644 --- a/src/main/java/redis/clients/jedis/mcf/CircuitBreakerFailoverConnectionProvider.java +++ b/src/main/java/redis/clients/jedis/mcf/CircuitBreakerFailoverConnectionProvider.java @@ -5,6 +5,7 @@ import io.github.resilience4j.decorators.Decorators.DecorateSupplier; import redis.clients.jedis.Connection; +import redis.clients.jedis.annots.Experimental; import redis.clients.jedis.providers.MultiClusterPooledConnectionProvider; import redis.clients.jedis.providers.MultiClusterPooledConnectionProvider.Cluster; @@ -13,6 +14,7 @@ * With this executor users can seamlessly failover to Disaster Recovery (DR), Backup, and Active-Active cluster(s) * by using simple configuration which is passed through from Resilience4j - https://resilience4j.readme.io/docs */ +@Experimental public class CircuitBreakerFailoverConnectionProvider extends CircuitBreakerFailoverBase { public CircuitBreakerFailoverConnectionProvider(MultiClusterPooledConnectionProvider provider) { diff --git a/src/main/java/redis/clients/jedis/mcf/MultiClusterPipeline.java b/src/main/java/redis/clients/jedis/mcf/MultiClusterPipeline.java index 00c0ba1d91..d7f1416e34 100644 --- a/src/main/java/redis/clients/jedis/mcf/MultiClusterPipeline.java +++ b/src/main/java/redis/clients/jedis/mcf/MultiClusterPipeline.java @@ -7,6 +7,7 @@ import java.util.Queue; import redis.clients.jedis.*; +import redis.clients.jedis.annots.Experimental; import redis.clients.jedis.graph.ResultSet; import redis.clients.jedis.providers.MultiClusterPooledConnectionProvider; import redis.clients.jedis.util.KeyValue; @@ -15,6 +16,7 @@ * This is high memory dependent solution as all the appending commands will be hold in memory until * {@link MultiClusterPipeline#sync() SYNC} (or {@link MultiClusterPipeline#close() CLOSE}) gets called. */ +@Experimental public class MultiClusterPipeline extends PipelineBase implements Closeable { private final CircuitBreakerFailoverConnectionProvider failoverProvider; diff --git a/src/main/java/redis/clients/jedis/mcf/MultiClusterTransaction.java b/src/main/java/redis/clients/jedis/mcf/MultiClusterTransaction.java index d759ce1da0..f39cdf36b6 100644 --- a/src/main/java/redis/clients/jedis/mcf/MultiClusterTransaction.java +++ b/src/main/java/redis/clients/jedis/mcf/MultiClusterTransaction.java @@ -14,6 +14,7 @@ import java.util.concurrent.atomic.AtomicInteger; import redis.clients.jedis.*; +import redis.clients.jedis.annots.Experimental; import redis.clients.jedis.exceptions.JedisDataException; import redis.clients.jedis.graph.ResultSet; import redis.clients.jedis.providers.MultiClusterPooledConnectionProvider; @@ -22,6 +23,7 @@ /** * This is high memory dependent solution as all the appending commands will be hold in memory. */ +@Experimental public class MultiClusterTransaction extends TransactionBase { private static final Builder NO_OP_BUILDER = BuilderFactory.RAW_OBJECT; diff --git a/src/main/java/redis/clients/jedis/providers/MultiClusterPooledConnectionProvider.java b/src/main/java/redis/clients/jedis/providers/MultiClusterPooledConnectionProvider.java index e6013a2c58..f26716086e 100644 --- a/src/main/java/redis/clients/jedis/providers/MultiClusterPooledConnectionProvider.java +++ b/src/main/java/redis/clients/jedis/providers/MultiClusterPooledConnectionProvider.java @@ -19,6 +19,7 @@ import redis.clients.jedis.*; import redis.clients.jedis.MultiClusterClientConfig.ClusterConfig; +import redis.clients.jedis.annots.Experimental; import redis.clients.jedis.exceptions.JedisConnectionException; import redis.clients.jedis.exceptions.JedisValidationException; import redis.clients.jedis.util.Pool; @@ -35,6 +36,7 @@ *

*/ // TODO: move? +@Experimental public class MultiClusterPooledConnectionProvider implements ConnectionProvider { private final Logger log = LoggerFactory.getLogger(getClass());