Merge branch 'master' into 3.0.0

# Conflicts:
#	pom.xml
#	redisson-all/pom.xml
#	redisson-tomcat/pom.xml
#	redisson-tomcat/redisson-tomcat-6/pom.xml
#	redisson-tomcat/redisson-tomcat-7/pom.xml
#	redisson-tomcat/redisson-tomcat-8/pom.xml
#	redisson/pom.xml
pull/872/head
Nikita 8 years ago
commit e0629821f1

@ -1,10 +1,19 @@
Redisson Releases History
================================
####Please Note: trunk is current development branch.
### Please Note: trunk is current development branch.
Try __ULTRA-FAST__ [Redisson PRO](https://redisson.pro) edition.
####19-Feb-2017 - versions 2.8.0 and 3.3.0 released
### 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)
Feature - __`RClusteredMapCache` object added__ More details [here](https://github.com/redisson/redisson/wiki/7.-distributed-collections#713-map-data-partitioning)
@ -19,7 +28,7 @@ Fixed - cascade slaves are not supported in cluster mode
Fixed - shutdown checking during master change state check added
Fixed - master isn't checked during new slave discovery in Sentinel mode
####02-Feb-2017 - versions 2.7.4 and 3.2.4 released
### 02-Feb-2017 - versions 2.7.4 and 3.2.4 released
Feature - Allow to specify Redisson instance/config during JCache cache creation
Fixed - `ByteBuf.release` method invocation is missed in `LZ4Codec` and `SnappyCodec`
@ -31,7 +40,7 @@ Fixed - `JCache` expiration listener doesn't work
Fixed - `RLocalCachedMap` doesn't work with `SerializationCodec`
Fixed - `Can't find entry` error during operation execution on slave nodes
####19-Jan-2017 - versions 2.7.3 and 3.2.3 released
### 19-Jan-2017 - versions 2.7.3 and 3.2.3 released
Redisson Team is pleased to announce __ULTRA-FAST__ Redisson PRO edition.
Performance measure results available in [Benchmark whitepaper](https://redisson.pro/Redisson%20PRO%20benchmark%20whitepaper.pdf)
@ -46,7 +55,7 @@ Fixed - `RSortedSet.removeAsync` and `RSortedSet.addAsync`
Fixed - `RBloomFilter.tryInit` were not validated properly
Fixed - CommandDecoder should print all replay body on error
####19-Dec-2016 - versions 2.7.2 and 3.2.2 released
### 19-Dec-2016 - versions 2.7.2 and 3.2.2 released
Feature - `RList`, `RSet` and `RScoredSortedSet` implements `RSortable` interface with SORT command support
Feature - `NodeAsync` interface
@ -54,7 +63,7 @@ Feature - `Node.info`, `Node.getNode` methods added
Fixed - elements distribution of `RBlockingFairQueue` across consumers
Fixed - `factory already defined` error during Redisson initialization under Apache Tomcat
####14-Dec-2016 - versions 2.7.1 and 3.2.1 released
### 14-Dec-2016 - versions 2.7.1 and 3.2.1 released
Url format used in config files __has changed__. For example:
@ -68,7 +77,7 @@ Fixed - command timeout didn't respect during topic subscription
Fixed - possible PublishSubscribe race-condition
Fixed - blocking queue/deque poll method blocks infinitely if delay less than 1 second
####26-Nov-2016 - versions 2.7.0 and 3.2.0 released
### 26-Nov-2016 - versions 2.7.0 and 3.2.0 released
Feature - __Spring Session implementation__. More details [here](https://github.com/redisson/redisson/wiki/14.-Integration%20with%20frameworks/#145-spring-session)
Feature - __Tomcat Session Manager implementation__. More details [here](https://github.com/redisson/redisson/wiki/14.-Integration%20with%20frameworks/#144-tomcat-redis-session-manager)
@ -80,31 +89,31 @@ Fixed - Wrong nodes parsing in result of cluster info command
Fixed - NullPointerException in CommandDecoder.handleResult
Fixed - Redisson shutdown status should be checked during async command invocation
####07-Nov-2016 - versions 2.6.0 and 3.1.0 released
### 07-Nov-2016 - versions 2.6.0 and 3.1.0 released
Feature - __new object added__ `RBinaryStream`. More info about it [here](https://github.com/redisson/redisson/wiki/6.-distributed-objects/#62-binary-stream-holder)
Improvement - limit Payload String on RedisTimeoutException
Improvement - Elasticache master node change detection process optimization
####27-Oct-2016 - versions 2.5.1 and 3.0.1 released
### 27-Oct-2016 - versions 2.5.1 and 3.0.1 released
Include all code changes from __2.2.27__ version
Fixed - RMapCache.fastPutIfAbsentAsync doesn't take in account expiration
Fixed - timer field of RedisClient hasn't been initialized properly in some cases
####27-Oct-2016 - version 2.2.27 released
### 27-Oct-2016 - version 2.2.27 released
This version fixes old and annonying problem with `ConnectionPool exhusted` error. From this moment connection pool waits for free connection instead of throwing pool exhausted error. This leads to more effective Redis connection utilization.
Improvement - remove `Connection pool exhausted` exception
####17-Oct-2016 - version 3.0.0 released
### 17-Oct-2016 - version 3.0.0 released
Fully compatible with JDK 8. Includes all code changes from __2.5.0__ version
Feature - `RFeature` extends `CompletionStage`
####17-Oct-2016 - version 2.5.0 released
### 17-Oct-2016 - version 2.5.0 released
This version brings greatly improved version of `RLiveObjectService` and adds cascade handling, cyclic dependency resolving, simplified object creation. Read more in this [article](https://dzone.com/articles/java-distributed-in-memory-data-model-powered-by-r)
Includes all code changes from __2.2.26__ version
@ -130,11 +139,11 @@ Fixed - `RLiveObjectService` can't detach content of List object
Fixed - `RLiveObjectService` doesn't create objects mapped to Redisson objects in runtime during getter accesss
Fixed - `RLiveObjectService` can't recognize id field of object without setter
####17-Oct-2016 - version 2.2.26 released
### 17-Oct-2016 - version 2.2.26 released
Fixed - NPE in CommandDecoder
Fixed - PubSub connection re-subscription doesn't work in case when there is only one slave available
####27-Sep-2016 - version 2.4.0 released
### 27-Sep-2016 - version 2.4.0 released
Includes all code changes from __2.2.25__ version
Feature - __new object added__ `RPermitExpirableSemaphore`. More info about it [here](https://github.com/redisson/redisson/wiki/8.-distributed-locks-and-synchronizers#87-permitexpirablesemaphore)
@ -153,7 +162,7 @@ Improvement - `RMultimap.get` should return `RSet` or `RList` interface instead
Fixed - `RExecutorService` should reject non-static inner task class
Fixed - wrong object encoding in `RScoredSortedSet.addScore` method
####27-Sep-2016 - version 2.2.25 released
### 27-Sep-2016 - version 2.2.25 released
Improvement - log unexpected errors in netty handlers
Improvement - `Not all slots are covered` error should be more informative
Improvement - implement random wait time in `lock` method of `RedissonRedLock` and `RedissonMultiLock` objects
@ -167,7 +176,7 @@ Fixed - TRYAGAIN error handling in cluster mode
Fixed - sync commands in connectionListener leads to connection timeout exception
Fixed - can't find slave error in cluster mode if failed slave hasn't been added before
####24-Aug-2016 - version 2.3.0 released
### 24-Aug-2016 - version 2.3.0 released
Starting from this version Redisson could be run as standalone node to execute distributed tasks. More features will be added to it in future. Read docs about it [here](https://github.com/mrniko/redisson/wiki/12.-Standalone-node)
Feature - __new service added__ `RExecutorService`. More info about it [here](https://github.com/mrniko/redisson/wiki/9.-distributed-services/#93-distributed-executor-service)
@ -185,11 +194,11 @@ __Breaking api change__ - all classes moved from `org.redisson.core` to `org.red
__Breaking api change__ - switched from `io.netty.util.concurrent.Future` to `org.redisson.api.RFuture` interface
Fixed - division by zero in WeightedRoundRobinBalancer (thanks to Shailender R Bathula)
####08-Aug-2016 - version 2.2.24 released
### 08-Aug-2016 - version 2.2.24 released
Fixed - PubSub connection in cluster mode should be connected to node according slot derived from channel name
Fixed - `RLock.tryLock` could block forever under some conditions
####04-Aug-2016 - version 2.2.23 released
### 04-Aug-2016 - version 2.2.23 released
Improvement - `Future.cancel` method handling for RemoteService async call
Fixed - unable to redefine RedisClient command execution timeout
Fixed - exception occured in CommandEncoder leads to reponse timeout exception
@ -197,23 +206,23 @@ Fixed - exception occured in CommandDecoder leads to reponse timeout exception
Fixed - BLPOP timeout calculation fixed
Fixed - object used in RemoteService to prevent race-condition during ack receiving should be created per request
####26-Jul-2016 - version 2.2.22 released
### 26-Jul-2016 - version 2.2.22 released
Fixed - java.lang.UnsupportedOperationException during command batch usage with netty 4.0.38 and higher
####15-Jul-2016 - version 2.2.21 released
### 15-Jul-2016 - version 2.2.21 released
Fixed - `RLock`, `RReadWriteLock`, `RSemaphore` and `RCountDownLatch` can blocks forever under some conditions
####14-Jul-2016 - version 2.2.20 released
### 14-Jul-2016 - version 2.2.20 released
Fixed - NPE during pubsub re-subscription (regression since 2.2.18)
Fixed - `RSortedSet` doesn't work in cluster mode (regression since 2.2.16)
Fixed - PubSub connection pool initialization in cluster mode
Fixed - NPE during pubsub usage in cluster mode (regression since 2.2.18)
####13-Jul-2016 - version 2.2.19 released
### 13-Jul-2016 - version 2.2.19 released
Feature - `RSetReactive.readIntersection`, `RSetReactive.diff` and `RSetReactive.intersection` added
Fixed - cluster commands handling regression (regression since 2.2.18)
####13-Jul-2016 - version 2.2.18 released
### 13-Jul-2016 - version 2.2.18 released
Feature - `RSet.randomAsync` and `RSet.random` commands added (thanks to dcheckoway)
Feature - commandTimeout param added to RedisClient
Feature - `JsonJacksonMapValueCodec` basic typed map value codec added (thanks to andrejserafim)
@ -226,7 +235,7 @@ Fixed - response parsing of cluster nodes command
Fixed - Connections weren't closing during `RedisClient` shutdown
Fixed - `RedissonRedLock.unlock`
####30-Jun-2016 - version 2.2.17 released
### 30-Jun-2016 - version 2.2.17 released
Feature - `RMultimap.keySize` method added
Feature - `RKeys.getType` method added
Feature - `RKeys.getKeysByPattern` method with count param added
@ -242,7 +251,7 @@ Fixed - RLock.lock can hang in some cases
Fixed - PubSub subscription may stuck in some cases
Fixed - return value of `RedissonMultimap.keySet.size` method
####12-Jun-2016 - version 2.2.16 released
### 12-Jun-2016 - version 2.2.16 released
Feature - `RGeo`, `RMultimapCache` added to `RBatch`
Feature - `fastRemove` and `fastRemoveAsync` methods were added to `RList`
Improvement - added Spring 4.3.0 support to RedissonSpringCacheManager
@ -252,14 +261,14 @@ Improvement - ability to define `Codec` for `RRemoteService`
Fixed - cluster state managing with redis masters only
Fixed - dead lock during `RLock`, `RSemaphore`, `RReadWriteLock`, `RCountDownLatch` usage under heavy load
####08-Jun-2016 - version 2.2.15 released
### 08-Jun-2016 - version 2.2.15 released
Improvement - Performance boost up to 30% for `RSortedSet.add` method
Fixed - auth during reconnection (thanks to fransiskusx)
Fixed - Infinity loop with iterator
Fixed - NPE in `RSortedSet`
Fixed - `RSortedSet.remove` and `iterator.remove` methods can break elements ordering
####27-May-2016 - version 2.2.14 released
### 27-May-2016 - version 2.2.14 released
Redisson Team is pleased to announce [Redisson PRO](http://redisson.pro) edition. This version is based on open-source edition and has 24x7 support and some features.
Feature - __data sharding for `RMap`, `RSet` structures in cluster mode__ available only in [Redisson PRO](http://redisson.pro) edition
@ -284,7 +293,7 @@ Fixed - FSTObjectOutput shouldn't be closed after write
Fixed - possible race-condition during ack waiting in `RRemoteService` object
Fixed - timeWait checking fixed in `RLock.tryLockAsync`
####30-Apr-2016 - version 2.2.13 released
### 30-Apr-2016 - version 2.2.13 released
Feature - `RSet.diff` and `RSet.intersection` methods added
Imporovement - `RScoredSortedSet`.`containsAll`, `removeAll` and `retainAll` methods speed optimization
@ -294,7 +303,7 @@ Fixed - possible infinity `RLock` expiration renewal process
Fixed - error during `RSetCache.readAll` invocation.
Fixed - expiration override wasn't work in `RSetCache.add`
####22-Apr-2016 - version 2.2.12 released
### 22-Apr-2016 - version 2.2.12 released
Imporovement - Replaying phase handling in CommandDecoder
Fixed - cluster state update manager can't try next node if current node has failed to response
@ -311,7 +320,7 @@ Fixed - array start index in LUA scripts
Fixed - RMap iterator
Fixed - probably thread blocking issues
####04-Apr-2016 - version 2.2.11 released
### 04-Apr-2016 - version 2.2.11 released
Since this version Redisson has __perfomance boost up to 43%__
@ -326,7 +335,7 @@ Fixed - RTopic listeners hangs during synchronous commands execution inside it
Fixed - Redisson hangs during shutdown if `RBlockingQueue\Deque.take` or `RBlockingQueue\Deque.poll` methods were invoked
####23-Mar-2016 - version 2.2.10 released
### 23-Mar-2016 - version 2.2.10 released
Feature - __new object added__ `RRemoteService`
Feature - __new object added__ `RSetMultimapCache`
@ -341,7 +350,7 @@ Fixed - `RLock.tryLockAsync` NPE
Fixed - possible NPE during Redisson version logging
Fixed - Netty threads shutdown after connection error
####04-Mar-2016 - version 2.2.9 released
### 04-Mar-2016 - version 2.2.9 released
Feature - __new object added__ `RSetMultimap`
Feature - __new object added__ `RListMultimap`
@ -352,7 +361,7 @@ Improvement - Add DynamicImport-Package to OSGi headers
Fixed - `RedissonSpringCacheManager` Sentinel compatibility
Fixed - `RAtomicLong.compareAndSet` doesn't work when expected value is 0 and it wasn't initialized
####12-Feb-2016 - version 2.2.8 released
### 12-Feb-2016 - version 2.2.8 released
Feature - `union`, `unionAsync`, `readUnion` and `readUnionAsync` methods were added to `RSet` object
Feature - `readAll` and `readAllAsync` methods were added to `RSetCache` object
@ -361,7 +370,7 @@ Fixed - Script error during `RSetCache.toArray` and `RSetCache.readAll` methods
Fixed - Sentinel doesn't support AUTH command
Fixed - RMap iterator
####03-Feb-2016 - version 2.2.7 released
### 03-Feb-2016 - version 2.2.7 released
Feature - `readAllKeySet`, `readAllValues`, `readAllEntry`, `readAllKeySetAsync`, `readAllValuesAsync`, `readAllEntryAsync` methods were added to `RMap` object
Improvement - `RKeys.delete` optimization in Cluster mode
@ -376,7 +385,7 @@ Fixed - offline slaves handling during Redisson start in Sentinel mode
Fixed - `SELECT` command can't be executed in Sentinel mode
Fixed - `database` setting removed from cluster config
####28-Jan-2016 - version 2.2.6 released
### 28-Jan-2016 - version 2.2.6 released
Feature - __new object added__ `RedissonMultiLock`
Feature - `move` method added to `RSet`, `RSetReactive` objects (thanks to thrau)
@ -396,7 +405,7 @@ Fixed - can't connect with password to Sentinel and Elasticache servers
Fixed - Cluster slave discovery (regression since 2.1.5)
Fixed - Sentinel slave discovery (regression since 2.1.5)
####09-Jan-2015 - version 2.2.5 released
### 09-Jan-2015 - version 2.2.5 released
Feature - __new object added__ `RBloomFilter`
Feature - __new object added__ `RAtomicDouble`
@ -415,7 +424,7 @@ Fixed - `RMap.addAndGetAsync` key encoding
Fixed - `RBatch` errors handling
Fixed - `RBlockingQueue.pollLastAndOfferFirstToAsync` does not block properly
####25-Dec-2015 - version 2.2.4 released
### 25-Dec-2015 - version 2.2.4 released
Please update to this version ASAP due to connection leak discovered in previous versions since Redisson 2.1.4.
Feature - __new object added__ `RBlockingDeque`
@ -432,18 +441,18 @@ Fixed - `RReadWriteLock.forceUnlock` works only for current thread
Fixed - MapKeyDecoder and MapValueDecoder are called in wrong order
Fixed - `RReadWriteLock` doesn't work in cluster mode
####15-Dec-2015 - version 2.2.3 released
### 15-Dec-2015 - version 2.2.3 released
Feature - ability to set connection listener via `Config.connectionListener` setting
Fixed - `RLock` expiration bug fixed (regression bug since 2.2.2)
Fixed - NPE in `RedissonSortedSet` constructor
####14-Dec-2015 - version 2.2.2 released
### 14-Dec-2015 - version 2.2.2 released
Feature - `isShuttingDown` and `isShutdown` methods were added to RedissonClient and RedissonReactiveClient
Feature - __new object added__ `RSetCacheReactive`
Fixed - RLock expiration renewal task scheduling fixed (regression bug since 2.2.1)
Fixed - RExpirable.expireAsync timeUnit precision fixed (regression bug since 2.2.1)
####11-Dec-2015 - version 2.2.1 released
### 11-Dec-2015 - version 2.2.1 released
Feature - __new object added__ `RReadWriteLock` with reentrant read/write locking
Feature - __new object added__ `RMapCache` map-based cache with TTL support for each entry
Feature - __new object added__ `RSetCache` set-based cache with TTL support for each value
@ -452,7 +461,7 @@ Feature - `RMap.values()`, `RMap.keySet()`, `RMap.entrySet()` reimplemented with
Feature - `RObjectReactive.isExists`, `RObject.isExists` and `RObject.isExistsAsync` added
Fixed - `RLock.unlock` not thrown IllegalMonitorStateException
####04-Dec-2015 - version 2.2.0 released
### 04-Dec-2015 - version 2.2.0 released
Since 2.2.0 version Redisson supports [Reactive Streams](http://www.reactive-streams.org). Use `Redisson.createReactive` method to access Reactive objects.
Feature - [Reactive Streams](http://www.reactive-streams.org) support
@ -467,12 +476,12 @@ Fixed - `RLock.delete` didn't check lock existence
Deprecated methods are dropped
####30-Nov-2015 - version 2.1.6 released
### 30-Nov-2015 - version 2.1.6 released
Fixed - connection pool regression bug
Fixed - connection init during `Node.ping` and `ClusterNode.info` invocation
####24-Nov-2015 - version 2.1.5 released
### 24-Nov-2015 - version 2.1.5 released
Feature - new methods with `limit` option support were added to `RLexSortedSet`: `lexRange`, `lexRangeHead`, `lexRangeHeadAsync`, `lexRangeTail`, `lexRangeTailAsync`, `lexRangeAsync` (thanks to jackygurui)
Feature - new methods with `limit` option support were added to `RScoredSortedSet`: `valueRange`, `valueRangeAsync`, `entryRange`, `entryRangeAsync`, `valueRange`, `valueRangeAsync` (thanks to jackygurui)
Feature - `LOADING` Redis server response handling
@ -488,7 +497,7 @@ Fixed - `RSet.iterator`
Fixed - `RBatch.execute` and `RBatch.executeAsync` errors handling
####11-Nov-2015 - version 2.1.4 released
### 11-Nov-2015 - version 2.1.4 released
Cluster support improvements. New codecs. Stability improvements.
Feature - [LZ4](https://github.com/jpountz/lz4-java) compression codec support
@ -513,7 +522,7 @@ Fixed - NPE during Publish/Subscribe event handling
Fixed - Redisson shutdown handling
Fixed - EOFException during RLock usage with SerializationCodec (thanks to Oleg Ternovoi)
####17-Sep-2015 - version 2.1.3 released
### 17-Sep-2015 - version 2.1.3 released
Feature - Ability to define `Codec` for each object
Feature - `refreshConnectionAfterFails` setting added
Feature - [AWS Elasticache](https://aws.amazon.com/elasticache/) support via `Config.useElasticacheServers` method (thanks to Steve Ungerer)
@ -521,7 +530,7 @@ Feature - `RScoredSortedSet` and `RLexSortedSet` added. Both uses native Redis S
Fixed - missed AUTH during channel reconnection
Fixed - resubscribe to subscribed topics during channel reconnection
####05-Sep-2015 - version 2.1.2 released
### 05-Sep-2015 - version 2.1.2 released
Fixed - possible NPE during channel reconnection
Fixed - executeAsync freezes in cluster mode
Fixed - use same node for SCAN/SSCAN/HSCAN during iteration
@ -531,7 +540,7 @@ Fixed - NPE with empty sentinel servers
Fixed - unable to read `clientName` config param in Master\Slave and Sentinel modes
Fixed - "Too many open files" error in cluster mode
####15-Aug-2015 - version 2.1.1 released
### 15-Aug-2015 - version 2.1.1 released
Feature - all keys operations extracted to `RKeys` interface
Feature - `RKeys.getKeys`, `RKeys.getKeysByPattern` and `RKeys.randomKey`methods added
Feature - `RBlockingQueueAsync.drainToAsync` method added
@ -545,7 +554,7 @@ Fixed - skip disconnected sentinels during startup
Fixed - slave node discovery in sentinel mode which has been disconnected since start
__Deprecated__ - Redisson methods `deleteAsync`, `delete`, `deleteByPatternAsync`, `deleteByPattern`, `findKeysByPatternAsync`, `findKeysByPattern`. Use same methods with `RKeys` interface
####03-Aug-2015 - version 2.1.0 released
### 03-Aug-2015 - version 2.1.0 released
Feature - `RTopic` subscribtion/unsubscription status listener added
Feature - `RSet`: `removeRandom` and `removeRandomAsync` methods added
Improvement - `RList`: `retainAll`,`containsAll`, `indexOf`, `lastIndexOf` optimization
@ -556,7 +565,7 @@ Fixed - timeout timer interval calculation
Fixed - `RBatch` NPE's with very big commands list
Fixed - `RBucket.set` with timeout
####26-Jul-2015 - version 2.0.0 released
### 26-Jul-2015 - version 2.0.0 released
Starting from 2.0.0 version Redisson has a new own async and lock-free Redis client under the hood. Thanks to the new architecture pipline (command batches) support has been implemented and a lot of code has gone.
Feature - new `RObject` methods: `move`, `moveAsync`, `migrate`, `migrateAsync`
@ -565,12 +574,12 @@ Feature - multiple commands batch (Redis pipelining) support via `Redisson.creat
Feature - new methods `flushall`, `deleteAsync`, `delete`, `deleteByPatternAsync`, `deleteByPattern`, `findKeysByPatternAsync`, `findKeysByPattern` added to `RedissonClient` interface
Improvement - closed channel detection speedup
####22-Jul-2015 - version 1.3.1 released
### 22-Jul-2015 - version 1.3.1 released
Fixed - requests state sync during shutdown
Fixed - netty-transport-native-epoll is now has a provided scope
Fixed - NPE during `BlockingQueue.poll` invocation
####04-Jul-2015 - version 1.3.0 released
### 04-Jul-2015 - version 1.3.0 released
Feature - `RQueue.pollLastAndOfferFirstTo` method added
Feature - `RObject.rename`, `RObject.renameAsync`, `RObject.renamenx`, `RObject.renamenxAsync` methods added
Feature - `RList.getAsync`, `RList.addAsync`, `RList.addAllAsync` methods added
@ -591,7 +600,7 @@ Fixed - `RedissonClient.getScript` method added
Fixed - `BlockingQueue.poll` method
Fixed - Incorrect map key encoding makes hmget return no fields when string keys are used (thanks to sammiq)
####02-Apr-2015 - version 1.2.1 released
### 02-Apr-2015 - version 1.2.1 released
Feature - all redis-script commands via 'RScript' object
Feature - implementation of `java.util.concurrent.BlockingQueue` (thanks to pdeschen)
Feature - buckets load by pattern (thanks to mathieucarbou)
@ -605,13 +614,13 @@ Fixed - `RMap.replace` concurrency issue (thanks to AndrewKolpakov)
Fixed - `RLock` subscription timeout units fixed (thanks to AndrewKolpakov)
Fixed - Re-throw async exceptions (thanks to AndrewKolpakov)
####09-Jan-2015 - version 1.2.0 released
### 09-Jan-2015 - version 1.2.0 released
Feature - cluster mode support
Fixed - `RList` iterator race conditions
Fixed - `RDeque.addFirst` `RDeque.addLast` methods
Fixed - OSGi support
####16-Dec-2014 - version 1.1.7 released
### 16-Dec-2014 - version 1.1.7 released
Improvement - `RAtomicLong` optimization
Fixed - `RMap.fastRemove` and `RMap.getAll` methods
Fixed - `RTopic` listeners re-subscribing in sentinel mode
@ -622,7 +631,7 @@ Fixed - `RAtomicLong` NPE
Fixed - infinity loop during master/slave connection acquiring
Fixed - `RedissonList.addAll` result
####18-Nov-2014 - version 1.1.6 released
### 18-Nov-2014 - version 1.1.6 released
Feature - `RBucket.exists` and `RBucket.existsAsync` methods added
Feature - `RMap.addAndGet` method added
Feature - database index via `database` and operation timeout via `timeout` config params added
@ -635,40 +644,40 @@ Fixed - HashedWheelTimer shutdown
Fixed - `RLock` race conditions (thanks to jsotuyod and AndrewKolpakov)
Fixed - `RCountDownLatch` race conditions
####23-Jul-2014 - version 1.1.5 released
### 23-Jul-2014 - version 1.1.5 released
Feature - operations auto-retry. `retryAttempts` and `retryInterval` params added for each connection type
Feature - `RMap.filterEntries`, `RMap.getAll`, `RMap.filterKeys`, `RMap.filterValues` methods added
Feature - `RMap.fastRemove`, `RMap.fastRemoveAsync`, `RMap.fastPut` & `RMap.fastPutAsync` methods added
Fixed - async operations timeout handling
Fixed - sorting algorithm used in `RSortedSet`.
####15-Jul-2014 - version 1.1.4 released
### 15-Jul-2014 - version 1.1.4 released
Feature - new `RLock.lockInterruptibly`, `RLock.tryLock`, `RLock.lock` methods with TTL support
Fixed - pub/sub connections reattach then slave/master down
Fixed - turn off connection watchdog then slave/master down
Fixed - sentinel master switch
Fixed - slave down connection closing
####13-Jul-2014 - version 1.1.3 released
### 13-Jul-2014 - version 1.1.3 released
Improvement - RedissonCountDownLatch optimization
Improvement - RedissonLock optimization
Fixed - RedissonLock thread-safety
Fixed - master/slave auth using Sentinel servers
Fixed - slave down handling using Sentinel servers
####03-Jul-2014 - version 1.1.2 released
### 03-Jul-2014 - version 1.1.2 released
Improvement - RedissonSet.iterator implemented with sscan
Improvement - RedissonSortedSet.iterator optimization
Feature - `RSortedSet.removeAsync`, `RSortedSet.addAsync`, `RSet.removeAsync`, RSet.addAsync methods added
Feature - slave up/down detection in Sentinel servers connection mode
Feature - new-slave automatic discovery in Sentinel servers connection mode
####17-June-2014 - version 1.1.1 released
### 17-June-2014 - version 1.1.1 released
Feature - sentinel servers support
Fixed - connection leak in `RTopic`
Fixed - setted password not used in single server connection
####07-June-2014 - version 1.1.0 released
### 07-June-2014 - version 1.1.0 released
Feature - master/slave connection management
Feature - simple set/get object support via `org.redisson.core.RBucket`
Feature - hyperloglog support via `org.redisson.core.RHyperLogLog`
@ -682,24 +691,24 @@ Fixed - `RTopic.publish` now returns the number of clients that received the mes
Fixed - reconnection handling (thanks to renzihui)
Improvement - `org.redisson.core.RTopic` now use lazy apporach for subscribe/unsubscribe
####04-May-2014 - version 1.0.4 released
### 04-May-2014 - version 1.0.4 released
Feature - distributed implementation of `java.util.Deque`
Feature - some objects implements `org.redisson.core.RExpirable`
Fixed - JsonJacksonCodec lazy init
####26-Mar-2014 - version 1.0.3 released
### 26-Mar-2014 - version 1.0.3 released
Fixed - RedissonAtomicLong state format
Fixed - Long serialization in JsonJacksonCodec
####05-Feb-2014 - version 1.0.2 released
### 05-Feb-2014 - version 1.0.2 released
Feature - distributed implementation of `java.util.SortedSet`
Fixed - OSGi compability
####17-Jan-2014 - version 1.0.1 released
### 17-Jan-2014 - version 1.0.1 released
Improvement - forceUnlock, isLocked, isHeldByCurrentThread and getHoldCount methods added to RLock
Feature - connection load balancer to use multiple Redis servers
Feature - published in maven central repo
####11-Jan-2014 - version 1.0.0 released
### 11-Jan-2014 - version 1.0.0 released
First stable release.

@ -1,14 +1,14 @@
Redis based In-Memory Data Grid for Java. Redisson.
Redisson: Redis based In-Memory Data Grid for Java.
====
[Documentation](https://github.com/redisson/redisson/wiki) | [Javadocs](http://www.javadoc.io/doc/org.redisson/redisson/3.3.0) | [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)
[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 added in 3.x.x
@ -55,7 +55,7 @@ Features
Who uses Redisson
================================
[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)
[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
================================
@ -82,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
@ -123,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

@ -22,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)

@ -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();

@ -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();

@ -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.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>
@ -198,51 +203,66 @@
<artifactId>jackson-dataformat-cbor</artifactId>
<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.8.7</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-avro</artifactId>
<version>2.8.7</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>net.openhft</groupId>
<artifactId>zero-allocation-hashing</artifactId>
<version>0.7</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy</artifactId>
<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>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-actuator</artifactId>
<version>[1.4,)</version>
<scope>provided</scope>
</dependency>
</dependencies>
@ -428,6 +448,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

@ -23,7 +23,6 @@ import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
@ -35,7 +34,6 @@ import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicReference;
@ -48,7 +46,6 @@ import org.redisson.api.RTopic;
import org.redisson.api.RedissonClient;
import org.redisson.api.RemoteInvocationOptions;
import org.redisson.api.annotation.RInject;
import org.redisson.api.listener.BaseStatusListener;
import org.redisson.api.listener.MessageListener;
import org.redisson.client.codec.Codec;
import org.redisson.client.codec.LongCodec;
@ -66,8 +63,6 @@ import org.redisson.misc.RPromise;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.netty.util.Timeout;
import io.netty.util.TimerTask;
import io.netty.util.concurrent.FutureListener;
import io.netty.util.internal.PlatformDependent;
@ -338,7 +333,7 @@ public class RedissonExecutorService implements RScheduledExecutorService {
}
@Override
public <T> Future<T> submit(Callable<T> task) {
public <T> RFuture<T> submit(Callable<T> task) {
RemotePromise<T> promise = (RemotePromise<T>) submitAsync(task);
execute(promise);
return promise;
@ -411,7 +406,7 @@ public class RedissonExecutorService implements RScheduledExecutorService {
}
@Override
public Future<?> submit(Runnable task) {
public RFuture<?> submit(Runnable task) {
RemotePromise<Void> promise = (RemotePromise<Void>) submitAsync(task);
execute(promise);
return promise;
@ -428,7 +423,7 @@ public class RedissonExecutorService implements RScheduledExecutorService {
}
@Override
public ScheduledFuture<?> schedule(Runnable task, long delay, TimeUnit unit) {
public RScheduledFuture<?> schedule(Runnable task, long delay, TimeUnit unit) {
RedissonScheduledFuture<?> future = (RedissonScheduledFuture<?>) scheduleAsync(task, delay, unit);
execute((RemotePromise<?>)future.getInnerPromise());
return future;
@ -446,7 +441,7 @@ public class RedissonExecutorService implements RScheduledExecutorService {
}
@Override
public <V> ScheduledFuture<V> schedule(Callable<V> task, long delay, TimeUnit unit) {
public <V> RScheduledFuture<V> schedule(Callable<V> task, long delay, TimeUnit unit) {
RedissonScheduledFuture<V> future = (RedissonScheduledFuture<V>) scheduleAsync(task, delay, unit);
execute((RemotePromise<V>)future.getInnerPromise());
return future;
@ -464,7 +459,7 @@ public class RedissonExecutorService implements RScheduledExecutorService {
}
@Override
public ScheduledFuture<?> scheduleAtFixedRate(Runnable task, long initialDelay, long period, TimeUnit unit) {
public RScheduledFuture<?> scheduleAtFixedRate(Runnable task, long initialDelay, long period, TimeUnit unit) {
RedissonScheduledFuture<?> future = (RedissonScheduledFuture<?>) scheduleAtFixedRateAsync(task, initialDelay, period, unit);
execute((RemotePromise<?>)future.getInnerPromise());
return future;
@ -505,7 +500,7 @@ public class RedissonExecutorService implements RScheduledExecutorService {
}
@Override
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable task, long initialDelay, long delay, TimeUnit unit) {
public RScheduledFuture<?> scheduleWithFixedDelay(Runnable task, long initialDelay, long delay, TimeUnit unit) {
RedissonScheduledFuture<?> future = (RedissonScheduledFuture<?>) scheduleWithFixedDelayAsync(task, initialDelay, delay, unit);
execute((RemotePromise<?>)future.getInnerPromise());
return future;

@ -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());
}

@ -17,7 +17,6 @@ package org.redisson;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
@ -132,14 +131,45 @@ public class RedissonKeys implements RKeys {
}
@Override
public Long isExists(String... names) {
return commandExecutor.get(isExistsAsync(names));
public long touch(String... names) {
return commandExecutor.get(touchAsync(names));
}
@Override
public RFuture<Long> isExistsAsync(String... names) {
Object[] params = Arrays.copyOf(names, names.length, Object[].class);
return commandExecutor.readAsync((String)null, null, RedisCommands.EXISTS_LONG, params);
public RFuture<Long> touchAsync(String... names) {
return commandExecutor.writeAllAsync(RedisCommands.TOUCH_LONG, new SlotCallback<Long, Long>() {
AtomicLong results = new AtomicLong();
@Override
public void onSlotResult(Long result) {
results.addAndGet(result);
}
@Override
public Long onFinish() {
return results.get();
}
}, names);
}
@Override
public long countExists(String... names) {
return commandExecutor.get(countExistsAsync(names));
}
@Override
public RFuture<Long> countExistsAsync(String... names) {
return commandExecutor.readAllAsync(RedisCommands.EXISTS_LONG, new SlotCallback<Long, Long>() {
AtomicLong results = new AtomicLong();
@Override
public void onSlotResult(Long result) {
results.addAndGet(result);
}
@Override
public Long onFinish() {
return results.get();
}
}, names);
}

@ -389,35 +389,42 @@ public class RedissonLocalCachedMap<K, V> extends RedissonMap<K, V> implements R
throw new NullPointerException();
}
List<Object> params = new ArrayList<Object>();
params.add(invalidateEntryOnChange);
if (invalidateEntryOnChange == 1) {
List<Object> params = new ArrayList<Object>(keys.length*2);
for (K k : keys) {
byte[] keyEncoded = encodeMapKey(k);
params.add(keyEncoded);
CacheKey cacheKey = toCacheKey(keyEncoded);
cache.remove(cacheKey);
byte[] msgEncoded = encode(new LocalCachedMapInvalidate(instanceId, cacheKey.getKeyHash()));
params.add(msgEncoded);
}
return commandExecutor.evalWriteAsync(getName(), codec, RedisCommands.EVAL_LONG,
"local counter = 0; " +
"for j = 1, #ARGV, 2 do "
+ "if redis.call('hdel', KEYS[1], ARGV[j]) == 1 then "
+ "redis.call('publish', KEYS[2], ARGV[j+1]); "
+ "counter = counter + 1;"
+ "end;"
+ "end;"
+ "return counter;",
Arrays.<Object>asList(getName(), invalidationTopic.getChannelNames().get(0)),
params.toArray());
}
List<Object> params = new ArrayList<Object>(keys.length + 1);
params.add(getName());
for (K k : keys) {
byte[] keyEncoded = encodeMapKey(k);
params.add(keyEncoded);
CacheKey cacheKey = toCacheKey(keyEncoded);
cache.remove(cacheKey);
if (invalidateEntryOnChange == 1) {
byte[] msgEncoded = encode(new LocalCachedMapInvalidate(instanceId, cacheKey.getKeyHash()));
params.add(msgEncoded);
} else {
params.add(null);
}
}
return commandExecutor.evalWriteAsync(getName(), codec, RedisCommands.EVAL_LONG,
"local counter = 0; " +
"for j = 2, #ARGV, 2 do "
+ "if redis.call('hdel', KEYS[1], ARGV[j]) == 1 then "
+ "if ARGV[1] == '1' then "
+ "redis.call('publish', KEYS[2], ARGV[j+1]); "
+ "end; "
+ "counter = counter + 1;"
+ "end;"
+ "end;"
+ "return counter;",
Arrays.<Object>asList(getName(), invalidationTopic.getChannelNames().get(0)),
params.toArray());
return commandExecutor.writeAsync(getName(), codec, RedisCommands.HDEL, params.toArray());
}

@ -33,6 +33,7 @@ import java.util.UUID;
import org.redisson.api.RFuture;
import org.redisson.api.RLock;
import org.redisson.api.RMap;
import org.redisson.api.RReadWriteLock;
import org.redisson.client.codec.Codec;
import org.redisson.client.codec.MapScanCodec;
import org.redisson.client.codec.StringCodec;
@ -83,10 +84,16 @@ public class RedissonMap<K, V> extends RedissonExpirable implements RMap<K, V> {
return new RedissonLock((CommandExecutor)commandExecutor, lockName, id);
}
@Override
public RReadWriteLock getReadWriteLock(K key) {
String lockName = getLockName(key);
return new RedissonReadWriteLock((CommandExecutor)commandExecutor, lockName, id);
}
private String getLockName(Object key) {
try {
byte[] keyState = codec.getMapKeyEncoder().encode(key);
return "{" + getName() + "}:" + Hash.hashToBase64(keyState) + ":key";
return suffixName(getName(), Hash.hashToBase64(keyState) + ":key");
} catch (IOException e) {
throw new IllegalStateException(e);
}

@ -136,6 +136,16 @@ public abstract class RedissonObject implements RObject {
return commandExecutor.writeAsync(getName(), RedisCommands.DEL_BOOL, getName());
}
@Override
public boolean touch() {
return get(touchAsync());
}
@Override
public RFuture<Boolean> touchAsync() {
return commandExecutor.writeAsync(getName(), codec, RedisCommands.TOUCH, getName());
}
@Override
public boolean isExists() {
return get(isExistsAsync());

@ -65,15 +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] .. ':timeout:1', 1); " +
"redis.call('pexpire', KEYS[1] .. ':timeout:1', ARGV[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 " +
"local ind = redis.call('hincrby', KEYS[1], ARGV[2], 1); " +
"redis.call('set', KEYS[1] .. ':timeout:' .. ind, 1); " +
"redis.call('pexpire', KEYS[1] .. ':timeout:' .. ind, ARGV[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;" +
@ -82,55 +83,48 @@ 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; " +
"local lockExists = redis.call('hexists', KEYS[1], ARGV[2]); " +
"if (lockExists == 0) then " +
"return nil;" +
"else " +
"local counter = redis.call('hincrby', KEYS[1], ARGV[2], -1); " +
"redis.call('del', KEYS[1] .. ':timeout:' .. (counter+1)); " +
"if (counter > 0) then " +
"local maxRemainTime = -3; " +
"for i=counter, 1, -1 do " +
"local remainTime = redis.call('pttl', KEYS[1] .. ':timeout:' .. i); " +
"maxRemainTime = math.max(remainTime, maxRemainTime);" +
"end; " +
"if maxRemainTime > 0 then " +
"redis.call('pexpire', KEYS[1], maxRemainTime); " +
"else " +
"redis.call('hdel', KEYS[1], ARGV[2]); " +
"if (redis.call('hlen', KEYS[1]) == 1) then " +
"redis.call('del', KEYS[1]); " +
"redis.call('publish', KEYS[2], ARGV[1]); " +
"end; " +
"end;" +
"return 0; " +
"else " +
"redis.call('hdel', KEYS[1], ARGV[2]); " +
"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; " +
"return nil; ",
Arrays.<Object>asList(getName(), getChannelName()), LockPubSub.unlockMessage, 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
public Condition newCondition() {
throw new UnsupportedOperationException();
@ -143,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,46 +81,39 @@ 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
public Condition newCondition() {
throw new UnsupportedOperationException();
@ -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>() {

@ -15,6 +15,7 @@
*/
package org.redisson.api;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
/**
@ -25,6 +26,43 @@ import java.util.concurrent.ExecutorService;
*/
public interface RExecutorService extends ExecutorService, RExecutorServiceAsync {
/**
* Submits a value-returning task for execution and returns a
* Future representing the pending results of the task. The
* Future's {@code get} method will return the task's result upon
* successful completion.
*
* @param task the task to submit
* @param <T> the type of the task's result
* @return a Future representing pending completion of the task
*/
@Override
<T> RFuture<T> submit(Callable<T> task);
/**
* Submits a Runnable task for execution and returns a Future
* representing that task. The Future's {@code get} method will
* return the given result upon successful completion.
*
* @param task the task to submit
* @param result the result to return
* @param <T> the type of the result
* @return a Future representing pending completion of the task
*/
@Override
<T> RFuture<T> submit(Runnable task, T result);;
/**
* Submits a Runnable task for execution and returns a Future
* representing that task. The Future's {@code get} method will
* return {@code null} upon <em>successful</em> completion.
*
* @param task the task to submit
* @return a Future representing pending completion of the task
*/
@Override
RFuture<?> submit(Runnable task);
/**
* Returns executor name
*

@ -24,13 +24,20 @@ import java.util.Collection;
*/
public interface RKeys extends RKeysAsync {
/**
* Update the last access time of an object.
*
* @return count of objects were touched
*/
long touch(String... names);
/**
* Checks if provided keys exist
*
* @param names of keys
* @return amount of existing keys
*/
Long isExists(String... names);
long countExists(String... names);
/**
* Get Redis object type by key

@ -24,13 +24,20 @@ import java.util.Collection;
*/
public interface RKeysAsync {
/**
* Update the last access time of an object.
*
* @return count of objects were touched
*/
RFuture<Long> touchAsync(String... names);
/**
* Checks if provided keys exist
*
* @param names of keys
* @return amount of existing keys
*/
RFuture<Long> isExistsAsync(String... names);
RFuture<Long> countExistsAsync(String... names);
/**
* Get Redis object type by key

@ -33,6 +33,14 @@ import java.util.concurrent.ConcurrentMap;
*/
public interface RMap<K, V> extends ConcurrentMap<K, V>, RExpirable, RMapAsync<K, V> {
/**
* Returns <code>RReadWriteLock</code> instance associated with key
*
* @param key - map key
* @return readWriteLock
*/
RReadWriteLock getReadWriteLock(K key);
/**
* Returns <code>RLock</code> instance associated with key
*

@ -25,6 +25,13 @@ import org.redisson.client.codec.Codec;
*/
public interface RObject extends RObjectAsync {
/**
* Update the last access time of an object.
*
* @return <code>true</code> if object was touched else <code>false</code>
*/
boolean touch();
/**
* Transfer an object from source Redis instance to destination Redis instance
*

@ -23,6 +23,13 @@ package org.redisson.api;
*/
public interface RObjectAsync {
/**
* Update the last access time of an object in async mode.
*
* @return <code>true</code> if object was touched else <code>false</code>
*/
RFuture<Boolean> touchAsync();
/**
* Transfer an object from source Redis instance to destination Redis instance
* in async mode

@ -15,8 +15,10 @@
*/
package org.redisson.api;
import java.util.concurrent.Callable;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
/**
* Distributed implementation of {@link java.util.concurrent.ScheduledExecutorService}
@ -26,6 +28,86 @@ import java.util.concurrent.ScheduledFuture;
*/
public interface RScheduledExecutorService extends RExecutorService, ScheduledExecutorService, RScheduledExecutorServiceAsync {
/**
* Creates and executes a one-shot action that becomes enabled
* after the given delay.
*
* @param command the task to execute
* @param delay the time from now to delay execution
* @param unit the time unit of the delay parameter
* @return a ScheduledFuture representing pending completion of
* the task and whose {@code get()} method will return
* {@code null} upon completion
*/
@Override
RScheduledFuture<?> schedule(Runnable command,
long delay, TimeUnit unit);
/**
* Creates and executes a ScheduledFuture that becomes enabled after the
* given delay.
*
* @param callable the function to execute
* @param delay the time from now to delay execution
* @param unit the time unit of the delay parameter
* @param <V> the type of the callable's result
* @return a ScheduledFuture that can be used to extract result or cancel
*/
@Override
<V> RScheduledFuture<V> schedule(Callable<V> callable,
long delay, TimeUnit unit);
/**
* Creates and executes a periodic action that becomes enabled first
* after the given initial delay, and subsequently with the given
* period; that is executions will commence after
* {@code initialDelay} then {@code initialDelay+period}, then
* {@code initialDelay + 2 * period}, and so on.
* If any execution of the task
* encounters an exception, subsequent executions are suppressed.
* Otherwise, the task will only terminate via cancellation or
* termination of the executor. If any execution of this task
* takes longer than its period, then subsequent executions
* may start late, but will not concurrently execute.
*
* @param command the task to execute
* @param initialDelay the time to delay first execution
* @param period the period between successive executions
* @param unit the time unit of the initialDelay and period parameters
* @return a ScheduledFuture representing pending completion of
* the task, and whose {@code get()} method will throw an
* exception upon cancellation
*/
@Override
RScheduledFuture<?> scheduleAtFixedRate(Runnable command,
long initialDelay,
long period,
TimeUnit unit);
/**
* Creates and executes a periodic action that becomes enabled first
* after the given initial delay, and subsequently with the
* given delay between the termination of one execution and the
* commencement of the next. If any execution of the task
* encounters an exception, subsequent executions are suppressed.
* Otherwise, the task will only terminate via cancellation or
* termination of the executor.
*
* @param command the task to execute
* @param initialDelay the time to delay first execution
* @param delay the delay between the termination of one
* execution and the commencement of the next
* @param unit the time unit of the initialDelay and delay parameters
* @return a ScheduledFuture representing pending completion of
* the task, and whose {@code get()} method will throw an
* exception upon cancellation
*/
@Override
RScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
long initialDelay,
long delay,
TimeUnit unit);
/**
* Cancels scheduled task by id
*

@ -385,7 +385,7 @@ public interface RedissonClient {
*
* @param <V> type of value
* @param name - name of object
* @return Lock object
* @return Set object
*/
<V> RSet<V> getSet(String name);
@ -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)
*

@ -278,8 +278,10 @@ 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> TOUCH_LONG = new RedisStrictCommand<Long>("TOUCH");
RedisStrictCommand<Boolean> TOUCH = new RedisStrictCommand<Boolean>("TOUCH", new BooleanReplayConvertor());
RedisStrictCommand<Long> EXISTS_LONG = new RedisStrictCommand<Long>("EXISTS");
RedisStrictCommand<Boolean> EXISTS = new RedisStrictCommand<Boolean>("EXISTS", new BooleanReplayConvertor());
RedisStrictCommand<Boolean> NOT_EXISTS = new RedisStrictCommand<Boolean>("EXISTS", new BooleanNumberReplayConvertor(1L));

@ -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) {

@ -26,6 +26,8 @@ import org.redisson.client.codec.Codec;
import org.redisson.codec.CodecProvider;
import org.redisson.codec.DefaultCodecProvider;
import org.redisson.codec.JsonJacksonCodec;
import org.redisson.connection.ConnectionManager;
import org.redisson.connection.ReplicatedConnectionManager;
import org.redisson.liveobject.provider.DefaultResolverProvider;
import org.redisson.liveobject.provider.ResolverProvider;
@ -50,6 +52,8 @@ public class Config {
private ElasticacheServersConfig elasticacheServersConfig;
private ReplicatedServersConfig replicatedServersConfig;
private ConnectionManager connectionManager;
/**
* Threads amount shared between all redis node clients
@ -122,6 +126,9 @@ public class Config {
if (oldConf.getReplicatedServersConfig() != null) {
setReplicatedServersConfig(new ReplicatedServersConfig(oldConf.getReplicatedServersConfig()));
}
if (oldConf.getConnectionManager() != null) {
useCustomServers(oldConf.getConnectionManager());
}
}
@ -296,6 +303,28 @@ public class Config {
void setReplicatedServersConfig(ReplicatedServersConfig replicatedServersConfig) {
this.replicatedServersConfig = replicatedServersConfig;
}
/**
* Returns the connection manager if supplied via
* {@link #useCustomServers(ConnectionManager)}
*
* @return ConnectionManager
*/
ConnectionManager getConnectionManager() {
return connectionManager;
}
/**
* This is an extension point to supply custom connection manager.
*
* @see ReplicatedConnectionManager on how to implement a connection
* manager.
* @param connectionManager
*/
public void useCustomServers(ConnectionManager connectionManager) {
this.connectionManager = connectionManager;
}
/**
* Init single server configuration.
@ -447,6 +476,7 @@ public class Config {
throw new IllegalStateException("Replication servers config already used!");
}
}
/**
* Activates an unix socket if servers binded to loopback interface.
@ -573,7 +603,7 @@ public class Config {
* @throws IOException error
*/
public static Config fromJSON(File file) throws IOException {
return fromJSON(file);
return fromJSON(file, null);
}
/**
@ -643,8 +673,7 @@ public class Config {
* @throws IOException error
*/
public static Config fromYAML(File file) throws IOException {
ConfigSupport support = new ConfigSupport();
return support.fromYAML(file, Config.class);
return fromYAML(file, null);
}
public static Config fromYAML(File file, ClassLoader classLoader) throws IOException {

@ -265,7 +265,9 @@ public class ConfigSupport {
} else if (configCopy.getReplicatedServersConfig() != null) {
validate(configCopy.getReplicatedServersConfig());
return new ReplicatedConnectionManager(configCopy.getReplicatedServersConfig(), configCopy);
} else {
} else if (configCopy.getConnectionManager() != null) {
return configCopy.getConnectionManager();
}else {
throw new IllegalArgumentException("server(s) address(es) not defined!");
}
}

@ -0,0 +1,112 @@
/**
* 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.executor;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionService;
import java.util.concurrent.Executor;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import org.redisson.api.RFuture;
import org.redisson.api.RScheduledExecutorService;
import io.netty.util.concurrent.FutureListener;
/**
* A {@link CompletionService} that uses a supplied {@link Executor}
* to execute tasks. This class arranges that submitted tasks are,
* upon completion, placed on a queue accessible using {@code take}.
* The class is lightweight enough to be suitable for transient use
* when processing groups of tasks.
*
* @author Nikita Koksharov
*
* @param <V>
*/
public class RedissonCompletionService<V> implements CompletionService<V> {
protected final RScheduledExecutorService executorService;
protected final BlockingQueue<RFuture<V>> completionQueue;
public RedissonCompletionService(RScheduledExecutorService executorService) {
this(executorService, null);
}
public RedissonCompletionService(RScheduledExecutorService executorService, BlockingQueue<RFuture<V>> completionQueue) {
if (executorService == null) {
throw new NullPointerException("executorService can't be null");
}
this.executorService = executorService;
if (completionQueue == null) {
completionQueue = new LinkedBlockingQueue<RFuture<V>>();
}
this.completionQueue = completionQueue;
}
@Override
public Future<V> submit(Callable<V> task) {
if (task == null) {
throw new NullPointerException("taks can't be null");
}
final RFuture<V> f = executorService.submit(task);
f.addListener(new FutureListener<V>() {
@Override
public void operationComplete(io.netty.util.concurrent.Future<V> future) throws Exception {
completionQueue.add(f);
}
});
return f;
}
@Override
public Future<V> submit(Runnable task, V result) {
if (task == null) {
throw new NullPointerException("taks can't be null");
}
final RFuture<V> f = executorService.submit(task, result);
f.addListener(new FutureListener<V>() {
@Override
public void operationComplete(io.netty.util.concurrent.Future<V> future) throws Exception {
completionQueue.add(f);
}
});
return f;
}
@Override
public Future<V> take() throws InterruptedException {
return completionQueue.take();
}
@Override
public Future<V> poll() {
return completionQueue.poll();
}
@Override
public Future<V> poll(long timeout, TimeUnit unit) throws InterruptedException {
return completionQueue.poll(timeout, unit);
}
}

@ -62,7 +62,7 @@ public class URLBuilder {
}
};
public static void restoreURLFactory() {
public static synchronized void restoreURLFactory() {
try {
Field field = URL.class.getDeclaredField("factory");
field.setAccessible(true);
@ -72,7 +72,7 @@ public class URLBuilder {
}
}
public static void replaceURLFactory() {
public static synchronized void replaceURLFactory() {
try {
Field field = URL.class.getDeclaredField("factory");
field.setAccessible(true);

@ -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);
}
}

@ -18,6 +18,7 @@ package org.redisson.spring.cache;
import java.lang.reflect.Constructor;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import org.redisson.api.RLock;
import org.redisson.api.RMap;
@ -41,6 +42,10 @@ public class RedissonCache implements Cache {
private final RedissonClient redisson;
private final AtomicLong hits = new AtomicLong();
private final AtomicLong misses = new AtomicLong();
public RedissonCache(RedissonClient redisson, RMapCache<Object, Object> mapCache, CacheConfig config) {
this.mapCache = mapCache;
this.map = mapCache;
@ -66,12 +71,20 @@ public class RedissonCache implements Cache {
@Override
public ValueWrapper get(Object key) {
Object value = map.get(key);
if (value == null) {
addCacheMiss();
}else{
addCacheHit();
}
return toValueWrapper(value);
}
public <T> T get(Object key, Class<T> type) {
Object value = map.get(key);
if (value != null) {
if (value == null) {
addCacheMiss();
}else{
addCacheHit();
if (value.getClass().getName().equals(NullValue.class.getName())) {
return null;
}
@ -124,6 +137,7 @@ public class RedissonCache implements Cache {
public <T> T get(Object key, Callable<T> valueLoader) {
Object value = map.get(key);
if (value == null) {
addCacheMiss();
RLock lock = map.getLock(key);
lock.lock();
try {
@ -146,6 +160,8 @@ public class RedissonCache implements Cache {
} finally {
lock.unlock();
}
}else{
addCacheHit();
}
return (T) fromStoreValue(value);
@ -165,4 +181,26 @@ public class RedissonCache implements Cache {
return userValue;
}
/** The number of get requests that were satisfied by the cache.
* @return the number of hits
*/
long getCacheHits(){
return hits.get();
}
/** A miss is a get request that is not satisfied.
* @return the number of misses
*/
long getCacheMisses(){
return misses.get();
}
private void addCacheHit(){
hits.incrementAndGet();
}
private void addCacheMiss(){
misses.incrementAndGet();
}
}

@ -0,0 +1,41 @@
/**
* 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.cache;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.cache.CacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
*
* @author Craig Andrews
*
* {@link EnableAutoConfiguration Auto-configuration} for {@link RedissonCacheStatisticsProvider}
*
*/
@Configuration
@AutoConfigureAfter(CacheAutoConfiguration.class)
@ConditionalOnBean(CacheManager.class)
public class RedissonCacheStatisticsAutoConfiguration {
@Bean
public RedissonCacheStatisticsProvider redissonCacheStatisticsProvider(){
return new RedissonCacheStatisticsProvider();
}
}

@ -0,0 +1,38 @@
/**
* 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.cache;
import org.springframework.boot.actuate.cache.CacheStatistics;
import org.springframework.boot.actuate.cache.CacheStatisticsProvider;
import org.springframework.boot.actuate.cache.DefaultCacheStatistics;
import org.springframework.cache.CacheManager;
/**
*
* @author Craig Andrews
*
*/
public class RedissonCacheStatisticsProvider implements CacheStatisticsProvider<RedissonCache> {
@Override
public CacheStatistics getCacheStatistics(final CacheManager cacheManager, final RedissonCache cache) {
final DefaultCacheStatistics defaultCacheStatistics = new DefaultCacheStatistics();
defaultCacheStatistics.setSize((long) cache.getNativeCache().size());
defaultCacheStatistics.setGetCacheCounts(cache.getCacheHits(), cache.getCacheMisses());
return defaultCacheStatistics;
}
}

@ -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 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=org.redisson.spring.cache.RedissonCacheStatisticsAutoConfiguration

@ -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;
@ -172,7 +186,7 @@ public class RedisRunner {
e,
A
}
private final LinkedHashMap<REDIS_OPTIONS, String> options = new LinkedHashMap<>();
protected static RedisRunner.RedisProcess defaultRedisInstance;
private static int defaultRedisInstanceExitCode;
@ -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()
@ -306,7 +347,7 @@ public class RedisRunner {
options.remove(REDIS_OPTIONS.PORT);
return this;
}
public int getPort() {
return this.port;
}
@ -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;
}
@ -702,7 +749,70 @@ public class RedisRunner {
addConfigOption(REDIS_OPTIONS.AOF_REWRITE_INCREMENTAL_FSYNC, convertBoolean(aofRewriteIncrementalFsync));
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() {
}
}

@ -80,6 +80,16 @@ public class RedissonBucketTest extends BaseTest {
Assert.assertNull(bucket.get());
}
@Test
public void testTouch() {
RBucket<String> bucket = redisson.getBucket("test");
bucket.set("someValue");
assertThat(bucket.touch()).isTrue();
RBucket<String> bucket2 = redisson.getBucket("test2");
assertThat(bucket2.touch()).isFalse();
}
@Test
public void testRenamenx() {
RBucket<String> bucket = redisson.getBucket("test");

@ -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();
@ -76,14 +81,21 @@ public class RedissonCodecTest extends BaseTest {
test(redisson);
}
@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");
@ -28,7 +64,6 @@ public class RedissonDelayedQueueTest extends BaseTest {
dealyedQueue.destroy();
}
@Test
public void testDealyedQueueReadAll() {

@ -15,15 +15,27 @@ import org.redisson.api.RType;
public class RedissonKeysTest extends BaseTest {
@Test
public void testTouch() {
redisson.getSet("test").add("1");
redisson.getSet("test10").add("1");
assertThat(redisson.getKeys().touch("test")).isEqualTo(1);
assertThat(redisson.getKeys().touch("test", "test2")).isEqualTo(1);
assertThat(redisson.getKeys().touch("test3", "test2")).isEqualTo(0);
assertThat(redisson.getKeys().touch("test3", "test10", "test")).isEqualTo(2);
}
@Test
public void testExists() {
redisson.getSet("test").add("1");
redisson.getSet("test10").add("1");
assertThat(redisson.getKeys().isExists("test")).isEqualTo(1);
assertThat(redisson.getKeys().isExists("test", "test2")).isEqualTo(1);
assertThat(redisson.getKeys().isExists("test3", "test2")).isEqualTo(0);
assertThat(redisson.getKeys().isExists("test3", "test10", "test")).isEqualTo(2);
assertThat(redisson.getKeys().countExists("test")).isEqualTo(1);
assertThat(redisson.getKeys().countExists("test", "test2")).isEqualTo(1);
assertThat(redisson.getKeys().countExists("test3", "test2")).isEqualTo(0);
assertThat(redisson.getKeys().countExists("test3", "test10", "test")).isEqualTo(2);
}
@Test

@ -570,6 +570,17 @@ public class RedissonLocalCachedMapTest extends BaseTest {
assertThat(map.fastRemove(2)).isEqualTo(0);
assertThat(map.size()).isEqualTo(1);
}
@Test
public void testFastRemoveEmpty() throws InterruptedException, ExecutionException {
LocalCachedMapOptions options = LocalCachedMapOptions.defaults()
.evictionPolicy(EvictionPolicy.NONE)
.cacheSize(3)
.invalidateEntryOnChange(false);
RLocalCachedMap<String, Integer> map = redisson.getLocalCachedMap("test", options);
assertThat(map.fastRemove("test")).isZero();
}
@Test
public void testFastPut() {

@ -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,68 @@ 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();

@ -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;

@ -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>

@ -0,0 +1,71 @@
<?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:replicated-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"
database="0"
>
<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:replicated-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:sentinel-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-name="myMaster"
database="0"
>
<redisson:sentinel-address value="127.0.0.1:26379" />
<redisson:sentinel-address value="127.0.0.1:26380" />
</redisson:sentinel-servers>
</redisson:client>
</beans>

@ -0,0 +1,63 @@
<?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"/>
<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:single-server
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"
address="127.0.0.1:6379"
subscription-connection-minimum-idle-size="1"
subscription-connection-pool-size="50"
connection-minimum-idle-size="10"
connection-pool-size="64"
database="0"
dns-monitoring="false"
dns-monitoring-interval="5000"
/>
</redisson:client>
</beans>

@ -0,0 +1,186 @@
<?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>
<redisson:single-server address="${redisAddress}"/>
<redisson:binary-stream id="binary-stream" key="binary-stream"/>
<redisson:geo id="geo" key="geo"/>
<redisson:set-cache id="set-cache" key="set-cache"/>
<redisson:map-cache id="map-cache" key="map-cache"/>
<redisson:bucket id="bucket" key="bucket"/>
<redisson:buckets id="buckets"/>
<redisson:hyper-log-log id="hyper-log-log" key="hyper-log-log"/>
<redisson:list id="list" key="list"/>
<redisson:list-multimap id="list-multimap" key="list-multimap"/>
<redisson:list-multimap-cache id="list-multimap-cache" key="list-multimap-cache"/>
<redisson:local-cached-map id="local-cached-map" key="local-cached-map">
<redisson:local-cached-map-options id="local-options" eviction-policy="LRU"
time-to-live="1" time-to-live-unit="SECONDS" />
</redisson:local-cached-map>
<redisson:map id="map" key="map"/>
<redisson:set-multimap id="set-multimap" key="set-multimap"/>
<redisson:set-multimap-cache id="set-multimap-cache" key="set-multimap-cache"/>
<redisson:semaphore id="semaphore" key="semaphore"/>
<redisson:permit-expirable-semaphore id="permit-expirable-semaphore" key="permit-expirable-semaphore"/>
<redisson:lock id="lock" key="lock"/>
<redisson:fair-lock id="fair-lock" key="fair-lock"/>
<redisson:read-write-lock id="read-write-lock" key="read-write-lock">
<redisson:read-lock id="read-lock"/>
<redisson:write-lock id="write-lock"/>
</redisson:read-write-lock>
<redisson:multi-lock id="multi-lock">
<ref bean="lock"/>
<redisson:lock id="lock-1" key="lock-1"/>
<redisson:fair-lock id="fair-lock-1" key="fair-lock-1"/>
<redisson:write-lock id="write-lock-1" read-write-lock-ref="read-write-lock"/>
<redisson:read-lock id="read-lock-1" read-write-lock-ref="read-write-lock"/>
</redisson:multi-lock>
<redisson:red-lock id="red-lock">
<ref bean="lock"/>
<redisson:lock id="lock-2" key="lock-2"/>
<redisson:fair-lock id="fair-lock-2" key="fair-lock-2"/>
<redisson:write-lock id="write-lock-2" read-write-lock-ref="read-write-lock"/>
<redisson:read-lock id="read-lock-2" read-write-lock-ref="read-write-lock"/>
</redisson:red-lock>
<redisson:set id="set" key="set"/>
<redisson:sorted-set id="sorted-set" key="sorted-set"/>
<redisson:scored-sorted-set id="scored-sorted-set" key="scored-sorted-set"/>
<redisson:lex-sorted-set id="lex-sorted-set" key="lex-sorted-set"/>
<redisson:topic id="topic" topic="topic"/>
<redisson:pattern-topic id="pattern-topic" pattern="pattern-topic"/>
<redisson:blocking-fair-queue id="blocking-fair-queue" key="blocking-fair-queue"/>
<redisson:queue id="queue" key="queue"/>
<redisson:delayed-queue id="delayed-queue" destination-queue-ref="queue"/>
<redisson:priority-queue id="priority-queue" key="priority-queue"/>
<redisson:priority-deque id="priority-deque" key="priority-deque"/>
<redisson:blocking-queue id="blocking-queue" key="blocking-queue"/>
<redisson:bounded-blocking-queue id="bounded-blocking-queue" key="bounded-blocking-queue"/>
<redisson:deque id="deque" key="deque"/>
<redisson:blocking-deque id="blocking-deque" key="blocking-deque"/>
<redisson:atomic-long id="atomic-long" key="atomic-long"/>
<redisson:atomic-double id="atomic-double" key="atomic-double"/>
<redisson:count-down-latch id="count-down-latch" key="count-down-latch"/>
<redisson:bit-set id="bit-set" key="bit-set"/>
<redisson:bloom-filter id="bloom-filter" key="bloom-filter"/>
<redisson:script id="script"/>
<redisson:executor-service id="executor-service" service="executor-service"/>
<redisson:remote-service id="remote-service" service="remote-service">
<redisson:rpc-server api-class="org.redisson.RedissonRemoteServiceTest$RemoteInterface"
bean="remoteBean"/>
<redisson:rpc-client id="rpc-client" api-class="org.redisson.RedissonRemoteServiceTest$RemoteInterface">
<redisson:remote-invocation-options id="options">
<!--one of two-->
<!--<redisson:remote-no-ack/>-->
<redisson:remote-ack within="1" time-unit="SECONDS"/>
<!--one of two-->
<!--<redisson:remote-no-result/>-->
<redisson:remote-result within="1" time-unit="SECONDS"/>
</redisson:remote-invocation-options>
</redisson:rpc-client>
</redisson:remote-service>
<redisson:keys id="keys"/>
<redisson:live-object-service id="live-object-service">
<redisson:live-object-registration class="org.redisson.RedissonLiveObjectServiceTest$TestREntity" />
<redisson:live-object id="live-object" object-id="live-object"
class="org.redisson.RedissonLiveObjectServiceTest$TestREntity" />
</redisson:live-object-service>
</redisson:client>
<redisson:client id="myRedisson">
<redisson:single-server address="${redisAddress}"/>
</redisson:client>
<redisson:client id="myRedisson1">
<redisson:single-server address="${redisAddress}"/>
</redisson:client>
<!--External definitions-->
<redisson:binary-stream id="binary-stream-ext" key="binary-stream-ext" redisson-ref="myRedisson"/>
<redisson:geo id="geo-ext" key="geo-ext" redisson-ref="myRedisson"/>
<redisson:set-cache id="set-cache-ext" key="set-cache-ext" redisson-ref="myRedisson"/>
<redisson:map-cache id="map-cache-ext" key="map-cache-ext" redisson-ref="myRedisson"/>
<redisson:bucket id="bucket-ext" key="bucket-ext" redisson-ref="myRedisson"/>
<redisson:buckets id="buckets-ext" redisson-ref="myRedisson"/>
<redisson:hyper-log-log id="hyper-log-log-ext" key="hyper-log-log-ext" redisson-ref="myRedisson"/>
<redisson:list id="list-ext" key="list-ext" redisson-ref="myRedisson"/>
<redisson:list-multimap id="list-multimap-ext" key="list-multimap-ext" redisson-ref="myRedisson"/>
<redisson:list-multimap-cache id="list-multimap-cache-ext" key="list-multimap-cache-ext" redisson-ref="myRedisson"/>
<redisson:local-cached-map id="local-cached-map-ext" key="local-cached-map-ext" redisson-ref="myRedisson">
<redisson:local-cached-map-options id="local-options-ext" eviction-policy="LRU"
time-to-live="1" time-to-live-unit="SECONDS" />
</redisson:local-cached-map>
<redisson:map id="map-ext" key="map-ext" redisson-ref="myRedisson"/>
<redisson:set-multimap id="set-multimap-ext" key="set-multimap-ext" redisson-ref="myRedisson"/>
<redisson:set-multimap-cache id="set-multimap-cache-ext" key="set-multimap-cache-ext" redisson-ref="myRedisson"/>
<redisson:semaphore id="semaphore-ext" key="semaphore-ext" redisson-ref="myRedisson"/>
<redisson:permit-expirable-semaphore id="permit-expirable-semaphore-ext" key="permit-expirable-semaphore-ext" redisson-ref="myRedisson"/>
<redisson:lock id="lock-ext" key="lock-ext" redisson-ref="myRedisson"/>
<redisson:fair-lock id="fair-lock-ext" key="fair-lock-ext" redisson-ref="myRedisson"/>
<redisson:read-write-lock id="read-write-lock-ext" key="read-write-lock-ext" redisson-ref="myRedisson">
<redisson:read-lock id="read-lock-ext"/>
<redisson:write-lock id="write-lock-ext"/>
</redisson:read-write-lock>
<redisson:multi-lock id="multi-lock-ext" redisson-ref="myRedisson">
<ref bean="lock-ext"/>
<redisson:lock id="lock-1-ext" key="lock-1-ext" redisson-ref="myRedisson1"/>
<redisson:fair-lock id="fair-lock-1-ext" key="fair-lock-1-ext" redisson-ref="myRedisson1"/>
<redisson:write-lock id="write-lock-1-ext" read-write-lock-ref="read-write-lock-ext"/>
<redisson:read-lock id="read-lock-1-ext" read-write-lock-ref="read-write-lock-ext"/>
</redisson:multi-lock>
<redisson:red-lock id="red-lock-ext" redisson-ref="myRedisson">
<ref bean="lock-ext"/>
<redisson:lock id="lock-2-ext" key="lock-2-ext"/>
<redisson:fair-lock id="fair-lock-2-ext" key="fair-lock-2-ext"/>
<redisson:write-lock id="write-lock-2-ext" read-write-lock-ref="read-write-lock-ext"/>
<redisson:read-lock id="read-lock-2-ext" read-write-lock-ref="read-write-lock-ext"/>
</redisson:red-lock>
<redisson:set id="set-ext" key="set-ext" redisson-ref="myRedisson"/>
<redisson:sorted-set id="sorted-set-ext" key="sorted-set-ext" redisson-ref="myRedisson"/>
<redisson:scored-sorted-set id="scored-sorted-set-ext" key="scored-sorted-set-ext" redisson-ref="myRedisson"/>
<redisson:lex-sorted-set id="lex-sorted-set-ext" key="lex-sorted-set-ext" redisson-ref="myRedisson"/>
<redisson:topic id="topic-ext" topic="topic-ext" redisson-ref="myRedisson"/>
<redisson:pattern-topic id="pattern-topic-ext" pattern="pattern-topic-ext" redisson-ref="myRedisson"/>
<redisson:blocking-fair-queue id="blocking-fair-queue-ext" key="blocking-fair-queue-ext" redisson-ref="myRedisson"/>
<redisson:queue id="queue-ext" key="queue-ext" redisson-ref="myRedisson"/>
<redisson:delayed-queue id="delayed-queue-ext" destination-queue-ref="queue-ext" redisson-ref="myRedisson"/>
<redisson:priority-queue id="priority-queue-ext" key="priority-queue-ext" redisson-ref="myRedisson"/>
<redisson:priority-deque id="priority-deque-ext" key="priority-deque-ext" redisson-ref="myRedisson"/>
<redisson:blocking-queue id="blocking-queue-ext" key="blocking-queue-ext" redisson-ref="myRedisson"/>
<redisson:bounded-blocking-queue id="bounded-blocking-queue-ext" key="bounded-blocking-queue-ext" redisson-ref="myRedisson"/>
<redisson:deque id="deque-ext" key="deque-ext" redisson-ref="myRedisson"/>
<redisson:blocking-deque id="blocking-deque-ext" key="blocking-deque-ext" redisson-ref="myRedisson"/>
<redisson:atomic-long id="atomic-long-ext" key="atomic-long-ext" redisson-ref="myRedisson"/>
<redisson:atomic-double id="atomic-double-ext" key="atomic-double-ext" redisson-ref="myRedisson"/>
<redisson:count-down-latch id="count-down-latch-ext" key="count-down-latch-ext" redisson-ref="myRedisson"/>
<redisson:bit-set id="bit-set-ext" key="bit-set-ext" redisson-ref="myRedisson"/>
<redisson:bloom-filter id="bloom-filter-ext" key="bloom-filter-ext" redisson-ref="myRedisson"/>
<redisson:script id="script-ext" redisson-ref="myRedisson"/>
<redisson:executor-service id="executor-service-ext" service="executor-service-ext" redisson-ref="myRedisson"/>
<redisson:remote-service id="remote-service-ext" service="remote-service-ext" redisson-ref="myRedisson">
<redisson:rpc-server api-class="org.redisson.RedissonRemoteServiceTest$RemoteInterface"
bean="remoteBean"/>
<redisson:rpc-client id="rpc-client-ext" api-class="org.redisson.RedissonRemoteServiceTest$RemoteInterface">
<redisson:remote-invocation-options id="options-ext">
<redisson:remote-ack within="1" time-unit="SECONDS"/>
<redisson:remote-result within="1" time-unit="SECONDS"/>
</redisson:remote-invocation-options>
</redisson:rpc-client>
</redisson:remote-service>
<redisson:keys id="keys-ext" redisson-ref="myRedisson"/>
<redisson:live-object-service id="live-object-service-ext" redisson-ref="myRedisson">
<redisson:live-object-registration class="org.redisson.RedissonLiveObjectServiceTest$TestREntity" />
<redisson:live-object id="live-object-ext" object-id="live-object-ext"
class="org.redisson.RedissonLiveObjectServiceTest$TestREntity" />
</redisson:live-object-service>
<bean id="remoteBean" class="org.redisson.RedissonRemoteServiceTest.RemoteImpl" />
</beans>
Loading…
Cancel
Save