Merge branch 'redisson/master'

pull/894/head
Rui Gu 8 years ago
commit ba4747ec9c

@ -224,4 +224,4 @@ before_script:
- export REDIS_VERSION="$(redis-cli INFO SERVER | sed -n 2p)"
- echo $REDIS_VERSION
- redis-cli SHUTDOWN NOSAVE
script: mvn -Dtest=$REDISSON_TEST -Dsurefire.rerunFailingTestsCount=5 -DargLine="-Xmx2g -DredisBinary=$REDIS_BIN/redis-server -DtravisEnv=true" -Punit-test clean test -e -X
script: mvn -Dtest=$REDISSON_TEST -Dsurefire.rerunFailingTestsCount=5 -DargLine="-Xmx2g -DredisBinary=$REDIS_BIN/redis-server -DtravisEnv=true -XX:SoftRefLRUPolicyMSPerMB=0" -Punit-test clean test -e -X

@ -4,6 +4,15 @@ Redisson Releases History
Try __ULTRA-FAST__ [Redisson PRO](https://redisson.pro) edition.
####04-Mar-2017 - versions 2.8.1 and 3.3.1 released
Feature - Cache with SoftReference support added for `RLocalCachedMap`
Feature - `Config.subscriptionMode` setting added
Improvement - errors handling during RBatch execution
Fixed - StackOverflowException in URLBuilder
Fixed - TomcatSessionManager can't be used in Tomcat if Redisson has been deployed in web application
Fixed - skip cluster nodes with the "handshake" flag (thanks to @dcheckoway)
####19-Feb-2017 - versions 2.8.0 and 3.3.0 released
Feature - __`RClusteredLocalCachedMap` object added__ More details [here](https://github.com/redisson/redisson/wiki/7.-distributed-collections#713-map-data-partitioning)

@ -1,24 +1,16 @@
Redis based In-Memory Data Grid for Java. Redisson.
Redisson: Redis based In-Memory Data Grid for Java.
====
[Quick start](https://github.com/redisson/redisson#quick-start) | [Documentation](https://github.com/redisson/redisson/wiki) | [Javadocs](http://www.javadoc.io/doc/org.redisson/redisson/3.3.1) | [Changelog](https://github.com/redisson/redisson/blob/master/CHANGELOG.md) | [Code examples](https://github.com/redisson/redisson-examples) | [Support chat](https://gitter.im/mrniko/redisson)
Based on high-performance async and lock-free Java Redis client and [Netty](http://netty.io) framework.
Redis 2.8+ compatible.
| Stable Release Version | JDK Version compatibility | Release Date |
| ------------- | ------------- | ------------|
| 3.3.0 | 1.8+ | 19.02.2017 |
| 2.8.0 | 1.6, 1.7, 1.8 and Android | 19.02.2017 |
| 3.3.1 | 1.8+ | 03.03.2017 |
| 2.8.1 | 1.6, 1.7, 1.8 and Android | 03.03.2017 |
__NOTE__: Both version lines have same features except `CompletionStage` interface supported by 3.x.x line
Please read [documentation](https://github.com/redisson/redisson/wiki) for more details.
Redisson [releases history](https://github.com/redisson/redisson/blob/master/CHANGELOG.md)
Checkout more [code examples](https://github.com/redisson/redisson-examples)
Browse [javadocs](http://www.javadoc.io/doc/org.redisson/redisson/3.2.4)
Licensed under the Apache License 2.0.
Welcome to support chat [![Join the chat at https://gitter.im/mrniko/redisson](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/mrniko/redisson?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
__NOTE__: Both version lines have same features except `CompletionStage` interface added in 3.x.x
Features
@ -42,7 +34,7 @@ Features
Object holder, Binary stream holder, Geospatial holder, BitSet, AtomicLong, AtomicDouble, PublishSubscribe,
Bloom filter, HyperLogLog
* [Distributed collections](https://github.com/redisson/redisson/wiki/7.-Distributed-collections)
Map, Multimap, Set, List, SortedSet, ScoredSortedSet, LexSortedSet, Queue, Deque, Blocking Queue, Bounded Blocking Queue, Blocking Deque, Delayed Queue
Map, Multimap, Set, List, SortedSet, ScoredSortedSet, LexSortedSet, Queue, Deque, Blocking Queue, Bounded Blocking Queue, Blocking Deque, Delayed Queue, Priority Queue, Priority Deque
* [Distributed locks and synchronizers](https://github.com/redisson/redisson/wiki/8.-Distributed-locks-and-synchronizers)
Lock, FairLock, MultiLock, RedLock, ReadWriteLock, Semaphore, PermitExpirableSemaphore, CountDownLatch
* [Distributed services](https://github.com/redisson/redisson/wiki/9.-distributed-services)
@ -63,7 +55,7 @@ Features
Who uses Redisson
================================
[Electronic Arts](http://ea.com), [Baidu](http://baidu.com), [New Relic Synthetics](https://newrelic.com/synthetics), [National Australia Bank](https://www.nab.com.au/), [Brookhaven National Laboratory](http://bnl.gov/), [Singtel](http://singtel.com), [Infor](http://www.infor.com/), [Setronica](http://setronica.com/), [Monits](http://monits.com/), [Netflix Dyno client] (https://github.com/Netflix/dyno), [武林Q传](http://www.nbrpg.com/), [Ocous](http://www.ocous.com/), [Invaluable](http://www.invaluable.com/), [Clover](https://www.clover.com/) , [Apache Karaf Decanter](https://karaf.apache.org/projects.html#decanter), [Atmosphere Framework](http://async-io.org/), [BrandsEye](http://brandseye.com), [Datorama](http://datorama.com/), [BrightCloud](http://brightcloud.com/), [Azar](http://azarlive.com/), [Snapfish](http://snapfish.com), [Crimson Hexagon](http://www.crimsonhexagon.com)
[Electronic Arts](http://ea.com), [Baidu](http://baidu.com), [New Relic Synthetics](https://newrelic.com/synthetics), [Brookhaven National Laboratory](http://bnl.gov/), [Singtel](http://singtel.com), [Infor](http://www.infor.com/), [Setronica](http://setronica.com/), [Monits](http://monits.com/), [Netflix Dyno client] (https://github.com/Netflix/dyno), [武林Q传](http://www.nbrpg.com/), [Ocous](http://www.ocous.com/), [Invaluable](http://www.invaluable.com/), [Clover](https://www.clover.com/) , [Apache Karaf Decanter](https://karaf.apache.org/projects.html#decanter), [Atmosphere Framework](http://async-io.org/), [BrandsEye](http://brandseye.com), [Datorama](http://datorama.com/), [BrightCloud](http://brightcloud.com/), [Azar](http://azarlive.com/), [Snapfish](http://snapfish.com), [Crimson Hexagon](http://www.crimsonhexagon.com), [Quby](http://quby.com/), [Base CRM](http://getbase.com)
Articles
================================
@ -90,23 +82,23 @@ Quick start
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.3.0</version>
<version>3.3.1</version>
</dependency>
<!-- JDK 1.6+ compatible -->
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>2.8.0</version>
<version>2.8.1</version>
</dependency>
#### Gradle
// JDK 1.8+ compatible
compile 'org.redisson:redisson:3.3.0'
compile 'org.redisson:redisson:3.3.1'
// JDK 1.6+ compatible
compile 'org.redisson:redisson:2.8.0'
compile 'org.redisson:redisson:2.8.1'
#### Java
@ -131,11 +123,11 @@ RExecutorService executor = redisson.getExecutorService("myExecutorService");
Downloads
===============================
[Redisson 3.3.0](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson&v=3.3.0&e=jar),
[Redisson node 3.3.0](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson-all&v=3.3.0&e=jar)
[Redisson 3.3.1](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson&v=3.3.1&e=jar),
[Redisson node 3.3.1](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson-all&v=3.3.1&e=jar)
[Redisson 2.8.0](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson&v=2.8.0&e=jar),
[Redisson node 2.8.0](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson-all&v=2.8.0&e=jar)
[Redisson 2.8.1](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson&v=2.8.1&e=jar),
[Redisson node 2.8.1](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson-all&v=2.8.1&e=jar)
### Supported by

@ -3,7 +3,7 @@
<groupId>org.redisson</groupId>
<artifactId>redisson-parent</artifactId>
<version>2.8.1-SNAPSHOT</version>
<version>2.8.2-SNAPSHOT</version>
<packaging>pom</packaging>
<name>Redisson</name>

@ -4,7 +4,7 @@
<parent>
<groupId>org.redisson</groupId>
<artifactId>redisson-parent</artifactId>
<version>2.8.1-SNAPSHOT</version>
<version>2.8.2-SNAPSHOT</version>
<relativePath>../</relativePath>
</parent>

@ -1,13 +1,14 @@
Redis based Tomcat Session Manager
===
Implements non-sticky session management backed by Redis.
Supports Tomcat 6.x, 7.x, 8.x
Stores session of Apache Tomcat in Redis and allows to distribute requests across a cluster of Tomcat servers. Implements non-sticky session management backed by Redis.
Supports Apache Tomcat 6.x, 7.x, 8.x
Advantages
===
Current implementation differs from any other Tomcat Session Manager in terms of efficient storage and optimized writes. Each session attribute is written into Redis during each `HttpSession.setAttribute` invocation. While other solutions serialize whole session each time.
Current implementation differs from any other Redis based Tomcat Session Manager in terms of efficient storage and optimized writes. Each session attribute is written into Redis during each `HttpSession.setAttribute` invocation. While other solutions serialize whole session each time.
Usage
===
@ -21,22 +22,22 @@ Usage
2. Copy two jars into `TOMCAT_BASE/lib` directory:
1. __For JDK 1.8+__
[redisson-all-3.3.0.jar](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson-all&v=3.3.0&e=jar)
[redisson-all-3.3.1.jar](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson-all&v=3.3.1&e=jar)
for Tomcat 6.x
[redisson-tomcat-6-3.3.0.jar](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson-tomcat-6&v=3.3.0&e=jar)
[redisson-tomcat-6-3.3.1.jar](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson-tomcat-6&v=3.3.1&e=jar)
for Tomcat 7.x
[redisson-tomcat-7-3.3.0.jar](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson-tomcat-7&v=3.3.0&e=jar)
[redisson-tomcat-7-3.3.1.jar](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson-tomcat-7&v=3.3.1&e=jar)
for Tomcat 8.x
[redisson-tomcat-8-3.3.0.jar](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson-tomcat-8&v=3.3.0&e=jar)
[redisson-tomcat-8-3.3.1.jar](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson-tomcat-8&v=3.3.1&e=jar)
1. __For JDK 1.6+__
[redisson-all-2.8.0.jar](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson-all&v=2.8.0&e=jar)
[redisson-all-2.8.1.jar](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson-all&v=2.8.1&e=jar)
for Tomcat 6.x
[redisson-tomcat-6-2.8.0.jar](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson-tomcat-6&v=2.8.0&e=jar)
[redisson-tomcat-6-2.8.1.jar](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson-tomcat-6&v=2.8.1&e=jar)
for Tomcat 7.x
[redisson-tomcat-7-2.8.0.jar](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson-tomcat-7&v=2.8.0&e=jar)
[redisson-tomcat-7-2.8.1.jar](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson-tomcat-7&v=2.8.1&e=jar)
for Tomcat 8.x
[redisson-tomcat-8-2.8.0.jar](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson-tomcat-8&v=2.8.0&e=jar)
[redisson-tomcat-8-2.8.1.jar](https://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&g=org.redisson&a=redisson-tomcat-8&v=2.8.1&e=jar)

@ -4,7 +4,7 @@
<parent>
<groupId>org.redisson</groupId>
<artifactId>redisson-parent</artifactId>
<version>2.8.1-SNAPSHOT</version>
<version>2.8.2-SNAPSHOT</version>
<relativePath>../</relativePath>
</parent>

@ -4,7 +4,7 @@
<parent>
<groupId>org.redisson</groupId>
<artifactId>redisson-tomcat</artifactId>
<version>2.8.1-SNAPSHOT</version>
<version>2.8.2-SNAPSHOT</version>
<relativePath>../</relativePath>
</parent>

@ -143,11 +143,11 @@ public class RedissonSessionManager extends ManagerBase implements Lifecycle {
public void start() throws LifecycleException {
Config config = null;
try {
config = Config.fromJSON(new File(configPath));
config = Config.fromJSON(new File(configPath), getClass().getClassLoader());
} catch (IOException e) {
// trying next format
try {
config = Config.fromYAML(new File(configPath));
config = Config.fromYAML(new File(configPath), getClass().getClassLoader());
} catch (IOException e1) {
log.error("Can't parse json config " + configPath, e);
throw new LifecycleException("Can't parse yaml config " + configPath, e1);

@ -4,7 +4,7 @@
<parent>
<groupId>org.redisson</groupId>
<artifactId>redisson-tomcat</artifactId>
<version>2.8.1-SNAPSHOT</version>
<version>2.8.2-SNAPSHOT</version>
<relativePath>../</relativePath>
</parent>

@ -19,13 +19,10 @@ import java.io.File;
import java.io.IOException;
import org.apache.catalina.Context;
import org.apache.catalina.Lifecycle;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.LifecycleListener;
import org.apache.catalina.LifecycleState;
import org.apache.catalina.Session;
import org.apache.catalina.session.ManagerBase;
import org.apache.catalina.util.LifecycleSupport;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import org.redisson.Redisson;
@ -39,12 +36,10 @@ import org.redisson.config.Config;
* @author Nikita Koksharov
*
*/
public class RedissonSessionManager extends ManagerBase implements Lifecycle {
public class RedissonSessionManager extends ManagerBase {
private final Log log = LogFactory.getLog(RedissonSessionManager.class);
protected LifecycleSupport lifecycle = new LifecycleSupport(this);
private RedissonClient redisson;
private String configPath;
@ -61,11 +56,6 @@ public class RedissonSessionManager extends ManagerBase implements Lifecycle {
return RedissonSessionManager.class.getSimpleName();
}
@Override
public int getRejectedSessions() {
return 0;
}
@Override
public void load() throws ClassNotFoundException, IOException {
}
@ -74,21 +64,6 @@ public class RedissonSessionManager extends ManagerBase implements Lifecycle {
public void unload() throws IOException {
}
@Override
public void addLifecycleListener(LifecycleListener listener) {
lifecycle.addLifecycleListener(listener);
}
@Override
public LifecycleListener[] findLifecycleListeners() {
return lifecycle.findLifecycleListeners();
}
@Override
public void removeLifecycleListener(LifecycleListener listener) {
lifecycle.removeLifecycleListener(listener);
}
@Override
public Session createSession(String sessionId) {
RedissonSession session = (RedissonSession) createEmptySession();
@ -146,11 +121,11 @@ public class RedissonSessionManager extends ManagerBase implements Lifecycle {
super.startInternal();
Config config = null;
try {
config = Config.fromJSON(new File(configPath));
config = Config.fromJSON(new File(configPath), getClass().getClassLoader());
} catch (IOException e) {
// trying next format
try {
config = Config.fromYAML(new File(configPath));
config = Config.fromYAML(new File(configPath), getClass().getClassLoader());
} catch (IOException e1) {
log.error("Can't parse json config " + configPath, e);
throw new LifecycleException("Can't parse yaml config " + configPath, e1);

@ -4,7 +4,7 @@
<parent>
<groupId>org.redisson</groupId>
<artifactId>redisson-tomcat</artifactId>
<version>2.8.1-SNAPSHOT</version>
<version>2.8.2-SNAPSHOT</version>
<relativePath>../</relativePath>
</parent>

@ -18,14 +18,10 @@ package org.redisson.tomcat;
import java.io.File;
import java.io.IOException;
import org.apache.catalina.Context;
import org.apache.catalina.Lifecycle;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.LifecycleListener;
import org.apache.catalina.LifecycleState;
import org.apache.catalina.Session;
import org.apache.catalina.session.ManagerBase;
import org.apache.catalina.util.LifecycleSupport;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import org.redisson.Redisson;
@ -39,12 +35,10 @@ import org.redisson.config.Config;
* @author Nikita Koksharov
*
*/
public class RedissonSessionManager extends ManagerBase implements Lifecycle {
public class RedissonSessionManager extends ManagerBase {
private final Log log = LogFactory.getLog(RedissonSessionManager.class);
protected LifecycleSupport lifecycle = new LifecycleSupport(this);
private RedissonClient redisson;
private String configPath;
@ -61,11 +55,6 @@ public class RedissonSessionManager extends ManagerBase implements Lifecycle {
return RedissonSessionManager.class.getSimpleName();
}
@Override
public int getRejectedSessions() {
return 0;
}
@Override
public void load() throws ClassNotFoundException, IOException {
}
@ -74,21 +63,6 @@ public class RedissonSessionManager extends ManagerBase implements Lifecycle {
public void unload() throws IOException {
}
@Override
public void addLifecycleListener(LifecycleListener listener) {
lifecycle.addLifecycleListener(listener);
}
@Override
public LifecycleListener[] findLifecycleListeners() {
return lifecycle.findLifecycleListeners();
}
@Override
public void removeLifecycleListener(LifecycleListener listener) {
lifecycle.removeLifecycleListener(listener);
}
@Override
public Session createSession(String sessionId) {
RedissonSession session = (RedissonSession) createEmptySession();
@ -96,7 +70,7 @@ public class RedissonSessionManager extends ManagerBase implements Lifecycle {
session.setNew(true);
session.setValid(true);
session.setCreationTime(System.currentTimeMillis());
session.setMaxInactiveInterval(((Context) getContainer()).getSessionTimeout() * 60);
session.setMaxInactiveInterval(getContext().getSessionTimeout() * 60);
if (sessionId == null) {
sessionId = generateSessionId();
@ -146,11 +120,11 @@ public class RedissonSessionManager extends ManagerBase implements Lifecycle {
super.startInternal();
Config config = null;
try {
config = Config.fromJSON(new File(configPath));
config = Config.fromJSON(new File(configPath), getClass().getClassLoader());
} catch (IOException e) {
// trying next format
try {
config = Config.fromYAML(new File(configPath));
config = Config.fromYAML(new File(configPath), getClass().getClassLoader());
} catch (IOException e1) {
log.error("Can't parse json config " + configPath, e);
throw new LifecycleException("Can't parse yaml config " + configPath, e1);

@ -4,7 +4,7 @@
<parent>
<groupId>org.redisson</groupId>
<artifactId>redisson-parent</artifactId>
<version>2.8.1-SNAPSHOT</version>
<version>2.8.2-SNAPSHOT</version>
<relativePath>../</relativePath>
</parent>
@ -147,30 +147,35 @@
<artifactId>lz4</artifactId>
<version>1.3.0</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.msgpack</groupId>
<artifactId>jackson-dataformat-msgpack</artifactId>
<version>0.8.7</version>
<version>0.8.11</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.xerial.snappy</groupId>
<artifactId>snappy-java</artifactId>
<version>1.1.2.6</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>de.ruedigermoeller</groupId>
<artifactId>fst</artifactId>
<version>2.47</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.esotericsoftware</groupId>
<artifactId>kryo</artifactId>
<version>3.0.3</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
@ -181,68 +186,77 @@
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-yaml</artifactId>
<version>2.7.6</version>
<version>2.8.7</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.7.6</version>
<version>2.8.7</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.7.6</version>
<version>2.8.7</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-cbor</artifactId>
<version>2.7.6</version>
<version>2.8.7</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-smile</artifactId>
<version>2.7.6</version>
<version>2.8.7</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-avro</artifactId>
<version>2.7.6</version>
<version>2.8.7</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>net.openhft</groupId>
<artifactId>zero-allocation-hashing</artifactId>
<version>0.5</version>
<version>0.7</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy</artifactId>
<version>1.4.26</version>
<version>1.6.8</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.jodd</groupId>
<artifactId>jodd-bean</artifactId>
<version>3.7.1</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>[3.1,)</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>[3.1,)</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session</artifactId>
<version>1.2.2.RELEASE</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
</dependencies>
@ -428,6 +442,7 @@
<useDefaultExcludes>true</useDefaultExcludes>
<mapping>
<java>JAVADOC_STYLE</java>
<xsd>XML_STYLE</xsd>
</mapping>
<strictCheck>true</strictCheck>
<useDefaultMapping>true</useDefaultMapping>

@ -357,7 +357,13 @@ public class Redisson implements RedissonClient {
}
@Override
@Deprecated
public RScheduledExecutorService getExecutorService(Codec codec, String name) {
return getExecutorService(name, codec);
}
@Override
public RScheduledExecutorService getExecutorService(String name, Codec codec) {
return new RedissonExecutorService(codec, connectionManager.getCommandExecutor(), this, name);
}

@ -137,7 +137,7 @@ public class RedissonBucket<V> extends RedissonExpirable implements RBucket<V> {
throw new IllegalArgumentException("Value can't be null");
}
return commandExecutor.writeAsync(getName(), codec, RedisCommands.SETEX, getName(), timeUnit.toSeconds(timeToLive), value);
return commandExecutor.writeAsync(getName(), codec, RedisCommands.PSETEX, getName(), timeUnit.toMillis(timeToLive), value);
}
@Override

@ -30,6 +30,7 @@ import org.redisson.api.RTopic;
import org.redisson.client.codec.Codec;
import org.redisson.client.codec.LongCodec;
import org.redisson.client.protocol.RedisCommand;
import org.redisson.client.protocol.RedisCommand.ValueType;
import org.redisson.client.protocol.RedisCommands;
import org.redisson.client.protocol.convertor.BooleanReplayConvertor;
import org.redisson.client.protocol.convertor.VoidReplayConvertor;
@ -286,18 +287,19 @@ public class RedissonDelayedQueue<V> extends RedissonExpirable implements RDelay
}
protected RFuture<Boolean> removeAsync(Object o, int count) {
return commandExecutor.evalWriteAsync(getName(), codec, new RedisCommand<Boolean>("EVAL", new BooleanReplayConvertor(), 4),
return commandExecutor.evalWriteAsync(getName(), codec, new RedisCommand<Boolean>("EVAL", new BooleanReplayConvertor(), 5),
"local s = redis.call('llen', KEYS[1]);" +
"for i = 0, s-1, 1 do "
+ "local v = redis.call('lindex', KEYS[1], i);"
+ "local randomId, value = struct.unpack('dLc0', v);"
+ "if ARGV[1] == value then "
+ "redis.call('zrem', KEYS[2], v);"
+ "redis.call('lrem', KEYS[1], 1, v);"
+ "return 1;"
+ "end; "
+ "end;" +
"return 0;",
Collections.<Object>singletonList(getQueueName()), o);
Arrays.<Object>asList(getQueueName(), getTimeoutSetName()), o);
}
@Override
@ -338,7 +340,7 @@ public class RedissonDelayedQueue<V> extends RedissonExpirable implements RDelay
return newSucceededFuture(false);
}
return commandExecutor.evalWriteAsync(getName(), codec, RedisCommands.EVAL_BOOLEAN_WITH_VALUES,
return commandExecutor.evalWriteAsync(getName(), codec, new RedisCommand<Boolean>("EVAL", new BooleanReplayConvertor(), 5, ValueType.OBJECTS),
"local result = 0;" +
"local s = redis.call('llen', KEYS[1]);" +
"local i = 0;" +
@ -351,6 +353,7 @@ public class RedissonDelayedQueue<V> extends RedissonExpirable implements RDelay
+ "result = 1; "
+ "i = i - 1; "
+ "s = s - 1; "
+ "redis.call('zrem', KEYS[2], v);"
+ "redis.call('lrem', KEYS[1], 0, v); "
+ "break; "
+ "end; "
@ -358,7 +361,7 @@ public class RedissonDelayedQueue<V> extends RedissonExpirable implements RDelay
+ "i = i + 1;"
+ "end; "
+ "return result;",
Collections.<Object>singletonList(getQueueName()), c.toArray());
Arrays.<Object>asList(getQueueName(), getTimeoutSetName()), c.toArray());
}
@Override

@ -173,19 +173,6 @@ public class RedissonFairLock extends RedissonLock implements RLock {
throw new IllegalArgumentException();
}
@Override
public void unlock() {
Boolean opStatus = get(unlockInnerAsync(Thread.currentThread().getId()));
if (opStatus == null) {
throw new IllegalMonitorStateException("attempt to unlock lock, not locked by current thread by node id: "
+ id + " thread-id: " + Thread.currentThread().getId());
}
if (opStatus) {
cancelExpirationRenewal();
}
}
@Override
protected RFuture<Boolean> unlockInnerAsync(long threadId) {
return commandExecutor.evalWriteAsync(getName(), LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN,
@ -218,15 +205,14 @@ public class RedissonFairLock extends RedissonLock implements RLock {
"if (counter > 0) then " +
"redis.call('pexpire', KEYS[1], ARGV[2]); " +
"return 0; " +
"else " +
"redis.call('del', KEYS[1]); " +
"local nextThreadId = redis.call('lindex', KEYS[2], 0); " +
"if nextThreadId ~= false then " +
"redis.call('publish', KEYS[4] .. ':' .. nextThreadId, ARGV[1]); " +
"end; " +
"return 1; "+
"end; " +
"return nil;",
"redis.call('del', KEYS[1]); " +
"local nextThreadId = redis.call('lindex', KEYS[2], 0); " +
"if nextThreadId ~= false then " +
"redis.call('publish', KEYS[4] .. ':' .. nextThreadId, ARGV[1]); " +
"end; " +
"return 1; ",
Arrays.<Object>asList(getName(), getThreadsQueueName(), getTimeoutSetName(), getChannelName()),
LockPubSub.unlockMessage, internalLockLeaseTime, getLockName(threadId), System.currentTimeMillis());
}

@ -629,12 +629,18 @@ public class RedissonLiveObjectService implements RLiveObjectService {
.and(ElementMatchers.isGetter().or(ElementMatchers.isSetter())
.or(ElementMatchers.named("isPhantom"))
.or(ElementMatchers.named("delete"))))
.intercept(MethodDelegation.to(
new LiveObjectInterceptor(redisson, codecProvider, entityClass,
getRIdFieldName(entityClass)))
.appendParameterBinder(FieldProxy.Binder
.intercept(MethodDelegation.withDefaultConfiguration()
.withBinders(FieldProxy.Binder
.install(LiveObjectInterceptor.Getter.class,
LiveObjectInterceptor.Setter.class)))
LiveObjectInterceptor.Setter.class))
.to(new LiveObjectInterceptor(redisson, codecProvider, entityClass,
getRIdFieldName(entityClass))))
// .intercept(MethodDelegation.to(
// new LiveObjectInterceptor(redisson, codecProvider, entityClass,
// getRIdFieldName(entityClass)))
// .appendParameterBinder(FieldProxy.Binder
// .install(LiveObjectInterceptor.Getter.class,
// LiveObjectInterceptor.Setter.class)))
.implement(RLiveObject.class)
.method(ElementMatchers.isAnnotatedWith(RFieldAccessor.class)
.and(ElementMatchers.named("get")

@ -38,6 +38,11 @@ import org.redisson.api.RFuture;
import org.redisson.api.RLocalCachedMap;
import org.redisson.api.RTopic;
import org.redisson.api.listener.MessageListener;
import org.redisson.cache.Cache;
import org.redisson.cache.LFUCacheMap;
import org.redisson.cache.LRUCacheMap;
import org.redisson.cache.NoneCacheMap;
import org.redisson.cache.SoftCacheMap;
import org.redisson.client.codec.Codec;
import org.redisson.client.codec.LongCodec;
import org.redisson.client.codec.StringCodec;
@ -48,11 +53,7 @@ import org.redisson.client.protocol.convertor.NumberConvertor;
import org.redisson.client.protocol.decoder.ObjectMapEntryReplayDecoder;
import org.redisson.client.protocol.decoder.ObjectSetReplayDecoder;
import org.redisson.command.CommandAsyncExecutor;
import org.redisson.misc.Cache;
import org.redisson.misc.Hash;
import org.redisson.misc.LFUCacheMap;
import org.redisson.misc.LRUCacheMap;
import org.redisson.misc.NoneCacheMap;
import org.redisson.misc.RPromise;
import io.netty.util.concurrent.Future;
@ -73,14 +74,14 @@ public class RedissonLocalCachedMap<K, V> extends RedissonMap<K, V> implements R
public static class LocalCachedMapInvalidate implements Serializable {
private byte[] excludedId;
private byte[] keyHash;
private List<byte[]> keyHashes;
public LocalCachedMapInvalidate() {
}
public LocalCachedMapInvalidate(byte[] excludedId, byte[] keyHash) {
public LocalCachedMapInvalidate(byte[] excludedId, byte[]... keyHash) {
super();
this.keyHash = keyHash;
this.keyHashes = Arrays.asList(keyHash);
this.excludedId = excludedId;
}
@ -88,8 +89,8 @@ public class RedissonLocalCachedMap<K, V> extends RedissonMap<K, V> implements R
return excludedId;
}
public byte[] getKeyHash() {
return keyHash;
public Collection<byte[]> getKeyHashes() {
return keyHashes;
}
}
@ -215,6 +216,9 @@ public class RedissonLocalCachedMap<K, V> extends RedissonMap<K, V> implements R
if (options.getEvictionPolicy() == EvictionPolicy.LFU) {
cache = new LFUCacheMap<CacheKey, CacheValue>(options.getCacheSize(), options.getTimeToLiveInMillis(), options.getMaxIdleInMillis());
}
if (options.getEvictionPolicy() == EvictionPolicy.SOFT) {
cache = new SoftCacheMap<CacheKey, CacheValue>(options.getTimeToLiveInMillis(), options.getMaxIdleInMillis());
}
invalidationTopic = new RedissonTopic<Object>(commandExecutor, suffixName(name, "topic"));
if (options.isInvalidateEntryOnChange()) {
@ -227,8 +231,10 @@ public class RedissonLocalCachedMap<K, V> extends RedissonMap<K, V> implements R
if (msg instanceof LocalCachedMapInvalidate) {
LocalCachedMapInvalidate invalidateMsg = (LocalCachedMapInvalidate)msg;
if (!Arrays.equals(invalidateMsg.getExcludedId(), instanceId)) {
CacheKey key = new CacheKey(invalidateMsg.getKeyHash());
cache.remove(key);
for (byte[] keyHash : invalidateMsg.getKeyHashes()) {
CacheKey key = new CacheKey(keyHash);
cache.remove(key);
}
}
}
}
@ -722,27 +728,30 @@ public class RedissonLocalCachedMap<K, V> extends RedissonMap<K, V> implements R
}
List<Object> params = new ArrayList<Object>(map.size()*3);
List<Object> msgs = new ArrayList<Object>(map.size());
params.add(invalidateEntryOnChange);
params.add(map.size()*2);
byte[][] hashes = new byte[map.size()][];
int i = 0;
for (java.util.Map.Entry<? extends K, ? extends V> t : map.entrySet()) {
byte[] mapKey = encodeMapKey(t.getKey());
byte[] mapValue = encodeMapValue(t.getValue());
params.add(mapKey);
params.add(mapValue);
CacheKey cacheKey = toCacheKey(mapKey);
byte[] msgEncoded = encode(new LocalCachedMapInvalidate(instanceId, cacheKey.getKeyHash()));
msgs.add(msgEncoded);
hashes[i] = cacheKey.getKeyHash();
i++;
}
params.addAll(msgs);
byte[] msgEncoded = encode(new LocalCachedMapInvalidate(instanceId, hashes));
params.add(msgEncoded);
final RPromise<Void> result = newPromise();
RFuture<Void> future = commandExecutor.evalWriteAsync(getName(), codec, RedisCommands.EVAL_VOID,
"redis.call('hmset', KEYS[1], unpack(ARGV, 3, tonumber(ARGV[2]) + 2));"
+ "if ARGV[1] == '1' then "
+ "for i = tonumber(ARGV[2]) + 3, #ARGV, 1 do "
+ "redis.call('publish', KEYS[2], ARGV[i]); "
+ "end; "
// + "for i = tonumber(ARGV[2]) + 3, #ARGV, 1 do "
+ "redis.call('publish', KEYS[2], ARGV[#ARGV]); "
// + "end; "
+ "end;",
Arrays.<Object>asList(getName(), invalidationTopic.getChannelNames().get(0)), params.toArray());

@ -65,11 +65,16 @@ public class RedissonReadLock extends RedissonLock implements RLock {
"if (mode == false) then " +
"redis.call('hset', KEYS[1], 'mode', 'read'); " +
"redis.call('hset', KEYS[1], ARGV[2], 1); " +
"redis.call('set', KEYS[1] .. ':' .. ARGV[2] .. ':rwlock_timeout:1', 1); " +
"redis.call('pexpire', KEYS[1] .. ':' .. ARGV[2] .. ':rwlock_timeout:1', ARGV[1]); " +
"redis.call('pexpire', KEYS[1], ARGV[1]); " +
"return nil; " +
"end; " +
"if (mode == 'read') or (mode == 'write' and redis.call('hexists', KEYS[1], ARGV[3]) == 1) then " +
"redis.call('hincrby', KEYS[1], ARGV[2], 1); " +
"local ind = redis.call('hincrby', KEYS[1], ARGV[2], 1); " +
"local key = KEYS[1] .. ':' .. ARGV[2] .. ':rwlock_timeout:' .. ind;" +
"redis.call('set', key, 1); " +
"redis.call('pexpire', key, ARGV[1]); " +
"redis.call('pexpire', KEYS[1], ARGV[1]); " +
"return nil; " +
"end;" +
@ -78,41 +83,46 @@ public class RedissonReadLock extends RedissonLock implements RLock {
}
@Override
public void unlock() {
Boolean opStatus = commandExecutor.evalWrite(getName(), LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN,
"local mode = redis.call('hget', KEYS[1], 'mode'); " +
"if (mode == false) then " +
"redis.call('publish', KEYS[2], ARGV[1]); " +
"return 1; " +
"end; " +
// "if (mode == 'read') then " +
"local lockExists = redis.call('hexists', KEYS[1], ARGV[3]); " +
"if (lockExists == 0) then " +
"return nil;" +
"else " +
"local counter = redis.call('hincrby', KEYS[1], ARGV[3], -1); " +
"if (counter > 0) then " +
"redis.call('pexpire', KEYS[1], ARGV[2]); " +
"return 0; " +
"else " +
"redis.call('hdel', KEYS[1], ARGV[3]); " +
"if (redis.call('hlen', KEYS[1]) == 1) then " +
"redis.call('del', KEYS[1]); " +
"redis.call('publish', KEYS[2], ARGV[1]); " +
"end; " +
"return 1; "+
"end; " +
"end; " +
// "end; " +
"return nil; ",
Arrays.<Object>asList(getName(), getChannelName()), LockPubSub.unlockMessage, internalLockLeaseTime, getLockName(Thread.currentThread().getId()));
if (opStatus == null) {
throw new IllegalMonitorStateException("attempt to unlock read lock, not locked by current thread by node id: "
+ id + " thread-id: " + Thread.currentThread().getId());
}
if (opStatus) {
cancelExpirationRenewal();
}
protected RFuture<Boolean> unlockInnerAsync(long threadId) {
return commandExecutor.evalWriteAsync(getName(), LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN,
"local mode = redis.call('hget', KEYS[1], 'mode'); " +
"if (mode == false) then " +
"redis.call('publish', KEYS[2], ARGV[1]); " +
"return 1; " +
"end; " +
"local lockExists = redis.call('hexists', KEYS[1], ARGV[2]); " +
"if (lockExists == 0) then " +
"return nil;" +
"end; " +
"local counter = redis.call('hincrby', KEYS[1], ARGV[2], -1); " +
"if (counter == 0) then " +
"redis.call('hdel', KEYS[1], ARGV[2]); " +
"end;" +
"redis.call('del', KEYS[1] .. ':' .. ARGV[2] .. ':rwlock_timeout:' .. (counter+1)); " +
"if (redis.call('hlen', KEYS[1]) > 1) then " +
"local maxRemainTime = -3; " +
"local keys = redis.call('hkeys', KEYS[1]); " +
"for n, key in ipairs(keys) do " +
"counter = tonumber(redis.call('hget', KEYS[1], key)); " +
"if type(counter) == 'number' then " +
"for i=counter, 1, -1 do " +
"local remainTime = redis.call('pttl', KEYS[1] .. ':' .. key .. ':rwlock_timeout:' .. i); " +
"maxRemainTime = math.max(remainTime, maxRemainTime);" +
"end; " +
"end; " +
"end; " +
"if maxRemainTime > 0 then " +
"redis.call('pexpire', KEYS[1], maxRemainTime); " +
"return 0; " +
"end;" +
"end; " +
"redis.call('del', KEYS[1]); " +
"redis.call('publish', KEYS[2], ARGV[1]); " +
"return 1; ",
Arrays.<Object>asList(getName(), getChannelName()), LockPubSub.unlockMessage, getLockName(threadId));
}
@Override
@ -127,9 +137,8 @@ public class RedissonReadLock extends RedissonLock implements RLock {
"redis.call('del', KEYS[1]); " +
"redis.call('publish', KEYS[2], ARGV[1]); " +
"return 1; " +
"else " +
"return 0; " +
"end;",
"end; " +
"return 0; ",
Arrays.<Object>asList(getName(), getChannelName()), LockPubSub.unlockMessage);
result.addListener(new FutureListener<Boolean>() {

@ -113,10 +113,10 @@ public class RedissonRemoteService extends BaseRemoteService implements RRemoteS
@Override
public void operationComplete(Future<RemoteServiceRequest> future) throws Exception {
if (!future.isSuccess()) {
log.error("Can't process the remote service request.", future.cause());
if (future.cause() instanceof RedissonShutdownException) {
return;
}
log.error("Can't process the remote service request.", future.cause());
// re-subscribe after a failed takeAsync
subscribe(remoteInterface, requestQueue, executor);
return;

@ -81,44 +81,37 @@ public class RedissonWriteLock extends RedissonLock implements RLock {
}
@Override
public void unlock() {
Boolean opStatus = commandExecutor.evalWrite(getName(), LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN,
"local mode = redis.call('hget', KEYS[1], 'mode'); " +
"if (mode == false) then " +
"redis.call('publish', KEYS[2], ARGV[1]); " +
"return 1; " +
"end;" +
"if (mode == 'write') then " +
"local lockExists = redis.call('hexists', KEYS[1], ARGV[3]); " +
"if (lockExists == 0) then " +
"return nil;" +
"else " +
"local counter = redis.call('hincrby', KEYS[1], ARGV[3], -1); " +
"if (counter > 0) then " +
"redis.call('pexpire', KEYS[1], ARGV[2]); " +
"return 0; " +
"else " +
"redis.call('hdel', KEYS[1], ARGV[3]); " +
"if (redis.call('hlen', KEYS[1]) == 1) then " +
"redis.call('del', KEYS[1]); " +
"redis.call('publish', KEYS[2], ARGV[1]); " +
"else " +
// has unlocked read-locks
"redis.call('hset', KEYS[1], 'mode', 'read'); " +
"end; " +
"return 1; "+
"end; " +
"end; " +
"end; "
+ "return nil;",
Arrays.<Object>asList(getName(), getChannelName()), LockPubSub.unlockMessage, internalLockLeaseTime, getLockName(Thread.currentThread().getId()));
if (opStatus == null) {
throw new IllegalMonitorStateException("attempt to unlock read lock, not locked by current thread by node id: "
+ id + " thread-id: " + Thread.currentThread().getId());
}
if (opStatus) {
cancelExpirationRenewal();
}
protected RFuture<Boolean> unlockInnerAsync(long threadId) {
return commandExecutor.evalWriteAsync(getName(), LongCodec.INSTANCE, RedisCommands.EVAL_BOOLEAN,
"local mode = redis.call('hget', KEYS[1], 'mode'); " +
"if (mode == false) then " +
"redis.call('publish', KEYS[2], ARGV[1]); " +
"return 1; " +
"end;" +
"if (mode == 'write') then " +
"local lockExists = redis.call('hexists', KEYS[1], ARGV[3]); " +
"if (lockExists == 0) then " +
"return nil;" +
"else " +
"local counter = redis.call('hincrby', KEYS[1], ARGV[3], -1); " +
"if (counter > 0) then " +
"redis.call('pexpire', KEYS[1], ARGV[2]); " +
"return 0; " +
"else " +
"redis.call('hdel', KEYS[1], ARGV[3]); " +
"if (redis.call('hlen', KEYS[1]) == 1) then " +
"redis.call('del', KEYS[1]); " +
"redis.call('publish', KEYS[2], ARGV[1]); " +
"else " +
// has unlocked read-locks
"redis.call('hset', KEYS[1], 'mode', 'read'); " +
"end; " +
"return 1; "+
"end; " +
"end; " +
"end; "
+ "return nil;",
Arrays.<Object>asList(getName(), getChannelName()), LockPubSub.unlockMessage, internalLockLeaseTime, getLockName(threadId));
}
@Override
@ -133,9 +126,8 @@ public class RedissonWriteLock extends RedissonLock implements RLock {
"redis.call('del', KEYS[1]); " +
"redis.call('publish', KEYS[2], ARGV[1]); " +
"return 1; " +
"else " +
"return 0; " +
"end;",
"end; " +
"return 0; ",
Arrays.<Object>asList(getName(), getChannelName()), LockPubSub.unlockMessage);
result.addListener(new FutureListener<Boolean>() {

@ -25,7 +25,7 @@ import java.util.concurrent.TimeUnit;
*/
public class LocalCachedMapOptions {
public enum EvictionPolicy {NONE, LRU, LFU};
public enum EvictionPolicy {NONE, LRU, LFU, SOFT};
private boolean invalidateEntryOnChange;
private EvictionPolicy evictionPolicy;
@ -115,6 +115,7 @@ public class LocalCachedMapOptions {
* @param evictionPolicy
* <p><code>LRU</code> - uses cache with LRU (least recently used) eviction policy.
* <p><code>LFU</code> - uses cache with LFU (least frequently used) eviction policy.
* <p><code>SOFT</code> - uses cache with soft references. The garbage collector will evict items from the cache when the JVM is running out of memory.
* <p><code>NONE</code> - doesn't use eviction policy, but timeToLive and maxIdleTime params are still working.
* @return LocalCachedMapOptions instance
*/

@ -742,12 +742,28 @@ public interface RedissonClient {
* Returns ScheduledExecutorService by name
* using provided codec for task, response and request serialization
*
* Please use getExecutorService(String name, Codec codec) method instead.
*
* @deprecated - use {@link #getExecutorService(String, Codec)} instead.
*
* @param name - name of object
* @param codec - codec for task, response and request
* @return ScheduledExecutorService object
*/
@Deprecated
RScheduledExecutorService getExecutorService(Codec codec, String name);
/**
* Returns ScheduledExecutorService by name
* using provided codec for task, response and request serialization
*
* @param name - name of object
* @param codec - codec for task, response and request
* @return ScheduledExecutorService object
* @since 2.8.2
*/
RScheduledExecutorService getExecutorService(String name, Codec codec);
/**
* Returns object for remote operations prefixed with the default name (redisson_remote_service)
*

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.redisson.misc;
package org.redisson.cache;
import java.util.AbstractCollection;
import java.util.AbstractMap.SimpleEntry;
@ -37,56 +37,8 @@ import io.netty.util.internal.PlatformDependent;
*/
public abstract class AbstractCacheMap<K, V> implements Cache<K, V> {
public static class CachedValue {
private final Object key;
private final Object value;
long ttl;
long maxIdleTime;
long creationTime;
long lastAccess;
public CachedValue(Object key, Object value, long ttl, long maxIdleTime) {
this.value = value;
this.ttl = ttl;
this.key = key;
this.maxIdleTime = maxIdleTime;
creationTime = System.currentTimeMillis();
lastAccess = creationTime;
}
public boolean isExpired() {
boolean result = false;
long currentTime = System.currentTimeMillis();
if (ttl != 0 && creationTime + ttl < currentTime) {
result = true;
}
if (maxIdleTime != 0 && lastAccess + maxIdleTime < currentTime) {
result = true;
}
return result;
}
public Object getKey() {
return key;
}
public Object getValue() {
lastAccess = System.currentTimeMillis();
return value;
}
@Override
public String toString() {
return "CachedValue [key=" + key + ", value=" + value + "]";
}
}
final int size;
final ConcurrentMap<K, CachedValue> map = PlatformDependent.newConcurrentHashMap();
final ConcurrentMap<K, CachedValue<K, V>> map = PlatformDependent.newConcurrentHashMap();
private final long timeToLiveInMillis;
private final long maxIdleInMillis;
@ -100,11 +52,11 @@ public abstract class AbstractCacheMap<K, V> implements Cache<K, V> {
this.timeToLiveInMillis = timeToLiveInMillis;
}
protected void onValueRead(CachedValue value) {
protected void onValueRead(CachedValue<K, V> value) {
}
protected void onValueRemove(CachedValue value) {
protected void onValueRemove(CachedValue<K, V> value) {
}
@ -137,7 +89,7 @@ public abstract class AbstractCacheMap<K, V> implements Cache<K, V> {
throw new NullPointerException();
}
CachedValue entry = map.get(key);
CachedValue<K, V> entry = map.get(key);
if (entry == null) {
return false;
}
@ -161,8 +113,8 @@ public abstract class AbstractCacheMap<K, V> implements Cache<K, V> {
throw new NullPointerException();
}
for (Map.Entry<K, CachedValue> entry : map.entrySet()) {
CachedValue cachedValue = entry.getValue();
for (Map.Entry<K, CachedValue<K, V>> entry : map.entrySet()) {
CachedValue<K, V> cachedValue = entry.getValue();
if (cachedValue.getValue().equals(value)) {
if (cachedValue.isExpired()) {
if (map.remove(cachedValue.getKey(), cachedValue)) {
@ -187,7 +139,7 @@ public abstract class AbstractCacheMap<K, V> implements Cache<K, V> {
throw new NullPointerException();
}
CachedValue entry = map.get(key);
CachedValue<K, V> entry = map.get(key);
if (entry == null) {
return null;
}
@ -201,8 +153,7 @@ public abstract class AbstractCacheMap<K, V> implements Cache<K, V> {
return readValue(entry);
}
@SuppressWarnings("unchecked")
protected V readValue(CachedValue entry) {
protected V readValue(CachedValue<K, V> entry) {
onValueRead(entry);
return (V) entry.getValue();
}
@ -216,17 +167,16 @@ public abstract class AbstractCacheMap<K, V> implements Cache<K, V> {
return put(key, value, timeToLiveInMillis, TimeUnit.MILLISECONDS, maxIdleInMillis, TimeUnit.MILLISECONDS);
}
@SuppressWarnings("unchecked")
@Override
public V put(K key, V value, long ttl, TimeUnit ttlUnit, long maxIdleTime, TimeUnit maxIdleUnit) {
CachedValue entry = create(key, value, ttlUnit.toMillis(ttl), maxIdleUnit.toMillis(maxIdleTime));
CachedValue<K, V> entry = create(key, value, ttlUnit.toMillis(ttl), maxIdleUnit.toMillis(maxIdleTime));
if (isFull(key)) {
if (!removeExpiredEntries()) {
onMapFull();
}
}
onValueCreate(entry);
CachedValue prevCachedValue = map.put(key, entry);
CachedValue<K, V> prevCachedValue = map.put(key, entry);
if (prevCachedValue != null) {
onValueRemove(prevCachedValue);
if (!prevCachedValue.isExpired()) {
@ -236,17 +186,17 @@ public abstract class AbstractCacheMap<K, V> implements Cache<K, V> {
return null;
}
protected CachedValue create(K key, V value, long ttl, long maxIdleTime) {
return new CachedValue(key, value, ttl, maxIdleTime);
protected CachedValue<K, V> create(K key, V value, long ttl, long maxIdleTime) {
return new StdCachedValue<K, V>(key, value, ttl, maxIdleTime);
}
protected void onValueCreate(CachedValue entry) {
protected void onValueCreate(CachedValue<K, V> entry) {
}
private boolean removeExpiredEntries() {
protected boolean removeExpiredEntries() {
boolean removed = false;
// TODO optimize
for (CachedValue value : map.values()) {
for (CachedValue<K, V> value : map.values()) {
if (value.isExpired()) {
if (map.remove(value.getKey(), value)) {
onValueRemove(value);
@ -280,10 +230,9 @@ public abstract class AbstractCacheMap<K, V> implements Cache<K, V> {
* (non-Javadoc)
* @see java.util.Map#remove(java.lang.Object)
*/
@SuppressWarnings("unchecked")
@Override
public V remove(Object key) {
CachedValue entry = map.remove(key);
CachedValue<K, V> entry = map.remove(key);
if (entry != null) {
onValueRemove(entry);
if (!entry.isExpired()) {
@ -346,9 +295,9 @@ public abstract class AbstractCacheMap<K, V> implements Cache<K, V> {
abstract class MapIterator<M> implements Iterator<M> {
final Iterator<Map.Entry<K, CachedValue>> keyIterator = map.entrySet().iterator();
final Iterator<Map.Entry<K, CachedValue<K, V>>> keyIterator = map.entrySet().iterator();
Map.Entry<K, CachedValue> mapEntry;
Map.Entry<K, CachedValue<K, V>> mapEntry;
@Override
public boolean hasNext() {
@ -357,7 +306,7 @@ public abstract class AbstractCacheMap<K, V> implements Cache<K, V> {
}
mapEntry = null;
while (keyIterator.hasNext()) {
Map.Entry<K, CachedValue> entry = keyIterator.next();
Map.Entry<K, CachedValue<K, V>> entry = keyIterator.next();
if (entry.getValue().isExpired()) {
continue;
}

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.redisson.misc;
package org.redisson.cache;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@ -0,0 +1,27 @@
/**
* Copyright 2016 Nikita Koksharov
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.redisson.cache;
/**
* Created by jribble on 2/20/17.
*/
public interface CachedValue<K, V> {
boolean isExpired();
K getKey();
V getValue();
}

@ -0,0 +1,34 @@
/**
* Copyright 2016 Nikita Koksharov
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.redisson.cache;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
public class CachedValueReference<V> extends SoftReference<V> {
private final CachedValue<?, ?> owner;
public CachedValueReference(CachedValue<?, ?> owner, V referent, ReferenceQueue<? super V> q) {
super(referent, q);
this.owner = owner;
}
public CachedValue<?, ?> getOwner() {
return owner;
}
}

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.redisson.misc;
package org.redisson.cache;
import java.util.Map;
import java.util.concurrent.ConcurrentNavigableMap;
@ -57,7 +57,7 @@ public class LFUCacheMap<K, V> extends AbstractCacheMap<K, V> {
}
public static class LFUCachedValue extends CachedValue {
public static class LFUCachedValue extends StdCachedValue {
Long id;
long accessCount;

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.redisson.misc;
package org.redisson.cache;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.redisson.misc;
package org.redisson.cache;
/**
*

@ -0,0 +1,55 @@
/**
* Copyright 2016 Nikita Koksharov
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.redisson.cache;
import java.lang.ref.ReferenceQueue;
/**
*
* @author Nikita Koksharov
*
* @param <K> key
* @param <V> value
*/
public class SoftCacheMap<K, V> extends AbstractCacheMap<K, V> {
private final ReferenceQueue<V> queue = new ReferenceQueue<V>();
public SoftCacheMap(long timeToLiveInMillis, long maxIdleInMillis) {
super(0, timeToLiveInMillis, maxIdleInMillis);
}
protected CachedValue<K, V> create(K key, V value, long ttl, long maxIdleTime) {
return new SoftCachedValue<K, V>(key, value, ttl, maxIdleTime, queue);
}
@Override
protected boolean removeExpiredEntries() {
while (true) {
CachedValueReference<V> value = (CachedValueReference<V>) queue.poll();
if (value == null) {
break;
}
map.remove(value.getOwner().getKey(), value.getOwner());
}
return super.removeExpiredEntries();
}
@Override
protected void onMapFull() {
}
}

@ -0,0 +1,39 @@
/**
* Copyright 2016 Nikita Koksharov
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.redisson.cache;
import java.lang.ref.ReferenceQueue;
/**
* Created by jribble on 2/20/17.
*/
public class SoftCachedValue<K, V> extends StdCachedValue<K, V> implements CachedValue<K, V> {
private final CachedValueReference<V> ref;
public SoftCachedValue(K key, V value, long ttl, long maxIdleTime, ReferenceQueue<V> queue) {
super(key, null, ttl, maxIdleTime);
this.ref = new CachedValueReference<V>(this, value, queue);
}
@Override
public V getValue() {
super.getValue();
return ref.get();
}
}

@ -0,0 +1,71 @@
/**
* Copyright 2016 Nikita Koksharov
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.redisson.cache;
/**
* Created by jribble on 2/20/17.
*/
public class StdCachedValue<K, V> implements CachedValue<K, V> {
protected final K key;
protected final V value;
long ttl;
long maxIdleTime;
long creationTime;
long lastAccess;
public StdCachedValue(K key, V value, long ttl, long maxIdleTime) {
this.value = value;
this.ttl = ttl;
this.key = key;
this.maxIdleTime = maxIdleTime;
creationTime = System.currentTimeMillis();
lastAccess = creationTime;
}
@Override
public boolean isExpired() {
boolean result = false;
long currentTime = System.currentTimeMillis();
if (ttl != 0 && creationTime + ttl < currentTime) {
result = true;
}
if (maxIdleTime != 0 && lastAccess + maxIdleTime < currentTime) {
result = true;
}
return result;
}
@Override
public K getKey() {
return key;
}
@Override
public V getValue() {
lastAccess = System.currentTimeMillis();
return value;
}
@Override
public String toString() {
return "CachedValue [key=" + key + ", value=" + value + "]";
}
}

@ -38,6 +38,11 @@ import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.FutureListener;
import io.netty.util.concurrent.ScheduledFuture;
/**
*
* @author Nikita Koksharov
*
*/
public class RedisConnection implements RedisCommands {
private static final AttributeKey<RedisConnection> CONNECTION = AttributeKey.valueOf("connection");

@ -40,6 +40,11 @@ import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.FutureListener;
import io.netty.util.internal.PlatformDependent;
/**
*
* @author Nikita Koksharov
*
*/
public class RedisPubSubConnection extends RedisConnection {
final Queue<RedisPubSubListener<Object>> listeners = new ConcurrentLinkedQueue<RedisPubSubListener<Object>>();

@ -184,7 +184,7 @@ public class CommandDecoder extends ReplayingDecoder<State> {
CommandsData commandBatch) {
int i = state().getBatchIndex();
RedisException error = null;
Throwable error = null;
while (in.writerIndex() > in.readerIndex()) {
CommandData<Object, Object> cmd = null;
try {
@ -192,12 +192,12 @@ public class CommandDecoder extends ReplayingDecoder<State> {
state().setBatchIndex(i);
cmd = (CommandData<Object, Object>) commandBatch.getCommands().get(i);
decode(in, cmd, null, ctx.channel());
i++;
} catch (IOException e) {
} catch (Exception e) {
cmd.tryFailure(e);
}
i++;
if (!cmd.isSuccess()) {
error = (RedisException) cmd.cause();
error = cmd.cause();
}
}

@ -278,7 +278,7 @@ public interface RedisCommands {
RedisCommand<Void> SET = new RedisCommand<Void>("SET", new VoidReplayConvertor(), 2);
RedisCommand<Boolean> SETPXNX = new RedisCommand<Boolean>("SET", new BooleanNotNullReplayConvertor(), 2);
RedisCommand<Boolean> SETNX = new RedisCommand<Boolean>("SETNX", new BooleanReplayConvertor(), 2);
RedisCommand<Void> SETEX = new RedisCommand<Void>("SETEX", new VoidReplayConvertor(), 3);
RedisCommand<Void> PSETEX = new RedisCommand<Void>("PSETEX", new VoidReplayConvertor(), 3);
RedisStrictCommand<Long> EXISTS_LONG = new RedisStrictCommand<Long>("EXISTS");
RedisStrictCommand<Boolean> EXISTS = new RedisStrictCommand<Boolean>("EXISTS", new BooleanReplayConvertor());

@ -671,7 +671,7 @@ public class ClusterConnectionManager extends MasterSlaveConnectionManager {
private Collection<ClusterPartition> parsePartitions(List<ClusterNodeInfo> nodes) {
Map<String, ClusterPartition> partitions = new HashMap<String, ClusterPartition>();
for (ClusterNodeInfo clusterNodeInfo : nodes) {
if (clusterNodeInfo.containsFlag(Flag.NOADDR)) {
if (clusterNodeInfo.containsFlag(Flag.NOADDR) || clusterNodeInfo.containsFlag(Flag.HANDSHAKE)) {
// skip it
continue;
}

@ -15,8 +15,16 @@
*/
package org.redisson.codec;
import java.io.IOException;
import java.io.InputStream;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.avro.AvroFactory;
import com.fasterxml.jackson.dataformat.avro.AvroMapper;
import com.fasterxml.jackson.dataformat.avro.AvroSchema;
/**
* Avro binary codec
@ -26,12 +34,42 @@ import com.fasterxml.jackson.dataformat.avro.AvroFactory;
*/
public class AvroJacksonCodec extends JsonJacksonCodec {
public AvroJacksonCodec() {
super(new ObjectMapper(new AvroFactory()));
public static class AvroExtendedMapper extends AvroMapper {
private static final long serialVersionUID = -560070554221164163L;
private final AvroSchema schema;
private final Class<?> type;
public AvroExtendedMapper(Class<?> type, AvroSchema schema) {
super();
this.type = type;
this.schema = schema;
}
@Override
public byte[] writeValueAsBytes(Object value) throws JsonProcessingException {
return writerFor(type).with(schema).writeValueAsBytes(value);
}
@Override
public <T> T readValue(InputStream src, Class<T> valueType)
throws IOException, JsonParseException, JsonMappingException {
return readerFor(type).with(schema).readValue(src);
}
}
public AvroJacksonCodec(Class<?> type, AvroSchema schema) {
super(new AvroExtendedMapper(type, schema));
}
public AvroJacksonCodec(ClassLoader classLoader) {
super(createObjectMapper(classLoader, new ObjectMapper(new AvroFactory())));
}
@Override
protected void initTypeInclusion(ObjectMapper mapObjectMapper) {
}
}

@ -93,7 +93,10 @@ public class JsonJacksonCodec implements Codec {
public JsonJacksonCodec(ObjectMapper mapObjectMapper) {
this.mapObjectMapper = mapObjectMapper;
init(mapObjectMapper);
// type info inclusion
initTypeInclusion(mapObjectMapper);
}
protected void initTypeInclusion(ObjectMapper mapObjectMapper) {
TypeResolverBuilder<?> mapTyper = new DefaultTypeResolverBuilder(DefaultTyping.NON_FINAL) {
public boolean useForType(JavaType t) {
switch (_appliesFor) {

@ -31,16 +31,6 @@ public class BaseMasterSlaveServersConfig<T extends BaseMasterSlaveServersConfig
*/
private LoadBalancer loadBalancer = new RoundRobinLoadBalancer();
/**
* Redis 'slave' node minimum idle subscription (pub/sub) connection amount for <b>each</b> slave node
*/
private int slaveSubscriptionConnectionMinimumIdleSize = 1;
/**
* Redis 'slave' node maximum subscription (pub/sub) connection pool size for <b>each</b> slave node
*/
private int slaveSubscriptionConnectionPoolSize = 50;
/**
* Redis 'slave' node minimum idle connection amount for <b>each</b> slave node
*/
@ -63,6 +53,18 @@ public class BaseMasterSlaveServersConfig<T extends BaseMasterSlaveServersConfig
private ReadMode readMode = ReadMode.SLAVE;
private SubscriptionMode subscriptionMode = SubscriptionMode.SLAVE;
/**
* Redis 'slave' node minimum idle subscription (pub/sub) connection amount for <b>each</b> slave node
*/
private int subscriptionConnectionMinimumIdleSize = 1;
/**
* Redis 'slave' node maximum subscription (pub/sub) connection pool size for <b>each</b> slave node
*/
private int subscriptionConnectionPoolSize = 50;
public BaseMasterSlaveServersConfig() {
}
@ -71,11 +73,12 @@ public class BaseMasterSlaveServersConfig<T extends BaseMasterSlaveServersConfig
setLoadBalancer(config.getLoadBalancer());
setMasterConnectionPoolSize(config.getMasterConnectionPoolSize());
setSlaveConnectionPoolSize(config.getSlaveConnectionPoolSize());
setSlaveSubscriptionConnectionPoolSize(config.getSlaveSubscriptionConnectionPoolSize());
setSubscriptionConnectionPoolSize(config.getSubscriptionConnectionPoolSize());
setMasterConnectionMinimumIdleSize(config.getMasterConnectionMinimumIdleSize());
setSlaveConnectionMinimumIdleSize(config.getSlaveConnectionMinimumIdleSize());
setSlaveSubscriptionConnectionMinimumIdleSize(config.getSlaveSubscriptionConnectionMinimumIdleSize());
setSubscriptionConnectionMinimumIdleSize(config.getSubscriptionConnectionMinimumIdleSize());
setReadMode(config.getReadMode());
setSubscriptionMode(config.getSubscriptionMode());
}
/**
@ -134,24 +137,40 @@ public class BaseMasterSlaveServersConfig<T extends BaseMasterSlaveServersConfig
return loadBalancer;
}
/**
* @deprecated use {@link #setSubscriptionConnectionPoolSize(int)}
*
* @param slaveSubscriptionConnectionPoolSize - pool size
* @return config
*/
@Deprecated
public T setSlaveSubscriptionConnectionPoolSize(int slaveSubscriptionConnectionPoolSize) {
return setSubscriptionConnectionPoolSize(slaveSubscriptionConnectionPoolSize);
}
@Deprecated
public int getSlaveSubscriptionConnectionPoolSize() {
return getSubscriptionConnectionPoolSize();
}
/**
* Redis 'slave' node maximum subscription (pub/sub) connection pool size for <b>each</b> slave node
* <p>
* Default is <code>50</code>
* <p>
* @see #setSlaveSubscriptionConnectionMinimumIdleSize(int)
* @see #setSubscriptionConnectionMinimumIdleSize(int)
*
* @param slaveSubscriptionConnectionPoolSize - pool size
* @param subscriptionConnectionPoolSize - pool size
* @return config
*/
public T setSlaveSubscriptionConnectionPoolSize(int slaveSubscriptionConnectionPoolSize) {
this.slaveSubscriptionConnectionPoolSize = slaveSubscriptionConnectionPoolSize;
public T setSubscriptionConnectionPoolSize(int subscriptionConnectionPoolSize) {
this.subscriptionConnectionPoolSize = subscriptionConnectionPoolSize;
return (T)this;
}
public int getSlaveSubscriptionConnectionPoolSize() {
return slaveSubscriptionConnectionPoolSize;
public int getSubscriptionConnectionPoolSize() {
return subscriptionConnectionPoolSize;
}
/**
* Redis 'slave' node minimum idle connection amount for <b>each</b> slave node
* <p>
@ -188,24 +207,40 @@ public class BaseMasterSlaveServersConfig<T extends BaseMasterSlaveServersConfig
return masterConnectionMinimumIdleSize;
}
/**
* @deprecated use {@link #setSubscriptionConnectionMinimumIdleSize(int)}
*
* @param slaveSubscriptionConnectionMinimumIdleSize - pool size
* @return config
*/
@Deprecated
public T setSlaveSubscriptionConnectionMinimumIdleSize(int slaveSubscriptionConnectionMinimumIdleSize) {
return setSubscriptionConnectionMinimumIdleSize(slaveSubscriptionConnectionMinimumIdleSize);
}
@Deprecated
public int getSlaveSubscriptionConnectionMinimumIdleSize() {
return getSubscriptionConnectionMinimumIdleSize();
}
/**
* Redis 'slave' node minimum idle subscription (pub/sub) connection amount for <b>each</b> slave node.
* <p>
* Default is <code>1</code>
* <p>
* @see #setSlaveSubscriptionConnectionPoolSize(int)
* @see #setSubscriptionConnectionPoolSize(int)
*
* @param slaveSubscriptionConnectionMinimumIdleSize - pool size
* @param subscriptionConnectionMinimumIdleSize - pool size
* @return config
*/
public T setSlaveSubscriptionConnectionMinimumIdleSize(int slaveSubscriptionConnectionMinimumIdleSize) {
this.slaveSubscriptionConnectionMinimumIdleSize = slaveSubscriptionConnectionMinimumIdleSize;
public T setSubscriptionConnectionMinimumIdleSize(int subscriptionConnectionMinimumIdleSize) {
this.subscriptionConnectionMinimumIdleSize = subscriptionConnectionMinimumIdleSize;
return (T) this;
}
public int getSlaveSubscriptionConnectionMinimumIdleSize() {
return slaveSubscriptionConnectionMinimumIdleSize;
public int getSubscriptionConnectionMinimumIdleSize() {
return subscriptionConnectionMinimumIdleSize;
}
/**
* Set node type used for read operation.
* <p>
@ -222,4 +257,21 @@ public class BaseMasterSlaveServersConfig<T extends BaseMasterSlaveServersConfig
return readMode;
}
/**
* Set node type used for subscription operation.
* <p>
* Default is <code>SLAVE</code>
*
* @param subscriptionMode param
* @return config
*/
public T setSubscriptionMode(SubscriptionMode subscriptionMode) {
this.subscriptionMode = subscriptionMode;
return (T) this;
}
public SubscriptionMode getSubscriptionMode() {
return subscriptionMode;
}
}

@ -556,12 +556,24 @@ public class Config {
* Read config object stored in JSON format from <code>File</code>
*
* @param file object
* @param classLoader class loader
* @return config
* @throws IOException error
*/
public static Config fromJSON(File file) throws IOException {
public static Config fromJSON(File file, ClassLoader classLoader) throws IOException {
ConfigSupport support = new ConfigSupport();
return support.fromJSON(file, Config.class);
return support.fromJSON(file, Config.class, classLoader);
}
/**
* Read config object stored in JSON format from <code>File</code>
*
* @param file object
* @return config
* @throws IOException error
*/
public static Config fromJSON(File file) throws IOException {
return fromJSON(file, null);
}
/**
@ -631,8 +643,12 @@ public class Config {
* @throws IOException error
*/
public static Config fromYAML(File file) throws IOException {
return fromYAML(file, null);
}
public static Config fromYAML(File file, ClassLoader classLoader) throws IOException {
ConfigSupport support = new ConfigSupport();
return support.fromYAML(file, Config.class);
return support.fromYAML(file, Config.class, classLoader);
}
/**

@ -26,13 +26,16 @@ import java.util.List;
import org.redisson.api.RedissonNodeInitializer;
import org.redisson.client.codec.Codec;
import org.redisson.cluster.ClusterConnectionManager;
import org.redisson.codec.CodecProvider;
import org.redisson.connection.ConnectionManager;
import org.redisson.connection.ElasticacheConnectionManager;
import org.redisson.connection.ReplicatedConnectionManager;
import org.redisson.connection.MasterSlaveConnectionManager;
import org.redisson.connection.ReplicatedConnectionManager;
import org.redisson.connection.SentinelConnectionManager;
import org.redisson.connection.SingleConnectionManager;
import org.redisson.connection.balancer.LoadBalancer;
import org.redisson.liveobject.provider.ResolverProvider;
import org.redisson.misc.URLBuilder;
import com.fasterxml.jackson.annotation.JsonFilter;
import com.fasterxml.jackson.annotation.JsonIgnore;
@ -45,10 +48,8 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ser.FilterProvider;
import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter;
import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;
import com.fasterxml.jackson.databind.type.TypeFactory;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import org.redisson.codec.CodecProvider;
import org.redisson.liveobject.provider.ResolverProvider;
import org.redisson.misc.URLBuilder;
/**
*
@ -118,8 +119,8 @@ public class ConfigSupport {
}
private final ObjectMapper jsonMapper = createMapper(null);
private final ObjectMapper yamlMapper = createMapper(new YAMLFactory());
private ObjectMapper jsonMapper = createMapper(null, null);
private ObjectMapper yamlMapper = createMapper(new YAMLFactory(), null);
public <T> T fromJSON(String content, Class<T> configType) throws IOException {
URLBuilder.replaceURLFactory();
@ -131,8 +132,13 @@ public class ConfigSupport {
}
public <T> T fromJSON(File file, Class<T> configType) throws IOException {
return fromJSON(file, configType, null);
}
public <T> T fromJSON(File file, Class<T> configType, ClassLoader classLoader) throws IOException {
URLBuilder.replaceURLFactory();
try {
jsonMapper = createMapper(null, classLoader);
return jsonMapper.readValue(file, configType);
} finally {
URLBuilder.restoreURLFactory();
@ -193,6 +199,17 @@ public class ConfigSupport {
}
}
public <T> T fromYAML(File file, Class<T> configType, ClassLoader classLoader) throws IOException {
URLBuilder.replaceURLFactory();
try {
yamlMapper = createMapper(new YAMLFactory(), classLoader);
return yamlMapper.readValue(file, configType);
} finally {
URLBuilder.restoreURLFactory();
}
}
public <T> T fromYAML(URL url, Class<T> configType) throws IOException {
URLBuilder.replaceURLFactory();
try {
@ -266,12 +283,12 @@ public class ConfigSupport {
if (config.getMasterConnectionPoolSize() < config.getMasterConnectionMinimumIdleSize()) {
throw new IllegalArgumentException("masterConnectionPoolSize can't be lower than masterConnectionMinimumIdleSize");
}
if (config.getSlaveSubscriptionConnectionPoolSize() < config.getSlaveSubscriptionConnectionMinimumIdleSize()) {
if (config.getSubscriptionConnectionPoolSize() < config.getSubscriptionConnectionMinimumIdleSize()) {
throw new IllegalArgumentException("slaveSubscriptionConnectionMinimumIdleSize can't be lower than slaveSubscriptionConnectionPoolSize");
}
}
private ObjectMapper createMapper(JsonFactory mapping) {
private ObjectMapper createMapper(JsonFactory mapping, ClassLoader classLoader) {
ObjectMapper mapper = new ObjectMapper(mapping);
mapper.addMixIn(MasterSlaveServersConfig.class, MasterSlaveServersConfigMixIn.class);
mapper.addMixIn(SingleServerConfig.class, SingleSeverConfigMixIn.class);
@ -285,6 +302,13 @@ public class ConfigSupport {
.addFilter("classFilter", SimpleBeanPropertyFilter.filterOutAllExcept());
mapper.setFilterProvider(filterProvider);
mapper.setSerializationInclusion(Include.NON_NULL);
if (classLoader != null) {
TypeFactory tf = TypeFactory.defaultInstance()
.withClassLoader(classLoader);
mapper.setTypeFactory(tf);
}
return mapper;
}

@ -15,6 +15,11 @@
*/
package org.redisson.config;
/**
*
* @author Nikita Koksharov
*
*/
public enum ReadMode {
/**

@ -0,0 +1,35 @@
/**
* Copyright 2016 Nikita Koksharov
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.redisson.config;
/**
*
* @author Nikita Koksharov
*
*/
public enum SubscriptionMode {
/**
* Subscribe to slave nodes
*/
SLAVE,
/**
* Subscribe to master node
*/
MASTER
}

@ -0,0 +1,64 @@
/**
* Copyright 2016 Nikita Koksharov
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.redisson.connection;
import java.util.concurrent.atomic.AtomicInteger;
import org.redisson.api.RFuture;
import org.redisson.misc.RPromise;
import org.redisson.misc.RedissonPromise;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.FutureListener;
/**
*
* @author Nikita Koksharov
*
*/
public class CountListener implements FutureListener<Void> {
private final RPromise<Void> res;
private final AtomicInteger counter;
public static RPromise<Void> create(RFuture<Void>... futures) {
RPromise<Void> result = new RedissonPromise<Void>();
FutureListener<Void> listener = new CountListener(result, futures.length);
for (RFuture<Void> future : futures) {
future.addListener(listener);
}
return result;
}
public CountListener(RPromise<Void> res, int amount) {
super();
this.res = res;
this.counter = new AtomicInteger(amount);
}
@Override
public void operationComplete(Future<Void> future) throws Exception {
if (!future.isSuccess()) {
res.tryFailure(future.cause());
return;
}
if (counter.decrementAndGet() == 0) {
res.trySuccess(null);
}
}
}

@ -320,7 +320,7 @@ public class MasterSlaveConnectionManager implements ConnectionManager {
c.setClientName(cfg.getClientName());
c.setMasterConnectionPoolSize(cfg.getMasterConnectionPoolSize());
c.setSlaveConnectionPoolSize(cfg.getSlaveConnectionPoolSize());
c.setSlaveSubscriptionConnectionPoolSize(cfg.getSlaveSubscriptionConnectionPoolSize());
c.setSubscriptionConnectionPoolSize(cfg.getSubscriptionConnectionPoolSize());
c.setSubscriptionsPerConnection(cfg.getSubscriptionsPerConnection());
c.setConnectTimeout(cfg.getConnectTimeout());
c.setIdleConnectionTimeout(cfg.getIdleConnectionTimeout());
@ -329,8 +329,9 @@ public class MasterSlaveConnectionManager implements ConnectionManager {
c.setReconnectionTimeout(cfg.getReconnectionTimeout());
c.setMasterConnectionMinimumIdleSize(cfg.getMasterConnectionMinimumIdleSize());
c.setSlaveConnectionMinimumIdleSize(cfg.getSlaveConnectionMinimumIdleSize());
c.setSlaveSubscriptionConnectionMinimumIdleSize(cfg.getSlaveSubscriptionConnectionMinimumIdleSize());
c.setSubscriptionConnectionMinimumIdleSize(cfg.getSubscriptionConnectionMinimumIdleSize());
c.setReadMode(cfg.getReadMode());
c.setSubscriptionMode(cfg.getSubscriptionMode());
return c;
}

@ -37,9 +37,11 @@ import org.redisson.client.protocol.RedisCommands;
import org.redisson.cluster.ClusterSlotRange;
import org.redisson.config.MasterSlaveServersConfig;
import org.redisson.config.ReadMode;
import org.redisson.config.SubscriptionMode;
import org.redisson.connection.ClientConnectionsEntry.FreezeReason;
import org.redisson.connection.balancer.LoadBalancerManager;
import org.redisson.connection.pool.MasterConnectionPool;
import org.redisson.connection.pool.MasterPubSubConnectionPool;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -66,6 +68,8 @@ public class MasterSlaveEntry {
final MasterConnectionPool writeConnectionHolder;
final Set<Integer> slots = new HashSet<Integer>();
final MasterPubSubConnectionPool pubSubConnectionHolder;
final AtomicBoolean active = new AtomicBoolean(true);
public MasterSlaveEntry(Set<ClusterSlotRange> slotRanges, ConnectionManager connectionManager, MasterSlaveServersConfig config) {
@ -79,6 +83,7 @@ public class MasterSlaveEntry {
slaveBalancer = new LoadBalancerManager(config, connectionManager, this);
writeConnectionHolder = new MasterConnectionPool(config, connectionManager, this);
pubSubConnectionHolder = new MasterPubSubConnectionPool(config, connectionManager, this);
}
public List<RFuture<Void>> initSlaveBalancer(Collection<URL> disconnectedNodes) {
@ -98,8 +103,20 @@ public class MasterSlaveEntry {
public RFuture<Void> setupMasterEntry(String host, int port) {
RedisClient client = connectionManager.createClient(NodeType.MASTER, host, port);
masterEntry = new ClientConnectionsEntry(client, config.getMasterConnectionMinimumIdleSize(), config.getMasterConnectionPoolSize(),
0, 0, connectionManager, NodeType.MASTER);
masterEntry = new ClientConnectionsEntry(
client,
config.getMasterConnectionMinimumIdleSize(),
config.getMasterConnectionPoolSize(),
config.getSubscriptionConnectionMinimumIdleSize(),
config.getSubscriptionConnectionPoolSize(),
connectionManager,
NodeType.MASTER);
if (config.getSubscriptionMode() == SubscriptionMode.MASTER) {
RFuture<Void> f = writeConnectionHolder.add(masterEntry);
RFuture<Void> s = pubSubConnectionHolder.add(masterEntry);
return CountListener.create(s, f);
}
return writeConnectionHolder.add(masterEntry);
}
@ -307,8 +324,8 @@ public class MasterSlaveEntry {
ClientConnectionsEntry entry = new ClientConnectionsEntry(client,
this.config.getSlaveConnectionMinimumIdleSize(),
this.config.getSlaveConnectionPoolSize(),
this.config.getSlaveSubscriptionConnectionMinimumIdleSize(),
this.config.getSlaveSubscriptionConnectionPoolSize(), connectionManager, mode);
this.config.getSubscriptionConnectionMinimumIdleSize(),
this.config.getSubscriptionConnectionPoolSize(), connectionManager, mode);
if (freezed) {
synchronized (entry) {
entry.setFreezed(freezed);
@ -352,6 +369,7 @@ public class MasterSlaveEntry {
@Override
public void operationComplete(Future<Void> future) throws Exception {
writeConnectionHolder.remove(oldMaster);
pubSubConnectionHolder.remove(oldMaster);
slaveDown(oldMaster, FreezeReason.MANAGER);
// more than one slave available, so master can be removed from slaves
@ -406,10 +424,18 @@ public class MasterSlaveEntry {
}
RFuture<RedisPubSubConnection> nextPubSubConnection() {
if (config.getSubscriptionMode() == SubscriptionMode.MASTER) {
return pubSubConnectionHolder.get();
}
return slaveBalancer.nextPubSubConnection();
}
public void returnPubSubConnection(PubSubConnectionEntry entry) {
if (config.getSubscriptionMode() == SubscriptionMode.MASTER) {
pubSubConnectionHolder.returnConnection(masterEntry, entry.getConnection());
return;
}
slaveBalancer.returnPubSubConnection(entry.getConnection());
}

@ -25,6 +25,7 @@ import org.redisson.config.Config;
import org.redisson.config.MasterSlaveServersConfig;
import org.redisson.config.ReadMode;
import org.redisson.config.SingleServerConfig;
import org.redisson.config.SubscriptionMode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -71,15 +72,16 @@ public class SingleConnectionManager extends MasterSlaveConnectionManager {
newconfig.setMasterAddress(addr);
newconfig.setMasterConnectionPoolSize(cfg.getConnectionPoolSize());
newconfig.setSubscriptionsPerConnection(cfg.getSubscriptionsPerConnection());
newconfig.setSlaveSubscriptionConnectionPoolSize(cfg.getSubscriptionConnectionPoolSize());
newconfig.setSubscriptionConnectionPoolSize(cfg.getSubscriptionConnectionPoolSize());
newconfig.setConnectTimeout(cfg.getConnectTimeout());
newconfig.setIdleConnectionTimeout(cfg.getIdleConnectionTimeout());
newconfig.setFailedAttempts(cfg.getFailedAttempts());
newconfig.setReconnectionTimeout(cfg.getReconnectionTimeout());
newconfig.setMasterConnectionMinimumIdleSize(cfg.getConnectionMinimumIdleSize());
newconfig.setSlaveSubscriptionConnectionMinimumIdleSize(cfg.getSubscriptionConnectionMinimumIdleSize());
newconfig.setSubscriptionConnectionMinimumIdleSize(cfg.getSubscriptionConnectionMinimumIdleSize());
newconfig.setReadMode(ReadMode.MASTER);
newconfig.setSubscriptionMode(SubscriptionMode.MASTER);
return newconfig;
}

@ -17,69 +17,22 @@ package org.redisson.connection;
import java.net.InetSocketAddress;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import org.redisson.api.NodeType;
import org.redisson.api.RFuture;
import org.redisson.client.RedisClient;
import org.redisson.client.RedisConnection;
import org.redisson.client.RedisPubSubConnection;
import org.redisson.client.protocol.RedisCommand;
import org.redisson.cluster.ClusterSlotRange;
import org.redisson.config.MasterSlaveServersConfig;
import org.redisson.connection.pool.PubSubConnectionPool;
import org.redisson.connection.pool.SinglePubSubConnectionPool;
import org.redisson.misc.RPromise;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.FutureListener;
/**
*
* @author Nikita Koksharov
*
*/
public class SingleEntry extends MasterSlaveEntry {
final PubSubConnectionPool pubSubConnectionHolder;
public SingleEntry(Set<ClusterSlotRange> slotRanges, ConnectionManager connectionManager, MasterSlaveServersConfig config) {
super(slotRanges, connectionManager, config);
pubSubConnectionHolder = new SinglePubSubConnectionPool(config, connectionManager, this);
}
@Override
public RFuture<Void> setupMasterEntry(String host, int port) {
RedisClient masterClient = connectionManager.createClient(NodeType.MASTER, host, port);
masterEntry = new ClientConnectionsEntry(masterClient,
config.getMasterConnectionMinimumIdleSize(),
config.getMasterConnectionPoolSize(),
config.getSlaveConnectionMinimumIdleSize(),
config.getSlaveSubscriptionConnectionPoolSize(), connectionManager, NodeType.MASTER);
final RPromise<Void> res = connectionManager.newPromise();
RFuture<Void> f = writeConnectionHolder.add(masterEntry);
RFuture<Void> s = pubSubConnectionHolder.add(masterEntry);
FutureListener<Void> listener = new FutureListener<Void>() {
AtomicInteger counter = new AtomicInteger(2);
@Override
public void operationComplete(Future<Void> future) throws Exception {
if (!future.isSuccess()) {
res.tryFailure(future.cause());
return;
}
if (counter.decrementAndGet() == 0) {
res.trySuccess(null);
}
}
};
f.addListener(listener);
s.addListener(listener);
return res;
}
@Override
RFuture<RedisPubSubConnection> nextPubSubConnection() {
return pubSubConnectionHolder.get();
}
@Override
public void returnPubSubConnection(PubSubConnectionEntry entry) {
pubSubConnectionHolder.returnConnection(masterEntry, entry.getConnection());
}
@Override

@ -26,15 +26,20 @@ import org.redisson.connection.MasterSlaveEntry;
* @author Nikita Koksharov
*
*/
public class SinglePubSubConnectionPool extends PubSubConnectionPool {
public class MasterPubSubConnectionPool extends PubSubConnectionPool {
public SinglePubSubConnectionPool(MasterSlaveServersConfig config, ConnectionManager connectionManager,
public MasterPubSubConnectionPool(MasterSlaveServersConfig config, ConnectionManager connectionManager,
MasterSlaveEntry masterSlaveEntry) {
super(config, connectionManager, masterSlaveEntry);
}
@Override
protected ClientConnectionsEntry getEntry() {
return entries.get(0);
}
public void remove(ClientConnectionsEntry entry) {
entries.remove(entry);
}
}

@ -47,7 +47,7 @@ public class PubSubConnectionPool extends ConnectionPool<RedisPubSubConnection>
@Override
protected int getMinimumIdleSize(ClientConnectionsEntry entry) {
return config.getSlaveSubscriptionConnectionMinimumIdleSize();
return config.getSubscriptionConnectionMinimumIdleSize();
}
@Override

@ -33,7 +33,36 @@ public class URLBuilder {
private static URLStreamHandlerFactory currentFactory;
public static void restoreURLFactory() {
private final static URLStreamHandlerFactory newFactory = new URLStreamHandlerFactory() {
@Override
public URLStreamHandler createURLStreamHandler(String protocol) {
if ("redis".equals(protocol)) {
return new URLStreamHandler() {
@Override
protected URLConnection openConnection(URL u) throws IOException {
throw new UnsupportedOperationException();
};
@Override
protected boolean equals(URL u1, URL u2) {
return u1.toString().equals(u2.toString());
}
@Override
protected int hashCode(URL u) {
return u.toString().hashCode();
}
};
}
if (currentFactory != null) {
return currentFactory.createURLStreamHandler(protocol);
}
return null;
}
};
public static synchronized void restoreURLFactory() {
try {
Field field = URL.class.getDeclaredField("factory");
field.setAccessible(true);
@ -43,43 +72,20 @@ public class URLBuilder {
}
}
public static void replaceURLFactory() {
public static synchronized void replaceURLFactory() {
try {
Field field = URL.class.getDeclaredField("factory");
field.setAccessible(true);
currentFactory = (URLStreamHandlerFactory) field.get(null);
if (currentFactory != null) {
if (currentFactory != null && currentFactory != newFactory) {
field.set(null, null);
}
URL.setURLStreamHandlerFactory(new URLStreamHandlerFactory() {
@Override
public URLStreamHandler createURLStreamHandler(String protocol) {
if ("redis".equals(protocol)) {
return new URLStreamHandler() {
@Override
protected URLConnection openConnection(URL u) throws IOException {
throw new UnsupportedOperationException();
};
@Override
protected boolean equals(URL u1, URL u2) {
return u1.toString().equals(u2.toString());
}
@Override
protected int hashCode(URL u) {
return u.toString().hashCode();
}
};
}
if (currentFactory != null) {
return currentFactory.createURLStreamHandler(protocol);
}
return null;
}
});
if (currentFactory != newFactory) {
URL.setURLStreamHandlerFactory(newFactory);
} else {
currentFactory = null;
}
} catch (Exception e) {
throw new IllegalStateException(e);
}

@ -34,7 +34,6 @@ import io.netty.util.internal.PlatformDependent;
*
* @author Nikita Koksharov
*
* @param <E>
*/
abstract class PublishSubscribe<E extends PubSubEntry<E>> {

@ -45,7 +45,7 @@ public class RedissonBucketReactive<V> extends RedissonExpirableReactive impleme
@Override
public Publisher<Void> set(V value, long timeToLive, TimeUnit timeUnit) {
return commandExecutor.writeReactive(getName(), codec, RedisCommands.SETEX, getName(), timeUnit.toSeconds(timeToLive), value);
return commandExecutor.writeReactive(getName(), codec, RedisCommands.PSETEX, getName(), timeUnit.toMillis(timeToLive), value);
}
}

@ -0,0 +1,44 @@
/**
* Copyright 2016 Nikita Koksharov
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.redisson.spring.misc;
import java.lang.reflect.InvocationTargetException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.support.ArgumentConvertingMethodInvoker;
/**
*
* @author Rui Gu (https://github.com/jackygurui)
*/
public class BeanMethodInvoker extends ArgumentConvertingMethodInvoker
implements InitializingBean {
@Override
public void afterPropertiesSet() throws Exception {
prepare();
try {
invoke();
} catch (InvocationTargetException ex) {
if (ex.getTargetException() instanceof Exception) {
throw (Exception) ex.getTargetException();
}
if (ex.getTargetException() instanceof Error) {
throw (Error) ex.getTargetException();
}
throw ex;
}
}
}

@ -0,0 +1,84 @@
/**
* Copyright 2016 Nikita Koksharov
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.redisson.spring.support;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.util.Assert;
import org.w3c.dom.Element;
/**
*
* @author Rui Gu (https://github.com/jackygurui)
*/
public abstract class AbstractRedissonNamespaceDefinitionParser
extends AbstractSingleBeanDefinitionParser {
protected final RedissonNamespaceParserSupport helper;
private final RedissonNamespaceDecorator decorator;
private final String parentRefAttribute;
protected AbstractRedissonNamespaceDefinitionParser(RedissonNamespaceParserSupport helper, String parentRefAttribute) {
this.helper = helper;
this.parentRefAttribute = parentRefAttribute;
this.decorator = new RedissonNamespaceDefaultDecorator();
}
public AbstractRedissonNamespaceDefinitionParser(RedissonNamespaceParserSupport helper, String parentRefAttribute, RedissonNamespaceDecorator decorator) {
this.helper = helper;
this.parentRefAttribute = parentRefAttribute;
this.decorator = decorator;
}
@Override
protected final void doParse(Element element, BeanDefinitionBuilder builder) {
}
@Override
protected final void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
Assert.state(helper.isRedissonNS(element),
"Illegal state. "
+ this.getClass().getName()
+ " can only parse "
+ RedissonNamespaceParserSupport.REDISSON_NAMESPACE
+ " namespace elements");
Assert.state(element.hasAttribute(parentRefAttribute),
"Illegal state. property \"" + parentRefAttribute
+ "\" is required in the \""
+ helper.getName(element)
+ "\" element.");
helper.populateIdAttribute(element, builder, parserContext);
AbstractBeanDefinition bd = builder.getRawBeanDefinition();
parseNested(element, parserContext, builder, bd);
decorator.decorate(element, parserContext, builder, helper);
parserContext.getDelegate().parseQualifierElements(element, bd);
if (parserContext.isNested()) {
helper.registerBeanDefinition(builder, element, parserContext);
}
}
protected abstract void parseNested(Element element, ParserContext parserContext, BeanDefinitionBuilder builder, BeanDefinition bd);
@Override
protected final boolean shouldGenerateIdAsFallback() {
return true;
}
}

@ -0,0 +1,44 @@
/**
* Copyright 2016 Nikita Koksharov
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.redisson.spring.support;
import org.redisson.api.RQueue;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.util.Assert;
import org.w3c.dom.Element;
/**
*
* @author Rui Gu (https://github.com/jackygurui)
*/
public class DelayedQueueDecorator implements RedissonNamespaceDecorator {
private static final String DESTINATION_QUEUE_REF = "destination-queue-ref";
@Override
public void decorate(Element element, ParserContext parserContext, BeanDefinitionBuilder builder, RedissonNamespaceParserSupport helper) {
Assert.state(element.hasAttribute(DESTINATION_QUEUE_REF),
"Illegal state. property \"" + DESTINATION_QUEUE_REF
+ "\" is required in the \""
+ helper.getName(element)
+ "\" element.");
helper.addConstructorArgs(new RuntimeBeanReference(
helper.getAttribute(element, DESTINATION_QUEUE_REF)),
RQueue.class, builder);
}
}

@ -0,0 +1,95 @@
/**
* Copyright 2016 Nikita Koksharov
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.redisson.spring.support;
import org.redisson.api.LocalCachedMapOptions;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.core.Conventions;
import org.springframework.util.Assert;
import org.w3c.dom.Attr;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
/**
*
* @author Rui Gu (https://github.com/jackygurui)
*/
public class LocalCachedMapOptionsDecorator implements RedissonNamespaceDecorator {
@Override
public void decorate(Element element, ParserContext parserContext, BeanDefinitionBuilder builder, RedissonNamespaceParserSupport helper) {
NodeList list = element.getElementsByTagNameNS(
RedissonNamespaceParserSupport.REDISSON_NAMESPACE,
RedissonNamespaceParserSupport.LOCAL_CACHED_MAP_OPTIONS_ELEMENT);
Element options = null;
String id;
if (list.getLength() == 1) {
options = (Element) list.item(0);
id = invokeOptions(options, parserContext, helper);
for (int i = 0; i < options.getAttributes().getLength(); i++) {
Attr item = (Attr) options.getAttributes().item(i);
if (helper.isEligibleAttribute(item)
&& !RedissonNamespaceParserSupport.TIME_TO_LIVE_UNIT_ATTRIBUTE
.equals(item.getLocalName())
&& !RedissonNamespaceParserSupport.MAX_IDLE_UNIT_ATTRIBUTE
.equals(item.getLocalName())) {
helper.invoker(id,
helper.getName(item),
new Object[]{item.getValue()},
parserContext);
}
}
invokeTimeUnitOptions(options, id, parserContext, helper,
RedissonNamespaceParserSupport.TIME_TO_LIVE_ATTRIBUTE,
RedissonNamespaceParserSupport.TIME_TO_LIVE_UNIT_ATTRIBUTE);
invokeTimeUnitOptions(options, id, parserContext, helper,
RedissonNamespaceParserSupport.MAX_IDLE_ATTRIBUTE,
RedissonNamespaceParserSupport.MAX_IDLE_UNIT_ATTRIBUTE);
} else {
id = invokeOptions(options, parserContext, helper);
}
helper.addConstructorArgs(new RuntimeBeanReference(id),
LocalCachedMapOptions.class, builder);
}
private String invokeOptions(Element element, ParserContext parserContext, RedissonNamespaceParserSupport helper) {
BeanComponentDefinition defaultOption
= helper.factoryInvoker(element, LocalCachedMapOptions.class,
"defaults", null, parserContext);
return defaultOption.getName();
}
private void invokeTimeUnitOptions(Element element, String id, ParserContext parserContext, RedissonNamespaceParserSupport helper, String timeAttrubute, String timeUnitAttribute) {
if (helper.hasAttribute(element, timeUnitAttribute)) {
Assert.state(
helper.hasAttribute(element, timeAttrubute),
"Missing \"" + timeAttrubute + "\" attribute in \""
+ RedissonNamespaceParserSupport.LOCAL_CACHED_MAP_OPTIONS_ELEMENT
+ "\" element.");
helper.invoker(id,
Conventions.attributeNameToPropertyName(timeAttrubute),
new Object[]{
Integer.parseInt(
helper.getAttribute(element, timeAttrubute)),
helper.getAttribute(element, timeUnitAttribute)},
parserContext);
}
}
}

@ -0,0 +1,48 @@
/**
* Copyright 2016 Nikita Koksharov
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.redisson.spring.support;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.ParserContext;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
/**
*
* @author Rui Gu (https://github.com/jackygurui)
*/
public class ReadWriteLockDecorator implements RedissonNamespaceDecorator {
@Override
public void decorate(Element element, ParserContext parserContext, BeanDefinitionBuilder builder, RedissonNamespaceParserSupport helper) {
parseNested(element, RedissonNamespaceParserSupport.READ_LOCK_ELEMENT, parserContext, builder, helper);
parseNested(element, RedissonNamespaceParserSupport.WRITE_LOCK_ELEMENT, parserContext, builder, helper);
}
private void parseNested(Element element, String eltType, ParserContext parserContext, BeanDefinitionBuilder builder, RedissonNamespaceParserSupport helper) {
NodeList list = element.getElementsByTagNameNS(
RedissonNamespaceParserSupport.REDISSON_NAMESPACE, eltType);
if (list.getLength() == 1) {
Element elt = (Element) list.item(0);
helper.setAttribute(elt, RedissonNamespaceParserSupport.READ_WRITE_LOCK_REF_ATTRIBUTE,
helper.getAttribute(element,
RedissonNamespaceParserSupport.ID_ATTRIBUTE));
parserContext.getDelegate()
.parseCustomElement(elt, builder.getRawBeanDefinition());
}
}
}

@ -0,0 +1,78 @@
/**
* Copyright 2016 Nikita Koksharov
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.redisson.spring.support;
import org.redisson.client.RedisClient;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.AbstractSimpleBeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.w3c.dom.Attr;
import org.w3c.dom.Element;
/**
*
* @author Rui Gu (https://github.com/jackygurui)
*/
public final class RedisDefinitionParser
extends AbstractSimpleBeanDefinitionParser {
private static final String HOST_ATTRIBUTE = "host";
private static final String PORT_ATTRIBUTE = "port";
private static final String CONNECTION_TIMEOUT_ATTRIBUTE = "connectionTimeout";
private static final String COMMAND_TIMEOUT_ATTRIBUTE = "commandTimeout";
private final RedissonNamespaceParserSupport helper;
public RedisDefinitionParser(RedissonNamespaceParserSupport helper) {
this.helper = helper;
}
@Override
protected Class<RedisClient> getBeanClass(Element element) {
return RedisClient.class;
}
@Override
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
builder.getRawBeanDefinition().setBeanClass(RedisClient.class);
helper.addConstructorArgs(element,
HOST_ATTRIBUTE, String.class, builder);
helper.addConstructorArgs(element,
PORT_ATTRIBUTE, int.class, builder);
helper.addConstructorArgs(element,
CONNECTION_TIMEOUT_ATTRIBUTE, int.class, builder);
helper.addConstructorArgs(element,
COMMAND_TIMEOUT_ATTRIBUTE, int.class, builder);
builder.setDestroyMethodName("shutdown");
parserContext.getDelegate().parseQualifierElements(element,
builder.getRawBeanDefinition());
}
@Override
protected boolean shouldGenerateIdAsFallback() {
return true;
}
@Override
protected boolean isEligibleAttribute(String attributeName) {
return helper.isEligibleAttribute(attributeName);
}
@Override
protected boolean isEligibleAttribute(Attr attribute, ParserContext parserContext) {
return helper.isEligibleAttribute(attribute);
}
}

@ -0,0 +1,210 @@
/**
* Copyright 2016 Nikita Koksharov
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.redisson.spring.support;
import java.util.List;
import org.redisson.Redisson;
import org.redisson.config.Config;
import org.redisson.misc.URLBuilder;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
import org.springframework.beans.factory.parsing.CompositeComponentDefinition;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.BeanDefinitionParserDelegate;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.core.Conventions;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;
import org.w3c.dom.Attr;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
/**
*
* @author Rui Gu (https://github.com/jackygurui)
*/
public final class RedissonDefinitionParser
implements BeanDefinitionParser {
public static final String ID_ATTRIBUTE = "id";
public static final String NAME_ATTRIBUTE = "name";
private static final String REF_SUFFIX = "-ref";
private static final String REDISSON_REF = "redisson-ref";
static enum ConfigType {
singleServer,
sentinelServers,
replicatedServers,
masterSlaveServers,
clusterServers;
public static boolean contains(String type) {
try {
valueOf(type);
return true;
} catch (IllegalArgumentException e) {
return false;
}
}
}
static enum AddressType {
slaveAddress,
sentinelAddress,
nodeAddress;
public static boolean contains(String type) {
try {
valueOf(type);
return true;
} catch (IllegalArgumentException e) {
return false;
}
}
}
private final RedissonNamespaceParserSupport helper;
RedissonDefinitionParser(RedissonNamespaceParserSupport helper) {
this.helper = helper;
}
private void parseChildElements(Element element, String parentId, String redissonRef, BeanDefinitionBuilder redissonDef, ParserContext parserContext) {
if (element.hasChildNodes()) {
CompositeComponentDefinition compositeDef
= new CompositeComponentDefinition(parentId,
parserContext.extractSource(element));
parserContext.pushContainingComponent(compositeDef);
List<Element> childElts = DomUtils.getChildElements(element);
for (Element elt : childElts) {
if(BeanDefinitionParserDelegate
.QUALIFIER_ELEMENT.equals(elt.getLocalName())) {
continue;//parsed elsewhere
}
String localName = parserContext.getDelegate().getLocalName(elt);
localName = Conventions.attributeNameToPropertyName(localName);
if (ConfigType.contains(localName)) {
parseConfigTypes(elt, localName, redissonDef, parserContext);
} else if (AddressType.contains(localName)) {
parseAddressTypes(elt, localName, redissonDef, parserContext);
} else if (helper.isRedissonNS(elt)) {
elt.setAttribute(REDISSON_REF, redissonRef);
parserContext.getDelegate().parseCustomElement(elt);
}
}
parserContext.popContainingComponent();
}
}
private void parseConfigTypes(Element element, String configType, BeanDefinitionBuilder redissonDef, ParserContext parserContext) {
BeanDefinitionBuilder builder
= helper.createBeanDefinitionBuilder(element,
parserContext, null);
//Use factory method on the Config bean
AbstractBeanDefinition bd = builder.getRawBeanDefinition();
bd.setFactoryMethodName("use" + StringUtils.capitalize(configType));
bd.setFactoryBeanName(parserContext.getContainingComponent().getName());
String id = parserContext.getReaderContext().generateBeanName(bd);
helper.registerBeanDefinition(builder, id,
helper.parseAliase(element), parserContext);
parseAttributes(element, parserContext, builder);
redissonDef.addDependsOn(id);
parseChildElements(element, id, null, redissonDef, parserContext);
parserContext.getDelegate().parseQualifierElements(element, bd);
}
private void parseAddressTypes(Element element, String addressType, BeanDefinitionBuilder redissonDef, ParserContext parserContext) {
BeanComponentDefinition invoker = helper.invoker(element,
parserContext.getContainingComponent().getName(),
"add" + StringUtils.capitalize(addressType),
new String[]{element.getAttribute("value")},
parserContext);
String id = invoker.getName();
redissonDef.addDependsOn(id);
}
private void parseAttributes(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
NamedNodeMap attributes = element.getAttributes();
for (int x = 0; x < attributes.getLength(); x++) {
Attr attribute = (Attr) attributes.item(x);
if (helper.isEligibleAttribute(attribute)) {
String propertyName
= attribute.getLocalName().endsWith(REF_SUFFIX)
? attribute.getLocalName()
.substring(0, attribute.getLocalName()
.length() - REF_SUFFIX.length())
: attribute.getLocalName();
propertyName = Conventions
.attributeNameToPropertyName(propertyName);
Assert.state(StringUtils.hasText(propertyName),
"Illegal property name returned from"
+ " 'extractPropertyName(String)': cannot be"
+ " null or empty.");
if (attribute.getLocalName().endsWith(REF_SUFFIX)) {
builder.addPropertyReference(propertyName,
attribute.getValue());
} else {
Object value = attribute.getValue();
String localName = helper.getName(element);
if ("masterAddress".equals(propertyName)
&& ConfigType.masterSlaveServers.name()
.equals(localName)) {
try {
value = URLBuilder.create((String) value);
} catch (Exception e) {
//value may be a placeholder
value = "redis://" + value;
}
}
builder.addPropertyValue(propertyName, value);
}
}
}
}
@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
//Sort out the Config Class
BeanDefinitionBuilder configBuilder
= helper.createBeanDefinitionBuilder(element, parserContext,
Config.class);
String configId = helper.getId(null, configBuilder, parserContext);
parseAttributes(element, parserContext, configBuilder);
helper.registerBeanDefinition(configBuilder, configId,
null, parserContext);
//Do the main Redisson bean
BeanDefinitionBuilder builder
= helper.createBeanDefinitionBuilder(element, parserContext,
Redisson.class);
builder.setFactoryMethod("create");
builder.setDestroyMethodName("shutdown");
builder.addConstructorArgReference(configId);
parserContext.getDelegate().parseQualifierElements(element,
builder.getRawBeanDefinition());
String id = helper.getId(element, builder, parserContext);
parseAttributes(element, parserContext, configBuilder);
//Sort out all the nested elements
parseChildElements(element, configId, id, builder, parserContext);
helper.registerBeanDefinition(builder, id,
helper.parseAliase(element), parserContext);
return builder.getBeanDefinition();
}
}

@ -0,0 +1,90 @@
/**
* Copyright 2016 Nikita Koksharov
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.redisson.spring.support;
import org.redisson.api.RDestroyable;
import org.redisson.client.codec.Codec;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.core.Conventions;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
/**
*
* @author Rui Gu (https://github.com/jackygurui)
*/
public class RedissonGenericObjectDefinitionParser
extends AbstractRedissonNamespaceDefinitionParser {
private final static String KEY_ATTRIBUTE = "key";
private final static String TOPIC_ATTRIBUTE = "topic";
private final static String PATTERN_ATTRIBUTE = "pattern";
private final static String SERVICE_ATTRIBUTE = "service";
private final static String CODEC_REF_ATTRIBUTE = "codec-ref";
private final static String FAIL_LOCK = "fairLock";
RedissonGenericObjectDefinitionParser(RedissonNamespaceParserSupport helper) {
super(helper, RedissonNamespaceParserSupport.REDISSON_REF_ATTRIBUTE);
}
RedissonGenericObjectDefinitionParser(RedissonNamespaceParserSupport helper, RedissonNamespaceDecorator decorator) {
super(helper,
RedissonNamespaceParserSupport.REDISSON_REF_ATTRIBUTE,
decorator);
}
@Override
protected void parseNested(Element element, ParserContext parserContext, BeanDefinitionBuilder builder, BeanDefinition bd) {
bd.setFactoryBeanName(element.getAttribute(
RedissonNamespaceParserSupport.REDISSON_REF_ATTRIBUTE));
String typeName
= Conventions.attributeNameToPropertyName(element.getLocalName());
bd.setFactoryMethodName("get" + StringUtils.capitalize(typeName));
helper.addConstructorArgs(element, KEY_ATTRIBUTE,
String.class, builder);
helper.addConstructorArgs(element, TOPIC_ATTRIBUTE,
String.class, builder);
helper.addConstructorArgs(element, PATTERN_ATTRIBUTE,
String.class, builder);
helper.addConstructorArgs(element, SERVICE_ATTRIBUTE,
String.class, builder);
helper.addConstructorArgs(element, CODEC_REF_ATTRIBUTE,
Codec.class, builder);
if (RDestroyable.class.isAssignableFrom(getBeanClass(element))) {
((AbstractBeanDefinition) bd).setDestroyMethodName("destroy");
}
}
@Override
protected Class<?> getBeanClass(Element element) {
String elementName
= Conventions.attributeNameToPropertyName(
element.getLocalName());
try {
return Class.forName(RedissonNamespaceParserSupport.API_CLASS_PATH_PREFIX
+ (StringUtils.capitalize(FAIL_LOCK.equals(elementName)
? "lock"
: elementName)));
} catch (ClassNotFoundException ex) {
throw new IllegalArgumentException(ex);
}
}
}

@ -0,0 +1,87 @@
/**
* Copyright 2016 Nikita Koksharov
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.redisson.spring.support;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.MethodInvokingFactoryBean;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.ManagedList;
import org.springframework.beans.factory.xml.ParserContext;
import org.w3c.dom.Element;
import reactor.core.support.Assert;
/**
*
* @author Rui Gu (https://github.com/jackygurui)
*/
public class RedissonLiveObjectDefinitionParser
extends AbstractRedissonNamespaceDefinitionParser {
public RedissonLiveObjectDefinitionParser(RedissonNamespaceParserSupport helper) {
super(helper, RedissonNamespaceParserSupport.LIVE_OBJECT_SERVICE_REF_ATTRIBUTE);
}
@Override
protected void parseNested(Element element, ParserContext parserContext, BeanDefinitionBuilder builder, BeanDefinition bd) {
Class<?> apiClass;
try {
apiClass = Class.forName(helper.getAttribute(element,
RedissonNamespaceParserSupport.CLASS_ATTRIBUTE));
} catch (ClassNotFoundException ex) {
throw new IllegalArgumentException(
"The class [" + helper.getAttribute(element,
RedissonNamespaceParserSupport.CLASS_ATTRIBUTE)
+ "] specified in \"api-class\" attribute has not "
+ "found. Please check the class path.", ex);
}
Assert.state(helper.hasAttribute(element,
RedissonNamespaceParserSupport.OBJECT_ID_ATTRIBUTE)
|| helper.hasAttribute(element,
RedissonNamespaceParserSupport.OBJECT_ID_REF_ATTRIBUTE),
"One of \""
+ RedissonNamespaceParserSupport.OBJECT_ID_ATTRIBUTE
+ "\" or \""
+ RedissonNamespaceParserSupport.OBJECT_ID_REF_ATTRIBUTE
+ "\" attribute is required in the \""
+ RedissonNamespaceParserSupport.LIVE_OBJECT_ELEMENT
+ "\" element.");
builder.addPropertyValue("targetObject", new RuntimeBeanReference(
helper.getAttribute(element,
RedissonNamespaceParserSupport.LIVE_OBJECT_SERVICE_REF_ATTRIBUTE)));
builder.addPropertyValue("targetMethod", "get");
ManagedList args = new ManagedList();
args.add(apiClass);
if (helper.hasAttribute(element,
RedissonNamespaceParserSupport.OBJECT_ID_ATTRIBUTE)) {
args.add(helper.getAttribute(element,
RedissonNamespaceParserSupport.OBJECT_ID_ATTRIBUTE));
}
if (helper.hasAttribute(element,
RedissonNamespaceParserSupport.OBJECT_ID_REF_ATTRIBUTE)) {
args.add(new RuntimeBeanReference(
helper.getAttribute(element,
RedissonNamespaceParserSupport.OBJECT_ID_REF_ATTRIBUTE)));
}
builder.addPropertyValue("arguments", args);
}
@Override
protected Class<?> getBeanClass(Element element) {
return MethodInvokingFactoryBean.class;
}
}

@ -0,0 +1,62 @@
/**
* Copyright 2016 Nikita Koksharov
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.redisson.spring.support;
import org.redisson.spring.misc.BeanMethodInvoker;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.ParserContext;
import org.w3c.dom.Element;
/**
*
* @author Rui Gu (https://github.com/jackygurui)
*/
public class RedissonLiveObjectRegistrationDefinitionParser
extends AbstractRedissonNamespaceDefinitionParser {
public RedissonLiveObjectRegistrationDefinitionParser(RedissonNamespaceParserSupport helper) {
super(helper,
RedissonNamespaceParserSupport.LIVE_OBJECT_SERVICE_REF_ATTRIBUTE);
}
@Override
protected void parseNested(Element element, ParserContext parserContext, BeanDefinitionBuilder builder, BeanDefinition bd) {
Class<?> apiClass;
try {
apiClass = Class.forName(helper.getAttribute(element,
RedissonNamespaceParserSupport.CLASS_ATTRIBUTE));
} catch (ClassNotFoundException ex) {
throw new IllegalArgumentException(
"The class [" + helper.getAttribute(element,
RedissonNamespaceParserSupport.CLASS_ATTRIBUTE)
+ "] specified in \"api-class\" attribute has not "
+ "found. Please check the class path.", ex);
}
builder.addPropertyValue("targetObject", new RuntimeBeanReference(
helper.getAttribute(element,
RedissonNamespaceParserSupport.LIVE_OBJECT_SERVICE_REF_ATTRIBUTE)));
builder.addPropertyValue("targetMethod", "registerClass");
builder.addPropertyValue("arguments", new Object[] {apiClass});
}
@Override
protected Class<?> getBeanClass(Element element) {
return BeanMethodInvoker.class;
}
}

@ -0,0 +1,102 @@
/**
* Copyright 2016 Nikita Koksharov
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.redisson.spring.support;
import java.util.List;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConstructorArgumentValues;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.ManagedList;
import org.springframework.beans.factory.xml.BeanDefinitionParserDelegate;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.core.Conventions;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;
import org.w3c.dom.Element;
/**
*
* @author Rui Gu (https://github.com/jackygurui)
*/
public class RedissonMultiLockDefinitionParser
extends AbstractRedissonNamespaceDefinitionParser {
public RedissonMultiLockDefinitionParser(RedissonNamespaceParserSupport helper) {
super(helper,
RedissonNamespaceParserSupport.REDISSON_REF_ATTRIBUTE);
}
@Override
protected void parseNested(Element element, ParserContext parserContext, BeanDefinitionBuilder builder, BeanDefinition bd) {
bd.setDependsOn(element.getAttribute(
RedissonNamespaceParserSupport.REDISSON_REF_ATTRIBUTE));
List<Element> childElements = DomUtils.getChildElements(element);
for (Element elt : childElements) {
String localName = elt.getLocalName();
if (BeanDefinitionParserDelegate
.QUALIFIER_ELEMENT.equals(localName)) {
continue;//parsed elsewhere
}
String id;
if (BeanDefinitionParserDelegate.REF_ELEMENT.equals(localName)){
id = elt.getAttribute(
BeanDefinitionParserDelegate.BEAN_REF_ATTRIBUTE);
} else {
if (!elt.hasAttribute(
RedissonNamespaceParserSupport.REDISSON_REF_ATTRIBUTE)) {
helper.setAttribute(elt,
RedissonNamespaceParserSupport.REDISSON_REF_ATTRIBUTE,
element.getAttribute(
RedissonNamespaceParserSupport.REDISSON_REF_ATTRIBUTE));
}
helper.populateIdAttribute(elt, builder, parserContext);
parserContext.getDelegate().parseCustomElement(elt, bd);
id = elt.getAttribute(
RedissonNamespaceParserSupport.ID_ATTRIBUTE);
}
ConstructorArgumentValues args
= builder.getRawBeanDefinition()
.getConstructorArgumentValues();
if (args.getArgumentCount() > 0) {
ConstructorArgumentValues.ValueHolder value
= args.getIndexedArgumentValues().get(0);
ManagedList list;
if (value.getValue() instanceof ManagedList) {
list = (ManagedList) value.getValue();
} else {
list = new ManagedList();
list.add(value.getValue());
value.setValue(list);
value.setType(ManagedList.class.getName());
}
list.add(new RuntimeBeanReference(id));
} else {
builder.addConstructorArgReference(id);
}
}
}
@Override
protected String getBeanClassName(Element element) {
String elementName
= Conventions.attributeNameToPropertyName(
element.getLocalName());
return RedissonNamespaceParserSupport.IMPL_CLASS_PATH_PREFIX
+ StringUtils.capitalize(elementName);
}
}

@ -0,0 +1,29 @@
/**
* Copyright 2016 Nikita Koksharov
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.redisson.spring.support;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.ParserContext;
import org.w3c.dom.Element;
/**
*
* @author Rui Gu (https://github.com/jackygurui)
*/
public interface RedissonNamespaceDecorator {
void decorate(Element element, ParserContext parserContext, BeanDefinitionBuilder builder, RedissonNamespaceParserSupport helper);
}

@ -0,0 +1,33 @@
/**
* Copyright 2016 Nikita Koksharov
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.redisson.spring.support;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.ParserContext;
import org.w3c.dom.Element;
/**
*
* @author Rui Gu (https://github.com/jackygurui)
*/
public class RedissonNamespaceDefaultDecorator implements RedissonNamespaceDecorator {
@Override
public void decorate(Element element, ParserContext parserContext, BeanDefinitionBuilder builder, RedissonNamespaceParserSupport helper) {
//default is no decoration;
}
}

@ -0,0 +1,144 @@
/**
* Copyright 2016 Nikita Koksharov
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.redisson.spring.support;
import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
/**
*
* @author Rui Gu (https://github.com/jackygurui)
*/
public class RedissonNamespaceHandlerSupport extends NamespaceHandlerSupport {
@Override
public void init() {
RedissonNamespaceParserSupport helper
= new RedissonNamespaceParserSupport();
RedissonGenericObjectDefinitionParser defaultParser
= new RedissonGenericObjectDefinitionParser(helper);
RedissonReadAndWriteLockDefinitionParser readAndWriteLockParser
= new RedissonReadAndWriteLockDefinitionParser(helper);
RedissonMultiLockDefinitionParser nestedParser
= new RedissonMultiLockDefinitionParser(helper);
RedissonNestedElementAwareDecorator readWriteLockDecorator
= new RedissonNestedElementAwareDecorator(
new String[]{
RedissonNamespaceParserSupport.READ_LOCK_ELEMENT,
RedissonNamespaceParserSupport.WRITE_LOCK_ELEMENT
},
RedissonNamespaceParserSupport.READ_WRITE_LOCK_REF_ATTRIBUTE);
RedissonGenericObjectDefinitionParser readWriteLockParser
= new RedissonGenericObjectDefinitionParser(helper,
readWriteLockDecorator);
RedissonNestedElementAwareDecorator remoteServiceDecorator
= new RedissonNestedElementAwareDecorator(
new String[]{
RedissonNamespaceParserSupport.RPC_SERVER_ELEMENT,
RedissonNamespaceParserSupport.RPC_CLIENT_ELEMENT
},
RedissonNamespaceParserSupport.REMOTE_SERVICE_REF_ATTRIBUTE);
RedissonGenericObjectDefinitionParser remoteServiceParser
= new RedissonGenericObjectDefinitionParser(helper,
remoteServiceDecorator);
RedissonNestedElementAwareDecorator liveObjectServiceDecorator
= new RedissonNestedElementAwareDecorator(
new String[]{
RedissonNamespaceParserSupport.LIVE_OBJECT_ELEMENT,
RedissonNamespaceParserSupport.LIVE_OBJECT_REGISTRATION_ELEMENT
},
RedissonNamespaceParserSupport.LIVE_OBJECT_SERVICE_REF_ATTRIBUTE);
RedissonGenericObjectDefinitionParser liveObjectServiceParser
= new RedissonGenericObjectDefinitionParser(helper,
liveObjectServiceDecorator);
//root beans
registerBeanDefinitionParser("client",
new RedissonDefinitionParser(helper));
registerBeanDefinitionParser("redis", new RedisDefinitionParser(helper));
//object parsers
registerBeanDefinitionParser("binary-stream", defaultParser);
registerBeanDefinitionParser("geo", defaultParser);
registerBeanDefinitionParser("set-cache", defaultParser);
registerBeanDefinitionParser("map-cache", defaultParser);
registerBeanDefinitionParser("bucket", defaultParser);
registerBeanDefinitionParser("buckets", defaultParser);
registerBeanDefinitionParser("hyper-log-log", defaultParser);
registerBeanDefinitionParser("list", defaultParser);
registerBeanDefinitionParser("list-multimap", defaultParser);
registerBeanDefinitionParser("list-multimap-cache", defaultParser);
registerBeanDefinitionParser("local-cached-map",
new RedissonGenericObjectDefinitionParser(helper,
new LocalCachedMapOptionsDecorator()));
registerBeanDefinitionParser("map", defaultParser);
registerBeanDefinitionParser("set-multimap", defaultParser);
registerBeanDefinitionParser("set-multimap-cache", defaultParser);
registerBeanDefinitionParser("semaphore", defaultParser);
registerBeanDefinitionParser("permit-expirable-semaphore", defaultParser);
registerBeanDefinitionParser("lock", defaultParser);
registerBeanDefinitionParser("fair-lock", defaultParser);
registerBeanDefinitionParser("read-write-lock",readWriteLockParser);
registerBeanDefinitionParser("read-lock", readAndWriteLockParser);
registerBeanDefinitionParser("write-lock", readAndWriteLockParser);
registerBeanDefinitionParser("multi-lock", nestedParser);
registerBeanDefinitionParser("red-lock", nestedParser);
registerBeanDefinitionParser("set", defaultParser);
registerBeanDefinitionParser("sorted-set", defaultParser);
registerBeanDefinitionParser("scored-sorted-set", defaultParser);
registerBeanDefinitionParser("lex-sorted-set", defaultParser);
registerBeanDefinitionParser("topic", defaultParser);
registerBeanDefinitionParser("pattern-topic", defaultParser);
registerBeanDefinitionParser("blocking-fair-queue", defaultParser);
registerBeanDefinitionParser("queue", defaultParser);
registerBeanDefinitionParser("delayed-queue",
new RedissonGenericObjectDefinitionParser(helper,
new DelayedQueueDecorator()));
registerBeanDefinitionParser("priority-queue", defaultParser);
registerBeanDefinitionParser("priority-deque", defaultParser);
registerBeanDefinitionParser("blocking-queue", defaultParser);
registerBeanDefinitionParser("bounded-blocking-queue", defaultParser);
registerBeanDefinitionParser("deque", defaultParser);
registerBeanDefinitionParser("blocking-deque", defaultParser);
registerBeanDefinitionParser("atomic-long", defaultParser);
registerBeanDefinitionParser("atomic-double", defaultParser);
registerBeanDefinitionParser("count-down-latch", defaultParser);
registerBeanDefinitionParser("bit-set", defaultParser);
registerBeanDefinitionParser("bloom-filter", defaultParser);
registerBeanDefinitionParser("script", defaultParser);
registerBeanDefinitionParser("executor-service", defaultParser);//nested unfinished
registerBeanDefinitionParser("remote-service", remoteServiceParser);
registerBeanDefinitionParser("rpc-server",
new RedissonRPCServerDefinitionParser(helper));
registerBeanDefinitionParser("rpc-client",
new RedissonRPCClientDefinitionParser(helper,
new RemoteInvocationOptionDecorator()));
registerBeanDefinitionParser("keys", defaultParser);
registerBeanDefinitionParser("live-object-service", liveObjectServiceParser);
registerBeanDefinitionParser("live-object",
new RedissonLiveObjectDefinitionParser(helper));
registerBeanDefinitionParser("live-object-registration",
new RedissonLiveObjectRegistrationDefinitionParser(helper));
}
}

@ -0,0 +1,300 @@
/**
* Copyright 2016 Nikita Koksharov
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.redisson.spring.support;
import org.redisson.spring.misc.BeanMethodInvoker;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.ConstructorArgumentValues;
import org.springframework.beans.factory.config.MethodInvokingFactoryBean;
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.core.Conventions;
import org.springframework.util.StringUtils;
import org.w3c.dom.Attr;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
/**
*
* @author Rui Gu (https://github.com/jackygurui)
*/
public class RedissonNamespaceParserSupport {
public final static String REDISSON_NAMESPACE
= "http://redisson.org/schema/redisson";
static final String API_CLASS_PATH_PREFIX = "org.redisson.api.R";
static final String IMPL_CLASS_PATH_PREFIX = "org.redisson.Redisson";
static final String ID_ATTRIBUTE = "id";
static final String NAME_ATTRIBUTE = "name";
static final String REDISSON_REF_ATTRIBUTE = "redisson-ref";
static final String READ_WRITE_LOCK_REF_ATTRIBUTE = "read-write-lock-ref";
static final String EXECUTOR_REF_ATTRIBUTE = "executor-ref";
static final String REMOTE_SERVICE_REF_ATTRIBUTE = "remote-service-ref";
static final String LIVE_OBJECT_SERVICE_REF_ATTRIBUTE
= "live-object-service-ref";
static final String OBJECT_ID_REF_ATTRIBUTE = "object-id-ref";
static final String MAX_IDLE_ATTRIBUTE = "max-idle";
static final String TIME_TO_LIVE_ATTRIBUTE = "time-to-live";
static final String MAX_IDLE_UNIT_ATTRIBUTE = "max-idle-unit";
static final String TIME_TO_LIVE_UNIT_ATTRIBUTE = "time-to-live-unit";
static final String CONCURRENT_WORKERS_ATTRIBUTE = "concurrent-workers";
static final String WITHIN_ATTRIBUTE = "within";
static final String TIME_UNIT_ATTRIBUTE = "time-unit";
static final String API_CLASS_ATTRIBUTE = "api-class";
static final String CLASS_ATTRIBUTE = "class";
static final String OBJECT_ID_ATTRIBUTE = "object-id";
static final String READ_LOCK_ELEMENT = "read-lock";
static final String WRITE_LOCK_ELEMENT = "write-lock";
static final String RPC_SERVER_ELEMENT = "rpc-server";
static final String RPC_CLIENT_ELEMENT = "rpc-client";
static final String REMOTE_INVOCATION_OPTIONS_ELEMENT
= "remote-invocation-options";
static final String REMOTE_NO_ACK_ELEMENT = "remote-no-ack";
static final String REMOTE_ACK_ELEMENT = "remote-ack";
static final String REMOTE_NO_RESULT_ELEMENT = "remote-no-result";
static final String REMOTE_RESULT_ELEMENT = "remote-result";
static final String LOCAL_CACHED_MAP_OPTIONS_ELEMENT
= "local-cached-map-options";
static final String LIVE_OBJECT_ELEMENT
= "live-object";
static final String LIVE_OBJECT_REGISTRATION_ELEMENT
= "live-object-registration";
public String[] parseAliase(Element element) {
if (element == null) {
return null;
}
String[] aliases = null;
String name = element.getAttribute(NAME_ATTRIBUTE);
if (StringUtils.hasLength(name)) {
aliases = StringUtils.trimArrayElements(
StringUtils.commaDelimitedListToStringArray(name));
}
return aliases;
}
public BeanDefinitionBuilder createBeanDefinitionBuilder(Element element, ParserContext parserContext, Class<?> cls) {
BeanDefinitionBuilder builder
= BeanDefinitionBuilder.genericBeanDefinition();
builder.getRawBeanDefinition().setBeanClass(cls);
builder.getRawBeanDefinition()
.setSource(parserContext.extractSource(element));
if (parserContext.isNested()) {
builder.setScope(parserContext.getContainingBeanDefinition()
.getScope());
}
if (parserContext.isDefaultLazyInit()) {
builder.setLazyInit(true);
}
return builder;
}
public BeanComponentDefinition registerBeanDefinition(BeanDefinitionBuilder builder, String id, String[] aliases, ParserContext parserContext) {
BeanDefinitionHolder holder
= new BeanDefinitionHolder(builder.getBeanDefinition(), id,
aliases);
BeanDefinitionReaderUtils
.registerBeanDefinition(holder, parserContext.getRegistry());
BeanComponentDefinition componentDefinition
= new BeanComponentDefinition(holder);
parserContext.registerComponent(componentDefinition);
return componentDefinition;
}
public BeanComponentDefinition registerBeanDefinition(BeanDefinitionBuilder builder, Element element, ParserContext parserContext) {
BeanDefinitionHolder holder
= new BeanDefinitionHolder(builder.getBeanDefinition(),
getId(element, builder, parserContext),
parseAliase(element));
BeanDefinitionReaderUtils
.registerBeanDefinition(holder, parserContext.getRegistry());
BeanComponentDefinition componentDefinition
= new BeanComponentDefinition(holder);
parserContext.registerComponent(componentDefinition);
return componentDefinition;
}
public void addConstructorArgs(Element element, String attribute, Class type, BeanDefinition bd) {
if (element.hasAttribute(attribute)) {
addConstructorArgs(element.getAttribute(attribute), type, bd);
}
}
public void addConstructorArgs(Object value, Class type, BeanDefinition bd) {
ConstructorArgumentValues.ValueHolder vHolder
= new ConstructorArgumentValues.ValueHolder(value, type.getName());
ConstructorArgumentValues args
= bd.getConstructorArgumentValues();
args.addIndexedArgumentValue(args.getArgumentCount(), vHolder);
}
public void addConstructorArgs(Element element, String attribute, Class type, BeanDefinitionBuilder builder) {
addConstructorArgs(element, attribute, type, builder.getRawBeanDefinition());
}
public void addConstructorArgs(Object value, Class type, BeanDefinitionBuilder builder) {
addConstructorArgs(value, type, builder.getRawBeanDefinition());
}
public String getName(Node node) {
return Conventions.attributeNameToPropertyName(node.getLocalName());
}
public String getId(Element element, BeanDefinitionBuilder builder, ParserContext parserContext) {
String id = element != null
? element.getAttribute(ID_ATTRIBUTE)
: null;
if (!StringUtils.hasText(id)) {
id = generateId(builder, parserContext);
}
return id;
}
public String generateId(BeanDefinitionBuilder builder, ParserContext parserContext) {
return parserContext.getReaderContext()
.generateBeanName(builder.getRawBeanDefinition());
}
public void populateIdAttribute(Element element, BeanDefinitionBuilder builder, ParserContext parserContext) {
if (element == null) {
return;
}
if (!StringUtils.hasText(element.getAttribute(ID_ATTRIBUTE))) {
element.setAttribute(ID_ATTRIBUTE,
generateId(builder, parserContext));
}
}
public BeanComponentDefinition factoryInvoker(Element element, String bean, String method, Object[] args, ParserContext parserContext) {
BeanDefinitionBuilder builder
= preInvoke(element, bean, method, args, parserContext, true);
builder.addPropertyReference("targetObject", bean);
return doInvoke(element, builder, parserContext);
}
public BeanComponentDefinition factoryInvoker(Element element, Object obj, String method, Object[] args, ParserContext parserContext) {
BeanDefinitionBuilder builder
= preInvoke(element, obj, method, args, parserContext, true);
builder.addPropertyValue("targetObject", obj);
return doInvoke(element, builder, parserContext);
}
public BeanComponentDefinition factoryInvoker(String bean, String method, Object[] args, ParserContext parserContext) {
return factoryInvoker(null, bean, method, args, parserContext);
}
public BeanComponentDefinition factoryInvoker(Object obj, String method, Object[] args, ParserContext parserContext) {
return factoryInvoker(null, obj, method, args, parserContext);
}
public BeanComponentDefinition invoker(Element element, String bean, String method, Object[] args, ParserContext parserContext) {
BeanDefinitionBuilder builder
= preInvoke(element, bean, method, args, parserContext, false);
builder.addPropertyReference("targetObject", bean);
return doInvoke(element, builder, parserContext);
}
public BeanComponentDefinition invoker(Element element, Object obj, String method, Object[] args, ParserContext parserContext) {
BeanDefinitionBuilder builder
= preInvoke(element, obj, method, args, parserContext, false);
builder.addPropertyValue("targetObject", obj);
return doInvoke(element, builder, parserContext);
}
public BeanComponentDefinition invoker(String bean, String method, Object[] args, ParserContext parserContext) {
return invoker(null, bean, method, args, parserContext);
}
public BeanComponentDefinition invoker(Object obj, String method, Object[] args, ParserContext parserContext) {
return invoker(null, obj, method, args, parserContext);
}
private BeanDefinitionBuilder preInvoke(Element element, Object obj, String method, Object[] args, ParserContext parserContext, boolean factory) {
BeanDefinitionBuilder builder
= createBeanDefinitionBuilder(element, parserContext,
factory
? MethodInvokingFactoryBean.class
: BeanMethodInvoker.class);
if (obj instanceof Class) {
builder.addPropertyValue("staticMethod",
((Class) obj).getName() + "." + method);
} else {
builder.addPropertyValue("targetMethod", method);
}
builder.addPropertyValue("arguments", args);
if (element != null) {
parserContext.getDelegate().parseQualifierElements(element,
builder.getRawBeanDefinition());
}
return builder;
}
private BeanComponentDefinition doInvoke(Element element, BeanDefinitionBuilder builder, ParserContext parserContext) {
String id = getId(element, builder, parserContext);
return registerBeanDefinition(builder, id,
parseAliase(element), parserContext);
}
public boolean isEligibleAttribute(String attributeName) {
return !attributeName.equals("xmlns")
&& !attributeName.startsWith("xmlns:")
&& !ID_ATTRIBUTE.equals(attributeName)
&& !NAME_ATTRIBUTE.equals(attributeName);
}
public boolean isEligibleAttribute(Attr attribute) {
return isEligibleAttribute(attribute.getName());
}
public boolean isRedissonNS(Node node) {
return node != null
&& REDISSON_NAMESPACE.equals(node.getNamespaceURI());
}
public String getAttribute(Element element, String attribute) {
return element.getAttribute(attribute);
}
public void setAttribute(Element element, String attribute, String value) {
element.setAttribute(attribute, value);
}
public boolean hasAttribute(Element element, String attribute) {
return element.hasAttribute(attribute);
}
public boolean hasElement(Element element, String tagName) {
return element.getElementsByTagNameNS(
RedissonNamespaceParserSupport.REDISSON_NAMESPACE, tagName)
.getLength() > 0;
}
public Element getSingleElement(Element element, String tagName) {
return (Element) element.getElementsByTagNameNS(
RedissonNamespaceParserSupport.REDISSON_NAMESPACE, tagName)
.item(0);
}
}

@ -0,0 +1,62 @@
/**
* Copyright 2016 Nikita Koksharov
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.redisson.spring.support;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
/**
*
* @author Rui Gu (https://github.com/jackygurui)
*/
public class RedissonNestedElementAwareDecorator implements RedissonNamespaceDecorator {
private final String[] nestedElements;
private final String referenceAttribute;
public RedissonNestedElementAwareDecorator(String[] nestedElements, String referenceAttribute) {
this.nestedElements = nestedElements;
this.referenceAttribute = referenceAttribute;
}
@Override
public void decorate(Element element, ParserContext parserContext, BeanDefinitionBuilder builder, RedissonNamespaceParserSupport helper) {
for (String nestedElement : nestedElements) {
parseNested(element, nestedElement, parserContext, builder, helper);
}
}
private void parseNested(Element element, String eltType, ParserContext parserContext, BeanDefinitionBuilder builder, RedissonNamespaceParserSupport helper) {
NodeList list = element.getElementsByTagNameNS(
RedissonNamespaceParserSupport.REDISSON_NAMESPACE, eltType);
if (list.getLength() == 1) {
Element elt = (Element) list.item(0);
if (StringUtils.hasText(referenceAttribute)) {
helper.setAttribute(elt, referenceAttribute,
helper.getAttribute(element,
RedissonNamespaceParserSupport.ID_ATTRIBUTE));
helper.setAttribute(elt, RedissonNamespaceParserSupport.REDISSON_REF_ATTRIBUTE,
helper.getAttribute(element,
RedissonNamespaceParserSupport.REDISSON_REF_ATTRIBUTE));
}
parserContext.getDelegate()
.parseCustomElement(elt, builder.getRawBeanDefinition());
}
}
}

@ -0,0 +1,65 @@
/**
* Copyright 2016 Nikita Koksharov
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.redisson.spring.support;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.MethodInvokingFactoryBean;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.ParserContext;
import org.w3c.dom.Element;
/**
*
* @author Rui Gu (https://github.com/jackygurui)
*/
public class RedissonRPCClientDefinitionParser
extends AbstractRedissonNamespaceDefinitionParser {
public RedissonRPCClientDefinitionParser(RedissonNamespaceParserSupport helper, RedissonNamespaceDecorator decorator) {
super(helper,
RedissonNamespaceParserSupport.REMOTE_SERVICE_REF_ATTRIBUTE,
decorator);
}
@Override
protected void parseNested(Element element, ParserContext parserContext, BeanDefinitionBuilder builder, BeanDefinition bd) {
Class<?> apiClass;
try {
apiClass = Class.forName(helper.getAttribute(element,
RedissonNamespaceParserSupport.API_CLASS_ATTRIBUTE));
} catch (ClassNotFoundException ex) {
throw new IllegalArgumentException(
"The class [" + helper.getAttribute(element,
RedissonNamespaceParserSupport.API_CLASS_ATTRIBUTE)
+ "] specified in \""
+ RedissonNamespaceParserSupport.API_CLASS_ATTRIBUTE
+ "\" attribute has not "
+ "found. Please check the class path.", ex);
}
builder.addPropertyValue("targetObject", new RuntimeBeanReference(
helper.getAttribute(element,
RedissonNamespaceParserSupport.REMOTE_SERVICE_REF_ATTRIBUTE)));
builder.addPropertyValue("targetMethod", "get");
builder.addPropertyValue("arguments", new Object[] {apiClass});
}
@Override
protected Class<?> getBeanClass(Element element) {
return MethodInvokingFactoryBean.class;
}
}

@ -0,0 +1,96 @@
/**
* Copyright 2016 Nikita Koksharov
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.redisson.spring.support;
import org.redisson.spring.misc.BeanMethodInvoker;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.ManagedList;
import org.springframework.beans.factory.xml.BeanDefinitionParserDelegate;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
import reactor.core.support.Assert;
/**
*
* @author Rui Gu (https://github.com/jackygurui)
*/
public class RedissonRPCServerDefinitionParser
extends AbstractRedissonNamespaceDefinitionParser {
public RedissonRPCServerDefinitionParser(RedissonNamespaceParserSupport helper) {
super(helper, RedissonNamespaceParserSupport.REMOTE_SERVICE_REF_ATTRIBUTE);
}
@Override
protected void parseNested(Element element, ParserContext parserContext, BeanDefinitionBuilder builder, BeanDefinition bd) {
Class<?> apiClass;
try {
apiClass = Class.forName(helper.getAttribute(element,
RedissonNamespaceParserSupport.API_CLASS_ATTRIBUTE));
} catch (ClassNotFoundException ex) {
throw new IllegalArgumentException(
"The class [" + helper.getAttribute(element,
RedissonNamespaceParserSupport.API_CLASS_ATTRIBUTE)
+ "] specified in \""
+ RedissonNamespaceParserSupport.API_CLASS_ATTRIBUTE
+ "\" attribute has not "
+ "found. Please check the class path.", ex);
}
builder.addPropertyValue("targetObject", new RuntimeBeanReference(
helper.getAttribute(element,
RedissonNamespaceParserSupport.REMOTE_SERVICE_REF_ATTRIBUTE)));
builder.addPropertyValue("targetMethod", "register");
ManagedList args = new ManagedList();
args.add(apiClass);
args.add(new RuntimeBeanReference(
helper.getAttribute(element,
BeanDefinitionParserDelegate.BEAN_REF_ATTRIBUTE)));
String workers = null;
if (helper.hasAttribute(element,
RedissonNamespaceParserSupport.CONCURRENT_WORKERS_ATTRIBUTE)) {
workers = helper.getAttribute(element,
RedissonNamespaceParserSupport.CONCURRENT_WORKERS_ATTRIBUTE);
}
if (StringUtils.hasText(workers)) {
args.add(Integer.parseInt(workers));
}
if (helper.hasAttribute(element,
RedissonNamespaceParserSupport.EXECUTOR_REF_ATTRIBUTE)) {
Assert.state(helper.hasAttribute(element,
RedissonNamespaceParserSupport.CONCURRENT_WORKERS_ATTRIBUTE),
"The \""
+ RedissonNamespaceParserSupport.CONCURRENT_WORKERS_ATTRIBUTE
+ "\" attribute in \""
+ RedissonNamespaceParserSupport.RPC_SERVER_ELEMENT
+ "\" element is required when \""
+ RedissonNamespaceParserSupport.EXECUTOR_REF_ATTRIBUTE
+ "\" attribute is specified.");
args.add(new RuntimeBeanReference(
helper.getAttribute(element,
RedissonNamespaceParserSupport.EXECUTOR_REF_ATTRIBUTE)));
}
builder.addPropertyValue("arguments", args);
}
@Override
protected Class<?> getBeanClass(Element element) {
return BeanMethodInvoker.class;
}
}

@ -0,0 +1,55 @@
/**
* Copyright 2016 Nikita Koksharov
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.redisson.spring.support;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.core.Conventions;
import org.w3c.dom.Element;
/**
*
* @author Rui Gu (https://github.com/jackygurui)
*/
public class RedissonReadAndWriteLockDefinitionParser
extends AbstractRedissonNamespaceDefinitionParser {
public RedissonReadAndWriteLockDefinitionParser(RedissonNamespaceParserSupport helper) {
super(helper,
RedissonNamespaceParserSupport.READ_WRITE_LOCK_REF_ATTRIBUTE);
}
@Override
protected void parseNested(Element element, ParserContext parserContext, BeanDefinitionBuilder builder, BeanDefinition bd) {
bd.setFactoryBeanName(element.getAttribute(
RedissonNamespaceParserSupport.READ_WRITE_LOCK_REF_ATTRIBUTE));
String typeName
= Conventions.attributeNameToPropertyName(element.getLocalName());
bd.setFactoryMethodName(typeName);
}
@Override
protected Class<?> getBeanClass(Element element) {
try {
return Class.forName(RedissonNamespaceParserSupport.API_CLASS_PATH_PREFIX
+ "Lock");
} catch (ClassNotFoundException ex) {
throw new IllegalArgumentException(ex);
}
}
}

@ -0,0 +1,116 @@
/**
* Copyright 2016 Nikita Koksharov
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.redisson.spring.support;
import java.util.ArrayList;
import java.util.Arrays;
import org.redisson.api.RemoteInvocationOptions;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.PropertyValue;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.ManagedList;
import org.springframework.beans.factory.xml.ParserContext;
import org.w3c.dom.Element;
import reactor.core.support.Assert;
/**
*
* @author Rui Gu (https://github.com/jackygurui)
*/
public class RemoteInvocationOptionDecorator implements RedissonNamespaceDecorator {
@Override
public void decorate(Element element, ParserContext parserContext, BeanDefinitionBuilder builder, RedissonNamespaceParserSupport helper) {
if (helper.hasElement(element,
RedissonNamespaceParserSupport.REMOTE_INVOCATION_OPTIONS_ELEMENT)) {
Element options = helper.getSingleElement(element,
RedissonNamespaceParserSupport.REMOTE_INVOCATION_OPTIONS_ELEMENT);
String optionBeanId = invokeOptions(options, parserContext, helper);
if (helper.hasElement(element,
RedissonNamespaceParserSupport.REMOTE_NO_ACK_ELEMENT)) {
helper.invoker(optionBeanId, "noAck", null, parserContext);
}
if (helper.hasElement(element,
RedissonNamespaceParserSupport.REMOTE_ACK_ELEMENT)) {
Element remoteAck = helper.getSingleElement(element,
RedissonNamespaceParserSupport.REMOTE_ACK_ELEMENT);
Assert.state(helper.hasAttribute(remoteAck,
RedissonNamespaceParserSupport.WITHIN_ATTRIBUTE),
"Missing \""
+ RedissonNamespaceParserSupport.WITHIN_ATTRIBUTE
+ "\" attribute in \""
+ RedissonNamespaceParserSupport.REMOTE_ACK_ELEMENT
+ "\" element.");
ArrayList args = new ArrayList(2);
args.add(helper.getAttribute(remoteAck,
RedissonNamespaceParserSupport.WITHIN_ATTRIBUTE));
if (helper.hasAttribute(remoteAck,
RedissonNamespaceParserSupport.TIME_UNIT_ATTRIBUTE)) {
args.add(helper.getAttribute(remoteAck,
RedissonNamespaceParserSupport.TIME_UNIT_ATTRIBUTE));
}
helper.invoker(optionBeanId, "expectAckWithin", args.toArray(),
parserContext);
}
if (helper.hasElement(element,
RedissonNamespaceParserSupport.REMOTE_NO_RESULT_ELEMENT)) {
helper.invoker(optionBeanId, "noResult", null, parserContext);
}
if (helper.hasElement(element,
RedissonNamespaceParserSupport.REMOTE_RESULT_ELEMENT)) {
Element remoteResult = helper.getSingleElement(element,
RedissonNamespaceParserSupport.REMOTE_RESULT_ELEMENT);
Assert.state(helper.hasAttribute(remoteResult,
RedissonNamespaceParserSupport.WITHIN_ATTRIBUTE),
"Missing \""
+ RedissonNamespaceParserSupport.WITHIN_ATTRIBUTE
+ "\" attribute in \""
+ RedissonNamespaceParserSupport.REMOTE_RESULT_ELEMENT
+ "\" element.");
ArrayList args = new ArrayList(2);
args.add(helper.getAttribute(remoteResult,
RedissonNamespaceParserSupport.WITHIN_ATTRIBUTE));
if (helper.hasAttribute(remoteResult,
RedissonNamespaceParserSupport.TIME_UNIT_ATTRIBUTE)) {
args.add(helper.getAttribute(remoteResult,
RedissonNamespaceParserSupport.TIME_UNIT_ATTRIBUTE));
}
helper.invoker(optionBeanId, "expectResultWithin", args.toArray(),
parserContext);
}
MutablePropertyValues properties = builder.getRawBeanDefinition()
.getPropertyValues();
PropertyValue propertyValue
= properties.getPropertyValue("arguments");
ManagedList<Object> args = new ManagedList();
args.addAll(Arrays.asList(
(Object[]) propertyValue.getValue()));
args.add(new RuntimeBeanReference(optionBeanId));
properties.removePropertyValue("arguments");
properties.addPropertyValue("arguments", args);
}
}
private String invokeOptions(Element element, ParserContext parserContext, RedissonNamespaceParserSupport helper) {
BeanComponentDefinition defaultOption
= helper.factoryInvoker(element, RemoteInvocationOptions.class,
"defaults", null, parserContext);
return defaultOption.getName();
}
}

@ -0,0 +1 @@
http\://redisson.org/schema/redisson=org.redisson.spring.support.RedissonNamespaceHandlerSupport

@ -0,0 +1,2 @@
http\://redisson.org/schema/redisson.xsd=org/redisson/spring/support/redisson-1.0.xsd
http\://redisson.org/schema/redisson-1.0.xsd=org/redisson/spring/support/redisson-1.0.xsd

@ -0,0 +1,4 @@
# Tooling related information for the redisson namespace
http\://redisson.org/schema/redisson@name=redisson Namespace
http\://redisson.org/schema/redisson@prefix=redisson
http\://redisson.org/schema/redisson@icon=org/redisson/spring/support/redisson.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

@ -38,7 +38,9 @@ public abstract class BaseTest {
if (redisson == null) {
redisson = defaultRedisson;
}
redisson.getKeys().flushall();
if (flushBetweenTests()) {
redisson.getKeys().flushall();
}
}
}
@ -74,4 +76,7 @@ public abstract class BaseTest {
return Redisson.create(config);
}
protected boolean flushBetweenTests() {
return true;
}
}

@ -0,0 +1,99 @@
package org.redisson;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.math.BigInteger;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
/**
*
* @author Rui Gu (https://github.com/jackygurui)
*/
public class ClusterRunner {
private final LinkedHashMap<RedisRunner, String> nodes = new LinkedHashMap<>();
public ClusterRunner addNode(RedisRunner runner) {
nodes.put(runner, getRandomId());
if (!runner.hasOption(RedisRunner.REDIS_OPTIONS.CLUSTER_ENABLED)) {
runner.clusterEnabled(true);
}
if (!runner.hasOption(RedisRunner.REDIS_OPTIONS.CLUSTER_NODE_TIMEOUT)) {
runner.clusterNodeTimeout(5000);
}
if (!runner.hasOption(RedisRunner.REDIS_OPTIONS.PORT)) {
runner.randomPort(1);
runner.port(RedisRunner.findFreePort());
}
if (!runner.hasOption(RedisRunner.REDIS_OPTIONS.BIND)) {
runner.bind("127.0.0.1");
}
return this;
}
public List<RedisRunner.RedisProcess> run() throws IOException, InterruptedException, RedisRunner.FailedToStartRedisException {
ArrayList<RedisRunner.RedisProcess> processes = new ArrayList<>();
for (RedisRunner runner : nodes.keySet()) {
List<String> options = getClusterConfig(runner);
String confFile = runner.defaultDir() + File.pathSeparator + nodes.get(runner) + ".conf";
System.out.println("WRITING CONFIG: for " + nodes.get(runner));
try (PrintWriter printer = new PrintWriter(new FileWriter(confFile))) {
options.stream().forEach((line) -> {
printer.println(line);
System.out.println(line);
});
}
processes.add(runner.clusterConfigFile(confFile).run());
}
Thread.sleep(1000);
for (RedisRunner.RedisProcess process : processes) {
if (!process.isAlive()) {
throw new RedisRunner.FailedToStartRedisException();
}
}
return processes;
}
private List<String> getClusterConfig(RedisRunner runner) {
String me = runner.getInitialBindAddr() + ":" + runner.getPort();
List<String> nodeConfig = new ArrayList<>();
int c = 0;
for (RedisRunner node : nodes.keySet()) {
StringBuilder sb = new StringBuilder();
String nodeAddr = node.getInitialBindAddr() + ":" + node.getPort();
sb.append(nodes.get(node)).append(" ");
sb.append(nodeAddr).append(" ");
sb.append(me.equals(nodeAddr)
? "myself,"
: "").append("master -").append(" ");
sb.append("0").append(" ");
sb.append(me.equals(nodeAddr)
? "0"
: "1").append(" ");
sb.append(c + 1).append(" ");
sb.append("connected ");
sb.append(getSlots(c, nodes.size()));
c++;
nodeConfig.add(sb.toString());
}
nodeConfig.add("vars currentEpoch 0 lastVoteEpoch 0");
return nodeConfig;
}
private String getSlots(int index, int groupNum) {
final double t = 16383;
int start = index == 0 ? 0 : (int) (t / groupNum * index);
int end = index == groupNum - 1 ? (int) t : (int) (t / groupNum * (index + 1)) - 1;
return start + "-" + end;
}
private String getRandomId() {
final SecureRandom r = new SecureRandom();
return new BigInteger(160, r).toString(16);
}
}

@ -2,8 +2,10 @@ package org.redisson;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Inet4Address;
import java.net.ServerSocket;
import java.net.URL;
@ -66,7 +68,7 @@ public class RedisRunner {
SLAVE_PRIORITY,
MIN_SLAVES_TO_WRITE,
MIN_SLAVES_MAX_LAG,
REQUREPASS,
REQUIREPASS,
RENAME_COMMAND(true),
MAXCLIENTS,
MAXMEMORY,
@ -103,7 +105,19 @@ public class RedisRunner {
CLIENT_OUTPUT_BUFFER_LIMIT$SLAVE,
CLIENT_OUTPUT_BUFFER_LIMIT$PUBSUB,
HZ,
AOF_REWRITE_INCREMENTAL_FSYNC;
AOF_REWRITE_INCREMENTAL_FSYNC,
PROTECTED_MODE,
SENTINEL,
SENTINEL$ANNOUNCE_IP,
SENTINEL$ANNOUNCE_PORT,
SENTINEL$MONITOR(true),
SENTINEL$AUTH_PASS(true),
SENTINEL$DOWN_AFTER_MILLISECONDS(true),
SENTINEL$PARALLEL_SYNCS(true),
SENTINEL$FAILOVER_TIMEOUT(true),
SENTINEL$NOTIFICATION_SCRIPT(true),
SENTINEL$CLIENT_RECONFIG_SCRIPT(true)
;
private final boolean allowMutiple;
@ -184,6 +198,8 @@ public class RedisRunner {
private int port = 6379;
private int retryCount = Integer.MAX_VALUE;
private boolean randomPort = false;
private String sentinelFile;
private String clusterFile;
{
this.options.put(REDIS_OPTIONS.BINARY_PATH, RedissonRuntimeEnvironment.redisBinaryPath);
@ -253,13 +269,38 @@ public class RedisRunner {
}
public RedisProcess runAndCheck() throws IOException, InterruptedException, FailedToStartRedisException {
RedisProcess rp = runWithOptions(this, options.values().toArray(new String[0]));
if (rp.redisProcess.waitFor(1000, TimeUnit.MILLISECONDS)) {
List<String> args = new ArrayList(options.values());
if (sentinelFile != null && sentinelFile.length() > 0) {
String confFile = defaultDir + File.pathSeparator + sentinelFile;
try (PrintWriter printer = new PrintWriter(new FileWriter(confFile))) {
args.stream().forEach((arg) -> {
if (arg.contains("--")) {
printer.println(arg.replace("--", "\n\r"));
}
});
}
args = args.subList(0, 1);
args.add(confFile);
args.add("--sentinel");
}
RedisProcess rp = runWithOptions(this, args.toArray(new String[0]));
if (!isCluster()
&& rp.redisProcess.waitFor(1000, TimeUnit.MILLISECONDS)) {
throw new FailedToStartRedisException();
}
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
try {
rp.stop();
} catch (InterruptedException ex) {
}
}));
return rp;
}
public boolean hasOption(REDIS_OPTIONS option) {
return options.containsKey(option);
}
private void addConfigOption(REDIS_OPTIONS option, Object... args) {
StringBuilder sb = new StringBuilder("--")
.append(option.toString()
@ -440,6 +481,11 @@ public class RedisRunner {
return this;
}
public RedisRunner slaveof(String masterip, int port) {
addConfigOption(REDIS_OPTIONS.SLAVEOF, masterip, port);
return this;
}
public RedisRunner masterauth(String masterauth) {
addConfigOption(REDIS_OPTIONS.MASTERAUTH, masterauth);
return this;
@ -506,7 +552,7 @@ public class RedisRunner {
}
public RedisRunner requirepass(String requirepass) {
addConfigOption(REDIS_OPTIONS.REQUREPASS, requirepass);
addConfigOption(REDIS_OPTIONS.REQUIREPASS, requirepass);
return this;
}
@ -582,6 +628,7 @@ public class RedisRunner {
public RedisRunner clusterConfigFile(String clusterConfigFile) {
addConfigOption(REDIS_OPTIONS.CLUSTER_CONFIG_FILE, clusterConfigFile);
this.clusterFile = clusterConfigFile;
return this;
}
@ -703,6 +750,69 @@ public class RedisRunner {
return this;
}
public RedisRunner protectedMode(boolean protectedMode) {
addConfigOption(REDIS_OPTIONS.PROTECTED_MODE, convertBoolean(protectedMode));
return this;
}
public RedisRunner sentinel() {
sentinelFile = "sentinel_conf_" + UUID.randomUUID() + ".conf";
return this;
}
public RedisRunner sentinelAnnounceIP(String sentinelAnnounceIP) {
addConfigOption(REDIS_OPTIONS.SENTINEL$ANNOUNCE_IP, sentinelAnnounceIP);
return this;
}
public RedisRunner sentinelAnnouncePort(int sentinelAnnouncePort) {
addConfigOption(REDIS_OPTIONS.SENTINEL$ANNOUNCE_PORT, sentinelAnnouncePort);
return this;
}
public RedisRunner sentinelMonitor(String masterName, String ip, int port, int quorum) {
addConfigOption(REDIS_OPTIONS.SENTINEL$MONITOR, masterName, ip, port, quorum);
return this;
}
public RedisRunner sentinelAuthPass(String masterName, String password) {
addConfigOption(REDIS_OPTIONS.SENTINEL$AUTH_PASS, masterName, password);
return this;
}
public RedisRunner sentinelDownAfterMilliseconds(String masterName, long downAfterMilliseconds) {
addConfigOption(REDIS_OPTIONS.SENTINEL$DOWN_AFTER_MILLISECONDS, masterName, downAfterMilliseconds);
return this;
}
public RedisRunner sentinelParallelSyncs(String masterName, int numSlaves) {
addConfigOption(REDIS_OPTIONS.SENTINEL$PARALLEL_SYNCS, masterName, numSlaves);
return this;
}
public RedisRunner sentinelFailoverTimeout(String masterName, long failoverTimeout) {
addConfigOption(REDIS_OPTIONS.SENTINEL$FAILOVER_TIMEOUT, masterName, failoverTimeout);
return this;
}
public RedisRunner sentinelNotificationScript(String masterName, String scriptPath) {
addConfigOption(REDIS_OPTIONS.SENTINEL$NOTIFICATION_SCRIPT, masterName, scriptPath);
return this;
}
public RedisRunner sentinelClientReconfigScript(String masterName, String scriptPath) {
addConfigOption(REDIS_OPTIONS.SENTINEL$CLIENT_RECONFIG_SCRIPT, masterName, scriptPath);
return this;
}
public boolean isSentinel() {
return this.sentinelFile != null;
}
public boolean isCluster() {
return this.clusterFile != null;
}
public boolean isRandomDir() {
return this.randomDir;
}
@ -722,14 +832,32 @@ public class RedisRunner {
public boolean deleteDBfileDir() {
File f = new File(defaultDir);
if (f.exists()) {
System.out.println("REDIS RUNNER: Deleting directory " + defaultDir);
System.out.println("REDIS RUNNER: Deleting directory " + f.getAbsolutePath());
return f.delete();
}
return false;
}
public boolean deleteSentinelFile() {
File f = new File(defaultDir + File.pathSeparator + sentinelFile);
if (f.exists()) {
System.out.println("REDIS RUNNER: Deleting sentinel config file " + f.getAbsolutePath());
return f.delete();
}
return false;
}
public boolean deleteClusterFile() {
File f = new File(clusterFile);
if (f.exists()) {
System.out.println("REDIS RUNNER: Deleting cluster config file " + f.getAbsolutePath());
return f.delete();
}
return false;
}
private void makeRandomDefaultDir() {
File f = new File(RedissonRuntimeEnvironment.tempDir + "/" + UUID.randomUUID());
File f = new File(RedissonRuntimeEnvironment.tempDir + File.pathSeparator + UUID.randomUUID());
if (f.exists()) {
makeRandomDefaultDir();
} else {
@ -761,6 +889,12 @@ public class RedisRunner {
}
redisProcess.destroy();
int exitCode = redisProcess.isAlive() ? redisProcess.waitFor() : redisProcess.exitValue();
if (runner.isSentinel()) {
runner.deleteSentinelFile();
}
if (runner.isCluster()) {
runner.deleteClusterFile();
}
if (runner.isRandomDir()) {
runner.deleteDBfileDir();
}
@ -799,18 +933,16 @@ public class RedisRunner {
public String getRedisServerAddressAndPort() {
return getRedisServerBindAddress() + ":" + getRedisServerPort();
}
public boolean isAlive() {
return redisProcess.isAlive();
}
}
public static RedisRunner.RedisProcess startDefaultRedisServerInstance() throws IOException, InterruptedException, FailedToStartRedisException {
if (defaultRedisInstance == null) {
System.out.println("REDIS RUNNER: Starting up default instance...");
defaultRedisInstance = new RedisRunner().nosave().randomDir().randomPort().run();
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
try {
shutDownDefaultRedisServerInstance();
} catch (InterruptedException ex) {
}
}));
}
return defaultRedisInstance;
}
@ -853,12 +985,11 @@ public class RedisRunner {
socket = new ServerSocket(0);
socket.setReuseAddress(true);
int port = socket.getLocalPort();
try {
socket.close();
} catch (IOException e) {
// Ignore IOException on close()
if (port > 55535 && isFreePort(port - 10000)) {
return port - 10000;
} else {
return port;
}
return port;
} catch (IOException e) {
} finally {
if (socket != null) {
@ -871,9 +1002,27 @@ public class RedisRunner {
throw new IllegalStateException("Could not find a free TCP/IP port.");
}
public static boolean isFreePort(int port) {
ServerSocket socket = null;
try {
socket = new ServerSocket(port);
socket.setReuseAddress(true);
return true;
} catch (IOException e) {
} finally {
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
}
}
}
return false;
}
public static class FailedToStartRedisException extends RuntimeException {
private FailedToStartRedisException() {
public FailedToStartRedisException() {
}
}

@ -1,12 +1,23 @@
package org.redisson;
import com.fasterxml.jackson.core.type.TypeReference;
import static org.assertj.core.api.Assertions.assertThat;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.junit.Assert;
import org.junit.Test;
import org.redisson.api.RBucket;
import org.redisson.api.RMap;
import org.redisson.api.RedissonClient;
import org.redisson.client.codec.Codec;
import org.redisson.client.codec.JsonJacksonMapValueCodec;
import org.redisson.codec.AvroJacksonCodec;
import org.redisson.codec.CborJacksonCodec;
import org.redisson.codec.FstCodec;
import org.redisson.codec.JsonJacksonCodec;
@ -18,17 +29,11 @@ import org.redisson.codec.SmileJacksonCodec;
import org.redisson.codec.SnappyCodec;
import org.redisson.config.Config;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static org.assertj.core.api.Assertions.assertThat;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.dataformat.avro.AvroMapper;
import com.fasterxml.jackson.dataformat.avro.AvroSchema;
public class RedissonCodecTest extends BaseTest {
private Codec avroCodec = new SmileJacksonCodec();
private Codec smileCodec = new SmileJacksonCodec();
private Codec codec = new SerializationCodec();
private Codec kryoCodec = new KryoCodec();
@ -78,12 +83,19 @@ public class RedissonCodecTest extends BaseTest {
}
@Test
public void testAvro() {
public void testAvro() throws IOException {
AvroMapper am = new AvroMapper();
AvroSchema schema = am.schemaFor(TestObject.class);
Codec avroCodec = new AvroJacksonCodec(TestObject.class, schema);
Config config = createConfig();
config.setCodec(avroCodec);
RedissonClient redisson = Redisson.create(config);
test(redisson);
RBucket<TestObject> b = redisson.getBucket("bucket");
b.set(new TestObject("1", "2"));
assertThat(b.get()).isEqualTo(new TestObject("1", "2"));
}
@Test

@ -1,6 +1,7 @@
package org.redisson;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;
@ -11,6 +12,41 @@ import org.redisson.api.RQueue;
public class RedissonDelayedQueueTest extends BaseTest {
@Test
public void testRemove() throws InterruptedException {
RBlockingFairQueue<String> blockingFairQueue = redisson.getBlockingFairQueue("delay_queue");
RDelayedQueue<String> delayedQueue = redisson.getDelayedQueue(blockingFairQueue);
delayedQueue.offer("1_1_1", 3, TimeUnit.SECONDS);
delayedQueue.offer("1_1_2", 7, TimeUnit.SECONDS);
assertThat(delayedQueue.contains("1_1_1")).isTrue();
assertThat(delayedQueue.remove("1_1_1")).isTrue();
assertThat(delayedQueue.contains("1_1_1")).isFalse();
Thread.sleep(9000);
assertThat(blockingFairQueue).containsOnly("1_1_2");
}
@Test
public void testRemoveAll() throws InterruptedException {
RBlockingFairQueue<String> blockingFairQueue = redisson.getBlockingFairQueue("delay_queue");
RDelayedQueue<String> delayedQueue = redisson.getDelayedQueue(blockingFairQueue);
delayedQueue.offer("1_1_1", 3, TimeUnit.SECONDS);
delayedQueue.offer("1_1_2", 7, TimeUnit.SECONDS);
assertThat(delayedQueue.contains("1_1_1")).isTrue();
assertThat(delayedQueue.contains("1_1_2")).isTrue();
assertThat(delayedQueue.removeAll(Arrays.asList("1_1_1", "1_1_2"))).isTrue();
assertThat(delayedQueue.contains("1_1_1")).isFalse();
assertThat(delayedQueue.contains("1_1_2")).isFalse();
Thread.sleep(9000);
assertThat(blockingFairQueue.isEmpty()).isTrue();
}
@Test
public void testDealyedQueueRetainAll() {
RBlockingFairQueue<Integer> queue1 = redisson.getBlockingFairQueue("test");
@ -29,7 +65,6 @@ public class RedissonDelayedQueueTest extends BaseTest {
dealyedQueue.destroy();
}
@Test
public void testDealyedQueueReadAll() {
RBlockingFairQueue<Integer> queue1 = redisson.getBlockingFairQueue("test");

@ -18,10 +18,10 @@ import org.redisson.RedissonMapTest.SimpleKey;
import org.redisson.RedissonMapTest.SimpleValue;
import org.redisson.api.LocalCachedMapOptions;
import org.redisson.api.LocalCachedMapOptions.EvictionPolicy;
import org.redisson.cache.Cache;
import org.redisson.api.RLocalCachedMap;
import org.redisson.api.RMap;
import org.redisson.api.RedissonClient;
import org.redisson.misc.Cache;
import mockit.Deencapsulation;

@ -1,5 +1,6 @@
package org.redisson;
import static com.jayway.awaitility.Awaitility.await;
import static org.assertj.core.api.Assertions.assertThat;
import java.security.SecureRandom;
@ -16,6 +17,84 @@ import org.redisson.api.RReadWriteLock;
public class RedissonReadWriteLockTest extends BaseConcurrentTest {
@Test
public void testReadLockLeaseTimeoutDiffThreadsWRR() throws InterruptedException {
RLock writeLock = redisson.getReadWriteLock("my_read_write_lock").writeLock();
Assert.assertTrue(writeLock.tryLock(1, 10, TimeUnit.SECONDS));
final AtomicInteger executed = new AtomicInteger();
Thread t1 = new Thread(() -> {
RLock readLock = redisson.getReadWriteLock("my_read_write_lock").readLock();
readLock.lock();
executed.incrementAndGet();
});
Thread t2 = new Thread(() -> {
RLock readLock = redisson.getReadWriteLock("my_read_write_lock").readLock();
readLock.lock();
executed.incrementAndGet();
});
t1.start();
t2.start();
await().atMost(11, TimeUnit.SECONDS).until(() -> executed.get() == 2);
}
@Test
public void testReadLockLeaseTimeoutDiffThreadsRRW() throws InterruptedException {
new Thread(() -> {
RLock readLock = redisson.getReadWriteLock("my_read_write_lock").readLock();
try {
Assert.assertTrue(readLock.tryLock(1, 10, TimeUnit.SECONDS));
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
Thread.sleep(5000);
new Thread(() -> {
RLock readLock2 = redisson.getReadWriteLock("my_read_write_lock").readLock();
try {
Assert.assertTrue(readLock2.tryLock(1, 10, TimeUnit.SECONDS));
} catch (InterruptedException e) {
e.printStackTrace();
}
readLock2.unlock();
}).start();
final AtomicBoolean executed = new AtomicBoolean();
new Thread(() -> {
RLock writeLock = redisson.getReadWriteLock("my_read_write_lock").writeLock();
try {
boolean locked = writeLock.tryLock(10, 10, TimeUnit.SECONDS);
executed.set(locked);
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
await().atMost(6, TimeUnit.SECONDS).untilTrue(executed);
}
@Test
public void testReadLockLeaseTimeout() throws InterruptedException {
RLock readLock = redisson.getReadWriteLock("my_read_write_lock").readLock();
Assert.assertTrue(readLock.tryLock(1, 4, TimeUnit.SECONDS));
Thread.sleep(3000);
RLock readLock2 = redisson.getReadWriteLock("my_read_write_lock").readLock();
Assert.assertTrue(readLock2.tryLock(1, 4, TimeUnit.SECONDS));
readLock2.unlock();
Thread.sleep(2000);
RLock writeLock = redisson.getReadWriteLock("my_read_write_lock").writeLock();
Assert.assertTrue(writeLock.tryLock());
}
@Test
public void testWriteReadReentrancy() throws InterruptedException {
RReadWriteLock readWriteLock = redisson.getReadWriteLock("TEST");

@ -1,7 +1,5 @@
package org.redisson;
import static org.assertj.core.api.Assertions.assertThat;
import java.io.IOException;
import java.io.NotSerializableException;
import java.io.Serializable;
@ -133,7 +131,7 @@ public class RedissonRemoteServiceTest extends BaseTest {
}
public class RemoteImpl implements RemoteInterface {
public static class RemoteImpl implements RemoteInterface {
private AtomicInteger iterations;

@ -5,6 +5,8 @@ import static org.assertj.core.api.Assertions.assertThat;
import java.util.concurrent.TimeUnit;
import org.junit.Test;
import org.redisson.cache.Cache;
import org.redisson.cache.LFUCacheMap;
public class LFUCacheMapTest {

@ -5,6 +5,8 @@ import static org.assertj.core.api.Assertions.*;
import java.util.concurrent.TimeUnit;
import org.junit.Test;
import org.redisson.cache.Cache;
import org.redisson.cache.LRUCacheMap;
public class LRUCacheMapTest {

@ -1,10 +1,15 @@
package org.redisson.misc;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertEquals;
import java.util.ArrayList;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import org.junit.Test;
import org.redisson.cache.Cache;
import org.redisson.cache.NoneCacheMap;
public class NoneCacheMapTest {

@ -0,0 +1,68 @@
package org.redisson.misc;
import org.junit.Test;
import org.redisson.cache.Cache;
import org.redisson.cache.SoftCacheMap;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import static org.assertj.core.api.Assertions.assertThat;
public class SoftCacheMapTest {
@Test
public void testMaxIdleTimeEviction() throws InterruptedException {
Cache<Integer, Integer> map = new SoftCacheMap<Integer, Integer>(0, 0);
map.put(1, 0, 0, TimeUnit.MILLISECONDS, 400, TimeUnit.MILLISECONDS);
assertThat(map.get(1)).isEqualTo(0);
Thread.sleep(200);
assertThat(map.get(1)).isEqualTo(0);
Thread.sleep(200);
assertThat(map.get(1)).isEqualTo(0);
Thread.sleep(200);
assertThat(map.get(1)).isEqualTo(0);
Thread.sleep(410);
assertThat(map.keySet()).isEmpty();
}
@Test
public void testTTLEviction() throws InterruptedException {
Cache<Integer, Integer> map = new SoftCacheMap<Integer, Integer>(0, 0);
map.put(1, 0, 500, TimeUnit.MILLISECONDS, 0, TimeUnit.MILLISECONDS);
assertThat(map.get(1)).isEqualTo(0);
Thread.sleep(100);
assertThat(map.get(1)).isEqualTo(0);
assertThat(map.keySet()).containsOnly(1);
Thread.sleep(500);
assertThat(map.keySet()).isEmpty();
}
@Test
public void testSizeEviction() {
Cache<Integer, Integer> map = new SoftCacheMap<Integer, Integer>(0, 0);
map.put(1, 0);
map.put(2, 0);
assertThat(map.keySet()).containsOnly(1, 2);
map.put(3, 0);
map.put(4, 0);
assertThat(map.keySet()).containsOnly(1, 2, 3, 4);
}
// This test requires using -XX:SoftRefLRUPolicyMSPerMB=0 to pass
@Test
public void testSoftReferences() {
Cache<Integer, Integer> map = new SoftCacheMap<Integer, Integer>(0, 0);
for(int i=0;i<100000;i++) {
map.put(i, new Integer(i));
}
assertThat(map.values().stream().filter(Objects::nonNull).count()).isEqualTo(100000);
System.gc();
assertThat(map.values().stream().filter(Objects::nonNull).count()).isZero();
assertThat(map.values().size()).isZero();
}
}

@ -0,0 +1,282 @@
package org.redisson.spring.support;
import java.util.Arrays;
import java.util.Collection;
import org.junit.After;
import org.junit.AfterClass;
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameter;
import org.junit.runners.Parameterized.Parameters;
import org.redisson.BaseTest;
import org.redisson.RedisRunner;
import org.redisson.RedissonFairLock;
import org.redisson.RedissonLiveObjectServiceTest.TestREntity;
import org.redisson.RedissonMultiLock;
import org.redisson.RedissonReadLock;
import org.redisson.RedissonRedLock;
import org.redisson.RedissonRuntimeEnvironment;
import org.redisson.RedissonWriteLock;
import org.redisson.api.LocalCachedMapOptions;
import org.redisson.api.RAtomicDouble;
import org.redisson.api.RAtomicLong;
import org.redisson.api.RBinaryStream;
import org.redisson.api.RBitSet;
import org.redisson.api.RBlockingDeque;
import org.redisson.api.RBlockingFairQueue;
import org.redisson.api.RBlockingQueue;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RBoundedBlockingQueue;
import org.redisson.api.RBucket;
import org.redisson.api.RBuckets;
import org.redisson.api.RCountDownLatch;
import org.redisson.api.RDelayedQueue;
import org.redisson.api.RDeque;
import org.redisson.api.RExecutorService;
import org.redisson.api.RGeo;
import org.redisson.api.RHyperLogLog;
import org.redisson.api.RKeys;
import org.redisson.api.RLexSortedSet;
import org.redisson.api.RList;
import org.redisson.api.RListMultimap;
import org.redisson.api.RLiveObject;
import org.redisson.api.RLiveObjectService;
import org.redisson.api.RLocalCachedMap;
import org.redisson.api.RLock;
import org.redisson.api.RMap;
import org.redisson.api.RMapCache;
import org.redisson.api.RObject;
import org.redisson.api.RPatternTopic;
import org.redisson.api.RPermitExpirableSemaphore;
import org.redisson.api.RPriorityDeque;
import org.redisson.api.RPriorityQueue;
import org.redisson.api.RQueue;
import org.redisson.api.RReadWriteLock;
import org.redisson.api.RRemoteService;
import org.redisson.api.RScoredSortedSet;
import org.redisson.api.RScript;
import org.redisson.api.RSemaphore;
import org.redisson.api.RSet;
import org.redisson.api.RSetCache;
import org.redisson.api.RSetMultimap;
import org.redisson.api.RSetMultimapCache;
import org.redisson.api.RSortedSet;
import org.redisson.api.RTopic;
import org.redisson.api.RemoteInvocationOptions;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
*
* @author Rui Gu (https://github.com/jackygurui)
*/
@RunWith(Parameterized.class)
public class SpringNamespaceObjectTest extends BaseTest {
private static ApplicationContext context;
@BeforeClass
public static void setupClass() throws Exception {
if (!RedissonRuntimeEnvironment.isTravis) {
startContext();
}
}
@AfterClass
public static void shutDownClass() {
if (!RedissonRuntimeEnvironment.isTravis) {
stopContext();
}
}
@Before
public void setup() throws Exception {
if (RedissonRuntimeEnvironment.isTravis) {
startContext();
}
}
@After
public void shutDown() {
if (RedissonRuntimeEnvironment.isTravis) {
stopContext();
}
}
@Override
protected boolean flushBetweenTests() {
return false;
}
public static void startContext() {
TestREntity entity = new TestREntity("live-object");
entity.setValue("1");
defaultRedisson.getLiveObjectService().merge(entity);
entity = new TestREntity("live-object-ext");
entity.setValue("1");
defaultRedisson.getLiveObjectService().merge(entity);
System.setProperty("redisAddress", RedisRunner.getDefaultRedisServerBindAddressAndPort());
context = new ClassPathXmlApplicationContext("classpath:org/redisson/spring/support/redisson_objects.xml");
}
public static void stopContext() {
((ConfigurableApplicationContext) context).close();
}
@Parameters(name = "{index}: key=[{0}], class=[{1}], parent=[{2}]")
public static Collection<Object[]> tests() {
return Arrays.asList(new Object[][]{
{"binary-stream", RBinaryStream.class, null},
{"geo", RGeo.class, null},
{"set-cache", RSetCache.class, null},
{"map-cache", RMapCache.class, null},
{"bucket", RBucket.class, null},
{"buckets", RBuckets.class, null},
{"hyper-log-log", RHyperLogLog.class, null},
{"list", RList.class, null},
{"list-multimap", RListMultimap.class, null},
{"local-cached-map", RLocalCachedMap.class, null},
{"local-options", LocalCachedMapOptions.class, null},
{"map", RMap.class, null},
{"set-multimap", RSetMultimap.class, null},
{"set-multimap-cache", RSetMultimapCache.class, null},
{"semaphore", RSemaphore.class, null},
{"permit-expirable-semaphore", RPermitExpirableSemaphore.class, null},
{"lock", RLock.class, null},
{"fair-lock", RedissonFairLock.class, null},
{"read-write-lock", RReadWriteLock.class, null},
{"read-lock", RedissonReadLock.class, "read-write-lock"},
{"write-lock", RedissonWriteLock.class, "read-write-lock"},
{"multi-lock", RedissonMultiLock.class, null},
{"lock-1", RLock.class, null},
{"fair-lock-1", RedissonFairLock.class, null},
{"read-lock-1", RedissonReadLock.class, "read-write-lock"},
{"write-lock-1", RedissonWriteLock.class, "read-write-lock"},
{"red-lock", RedissonRedLock.class, null},
{"lock-2", RLock.class, null},
{"fair-lock-2", RedissonFairLock.class, null},
{"read-lock-2", RedissonReadLock.class, "read-write-lock"},
{"write-lock-2", RedissonWriteLock.class, "read-write-lock"},
{"set", RSet.class, null},
{"sorted-set", RSortedSet.class, null},
{"scored-sorted-set", RScoredSortedSet.class, null},
{"lex-sorted-set", RLexSortedSet.class, null},
{"topic", RTopic.class, null},
{"pattern-topic", RPatternTopic.class, null},
{"blocking-fair-queue", RBlockingFairQueue.class, null},
{"queue", RQueue.class, null},
{"delayed-queue", RDelayedQueue.class, "queue"},
{"priority-queue", RPriorityQueue.class, null},
{"priority-deque", RPriorityDeque.class, null},
{"blocking-queue", RBlockingQueue.class, null},
{"bounded-blocking-queue", RBoundedBlockingQueue.class, null},
{"deque", RDeque.class, null},
{"blocking-deque", RBlockingDeque.class, null},
{"atomic-long", RAtomicLong.class, null},
{"atomic-double", RAtomicDouble.class, null},
{"count-down-latch", RCountDownLatch.class, null},
{"bit-set", RBitSet.class, null},
{"bloom-filter", RBloomFilter.class, null},
{"script", RScript.class, null},
{"executor-service", RExecutorService.class, null},
{"remote-service", RRemoteService.class, null},
{"rpc-client", org.redisson.RedissonRemoteServiceTest.RemoteInterface.class, null},
{"options", RemoteInvocationOptions.class, null},
{"keys", RKeys.class, null},
{"live-object-service", RLiveObjectService.class, null},
{"live-object", RLiveObject.class, null},
{"binary-stream-ext", RBinaryStream.class, null},
{"geo-ext", RGeo.class, null},
{"set-cache-ext", RSetCache.class, null},
{"map-cache-ext", RMapCache.class, null},
{"bucket-ext", RBucket.class, null},
{"buckets-ext", RBuckets.class, null},
{"hyper-log-log-ext", RHyperLogLog.class, null},
{"list-ext", RList.class, null},
{"list-multimap-ext", RListMultimap.class, null},
{"local-cached-map-ext", RLocalCachedMap.class, null},
{"local-options-ext", LocalCachedMapOptions.class, null},
{"map-ext", RMap.class, null},
{"set-multimap-ext", RSetMultimap.class, null},
{"set-multimap-cache-ext", RSetMultimapCache.class, null},
{"semaphore-ext", RSemaphore.class, null},
{"permit-expirable-semaphore-ext", RPermitExpirableSemaphore.class, null},
{"lock-ext", RLock.class, null},
{"fair-lock-ext", RedissonFairLock.class, null},
{"read-write-lock-ext", RReadWriteLock.class, null},
{"read-lock-ext", RedissonReadLock.class, "read-write-lock-ext"},
{"write-lock-ext", RedissonWriteLock.class, "read-write-lock-ext"},
{"multi-lock-ext", RedissonMultiLock.class, null},
{"lock-1-ext", RLock.class, null},
{"fair-lock-1-ext", RedissonFairLock.class, null},
{"read-lock-1-ext", RedissonReadLock.class, "read-write-lock-ext"},
{"write-lock-1-ext", RedissonWriteLock.class, "read-write-lock-ext"},
{"red-lock-ext", RedissonRedLock.class, null},
{"lock-2-ext", RLock.class, null},
{"fair-lock-2-ext", RedissonFairLock.class, null},
{"read-lock-2-ext", RedissonReadLock.class, "read-write-lock-ext"},
{"write-lock-2-ext", RedissonWriteLock.class, "read-write-lock-ext"},
{"set-ext", RSet.class, null},
{"sorted-set-ext", RSortedSet.class, null},
{"scored-sorted-set-ext", RScoredSortedSet.class, null},
{"lex-sorted-set-ext", RLexSortedSet.class, null},
{"topic-ext", RTopic.class, null},
{"pattern-topic-ext", RPatternTopic.class, null},
{"blocking-fair-queue-ext", RBlockingFairQueue.class, null},
{"queue-ext", RQueue.class, null},
{"delayed-queue-ext", RDelayedQueue.class, "queue-ext"},
{"priority-queue-ext", RPriorityQueue.class, null},
{"priority-deque-ext", RPriorityDeque.class, null},
{"blocking-queue-ext", RBlockingQueue.class, null},
{"bounded-blocking-queue-ext", RBoundedBlockingQueue.class, null},
{"deque-ext", RDeque.class, null},
{"blocking-deque-ext", RBlockingDeque.class, null},
{"atomic-long-ext", RAtomicLong.class, null},
{"atomic-double-ext", RAtomicDouble.class, null},
{"count-down-latch-ext", RCountDownLatch.class, null},
{"bit-set-ext", RBitSet.class, null},
{"bloom-filter-ext", RBloomFilter.class, null},
{"script-ext", RScript.class, null},
{"executor-service-ext", RExecutorService.class, null},
{"remote-service-ext", RRemoteService.class, null},
{"rpc-client-ext", org.redisson.RedissonRemoteServiceTest.RemoteInterface.class, null},
{"options-ext", RemoteInvocationOptions.class, null},
{"keys-ext", RKeys.class, null},
{"live-object-service-ext", RLiveObjectService.class, null},
{"live-object-ext", RLiveObject.class, null},
});
}
@Parameter
public String key;
@Parameter(1)
public Class cls;
@Parameter(2)
public String parentKey;
@Test
public void testRObjects() {
Object bean = context.getBean(key);
assertTrue(cls.isInstance(bean));
if (RObject.class.isAssignableFrom(cls)) {
assertEquals(parentKey == null ? key : parentKey, RObject.class.cast(bean).getName());
}
if (RTopic.class.isAssignableFrom(cls)) {
assertEquals(key, RTopic.class.cast(bean).getChannelNames().get(0));
}
if (RPatternTopic.class.isAssignableFrom(cls)) {
assertEquals(key, RPatternTopic.class.cast(bean).getPatternNames().get(0));
}
if (RLiveObject.class.isAssignableFrom(cls)) {
assertEquals(key, RLiveObject.class.cast(bean).getLiveObjectId());
}
}
}

@ -0,0 +1,368 @@
package org.redisson.spring.support;
import java.util.List;
import org.junit.After;
import org.junit.AfterClass;
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.redisson.BaseTest;
import org.redisson.ClusterRunner;
import org.redisson.RedisRunner;
import org.redisson.Redisson;
import org.redisson.RedissonRuntimeEnvironment;
import org.redisson.api.RedissonClient;
import org.redisson.client.RedisClient;
import org.redisson.client.RedisConnection;
import org.redisson.codec.MsgPackJacksonCodec;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
*
* @author Rui Gu (https://github.com/jackygurui)
*/
public class SpringNamespaceTest extends BaseTest {
private static ApplicationContext context;
@BeforeClass
public static void setupClass() throws Exception {
if (!RedissonRuntimeEnvironment.isTravis) {
startContext();
}
}
@AfterClass
public static void shutDownClass() throws Exception {
if (!RedissonRuntimeEnvironment.isTravis) {
stopContext();
}
}
@Before
public void setup() throws Exception {
if (RedissonRuntimeEnvironment.isTravis) {
startContext();
}
}
@After
public void shutDown() throws Exception {
if (RedissonRuntimeEnvironment.isTravis) {
stopContext();
}
}
public static void startContext() throws Exception {
System.setProperty("redisAddress", RedisRunner.getDefaultRedisServerBindAddressAndPort());
//Needs a instance running on the default port, launch it if there isn't one already
if (RedisRunner.isFreePort(6379)) {
new RedisRunner()
.nosave()
.randomDir()
.run();
}
RedisRunner.RedisProcess slave1 = new RedisRunner()
.nosave()
.randomDir()
.randomPort()
.slaveof(
RedisRunner.getDefaultRedisServerInstance().getRedisServerBindAddress(),
RedisRunner.getDefaultRedisServerInstance().getRedisServerPort())
.run();
System.setProperty("slave1Address", slave1.getRedisServerAddressAndPort());
RedisRunner.RedisProcess slave2 = new RedisRunner()
.nosave()
.randomDir()
.randomPort()
.slaveof(
RedisRunner.getDefaultRedisServerInstance().getRedisServerBindAddress(),
RedisRunner.getDefaultRedisServerInstance().getRedisServerPort())
.run();
System.setProperty("slave2Address", slave2.getRedisServerAddressAndPort());
RedisRunner.RedisProcess sentinel1 = new RedisRunner()
.nosave()
.randomDir()
.randomPort()
.sentinel()
.sentinelMonitor(
"myMaster",
RedisRunner.getDefaultRedisServerInstance().getRedisServerBindAddress(),
RedisRunner.getDefaultRedisServerInstance().getRedisServerPort(),
2).run();
System.setProperty("sentinel1Address", sentinel1.getRedisServerAddressAndPort());
RedisRunner.RedisProcess sentinel2 = new RedisRunner()
.nosave()
.randomDir()
.randomPort()
.sentinel()
.sentinelMonitor(
"myMaster",
RedisRunner.getDefaultRedisServerInstance().getRedisServerBindAddress(),
RedisRunner.getDefaultRedisServerInstance().getRedisServerPort(),
2).run();
System.setProperty("sentinel2Address", sentinel2.getRedisServerAddressAndPort());
RedisRunner.RedisProcess sentinel3 = new RedisRunner()
.nosave()
.randomDir()
.randomPort()
.sentinel()
.sentinelMonitor(
"myMaster",
RedisRunner.getDefaultRedisServerInstance().getRedisServerBindAddress(),
RedisRunner.getDefaultRedisServerInstance().getRedisServerPort(),
2).run();
System.setProperty("sentinel3Address", sentinel3.getRedisServerAddressAndPort());
ClusterRunner clusterRunner = new ClusterRunner()
.addNode(new RedisRunner().randomPort().randomDir().nosave())
.addNode(new RedisRunner().randomPort().randomDir().nosave())
.addNode(new RedisRunner().randomPort().randomDir().nosave());
List<RedisRunner.RedisProcess> nodes = clusterRunner.run();
nodes.stream().forEach((node) -> {
System.setProperty("node" + (nodes.indexOf(node) + 1) + "Address", node.getRedisServerAddressAndPort());
});
context = new ClassPathXmlApplicationContext("classpath:org/redisson/spring/support/namespace.xml");
}
public static void stopContext() throws Exception {
((ConfigurableApplicationContext) context).close();
}
public static class AutowireRedisson {
@Autowired
@Qualifier("redisson1")
private Redisson redisson1;
@Autowired
@Qualifier("redisson2")
private RedissonClient redisson2;
@Autowired
@Qualifier("redisson3")
private Redisson redisson3;
@Autowired
@Qualifier("redisson4")
private RedissonClient redisson4;
@Autowired
@Qualifier("myRedisson1")
private Redisson redisson5;
@Autowired
@Qualifier("myRedisson2")
private Redisson redisson6;
@Autowired
@Qualifier("qualifier1")
private RedissonClient redisson7;
@Autowired
@Qualifier("qualifier2")
private RedissonClient redisson8;
/**
* @return the redisson1
*/
public Redisson getRedisson1() {
return redisson1;
}
/**
* @param redisson1 the redisson1 to set
*/
public void setRedisson1(Redisson redisson1) {
this.redisson1 = redisson1;
}
/**
* @return the redisson2
*/
public RedissonClient getRedisson2() {
return redisson2;
}
/**
* @param redisson2 the redisson2 to set
*/
public void setRedisson2(RedissonClient redisson2) {
this.redisson2 = redisson2;
}
/**
* @return the redisson3
*/
public Redisson getRedisson3() {
return redisson3;
}
/**
* @param redisson3 the redisson3 to set
*/
public void setRedisson3(Redisson redisson3) {
this.redisson3 = redisson3;
}
/**
* @return the redisson4
*/
public RedissonClient getRedisson4() {
return redisson4;
}
/**
* @param redisson4 the redisson4 to set
*/
public void setRedisson4(RedissonClient redisson4) {
this.redisson4 = redisson4;
}
/**
* @return the redisson5
*/
public Redisson getRedisson5() {
return redisson5;
}
/**
* @param redisson5 the redisson5 to set
*/
public void setRedisson5(Redisson redisson5) {
this.redisson5 = redisson5;
}
/**
* @return the redisson6
*/
public Redisson getRedisson6() {
return redisson6;
}
/**
* @param redisson6 the redisson6 to set
*/
public void setRedisson6(Redisson redisson6) {
this.redisson6 = redisson6;
}
/**
* @return the redisson7
*/
public RedissonClient getRedisson7() {
return redisson7;
}
/**
* @param redisson7 the redisson7 to set
*/
public void setRedisson7(RedissonClient redisson7) {
this.redisson7 = redisson7;
}
/**
* @return the redisson8
*/
public RedissonClient getRedisson8() {
return redisson8;
}
/**
* @param redisson8 the redisson8 to set
*/
public void setRedisson8(RedissonClient redisson8) {
this.redisson8 = redisson8;
}
}
@Test
public void testNamespace() {
Object bean = context.getBean("myRedisson1");
assertTrue(bean instanceof Redisson);
}
@Test
public void testAlias() {
Object origin = context.getBean("myRedisson1");
assertTrue(origin instanceof Redisson);
Object bean = context.getBean("redisson1");
assertTrue(bean instanceof Redisson);
assertEquals(origin, bean);
bean = context.getBean("redisson2");
assertTrue(bean instanceof Redisson);
assertEquals(origin, bean);
}
@Test
public void testAutowire() {
AutowireRedisson bean = context.getAutowireCapableBeanFactory().getBean(AutowireRedisson.class);
assertNotNull(bean.getRedisson1());
assertNotNull(bean.getRedisson2());
assertNotNull(bean.getRedisson3());
assertNotNull(bean.getRedisson4());
assertNotNull(bean.getRedisson5());
assertNotNull(bean.getRedisson6());
assertNotNull(bean.getRedisson7());
assertNotNull(bean.getRedisson8());
assertEquals(bean.getRedisson1(), bean.getRedisson2());
assertEquals(bean.getRedisson1(), bean.getRedisson5());
assertNotEquals(bean.getRedisson1(), bean.getRedisson7());
assertNotEquals(bean.getRedisson1(), bean.getRedisson8());
assertEquals(bean.getRedisson3(), bean.getRedisson4());
assertEquals(bean.getRedisson3(), bean.getRedisson6());
assertNotEquals(bean.getRedisson3(), bean.getRedisson7());
assertNotEquals(bean.getRedisson3(), bean.getRedisson8());
assertNotEquals(bean.getRedisson7(), bean.getRedisson8());
}
@Test
public void testBeanRef() {
AutowireRedisson bean = context.getAutowireCapableBeanFactory().getBean(AutowireRedisson.class);
assertTrue(bean.getRedisson1().getConfig().getCodec() instanceof MsgPackJacksonCodec);
assertFalse(bean.getRedisson3().getConfig().getCodec() instanceof MsgPackJacksonCodec);
assertFalse(bean.getRedisson7().getConfig().getCodec() instanceof MsgPackJacksonCodec);
assertFalse(bean.getRedisson8().getConfig().getCodec() instanceof MsgPackJacksonCodec);
}
public static class AutowireRedis {
@Autowired
private RedisClient redisClient;
/**
* @return the redisClient
*/
public RedisClient getRedisClient() {
return redisClient;
}
/**
* @param redisClient the redisClient to set
*/
public void setRedisClient(RedisClient redisClient) {
this.redisClient = redisClient;
}
}
@Test
public void testAutowireRedis() {
AutowireRedis bean = context.getAutowireCapableBeanFactory().getBean(AutowireRedis.class);
RedisConnection connection = bean.getRedisClient().connect();
assertTrue(connection.isActive());
connection.closeAsync().awaitUninterruptibly();
}
}

@ -0,0 +1,195 @@
package org.redisson.spring.support;
import java.io.IOException;
import java.util.List;
import org.junit.Test;
import org.redisson.ClusterRunner;
import org.redisson.RedisRunner;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
*
* @author Rui Gu (https://github.com/jackygurui)
*/
public class SpringNamespaceWikiTest {
@Test
public void testSingle() throws Exception {
RedisRunner.RedisProcess run = new RedisRunner()
.requirepass("do_not_use_if_it_is_not_set")
.nosave()
.randomDir()
.run();
try {
((ConfigurableApplicationContext)
new ClassPathXmlApplicationContext("classpath:org/redisson/spring/support/namespace_wiki_single.xml"))
.close();
} finally {
run.stop();
}
}
@Test
public void testMasterSlave() throws Exception {
RedisRunner.RedisProcess master = new RedisRunner()
.requirepass("do_not_use_if_it_is_not_set")
.nosave()
.randomDir()
.run();
RedisRunner.RedisProcess slave1 = new RedisRunner()
.requirepass("do_not_use_if_it_is_not_set")
.masterauth("do_not_use_if_it_is_not_set")
.port(6380)
.nosave()
.randomDir()
.slaveof("127.0.0.1", 6379)
.run();
RedisRunner.RedisProcess slave2 = new RedisRunner()
.requirepass("do_not_use_if_it_is_not_set")
.masterauth("do_not_use_if_it_is_not_set")
.port(6381)
.nosave()
.randomDir()
.slaveof("127.0.0.1", 6379)
.run();
try {
((ConfigurableApplicationContext)
new ClassPathXmlApplicationContext("classpath:org/redisson/spring/support/namespace_wiki_master_slave.xml"))
.close();
} finally {
master.stop();
slave1.stop();
slave2.stop();
}
}
@Test
public void testSentinel() throws Exception {
RedisRunner.RedisProcess master = new RedisRunner()
.requirepass("do_not_use_if_it_is_not_set")
.nosave()
.randomDir()
.run();
RedisRunner.RedisProcess slave1 = new RedisRunner()
.requirepass("do_not_use_if_it_is_not_set")
.masterauth("do_not_use_if_it_is_not_set")
.port(6380)
.nosave()
.randomDir()
.slaveof("127.0.0.1", 6379)
.run();
RedisRunner.RedisProcess slave2 = new RedisRunner()
.requirepass("do_not_use_if_it_is_not_set")
.masterauth("do_not_use_if_it_is_not_set")
.port(6381)
.nosave()
.randomDir()
.slaveof("127.0.0.1", 6379)
.run();
RedisRunner.RedisProcess sentinel1 = new RedisRunner()
// .requirepass("do_not_use_if_it_is_not_set")
.nosave()
.randomDir()
.port(26379)
.sentinel()
.sentinelMonitor("myMaster", "127.0.0.1", 6379, 2)
.sentinelAuthPass("myMaster", "do_not_use_if_it_is_not_set")
.run();
RedisRunner.RedisProcess sentinel2 = new RedisRunner()
// .requirepass("do_not_use_if_it_is_not_set")
.nosave()
.randomDir()
.port(26380)
.sentinel()
.sentinelMonitor("myMaster", "127.0.0.1", 6379, 2)
.sentinelAuthPass("myMaster", "do_not_use_if_it_is_not_set")
.run();
RedisRunner.RedisProcess sentinel3 = new RedisRunner()
// .requirepass("do_not_use_if_it_is_not_set")
.nosave()
.randomDir()
.port(26381)
.sentinel()
.sentinelMonitor("myMaster", "127.0.0.1", 6379, 2)
.sentinelAuthPass("myMaster", "do_not_use_if_it_is_not_set")
.run();
try {
((ConfigurableApplicationContext)
new ClassPathXmlApplicationContext("classpath:org/redisson/spring/support/namespace_wiki_sentinel.xml"))
.close();
} finally {
master.stop();
slave1.stop();
slave2.stop();
sentinel1.stop();
sentinel2.stop();
sentinel3.stop();
}
}
@Test
public void testReplicated() throws Exception {
RedisRunner.RedisProcess master = new RedisRunner()
.requirepass("do_not_use_if_it_is_not_set")
.nosave()
.randomDir()
.run();
RedisRunner.RedisProcess slave1 = new RedisRunner()
.requirepass("do_not_use_if_it_is_not_set")
.masterauth("do_not_use_if_it_is_not_set")
.port(6380)
.nosave()
.randomDir()
.slaveof("127.0.0.1", 6379)
.run();
RedisRunner.RedisProcess slave2 = new RedisRunner()
.requirepass("do_not_use_if_it_is_not_set")
.masterauth("do_not_use_if_it_is_not_set")
.port(6381)
.nosave()
.randomDir()
.slaveof("127.0.0.1", 6379)
.run();
try {
((ConfigurableApplicationContext)
new ClassPathXmlApplicationContext("classpath:org/redisson/spring/support/namespace_wiki_replicated.xml"))
.close();
} finally {
master.stop();
slave1.stop();
slave2.stop();
}
}
@Test
public void testCluster() throws Exception {
ClusterRunner clusterRunner = new ClusterRunner()
.addNode(new RedisRunner()
.requirepass("do_not_use_if_it_is_not_set")
.port(6379)
.randomDir()
.nosave())
.addNode(new RedisRunner()
.requirepass("do_not_use_if_it_is_not_set")
.port(6380)
.randomDir()
.nosave())
.addNode(new RedisRunner()
.requirepass("do_not_use_if_it_is_not_set")
.port(6381)
.randomDir()
.nosave());
List<RedisRunner.RedisProcess> nodes = clusterRunner.run();
try {
((ConfigurableApplicationContext)
new ClassPathXmlApplicationContext("classpath:org/redisson/spring/support/namespace_wiki_cluster.xml"))
.close();
} finally {
for (RedisRunner.RedisProcess node : nodes) {
node.stop();
}
}
}
}

@ -0,0 +1,77 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:redisson="http://redisson.org/schema/redisson"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://redisson.org/schema/redisson classpath:org/redisson/spring/support/redisson-1.0.xsd
">
<context:annotation-config />
<context:property-placeholder system-properties-mode="OVERRIDE"/>
<redisson:client id="myRedisson1" name="redisson1,redisson2" codec-ref="myCodec" >
<redisson:single-server address="${redisAddress}" client-name="1"/>
</redisson:client>
<redisson:client id="myRedisson2" name="redisson3,redisson4">
<redisson:single-server address="${redisAddress}" client-name="2"/>
</redisson:client>
<redisson:client>
<qualifier value="qualifier1"/>
<redisson:single-server address="${redisAddress}" client-name="3"/>
</redisson:client>
<redisson:client>
<qualifier value="qualifier2"/>
<redisson:single-server address="${redisAddress}" client-name="4"/>
</redisson:client>
<!-- Minimal requirement for redisson client-->
<redisson:client>
<!-- Use default address "127.0.0.1:6379" -->
<redisson:single-server />
</redisson:client>
<redisson:client>
<redisson:sentinel-servers master-name="myMaster">
<redisson:sentinel-address value="${sentinel1Address}" />
<redisson:sentinel-address value="${sentinel2Address}" />
<redisson:sentinel-address value="${sentinel3Address}" />
</redisson:sentinel-servers>
</redisson:client>
<redisson:client>
<redisson:master-slave-servers master-address="${redisAddress}">
<redisson:slave-address value="${slave1Address}" />
<redisson:slave-address value="${slave2Address}" />
</redisson:master-slave-servers>
</redisson:client>
<redisson:client>
<redisson:cluster-servers>
<redisson:node-address value="${node1Address}" />
<redisson:node-address value="${node2Address}" />
<redisson:node-address value="${node3Address}" />
</redisson:cluster-servers>
</redisson:client>
<redisson:client>
<redisson:replicated-servers read-mode="MASTER_SLAVE" >
<redisson:node-address value="${redisAddress}" />
<redisson:node-address value="${slave1Address}" />
<redisson:node-address value="${slave2Address}" />
</redisson:replicated-servers>
</redisson:client>
<!-- Minimal requirement for redis client-->
<!-- Use default host 127.0.0.1 and port 6379 -->
<redisson:redis />
<bean id="myCodec" class="org.redisson.codec.MsgPackJacksonCodec" />
<bean class="org.redisson.spring.support.SpringNamespaceTest.AutowireRedisson" />
<bean class="org.redisson.spring.support.SpringNamespaceTest.AutowireRedis" />
</beans>

@ -0,0 +1,70 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:redisson="http://redisson.org/schema/redisson"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://redisson.org/schema/redisson classpath:org/redisson/spring/support/redisson-1.0.xsd
">
<bean id="myCodec" class="org.redisson.codec.MsgPackJacksonCodec"/>
<bean id="myCodecProvider" class="org.redisson.codec.DefaultCodecProvider"/>
<bean id="myResolverProvider" class="org.redisson.liveobject.provider.DefaultResolverProvider"/>
<bean id="myExecutor" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="staticMethod" value="java.util.concurrent.Executors.newFixedThreadPool"/>
<property name="arguments" value="8"/>
</bean>
<bean id="myEventLoopGroup" class="io.netty.channel.nio.NioEventLoopGroup"/>
<bean id="myLoadBalancer" class="org.redisson.connection.balancer.RoundRobinLoadBalancer"/>
<redisson:client
id="redisson"
name="redisson1,redisson2"
threads="0"
netty-threads="0"
codec-ref="myCodec"
use-linux-native-epoll="false"
redisson-reference-enabled="true"
codec-provider-ref="myCodecProvider"
resolver-provider-ref="myResolverProvider"
executor-ref="myExecutor"
event-loop-group-ref="myEventLoopGroup"
>
<!--
You can't have both name attribute and qualifier element at
the same time.
Both id attribute and name attribute can be used as qualifier
candidates.
-->
<!--<qualifier value="redisson3"/>-->
<redisson:cluster-servers
idle-connection-timeout="10000"
ping-timeout="1000"
connect-timeout="10000"
timeout="3000"
retry-attempts="3"
retry-interval="1500"
reconnection-timeout="3000"
failed-attempts="3"
password="do_not_use_if_it_is_not_set"
subscriptions-per-connection="5"
client-name="none"
load-balancer-ref="myLoadBalancer"
subscription-connection-minimum-idle-size="1"
subscription-connection-pool-size="50"
slave-connection-minimum-idle-size="10"
slave-connection-pool-size="64"
master-connection-minimum-idle-size="10"
master-connection-pool-size="64"
read-mode="SLAVE"
subscription-mode="SLAVE"
scan-interval="1000"
>
<redisson:node-address value="127.0.0.1:6379" />
<redisson:node-address value="127.0.0.1:6380" />
<redisson:node-address value="127.0.0.1:6381" />
</redisson:cluster-servers>
</redisson:client>
</beans>

@ -0,0 +1,70 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:redisson="http://redisson.org/schema/redisson"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://redisson.org/schema/redisson classpath:org/redisson/spring/support/redisson-1.0.xsd
">
<bean id="myCodec" class="org.redisson.codec.MsgPackJacksonCodec"/>
<bean id="myCodecProvider" class="org.redisson.codec.DefaultCodecProvider"/>
<bean id="myResolverProvider" class="org.redisson.liveobject.provider.DefaultResolverProvider"/>
<bean id="myExecutor" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="staticMethod" value="java.util.concurrent.Executors.newFixedThreadPool"/>
<property name="arguments" value="8"/>
</bean>
<bean id="myEventLoopGroup" class="io.netty.channel.nio.NioEventLoopGroup"/>
<bean id="myLoadBalancer" class="org.redisson.connection.balancer.RoundRobinLoadBalancer"/>
<redisson:client
id="redisson"
name="redisson1,redisson2"
threads="0"
netty-threads="0"
codec-ref="myCodec"
use-linux-native-epoll="false"
redisson-reference-enabled="true"
codec-provider-ref="myCodecProvider"
resolver-provider-ref="myResolverProvider"
executor-ref="myExecutor"
event-loop-group-ref="myEventLoopGroup"
>
<!--
You can't have both name attribute and qualifier element at
the same time.
Both id attribute and name attribute can be used as qualifier
candidates.
-->
<!--<qualifier value="redisson3"/>-->
<redisson:master-slave-servers
idle-connection-timeout="10000"
ping-timeout="1000"
connect-timeout="10000"
timeout="3000"
retry-attempts="3"
retry-interval="1500"
reconnection-timeout="3000"
failed-attempts="3"
password="do_not_use_if_it_is_not_set"
subscriptions-per-connection="5"
client-name="none"
load-balancer-ref="myLoadBalancer"
subscription-connection-minimum-idle-size="1"
subscription-connection-pool-size="50"
slave-connection-minimum-idle-size="10"
slave-connection-pool-size="64"
master-connection-minimum-idle-size="10"
master-connection-pool-size="64"
read-mode="SLAVE"
subscription-mode="SLAVE"
master-address="127.0.0.1:6379"
database="0"
>
<redisson:slave-address value="127.0.0.1:6380" />
<redisson:slave-address value="127.0.0.1:6381" />
</redisson:master-slave-servers>
</redisson:client>
</beans>

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save