diff --git a/.github/workflows/maven-ci.yml b/.github/workflows/maven-ci.yml
new file mode 100644
index 0000000..12d6f9f
--- /dev/null
+++ b/.github/workflows/maven-ci.yml
@@ -0,0 +1,59 @@
+name: build
+
+on: [push, pull_request]
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ services:
+ redis:
+ image: redis
+ ports:
+ - 6378:6378
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v2
+ with:
+ fetch-depth: '0'
+
+ - name: Set up Redis with password
+ uses: getong/redis-action@v1
+ with:
+ redis version: 'latest'
+ host port: 6379
+ container port: 6379
+ redis password: 'foobared'
+
+ - name: Set up JDK 1.8
+ uses: actions/setup-java@v1
+ with:
+ java-version: 1.8
+ server-username: OSSRH_USERNAME
+ server-password: OSSRH_PASSWORD
+ gpg-private-key: ${{ secrets.GPG_PRIVATE_KEY }}
+ gpg-passphrase: GPG_PASSPHRASE
+
+ - name: Build with Maven
+ run: mvn clean test cobertura:cobertura
+
+ - name: Codecov
+ uses: codecov/codecov-action@v1
+ with:
+ token: ${{ secrets.CODECOV_TOKEN }}
+
+ - name: Set up Node.js
+ uses: actions/setup-node@v2
+ with:
+ node-version: 16
+
+ - name: Sematic Release
+ run: |
+ npm install -g @conveyal/maven-semantic-release semantic-release
+ semantic-release --prepare @conveyal/maven-semantic-release --publish @semantic-release/github,@conveyal/maven-semantic-release --verify-conditions @semantic-release/github,@conveyal/maven-semantic-release --verify-release @conveyal/maven-semantic-release
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ GPG_KEY_NAME: ${{ secrets.GPG_KEY_NAME }}
+ GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
+ OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }}
+ OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }}
diff --git a/.gitignore b/.gitignore
index 524f096..d909bae 100644
--- a/.gitignore
+++ b/.gitignore
@@ -18,7 +18,12 @@
*.zip
*.tar.gz
*.rar
+*.iml
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
replay_pid*
+
+.idea
+target/
+out/
\ No newline at end of file
diff --git a/.releaserc.json b/.releaserc.json
new file mode 100644
index 0000000..8c262e0
--- /dev/null
+++ b/.releaserc.json
@@ -0,0 +1,17 @@
+{
+ "debug": true,
+ "dryRun": false,
+ "branches": [
+ "+([0-9])?(.{+([0-9]),x}).x",
+ "master",
+ {
+ "name": "beta",
+ "prerelease": true
+ }
+ ],
+ "plugins": [
+ "@semantic-release/commit-analyzer",
+ "@semantic-release/release-notes-generator",
+ "@semantic-release/github"
+ ]
+}
\ No newline at end of file
diff --git a/README.md b/README.md
index 99ccd63..6ada743 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,26 @@
-# lettuce-redis-watcher
\ No newline at end of file
+# lettuce-redis-watcher
+---
+
+[![GitHub Actions](https://github.com/jcasbin/lettuce-redis-watcher/actions/workflows/maven-ci.yml/badge.svg)](https://github.com/jcasbin/lettuce-redis-watcher/actions/workflows/maven-ci.yml)
+![License](https://img.shields.io/github/license/jcasbin/lettuce-redis-watcher)
+[![Javadoc](https://javadoc.io/badge2/org.casbin/jcasbin-lettuce-redis-watcher/javadoc.svg)](https://javadoc.io/doc/org.casbin/jcasbin-lettuce-redis-watcher)
+[![codecov](https://codecov.io/gh/jcasbin/lettuce-redis-watcher/branch/master/graph/badge.svg?token=ENt9xr4nFg)](https://codecov.io/gh/jcasbin/lettuce-redis-watcher)
+[![codebeat badge](https://codebeat.co/badges/8b3da1c4-3a61-4123-a3d4-002b2598a297)](https://codebeat.co/projects/github-com-jcasbin-lettuce-redis-watcher-master)
+[![Maven Central](https://img.shields.io/maven-central/v/org.casbin/jcasbin-lettuce-redis-watcher.svg)](https://mvnrepository.com/artifact/org.casbin/jcasbin-lettuce-redis-watcher/latest)
+[![Release](https://img.shields.io/github/release/jcasbin/lettuce-redis-watcher.svg)](https://github.com/jcasbin/lettuce-redis-watcher/releases/latest)
+[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/casbin/lobby)
+
+---
+[![Security Status](https://www.murphysec.com/platform3/v31/badge/1688427475171692544.svg)](https://www.murphysec.com/console/report/1688411419949424640/1688427475171692544)
+
+
+Lettuce Redis Watcher is a [Redis](http://redis.io) watcher for [jCasbin](https://github.com/casbin/jcasbin).
+
+## Getting Help
+
+- [jCasbin](https://github.com/casbin/jCasbin)
+- [Lettuce](https://lettuce.io)
+
+## License
+
+This project is under Apache 2.0 License. See the [LICENSE](https://github.com/jcasbin/lettuce-redis-watcher/blob/master/LICENSE) file for the full license text.
\ No newline at end of file
diff --git a/maven-settings.xml b/maven-settings.xml
new file mode 100644
index 0000000..410aee6
--- /dev/null
+++ b/maven-settings.xml
@@ -0,0 +1,22 @@
+
+
+
+ ossrh
+ ${OSSRH_USERNAME}
+ ${OSSRH_PASSWORD}
+
+
+
+
+ ossrh
+
+ true
+
+
+ gpg
+ ${GPG_KEY_NAME}
+ ${GPG_PASSPHRASE}
+
+
+
+
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..387332b
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,291 @@
+
+
+ 4.0.0
+ org.casbin
+ jcasbin-lettuce-redis-watcher
+ 1.0.0
+
+
+ org.sonatype.oss
+ oss-parent
+ 7
+
+
+
+
+ The Apache Software License, Version 2.0
+ http://www.apache.org/licenses/LICENSE-2.0.txt
+ repo
+
+
+
+ https://github.com/jcasbin/lettuce-redis-watcher
+ scm:git@github.com:jcasbin/lettuce-redis-watcher.git
+ scm:git:https://github.com/jcasbin/lettuce-redis-watcher.git
+
+
+
+ Shingmo Yeung
+ 525032303@qq.com
+ https://github.com/ShingmoYeung
+
+
+
+ Github
+ https://github.com/jcasbin/lettuce-redis-watcher/issues
+
+
+
+
+ ossrh
+ https://oss.sonatype.org/content/repositories/snapshots
+
+
+ ossrh
+ https://oss.sonatype.org/service/local/staging/deploy/maven2/
+
+
+
+
+
+ 1.8
+ UTF-8
+ ${java.version}
+ ${java.version}
+ ${source.encoding}
+ 3.3.0
+ 3.11.0
+ 3.1.0
+ 3.5.0
+ 2.7
+ 1.6.13
+ UTF-8
+ ${source.encoding}
+
+ 1.35.0
+ 6.2.5.RELEASE
+ 2.11.1
+ 3.13.0
+ 2.0.7
+ 5.3.3
+ 4.1.96.Final
+ 4.13.2
+
+
+
+
+
+ org.casbin
+ jcasbin
+ ${jcasbin.version}
+
+
+ io.lettuce
+ lettuce-core
+ ${lettuce-core.version}
+
+
+ org.apache.commons
+ commons-pool2
+ ${commons-pool2.version}
+
+
+ org.apache.commons
+ commons-lang3
+ ${commons-lang3.version}
+
+
+ org.slf4j
+ slf4j-api
+ ${slf4j.version}
+
+
+ com.googlecode.aviator
+ aviator
+ ${aviator.version}
+
+
+ io.netty
+ netty-common
+ ${netty.version}
+
+
+ io.netty
+ netty-handler
+ ${netty.version}
+
+
+ io.netty
+ netty-transport
+ ${netty.version}
+
+
+ io.netty
+ netty-resolver-dns
+ ${netty.version}
+ true
+
+
+ io.netty
+ netty-transport-native-epoll
+ ${netty.version}
+ linux-x86_64
+ true
+
+
+ io.netty
+ netty-transport-native-kqueue
+ ${netty.version}
+ osx-x86_64
+ true
+
+
+ junit
+ junit
+ ${junit.version}
+
+
+
+
+
+
+ org.casbin
+ jcasbin
+ true
+
+
+ io.lettuce
+ lettuce-core
+ true
+
+
+ org.apache.commons
+ commons-pool2
+ true
+
+
+ org.apache.commons
+ commons-lang3
+ true
+
+
+ org.slf4j
+ slf4j-api
+ true
+
+
+ junit
+ junit
+ test
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-gpg-plugin
+ ${maven-gpg-plugin.version}
+
+
+ sign-artifacts
+ verify
+
+ sign
+
+
+
+
+
+
+ --pinentry-mode
+ loopback
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-javadoc-plugin
+ ${maven-javadoc-plugin.version}
+
+
+ false
+
+
+ notnull
+ a
+ Not null
+
+
+ default
+ a
+ Default:
+
+
+
+
+
+
+ attach-javadocs
+
+ jar
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-source-plugin
+ ${maven-source-plugin.version}
+
+
+ attach-sources
+
+ jar-no-fork
+
+
+
+
+
+
+ org.sonatype.plugins
+ nexus-staging-maven-plugin
+ ${nexus-staging-maven-plugin.version}
+ true
+
+ ossrh
+ https://oss.sonatype.org/
+
+ true
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ ${maven-compiler-plugin.version}
+
+
+ ${java.version}
+
+
+
+ org.codehaus.mojo
+ cobertura-maven-plugin
+ ${cobertura-maven-plugin.version}
+
+
+ html
+ xml
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/java/org/casbin/watcher/lettuce/LettuceRedisWatcher.java b/src/main/java/org/casbin/watcher/lettuce/LettuceRedisWatcher.java
new file mode 100644
index 0000000..6c51ad0
--- /dev/null
+++ b/src/main/java/org/casbin/watcher/lettuce/LettuceRedisWatcher.java
@@ -0,0 +1,156 @@
+package org.casbin.watcher.lettuce;
+
+import io.lettuce.core.AbstractRedisClient;
+import io.lettuce.core.ClientOptions;
+import io.lettuce.core.RedisClient;
+import io.lettuce.core.RedisURI;
+import io.lettuce.core.cluster.ClusterClientOptions;
+import io.lettuce.core.cluster.RedisClusterClient;
+import io.lettuce.core.pubsub.StatefulRedisPubSubConnection;
+import io.lettuce.core.resource.ClientResources;
+import io.lettuce.core.resource.DefaultClientResources;
+import org.apache.commons.lang3.StringUtils;
+import org.casbin.jcasbin.persist.Watcher;
+import org.casbin.watcher.lettuce.constants.WatcherConstant;
+
+import java.time.Duration;
+import java.time.temporal.ChronoUnit;
+import java.util.UUID;
+import java.util.function.Consumer;
+
+public class LettuceRedisWatcher implements Watcher {
+ private final String localId;
+ private final String redisChannelName;
+ private final AbstractRedisClient abstractRedisClient;
+ private LettuceSubThread lettuceSubThread;
+ private Runnable updateCallback;
+
+ /**
+ * Constructor
+ *
+ * @param redisIp Redis IP
+ * @param redisPort Redis Port
+ * @param redisChannelName Redis Channel
+ * @param timeout Redis Timeout
+ * @param password Redis Password
+ * @param type Redis Type (standalone | cluster)
+ */
+ public LettuceRedisWatcher(String redisIp, int redisPort, String redisChannelName, int timeout, String password, String type) {
+ this.abstractRedisClient = this.getLettuceRedisClient(redisIp, redisPort, password, timeout, type);
+ this.localId = UUID.randomUUID().toString();
+ this.redisChannelName = redisChannelName;
+ this.startSub();
+ }
+
+ /**
+ * Constructor
+ *
+ * @param redisIp Redis IP
+ * @param redisPort Redis Port
+ * @param redisChannelName Redis Channel
+ * @param type Redis Type (standalone | cluster)
+ */
+ public LettuceRedisWatcher(String redisIp, int redisPort, String redisChannelName, String type) {
+ this(redisIp, redisPort, redisChannelName, 2000, null, type);
+ }
+
+ @Override
+ public void setUpdateCallback(Runnable runnable) {
+ this.updateCallback = runnable;
+ lettuceSubThread.setUpdateCallback(runnable);
+ }
+
+ @Override
+ public void setUpdateCallback(Consumer consumer) {
+ this.lettuceSubThread.setUpdateCallback(consumer);
+ }
+
+ @Override
+ public void update() {
+ try (StatefulRedisPubSubConnection statefulRedisPubSubConnection =
+ this.getStatefulRedisPubSubConnection(this.abstractRedisClient)) {
+ if (statefulRedisPubSubConnection.isOpen()) {
+ String msg = "Casbin policy has a new version from redis watcher: ".concat(this.localId);
+ statefulRedisPubSubConnection.async().publish(this.redisChannelName, msg);
+ }
+ }
+ }
+
+ private void startSub() {
+ this.lettuceSubThread = new LettuceSubThread(this.abstractRedisClient, this.redisChannelName, this.updateCallback);
+ this.lettuceSubThread.start();
+ }
+
+ /**
+ * Initialize the Redis Client
+ *
+ * @param host Redis Host
+ * @param port Redis Port
+ * @param password Redis Password
+ * @param timeout Redis Timeout
+ * @param type Redis Type (standalone | cluster) default:standalone
+ * @return AbstractRedisClient
+ */
+ private AbstractRedisClient getLettuceRedisClient(String host, int port, String password, int timeout, String type) {
+ // todo default standalone ?
+ // type = StringUtils.isEmpty(type) ? WatcherConstant.LETTUCE_REDIS_TYPE_STANDALONE : type;
+ if (StringUtils.isNotEmpty(type) && StringUtils.equalsAnyIgnoreCase(type,
+ WatcherConstant.LETTUCE_REDIS_TYPE_STANDALONE, WatcherConstant.LETTUCE_REDIS_TYPE_CLUSTER)) {
+ RedisURI redisUri = null;
+ if (StringUtils.isNotEmpty(password)) {
+ redisUri = RedisURI.builder()
+ .withHost(host)
+ .withPort(port)
+ .withPassword(password.toCharArray())
+ .withTimeout(Duration.of(timeout, ChronoUnit.SECONDS))
+ .build();
+ } else {
+ redisUri = RedisURI.builder()
+ .withHost(host)
+ .withPort(port)
+ .withTimeout(Duration.of(timeout, ChronoUnit.SECONDS))
+ .build();
+ }
+ ClientResources clientResources = DefaultClientResources.builder()
+ .ioThreadPoolSize(4)
+ .computationThreadPoolSize(4)
+ .build();
+ if (StringUtils.equalsIgnoreCase(type, WatcherConstant.LETTUCE_REDIS_TYPE_STANDALONE)) {
+ // standalone
+ ClientOptions clientOptions = ClientOptions.builder()
+ .autoReconnect(true)
+ .pingBeforeActivateConnection(true)
+ .build();
+ RedisClient redisClient = RedisClient.create(clientResources, redisUri);
+ redisClient.setOptions(clientOptions);
+ return redisClient;
+ } else {
+ // cluster
+ ClusterClientOptions clusterClientOptions = ClusterClientOptions.builder()
+ .autoReconnect(true)
+ .pingBeforeActivateConnection(true)
+ .validateClusterNodeMembership(true)
+ .build();
+ RedisClusterClient redisClusterClient = RedisClusterClient.create(clientResources, redisUri);
+ redisClusterClient.setOptions(clusterClientOptions);
+ return redisClusterClient;
+ }
+ } else {
+ throw new IllegalArgumentException("Redis-Type is required and can only be [standalone] or [cluster]");
+ }
+ }
+
+ /**
+ * Get Redis PubSub Connection
+ *
+ * @param abstractRedisClient Redis Client
+ * @return StatefulRedisPubSubConnection
+ */
+ private StatefulRedisPubSubConnection getStatefulRedisPubSubConnection(AbstractRedisClient abstractRedisClient) {
+ if (abstractRedisClient instanceof RedisClient) {
+ return ((RedisClient) abstractRedisClient).connectPubSub();
+ } else {
+ return ((RedisClusterClient) abstractRedisClient).connectPubSub();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/org/casbin/watcher/lettuce/LettuceSubThread.java b/src/main/java/org/casbin/watcher/lettuce/LettuceSubThread.java
new file mode 100644
index 0000000..62d1336
--- /dev/null
+++ b/src/main/java/org/casbin/watcher/lettuce/LettuceSubThread.java
@@ -0,0 +1,124 @@
+package org.casbin.watcher.lettuce;
+
+import io.lettuce.core.AbstractRedisClient;
+import io.lettuce.core.RedisClient;
+import io.lettuce.core.cluster.RedisClusterClient;
+import io.lettuce.core.pubsub.RedisPubSubListener;
+import io.lettuce.core.pubsub.StatefulRedisPubSubConnection;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.function.Consumer;
+
+public class LettuceSubThread extends Thread {
+ private static final Logger logger = LoggerFactory.getLogger(LettuceSubThread.class);
+ private final String channel;
+ private final LettuceSubscriber lettuceSubscriber;
+ private final AbstractRedisClient abstractRedisClient;
+ private StatefulRedisPubSubConnection statefulRedisPubSubConnection;
+
+ /**
+ * Construction method
+ *
+ * @param abstractRedisClient abstractRedisClient
+ * @param channel channel
+ * @param updateCallback updateCallback
+ */
+ public LettuceSubThread(AbstractRedisClient abstractRedisClient, String channel, Runnable updateCallback) {
+ super("LettuceSubThread");
+ this.channel = channel;
+ this.abstractRedisClient = abstractRedisClient;
+ lettuceSubscriber = new LettuceSubscriber(updateCallback);
+ }
+
+ /**
+ * set runnable
+ *
+ * @param runnable runnable
+ */
+ public void setUpdateCallback(Runnable runnable) {
+ lettuceSubscriber.setUpdateCallback(runnable);
+ }
+
+ /**
+ * set consumer
+ *
+ * @param consumer runnable
+ */
+ public void setUpdateCallback(Consumer consumer) {
+ lettuceSubscriber.setUpdateCallback(consumer);
+ }
+
+ @Override
+ public void run() {
+ try {
+ this.statefulRedisPubSubConnection = this.getStatefulRedisPubSubConnection(this.abstractRedisClient);
+ if (this.statefulRedisPubSubConnection.isOpen()) {
+ this.statefulRedisPubSubConnection.addListener(new RedisPubSubListener() {
+ @Override
+ public void unsubscribed(String channel, long count) {
+ logger.info("[unsubscribed] {}", channel);
+ }
+
+ @Override
+ public void subscribed(String channel, long count) {
+ logger.info("[subscribed] {}", channel);
+ }
+
+ @Override
+ public void punsubscribed(String pattern, long count) {
+ logger.info("[punsubscribed] {}", pattern);
+ }
+
+ @Override
+ public void psubscribed(String pattern, long count) {
+ logger.info("[psubscribed] {}", pattern);
+ }
+
+ @Override
+ public void message(String pattern, String channel, String message) {
+ logger.info("[message] {} -> {} -> {}", pattern, channel, message);
+ lettuceSubscriber.onMessage(channel, message);
+ }
+
+ @Override
+ public void message(String channel, String message) {
+ logger.info("[message] {} -> {}", channel, message);
+ lettuceSubscriber.onMessage(channel, message);
+ }
+ });
+ this.statefulRedisPubSubConnection.async().subscribe(this.channel);
+
+ Thread.sleep(500);
+ }
+ } catch (Exception e) {
+ logger.error("error message {}", e.getMessage());
+ this.close(this.statefulRedisPubSubConnection);
+ }
+ }
+
+ /**
+ * Close Redis PubSub Connection
+ *
+ * @param statefulRedisPubSubConnection Redis PubSub Connection
+ */
+ private void close(StatefulRedisPubSubConnection statefulRedisPubSubConnection) {
+ if (statefulRedisPubSubConnection.isOpen()) {
+ statefulRedisPubSubConnection.closeAsync();
+ }
+ }
+
+ /**
+ * Get Redis PubSub Connection
+ *
+ * @param abstractRedisClient Redis Client
+ * @return StatefulRedisPubSubConnection
+ */
+ private StatefulRedisPubSubConnection getStatefulRedisPubSubConnection(AbstractRedisClient abstractRedisClient) {
+ if (abstractRedisClient instanceof RedisClient) {
+ return ((RedisClient) abstractRedisClient).connectPubSub();
+ } else {
+ return ((RedisClusterClient) abstractRedisClient).connectPubSub();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/org/casbin/watcher/lettuce/LettuceSubscriber.java b/src/main/java/org/casbin/watcher/lettuce/LettuceSubscriber.java
new file mode 100644
index 0000000..286a032
--- /dev/null
+++ b/src/main/java/org/casbin/watcher/lettuce/LettuceSubscriber.java
@@ -0,0 +1,27 @@
+package org.casbin.watcher.lettuce;
+
+import java.util.function.Consumer;
+
+public class LettuceSubscriber {
+ private Runnable runnable;
+ private Consumer consumer;
+
+ public LettuceSubscriber(Runnable updateCallback) {
+ this.runnable = updateCallback;
+ }
+
+ public void setUpdateCallback(Runnable runnable){
+ this.runnable = runnable;
+ }
+
+ public void setUpdateCallback(Consumer consumer) {
+ this.consumer = consumer;
+ }
+
+ public void onMessage(String channel, String message) {
+ runnable.run();
+ if (this.consumer != null) {
+ this.consumer.accept("Channel: " + channel + " Message: " + message);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/org/casbin/watcher/lettuce/constants/WatcherConstant.java b/src/main/java/org/casbin/watcher/lettuce/constants/WatcherConstant.java
new file mode 100644
index 0000000..0875c08
--- /dev/null
+++ b/src/main/java/org/casbin/watcher/lettuce/constants/WatcherConstant.java
@@ -0,0 +1,19 @@
+package org.casbin.watcher.lettuce.constants;
+
+/**
+ * Created by IntelliJ IDEA 2023.
+ * FileName: WatcherConstant.java
+ *
+ * @author shingmoyeung
+ * @since 2023/8/5 21:02
+ * @version 1.0
+ * To change this template use File Or Preferences | Settings | Editor | File and Code Templates.
+ * File Description: Redis Watcher Constant
+ */
+public class WatcherConstant {
+ /**
+ * Redis Type
+ */
+ public static final String LETTUCE_REDIS_TYPE_STANDALONE = "standalone";
+ public static final String LETTUCE_REDIS_TYPE_CLUSTER = "cluster";
+}
\ No newline at end of file
diff --git a/src/test/java/org/casbin/test/LettuceRedisWatcherTest.java b/src/test/java/org/casbin/test/LettuceRedisWatcherTest.java
new file mode 100644
index 0000000..cf56ff2
--- /dev/null
+++ b/src/test/java/org/casbin/test/LettuceRedisWatcherTest.java
@@ -0,0 +1,63 @@
+package org.casbin.test;
+
+import org.casbin.jcasbin.main.Enforcer;
+import org.casbin.watcher.lettuce.LettuceRedisWatcher;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+public class LettuceRedisWatcherTest {
+ /**
+ * LettuceRedisWatcher
+ */
+ private LettuceRedisWatcher lettuceRedisWatcher;
+
+ /**
+ * You should replace the initWatcher() method's content with your own Redis instance.
+ */
+ @Before
+ public void initWatcher() {
+ String redisTopic = "jcasbin-topic";
+ this.lettuceRedisWatcher = new LettuceRedisWatcher("127.0.0.1", 6379, redisTopic, 2000, "foobared", "standalone");
+ Enforcer enforcer = new Enforcer();
+ enforcer.setWatcher(this.lettuceRedisWatcher);
+ }
+
+ @Test
+ public void testUpdate() throws InterruptedException {
+ this.initWatcher();
+ this.lettuceRedisWatcher.update();
+ Thread.sleep(100);
+ }
+
+ @Test
+ public void testConsumerCallback() throws InterruptedException {
+ this.initWatcher();
+ while (true) {
+ this.lettuceRedisWatcher.setUpdateCallback((s) -> System.out.println(s));
+ this.lettuceRedisWatcher.update();
+ Thread.sleep(500);
+ }
+ }
+
+ @Test
+ public void testConnectWatcherWithoutPassword() {
+ String redisTopic = "jcasbin-topic";
+ LettuceRedisWatcher lettuceRedisWatcherWithoutPassword = new LettuceRedisWatcher("127.0.0.1", 6378, redisTopic, "standalone");
+ Assert.assertNotNull(lettuceRedisWatcherWithoutPassword);
+ }
+
+ @Test
+ public void testConnectWatcherWithType() {
+ String redisTopic = "jcasbin-topic";
+ Assert.assertThrows(IllegalArgumentException.class, () -> {
+ new LettuceRedisWatcher("127.0.0.1", 6378, redisTopic, "sentinel");
+ });
+
+ LettuceRedisWatcher lettuceRedisWatcherStandalone = new LettuceRedisWatcher("127.0.0.1", 6378, redisTopic, "standalone");
+ Assert.assertNotNull(lettuceRedisWatcherStandalone);
+
+ LettuceRedisWatcher lettuceRedisWatcherCluster = new LettuceRedisWatcher("127.0.0.1", 6378, redisTopic, "cluster");
+ Assert.assertNotNull(lettuceRedisWatcherCluster);
+ }
+}
\ No newline at end of file