diff --git a/spring-datastore-redis/pom.xml b/spring-datastore-redis/pom.xml index 95b738e3c..45683d3a6 100644 --- a/spring-datastore-redis/pom.xml +++ b/spring-datastore-redis/pom.xml @@ -13,6 +13,7 @@ 02112010 + 1.4.0 @@ -96,7 +97,7 @@ redis.clients jedis - 1.3.1 + ${jedis.ver} compile diff --git a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/connection/DefaultTuple.java b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/connection/DefaultTuple.java index 62807b8d2..11d8d68e4 100644 --- a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/connection/DefaultTuple.java +++ b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/connection/DefaultTuple.java @@ -25,7 +25,7 @@ import org.springframework.datastore.redis.connection.RedisZSetCommands.Tuple; public class DefaultTuple implements Tuple { private final Double score; - private final String value; + private final byte[] value; /** @@ -34,7 +34,7 @@ public class DefaultTuple implements Tuple { * @param value * @param score */ - public DefaultTuple(String value, Double score) { + public DefaultTuple(byte[] value, Double score) { this.score = score; this.value = value; } @@ -45,7 +45,7 @@ public class DefaultTuple implements Tuple { } @Override - public String getValue() { + public byte[] getValue() { return value; } } diff --git a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/connection/RedisCommands.java b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/connection/RedisCommands.java index 74d284309..70e1cd397 100644 --- a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/connection/RedisCommands.java +++ b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/connection/RedisCommands.java @@ -26,27 +26,27 @@ import java.util.Collection; public interface RedisCommands extends RedisTxCommands, RedisStringCommands, RedisListCommands, RedisSetCommands, RedisZSetCommands, RedisHashCommands { - Boolean exists(String key); + Boolean exists(byte[] key); - Integer del(String... keys); + Integer del(byte[]... keys); - DataType type(String key); + DataType type(byte[] key); - Collection keys(String pattern); + Collection keys(byte[] pattern); - String randomKey(); + byte[] randomKey(); - void rename(String oldName, String newName); + void rename(byte[] oldName, byte[] newName); - Boolean renameNX(String oldName, String newName); + Boolean renameNX(byte[] oldName, byte[] newName); Integer dbSize(); - Boolean expire(String key, int seconds); + Boolean expire(byte[] key, int seconds); - Boolean persist(String key); + Boolean persist(byte[] key); - Integer ttl(String key); + Integer ttl(byte[] key); void select(int dbIndex); diff --git a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/connection/RedisConnection.java b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/connection/RedisConnection.java index ce94a9911..46de8ffd7 100644 --- a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/connection/RedisConnection.java +++ b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/connection/RedisConnection.java @@ -37,8 +37,6 @@ public interface RedisConnection extends RedisCommands { Object getNativeConnection(); - String getEncoding(); - /** * Indicates whether the connection is in "queue"(or "MULTI") mode or not. * When queueing, all commands are postponed until EXEC or DISCARD commands diff --git a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/connection/RedisHashCommands.java b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/connection/RedisHashCommands.java index e51cf5ddd..aac379edb 100644 --- a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/connection/RedisHashCommands.java +++ b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/connection/RedisHashCommands.java @@ -17,6 +17,7 @@ package org.springframework.datastore.redis.connection; import java.util.List; +import java.util.Map; import java.util.Set; /** @@ -26,33 +27,27 @@ import java.util.Set; */ public interface RedisHashCommands { - public interface Entry { - public String getField(); + Boolean hSet(byte[] key, byte[] field, byte[] value); - public String getValue(); - } + Boolean hSetNX(byte[] key, byte[] field, byte[] value); - Boolean hSet(String key, String field, String value); + byte[] hGet(byte[] key, byte[] field); - Boolean hSetNX(String key, String field, String value); + List hMGet(byte[] key, byte[]... fields); - String hGet(String key, String field); + void hMSet(byte[] key, Map hashes); - List hMGet(String key, String... fields); + Integer hIncrBy(byte[] key, byte[] field, int delta); - void hMSet(String key, String[] fields, String[] values); + Boolean hExists(byte[] key, byte[] field); - Integer hIncrBy(String key, String field, int delta); + Boolean hDel(byte[] key, byte[] field); - Boolean hExists(String key, String field); + Integer hLen(byte[] key); - Boolean hDel(String key, String field); + Set hKeys(byte[] key); - Integer hLen(String key); + List hVals(byte[] key); - Set hKeys(String key); - - List hVals(String key); - - Set hGetAll(String key); + Map hGetAll(byte[] key); } diff --git a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/connection/RedisListCommands.java b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/connection/RedisListCommands.java index bb2730005..0fdc343bf 100644 --- a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/connection/RedisListCommands.java +++ b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/connection/RedisListCommands.java @@ -25,29 +25,29 @@ import java.util.List; */ public interface RedisListCommands { - Integer rPush(String key, String value); + Integer rPush(byte[] key, byte[] value); - Integer lPush(String key, String value); + Integer lPush(byte[] key, byte[] value); - Integer lLen(String key); + Integer lLen(byte[] key); - List lRange(String key, int start, int end); + List lRange(byte[] key, int start, int end); - void lTrim(String key, int start, int end); + void lTrim(byte[] key, int start, int end); - String lIndex(String key, int index); + byte[] lIndex(byte[] key, int index); - void lSet(String key, int index, String value); + void lSet(byte[] key, int index, byte[] value); - Integer lRem(String key, int count, String value); + Integer lRem(byte[] key, int count, byte[] value); - String lPop(String key); + byte[] lPop(byte[] key); - String rPop(String key); + byte[] rPop(byte[] key); - List bLPop(int timeout, String... keys); + List bLPop(int timeout, byte[]... keys); - List bRPop(int timeout, String... keys); + List bRPop(int timeout, byte[]... keys); - String rPopLPush(String srcKey, String dstKey); + byte[] rPopLPush(byte[] srcKey, byte[] dstKey); } diff --git a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/connection/RedisSetCommands.java b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/connection/RedisSetCommands.java index 302710d1e..244d0f3d8 100644 --- a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/connection/RedisSetCommands.java +++ b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/connection/RedisSetCommands.java @@ -25,31 +25,31 @@ import java.util.Set; */ public interface RedisSetCommands { - Boolean sAdd(String key, String value); + Boolean sAdd(byte[] key, byte[] value); - Boolean sRem(String key, String value); + Boolean sRem(byte[] key, byte[] value); - String sPop(String key); + byte[] sPop(byte[] key); - Boolean sMove(String srcKey, String destKey, String value); + Boolean sMove(byte[] srcKey, byte[] destKey, byte[] value); - Integer sCard(String key); + Integer sCard(byte[] key); - Boolean sIsMember(String key, String value); + Boolean sIsMember(byte[] key, byte[] value); - Set sInter(String... keys); + Set sInter(byte[]... keys); - void sInterStore(String destKey, String... keys); + void sInterStore(byte[] destKey, byte[]... keys); - Set sUnion(String... keys); + Set sUnion(byte[]... keys); - void sUnionStore(String destKey, String... keys); + void sUnionStore(byte[] destKey, byte[]... keys); - Set sDiff(String... keys); + Set sDiff(byte[]... keys); - void sDiffStore(String destKey, String... keys); + void sDiffStore(byte[] destKey, byte[]... keys); - Set sMembers(String key); + Set sMembers(byte[] key); - String sRandMember(String key); + byte[] sRandMember(byte[] key); } diff --git a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/connection/RedisStringCommands.java b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/connection/RedisStringCommands.java index 2f163d3e5..b5c56f1a2 100644 --- a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/connection/RedisStringCommands.java +++ b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/connection/RedisStringCommands.java @@ -17,6 +17,7 @@ package org.springframework.datastore.redis.connection; import java.util.List; +import java.util.Map; /** * String specific commands supported by Redis. @@ -25,31 +26,31 @@ import java.util.List; */ public interface RedisStringCommands { - void set(String key, String value); + void set(byte[] key, byte[] value); - String get(String key); + byte[] get(byte[] key); - String getSet(String key, String value); + byte[] getSet(byte[] key, byte[] value); - List mGet(String... keys); + List mGet(byte[]... keys); - Boolean setNX(String key, String value); + Boolean setNX(byte[] key, byte[] value); - void setEx(String key, int seconds, String value); + void setEx(byte[] key, int seconds, byte[] value); - void mSet(String[] keys, String[] values); + void mSet(Map tuple); - void mSetNX(String[] keys, String[] values); + void mSetNX(Map tuple); - Integer incr(String key); + Integer incr(byte[] key); - Integer incrBy(String key, int value); + Integer incrBy(byte[] key, int value); - Integer decr(String key); + Integer decr(byte[] key); - Integer decrBy(String key, int value); + Integer decrBy(byte[] key, int value); - Integer append(String key, String value); + Integer append(byte[] key, byte[] value); - String substr(String key, int start, int end); + byte[] substr(byte[] key, int start, int end); } diff --git a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/connection/RedisTxCommands.java b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/connection/RedisTxCommands.java index 23ee193ae..db2592817 100644 --- a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/connection/RedisTxCommands.java +++ b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/connection/RedisTxCommands.java @@ -31,7 +31,7 @@ public interface RedisTxCommands { void discard(); - void watch(String... keys); + void watch(byte[]... keys); void unwatch(); } diff --git a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/connection/RedisZSetCommands.java b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/connection/RedisZSetCommands.java index 1024c3169..93a11200d 100644 --- a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/connection/RedisZSetCommands.java +++ b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/connection/RedisZSetCommands.java @@ -31,52 +31,52 @@ public interface RedisZSetCommands { } public interface Tuple { - String getValue(); + byte[] getValue(); Double getScore(); } - Boolean zAdd(String key, double score, String value); + Boolean zAdd(byte[] key, double score, byte[] value); - Boolean zRem(String key, String value); + Boolean zRem(byte[] key, byte[] value); - Double zIncrBy(String key, double increment, String value); + Double zIncrBy(byte[] key, double increment, byte[] value); - Integer zRank(String key, String value); + Integer zRank(byte[] key, byte[] value); - Integer zRevRank(String key, String value); + Integer zRevRank(byte[] key, byte[] value); - Set zRange(String key, int start, int end); + Set zRange(byte[] key, int start, int end); - Set zRangeWithScore(String key, int start, int end); + Set zRangeWithScore(byte[] key, int start, int end); - Set zRevRange(String key, int start, int end); + Set zRevRange(byte[] key, int start, int end); - Set zRevRangeWithScore(String key, int start, int end); + Set zRevRangeWithScore(byte[] key, int start, int end); - Set zRangeByScore(String key, double min, double max); + Set zRangeByScore(byte[] key, double min, double max); - Set zRangeByScoreWithScore(String key, double min, double max); + Set zRangeByScoreWithScore(byte[] key, double min, double max); - Set zRangeByScore(String key, double min, double max, int offset, int count); + Set zRangeByScore(byte[] key, double min, double max, int offset, int count); - Set zRangeByScoreWithScore(String key, double min, double max, int offset, int count); + Set zRangeByScoreWithScore(byte[] key, double min, double max, int offset, int count); - Integer zCount(String key, double min, double max); + Integer zCount(byte[] key, double min, double max); - Integer zCard(String key); + Integer zCard(byte[] key); - Double zScore(String key, String value); + Double zScore(byte[] key, byte[] value); - Integer zRemRange(String key, int start, int end); + Integer zRemRange(byte[] key, int start, int end); - Integer zRemRangeByScore(String key, double min, double max); + Integer zRemRangeByScore(byte[] key, double min, double max); - Integer zUnionStore(String destKey, String... sets); + Integer zUnionStore(byte[] destKey, byte[]... sets); - Integer zUnionStore(String destKey, Aggregate aggregate, int[] weights, String... sets); + Integer zUnionStore(byte[] destKey, Aggregate aggregate, int[] weights, byte[]... sets); - Integer zInterStore(String destKey, String... sets); + Integer zInterStore(byte[] destKey, byte[]... sets); - Integer zInterStore(String destKey, Aggregate aggregate, int[] weights, String... sets); + Integer zInterStore(byte[] destKey, Aggregate aggregate, int[] weights, byte[]... sets); } \ No newline at end of file diff --git a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/connection/jedis/JedisConnection.java b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/connection/jedis/JedisConnection.java index 075e15542..6a3c7c53e 100644 --- a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/connection/jedis/JedisConnection.java +++ b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/connection/jedis/JedisConnection.java @@ -17,8 +17,8 @@ package org.springframework.datastore.redis.connection.jedis; import java.io.IOException; import java.lang.reflect.Field; +import java.util.ArrayList; import java.util.Collection; -import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -30,6 +30,8 @@ import org.springframework.datastore.redis.connection.DataType; import org.springframework.datastore.redis.connection.RedisConnection; import org.springframework.util.ReflectionUtils; +import redis.clients.jedis.BinaryJedis; +import redis.clients.jedis.BinaryTransaction; import redis.clients.jedis.Client; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisException; @@ -46,13 +48,13 @@ public class JedisConnection implements RedisConnection { private static final Field CLIENT_FIELD; static { - CLIENT_FIELD = ReflectionUtils.findField(Jedis.class, "client", Client.class); + CLIENT_FIELD = ReflectionUtils.findField(BinaryJedis.class, "client", Client.class); ReflectionUtils.makeAccessible(CLIENT_FIELD); } private final Jedis jedis; private final Client client; - private final Transaction transaction; + private final BinaryTransaction transaction; public JedisConnection(Jedis jedis) { this.jedis = jedis; @@ -86,11 +88,6 @@ public class JedisConnection implements RedisConnection { } } - @Override - public String getEncoding() { - return "UTF-8"; - } - @Override public Jedis getNativeConnection() { return jedis; @@ -124,7 +121,7 @@ public class JedisConnection implements RedisConnection { } @Override - public Integer del(String... keys) { + public Integer del(byte[]... keys) { try { if (isQueueing()) { transaction.del(keys); @@ -155,7 +152,7 @@ public class JedisConnection implements RedisConnection { } @Override - public Boolean exists(String key) { + public Boolean exists(byte[] key) { try { if (isQueueing()) { transaction.exists(key); @@ -168,7 +165,7 @@ public class JedisConnection implements RedisConnection { } @Override - public Boolean expire(String key, int seconds) { + public Boolean expire(byte[] key, int seconds) { try { if (isQueueing()) { transaction.expire(key, seconds); @@ -181,7 +178,7 @@ public class JedisConnection implements RedisConnection { } @Override - public Collection keys(String pattern) { + public Collection keys(byte[] pattern) { try { if (isQueueing()) { transaction.keys(pattern); @@ -203,7 +200,7 @@ public class JedisConnection implements RedisConnection { } @Override - public Boolean persist(String key) { + public Boolean persist(byte[] key) { try { if (isQueueing()) { client.persist(key); @@ -216,20 +213,20 @@ public class JedisConnection implements RedisConnection { } @Override - public String randomKey() { + public byte[] randomKey() { try { if (isQueueing()) { - transaction.randomKey(); + transaction.randomBinaryKey(); return null; } - return jedis.randomKey(); + return jedis.randomBinaryKey(); } catch (Exception ex) { throw convertJedisAccessException(ex); } } @Override - public void rename(String oldName, String newName) { + public void rename(byte[] oldName, byte[] newName) { try { if (isQueueing()) { transaction.rename(oldName, newName); @@ -241,7 +238,7 @@ public class JedisConnection implements RedisConnection { } @Override - public Boolean renameNX(String oldName, String newName) { + public Boolean renameNX(byte[] oldName, byte[] newName) { try { if (isQueueing()) { transaction.renamenx(oldName, newName); @@ -266,7 +263,7 @@ public class JedisConnection implements RedisConnection { } @Override - public Integer ttl(String key) { + public Integer ttl(byte[] key) { try { if (isQueueing()) { transaction.ttl(key); @@ -279,7 +276,7 @@ public class JedisConnection implements RedisConnection { } @Override - public DataType type(String key) { + public DataType type(byte[] key) { try { if (isQueueing()) { transaction.type(key); @@ -301,14 +298,14 @@ public class JedisConnection implements RedisConnection { } @Override - public void watch(String... keys) { + public void watch(byte[]... keys) { if (isQueueing()) { // ignore (as watch not allowed in multi) return; } try { - for (String key : keys) { + for (byte[] key : keys) { jedis.watch(key); } } catch (Exception ex) { @@ -321,7 +318,7 @@ public class JedisConnection implements RedisConnection { // @Override - public String get(String key) { + public byte[] get(byte[] key) { try { if (isQueueing()) { transaction.get(key); @@ -335,7 +332,7 @@ public class JedisConnection implements RedisConnection { } @Override - public void set(String key, String value) { + public void set(byte[] key, byte[] value) { try { jedis.set(key, value); } catch (Exception ex) { @@ -345,7 +342,7 @@ public class JedisConnection implements RedisConnection { @Override - public String getSet(String key, String value) { + public byte[] getSet(byte[] key, byte[] value) { try { if (isQueueing()) { transaction.getSet(key, value); @@ -358,7 +355,7 @@ public class JedisConnection implements RedisConnection { } @Override - public Integer append(String key, String value) { + public Integer append(byte[] key, byte[] value) { try { if (isQueueing()) { transaction.append(key, value); @@ -371,7 +368,7 @@ public class JedisConnection implements RedisConnection { } @Override - public List mGet(String... keys) { + public List mGet(byte[]... keys) { try { if (isQueueing()) { transaction.mget(keys); @@ -384,31 +381,31 @@ public class JedisConnection implements RedisConnection { } @Override - public void mSet(String[] keys, String[] values) { + public void mSet(Map tuples) { try { if (isQueueing()) { - transaction.mset(JedisUtils.arrange(keys, values)); + transaction.mset(JedisUtils.convert(tuples)); } - jedis.mset(JedisUtils.arrange(keys, values)); + jedis.mset(JedisUtils.convert(tuples)); } catch (Exception ex) { throw convertJedisAccessException(ex); } } @Override - public void mSetNX(String[] keys, String[] values) { + public void mSetNX(Map tuples) { try { if (isQueueing()) { - transaction.msetnx(JedisUtils.arrange(keys, values)); + transaction.msetnx(JedisUtils.convert(tuples)); } - jedis.msetnx(JedisUtils.arrange(keys, values)); + jedis.msetnx(JedisUtils.convert(tuples)); } catch (Exception ex) { throw convertJedisAccessException(ex); } } @Override - public void setEx(String key, int time, String value) { + public void setEx(byte[] key, int time, byte[] value) { try { if (isQueueing()) { transaction.setex(key, time, value); @@ -420,7 +417,7 @@ public class JedisConnection implements RedisConnection { } @Override - public Boolean setNX(String key, String value) { + public Boolean setNX(byte[] key, byte[] value) { try { if (isQueueing()) { transaction.setnx(key, value); @@ -432,7 +429,7 @@ public class JedisConnection implements RedisConnection { } @Override - public String substr(String key, int start, int end) { + public byte[] substr(byte[] key, int start, int end) { try { if (isQueueing()) { transaction.substr(key, start, end); @@ -445,7 +442,7 @@ public class JedisConnection implements RedisConnection { } @Override - public Integer decr(String key) { + public Integer decr(byte[] key) { try { if (isQueueing()) { transaction.decr(key); @@ -458,7 +455,7 @@ public class JedisConnection implements RedisConnection { } @Override - public Integer decrBy(String key, int value) { + public Integer decrBy(byte[] key, int value) { try { if (isQueueing()) { transaction.decrBy(key, value); @@ -471,7 +468,7 @@ public class JedisConnection implements RedisConnection { } @Override - public Integer incr(String key) { + public Integer incr(byte[] key) { try { if (isQueueing()) { transaction.incr(key); @@ -484,7 +481,7 @@ public class JedisConnection implements RedisConnection { } @Override - public Integer incrBy(String key, int value) { + public Integer incrBy(byte[] key, int value) { try { if (isQueueing()) { transaction.incrBy(key, value); @@ -502,7 +499,7 @@ public class JedisConnection implements RedisConnection { @Override - public Integer lPush(String key, String value) { + public Integer lPush(byte[] key, byte[] value) { try { if (isQueueing()) { transaction.lpush(key, value); @@ -515,7 +512,7 @@ public class JedisConnection implements RedisConnection { } @Override - public Integer rPush(String key, String value) { + public Integer rPush(byte[] key, byte[] value) { try { if (isQueueing()) { transaction.rpush(key, value); @@ -528,7 +525,7 @@ public class JedisConnection implements RedisConnection { } @Override - public List bLPop(int timeout, String... keys) { + public List bLPop(int timeout, byte[]... keys) { try { if (isQueueing()) { throw new UnsupportedOperationException(); @@ -540,7 +537,7 @@ public class JedisConnection implements RedisConnection { } @Override - public List bRPop(int timeout, String... keys) { + public List bRPop(int timeout, byte[]... keys) { try { if (isQueueing()) { throw new UnsupportedOperationException(); @@ -552,7 +549,7 @@ public class JedisConnection implements RedisConnection { } @Override - public String lIndex(String key, int index) { + public byte[] lIndex(byte[] key, int index) { try { if (isQueueing()) { transaction.lindex(key, index); @@ -565,7 +562,7 @@ public class JedisConnection implements RedisConnection { } @Override - public Integer lLen(String key) { + public Integer lLen(byte[] key) { try { if (isQueueing()) { transaction.llen(key); @@ -578,7 +575,7 @@ public class JedisConnection implements RedisConnection { } @Override - public String lPop(String key) { + public byte[] lPop(byte[] key) { try { if (isQueueing()) { transaction.lpop(key); @@ -591,7 +588,7 @@ public class JedisConnection implements RedisConnection { } @Override - public List lRange(String key, int start, int end) { + public List lRange(byte[] key, int start, int end) { try { if (isQueueing()) { transaction.lrange(key, start, end); @@ -604,7 +601,7 @@ public class JedisConnection implements RedisConnection { } @Override - public Integer lRem(String key, int count, String value) { + public Integer lRem(byte[] key, int count, byte[] value) { try { if (isQueueing()) { transaction.lrem(key, count, value); @@ -617,7 +614,7 @@ public class JedisConnection implements RedisConnection { } @Override - public void lSet(String key, int index, String value) { + public void lSet(byte[] key, int index, byte[] value) { try { if (isQueueing()) { transaction.lset(key, index, value); @@ -629,7 +626,7 @@ public class JedisConnection implements RedisConnection { } @Override - public void lTrim(String key, int start, int end) { + public void lTrim(byte[] key, int start, int end) { try { if (isQueueing()) { transaction.ltrim(key, start, end); @@ -641,7 +638,7 @@ public class JedisConnection implements RedisConnection { } @Override - public String rPop(String key) { + public byte[] rPop(byte[] key) { try { if (isQueueing()) { transaction.rpop(key); @@ -654,7 +651,7 @@ public class JedisConnection implements RedisConnection { } @Override - public String rPopLPush(String srcKey, String dstKey) { + public byte[] rPopLPush(byte[] srcKey, byte[] dstKey) { try { if (isQueueing()) { transaction.rpoplpush(srcKey, dstKey); @@ -672,7 +669,7 @@ public class JedisConnection implements RedisConnection { // @Override - public Boolean sAdd(String key, String value) { + public Boolean sAdd(byte[] key, byte[] value) { try { if (isQueueing()) { transaction.sadd(key, value); @@ -685,7 +682,7 @@ public class JedisConnection implements RedisConnection { } @Override - public Integer sCard(String key) { + public Integer sCard(byte[] key) { try { if (isQueueing()) { transaction.scard(key); @@ -698,7 +695,7 @@ public class JedisConnection implements RedisConnection { } @Override - public Set sDiff(String... keys) { + public Set sDiff(byte[]... keys) { try { if (isQueueing()) { transaction.sdiff(keys); @@ -711,7 +708,7 @@ public class JedisConnection implements RedisConnection { } @Override - public void sDiffStore(String destKey, String... keys) { + public void sDiffStore(byte[] destKey, byte[]... keys) { try { if (isQueueing()) { transaction.sdiffstore(destKey, keys); @@ -723,7 +720,7 @@ public class JedisConnection implements RedisConnection { } @Override - public Set sInter(String... keys) { + public Set sInter(byte[]... keys) { try { if (isQueueing()) { transaction.sinter(keys); @@ -736,7 +733,7 @@ public class JedisConnection implements RedisConnection { } @Override - public void sInterStore(String destKey, String... keys) { + public void sInterStore(byte[] destKey, byte[]... keys) { try { if (isQueueing()) { transaction.sinterstore(destKey, keys); @@ -748,7 +745,7 @@ public class JedisConnection implements RedisConnection { } @Override - public Boolean sIsMember(String key, String value) { + public Boolean sIsMember(byte[] key, byte[] value) { try { if (isQueueing()) { transaction.sismember(key, value); @@ -761,7 +758,7 @@ public class JedisConnection implements RedisConnection { } @Override - public Set sMembers(String key) { + public Set sMembers(byte[] key) { try { if (isQueueing()) { transaction.smembers(key); @@ -774,7 +771,7 @@ public class JedisConnection implements RedisConnection { } @Override - public Boolean sMove(String srcKey, String destKey, String value) { + public Boolean sMove(byte[] srcKey, byte[] destKey, byte[] value) { try { if (isQueueing()) { transaction.smove(srcKey, destKey, value); @@ -787,7 +784,7 @@ public class JedisConnection implements RedisConnection { } @Override - public String sPop(String key) { + public byte[] sPop(byte[] key) { try { if (isQueueing()) { transaction.spop(key); @@ -800,7 +797,7 @@ public class JedisConnection implements RedisConnection { } @Override - public String sRandMember(String key) { + public byte[] sRandMember(byte[] key) { try { if (isQueueing()) { transaction.srandmember(key); @@ -813,7 +810,7 @@ public class JedisConnection implements RedisConnection { } @Override - public Boolean sRem(String key, String value) { + public Boolean sRem(byte[] key, byte[] value) { try { if (isQueueing()) { transaction.srem(key, value); @@ -826,7 +823,7 @@ public class JedisConnection implements RedisConnection { } @Override - public Set sUnion(String... keys) { + public Set sUnion(byte[]... keys) { try { if (isQueueing()) { transaction.sunion(keys); @@ -839,7 +836,7 @@ public class JedisConnection implements RedisConnection { } @Override - public void sUnionStore(String destKey, String... keys) { + public void sUnionStore(byte[] destKey, byte[]... keys) { try { if (isQueueing()) { transaction.sunionstore(destKey, keys); @@ -855,7 +852,7 @@ public class JedisConnection implements RedisConnection { // @Override - public Boolean zAdd(String key, double score, String value) { + public Boolean zAdd(byte[] key, double score, byte[] value) { try { if (isQueueing()) { transaction.zadd(key, score, value); @@ -868,7 +865,7 @@ public class JedisConnection implements RedisConnection { } @Override - public Integer zCard(String key) { + public Integer zCard(byte[] key) { try { if (isQueueing()) { transaction.zcard(key); @@ -881,7 +878,7 @@ public class JedisConnection implements RedisConnection { } @Override - public Integer zCount(String key, double min, double max) { + public Integer zCount(byte[] key, double min, double max) { try { if (isQueueing()) { throw new UnsupportedOperationException(); @@ -893,7 +890,7 @@ public class JedisConnection implements RedisConnection { } @Override - public Double zIncrBy(String key, double increment, String value) { + public Double zIncrBy(byte[] key, double increment, byte[] value) { try { if (isQueueing()) { transaction.zincrby(key, increment, value); @@ -906,7 +903,7 @@ public class JedisConnection implements RedisConnection { } @Override - public Integer zInterStore(String destKey, Aggregate aggregate, int[] weights, String... sets) { + public Integer zInterStore(byte[] destKey, Aggregate aggregate, int[] weights, byte[]... sets) { try { if (isQueueing()) { throw new UnsupportedOperationException(); @@ -920,7 +917,7 @@ public class JedisConnection implements RedisConnection { } @Override - public Integer zInterStore(String destKey, String... sets) { + public Integer zInterStore(byte[] destKey, byte[]... sets) { try { if (isQueueing()) { throw new UnsupportedOperationException(); @@ -932,7 +929,7 @@ public class JedisConnection implements RedisConnection { } @Override - public Set zRange(String key, int start, int end) { + public Set zRange(byte[] key, int start, int end) { try { if (isQueueing()) { transaction.zrange(key, start, end); @@ -945,7 +942,7 @@ public class JedisConnection implements RedisConnection { } @Override - public Set zRangeWithScore(String key, int start, int end) { + public Set zRangeWithScore(byte[] key, int start, int end) { try { if (isQueueing()) { transaction.zrangeWithScores(key, start, end); @@ -958,7 +955,7 @@ public class JedisConnection implements RedisConnection { } @Override - public Set zRangeByScore(String key, double min, double max) { + public Set zRangeByScore(byte[] key, double min, double max) { try { if (isQueueing()) { throw new UnsupportedOperationException(); @@ -970,7 +967,7 @@ public class JedisConnection implements RedisConnection { } @Override - public Set zRangeByScoreWithScore(String key, double min, double max) { + public Set zRangeByScoreWithScore(byte[] key, double min, double max) { try { if (isQueueing()) { throw new UnsupportedOperationException(); @@ -982,7 +979,7 @@ public class JedisConnection implements RedisConnection { } @Override - public Set zRevRangeWithScore(String key, int start, int end) { + public Set zRevRangeWithScore(byte[] key, int start, int end) { try { if (isQueueing()) { transaction.zrangeWithScores(key, start, end); @@ -995,7 +992,7 @@ public class JedisConnection implements RedisConnection { } @Override - public Set zRangeByScore(String key, double min, double max, int offset, int count) { + public Set zRangeByScore(byte[] key, double min, double max, int offset, int count) { try { if (isQueueing()) { throw new UnsupportedOperationException(); @@ -1007,7 +1004,7 @@ public class JedisConnection implements RedisConnection { } @Override - public Set zRangeByScoreWithScore(String key, double min, double max, int offset, int count) { + public Set zRangeByScoreWithScore(byte[] key, double min, double max, int offset, int count) { try { if (isQueueing()) { throw new UnsupportedOperationException(); @@ -1019,7 +1016,7 @@ public class JedisConnection implements RedisConnection { } @Override - public Integer zRank(String key, String value) { + public Integer zRank(byte[] key, byte[] value) { try { if (isQueueing()) { transaction.zrank(key, value); @@ -1032,7 +1029,7 @@ public class JedisConnection implements RedisConnection { } @Override - public Boolean zRem(String key, String value) { + public Boolean zRem(byte[] key, byte[] value) { try { if (isQueueing()) { transaction.zrem(key, value); @@ -1045,7 +1042,7 @@ public class JedisConnection implements RedisConnection { } @Override - public Integer zRemRange(String key, int start, int end) { + public Integer zRemRange(byte[] key, int start, int end) { try { if (isQueueing()) { throw new UnsupportedOperationException(); @@ -1057,7 +1054,7 @@ public class JedisConnection implements RedisConnection { } @Override - public Integer zRemRangeByScore(String key, double min, double max) { + public Integer zRemRangeByScore(byte[] key, double min, double max) { try { if (isQueueing()) { throw new UnsupportedOperationException(); @@ -1069,7 +1066,7 @@ public class JedisConnection implements RedisConnection { } @Override - public Set zRevRange(String key, int start, int end) { + public Set zRevRange(byte[] key, int start, int end) { try { if (isQueueing()) { transaction.zrevrange(key, start, end); @@ -1082,7 +1079,7 @@ public class JedisConnection implements RedisConnection { } @Override - public Integer zRevRank(String key, String value) { + public Integer zRevRank(byte[] key, byte[] value) { try { if (isQueueing()) { transaction.zrevrank(key, value); @@ -1095,7 +1092,7 @@ public class JedisConnection implements RedisConnection { } @Override - public Double zScore(String key, String value) { + public Double zScore(byte[] key, byte[] value) { try { if (isQueueing()) { transaction.zscore(key, value); @@ -1108,7 +1105,7 @@ public class JedisConnection implements RedisConnection { } @Override - public Integer zUnionStore(String destKey, Aggregate aggregate, int[] weights, String... sets) { + public Integer zUnionStore(byte[] destKey, Aggregate aggregate, int[] weights, byte[]... sets) { try { if (isQueueing()) { throw new UnsupportedOperationException(); @@ -1122,7 +1119,7 @@ public class JedisConnection implements RedisConnection { } @Override - public Integer zUnionStore(String destKey, String... sets) { + public Integer zUnionStore(byte[] destKey, byte[]... sets) { try { if (isQueueing()) { throw new UnsupportedOperationException(); @@ -1138,7 +1135,7 @@ public class JedisConnection implements RedisConnection { // @Override - public Boolean hSet(String key, String field, String value) { + public Boolean hSet(byte[] key, byte[] field, byte[] value) { try { if (isQueueing()) { transaction.hset(key, field, value); @@ -1151,7 +1148,7 @@ public class JedisConnection implements RedisConnection { } @Override - public Boolean hSetNX(String key, String field, String value) { + public Boolean hSetNX(byte[] key, byte[] field, byte[] value) { try { if (isQueueing()) { transaction.hsetnx(key, field, value); @@ -1164,7 +1161,7 @@ public class JedisConnection implements RedisConnection { } @Override - public Boolean hDel(String key, String field) { + public Boolean hDel(byte[] key, byte[] field) { try { if (isQueueing()) { transaction.hdel(key, field); @@ -1177,7 +1174,7 @@ public class JedisConnection implements RedisConnection { } @Override - public Boolean hExists(String key, String field) { + public Boolean hExists(byte[] key, byte[] field) { try { if (isQueueing()) { transaction.hexists(key, field); @@ -1190,7 +1187,7 @@ public class JedisConnection implements RedisConnection { } @Override - public String hGet(String key, String field) { + public byte[] hGet(byte[] key, byte[] field) { try { if (isQueueing()) { transaction.hget(key, field); @@ -1203,20 +1200,20 @@ public class JedisConnection implements RedisConnection { } @Override - public Set hGetAll(String key) { + public Map hGetAll(byte[] key) { try { if (isQueueing()) { transaction.hgetAll(key); return null; } - return JedisUtils.convert(jedis.hgetAll(key)); + return jedis.hgetAll(key); } catch (Exception ex) { throw convertJedisAccessException(ex); } } @Override - public Integer hIncrBy(String key, String field, int delta) { + public Integer hIncrBy(byte[] key, byte[] field, int delta) { try { if (isQueueing()) { transaction.hincrBy(key, field, delta); @@ -1229,20 +1226,20 @@ public class JedisConnection implements RedisConnection { } @Override - public Set hKeys(String key) { + public Set hKeys(byte[] key) { try { if (isQueueing()) { transaction.hkeys(key); return null; } - return new LinkedHashSet(jedis.hkeys(key)); + return jedis.hkeys(key); } catch (Exception ex) { throw convertJedisAccessException(ex); } } @Override - public Integer hLen(String key) { + public Integer hLen(byte[] key) { try { if (isQueueing()) { transaction.hlen(key); @@ -1255,7 +1252,7 @@ public class JedisConnection implements RedisConnection { } @Override - public List hMGet(String key, String... fields) { + public List hMGet(byte[] key, byte[]... fields) { try { if (isQueueing()) { transaction.hmget(key, fields); @@ -1268,26 +1265,25 @@ public class JedisConnection implements RedisConnection { } @Override - public void hMSet(String key, String[] fields, String[] values) { - Map param = JedisUtils.convert(fields, values); + public void hMSet(byte[] key, Map tuple) { try { if (isQueueing()) { - transaction.hmset(key, param); + transaction.hmset(key, tuple); } - jedis.hmset(key, param); + jedis.hmset(key, tuple); } catch (Exception ex) { throw convertJedisAccessException(ex); } } @Override - public List hVals(String key) { + public List hVals(byte[] key) { try { if (isQueueing()) { transaction.hvals(key); return null; } - return jedis.hvals(key); + return new ArrayList(jedis.hvals(key)); } catch (Exception ex) { throw convertJedisAccessException(ex); } diff --git a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/connection/jedis/JedisConnectionFactory.java b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/connection/jedis/JedisConnectionFactory.java index 296c7f672..1eb782033 100644 --- a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/connection/jedis/JedisConnectionFactory.java +++ b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/connection/jedis/JedisConnectionFactory.java @@ -117,10 +117,11 @@ public class JedisConnectionFactory implements InitializingBean, DisposableBean, int size = getPoolSize(); pool = new JedisPool(shardInfo); pool.setResourcesNumber(size); + pool.init(); } } - public void destroy() throws Exception { + public void destroy() { if (usePool && pool != null) { pool.destroy(); pool = null; diff --git a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/connection/jedis/JedisUtils.java b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/connection/jedis/JedisUtils.java index a1f097631..0306d72c5 100644 --- a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/connection/jedis/JedisUtils.java +++ b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/connection/jedis/JedisUtils.java @@ -28,9 +28,7 @@ import org.springframework.dao.DataAccessException; import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.datastore.redis.RedisConnectionFailureException; import org.springframework.datastore.redis.UncategorizedRedisException; -import org.springframework.datastore.redis.connection.DefaultEntry; import org.springframework.datastore.redis.connection.DefaultTuple; -import org.springframework.datastore.redis.connection.RedisHashCommands.Entry; import org.springframework.datastore.redis.connection.RedisZSetCommands.Tuple; import redis.clients.jedis.JedisException; @@ -79,19 +77,21 @@ public abstract class JedisUtils { static Set convertJedisTuple(Set tuples) { Set value = new LinkedHashSet(tuples.size()); for (redis.clients.jedis.Tuple tuple : tuples) { - value.add(new DefaultTuple(tuple.getElement(), tuple.getScore())); + value.add(new DefaultTuple(tuple.getBinaryElement(), tuple.getScore())); } return value; } - static Set convert(Map hgetAll) { - Set entries = new LinkedHashSet(hgetAll.size()); - for (Map.Entry entry : hgetAll.entrySet()) { - entries.add(new DefaultEntry(entry.getKey(), entry.getValue())); - } + static byte[][] convert(Map hgetAll) { + byte[][] result = new byte[hgetAll.size() * 2][]; - return entries; + int index = 0; + for (Map.Entry entry : hgetAll.entrySet()) { + result[index++] = entry.getKey(); + result[index++] = entry.getValue(); + } + return result; } static Map convert(String[] fields, String[] values) { diff --git a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/connection/jredis/JredisConnection.java b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/connection/jredis/JredisConnection.java index 371ba1876..52ea0341f 100644 --- a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/connection/jredis/JredisConnection.java +++ b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/connection/jredis/JredisConnection.java @@ -15,10 +15,12 @@ */ package org.springframework.datastore.redis.connection.jredis; +import java.nio.charset.Charset; import java.util.Arrays; import java.util.Collection; import java.util.LinkedHashSet; import java.util.List; +import java.util.Map; import java.util.Set; import org.jredis.JRedis; @@ -30,16 +32,19 @@ import org.springframework.datastore.redis.connection.DataType; import org.springframework.datastore.redis.connection.RedisConnection; /** + * JRedis based implementation. + * * @author Costin Leau */ public class JredisConnection implements RedisConnection { private final JRedis jredis; - private final String encoding; - public JredisConnection(JRedis jredis, String encoding) { + private final Charset charset; + + public JredisConnection(JRedis jredis, Charset charset) { this.jredis = jredis; - this.encoding = encoding; + this.charset = charset; } protected DataAccessException convertJedisAccessException(Exception ex) { @@ -55,11 +60,6 @@ public class JredisConnection implements RedisConnection { } - @Override - public String getEncoding() { - return encoding; - } - @Override public JRedis getNativeConnection() { return jredis; @@ -85,9 +85,9 @@ public class JredisConnection implements RedisConnection { } @Override - public Integer del(String... keys) { + public Integer del(byte[]... keys) { try { - return Integer.valueOf((int) jredis.del(keys)); + return Integer.valueOf((int) jredis.del(JredisUtils.convertMultiple(charset, keys))); } catch (RedisException ex) { throw JredisUtils.convertJredisAccessException(ex); } @@ -108,27 +108,27 @@ public class JredisConnection implements RedisConnection { } @Override - public Boolean exists(String key) { + public Boolean exists(byte[] key) { try { - return jredis.exists(key); + return jredis.exists(JredisUtils.convert(charset, key)); } catch (RedisException ex) { throw JredisUtils.convertJredisAccessException(ex); } } @Override - public Boolean expire(String key, int seconds) { + public Boolean expire(byte[] key, int seconds) { try { - return jredis.expire(key, seconds); + return jredis.expire(JredisUtils.convert(charset, key), seconds); } catch (RedisException ex) { throw JredisUtils.convertJredisAccessException(ex); } } @Override - public Collection keys(String pattern) { + public Collection keys(byte[] pattern) { try { - return jredis.keys(pattern); + return JredisUtils.convert(charset, jredis.keys(JredisUtils.convert(charset, pattern))); } catch (RedisException ex) { throw JredisUtils.convertJredisAccessException(ex); } @@ -140,32 +140,32 @@ public class JredisConnection implements RedisConnection { } @Override - public Boolean persist(String key) { + public Boolean persist(byte[] key) { throw new UnsupportedOperationException(); } @Override - public String randomKey() { + public byte[] randomKey() { try { - return jredis.randomkey(); + return JredisUtils.convert(charset, jredis.randomkey()); } catch (RedisException ex) { throw JredisUtils.convertJredisAccessException(ex); } } @Override - public void rename(String oldName, String newName) { + public void rename(byte[] oldName, byte[] newName) { try { - jredis.rename(oldName, newName); + jredis.rename(JredisUtils.convert(charset, oldName), JredisUtils.convert(charset, newName)); } catch (RedisException ex) { throw JredisUtils.convertJredisAccessException(ex); } } @Override - public Boolean renameNX(String oldName, String newName) { + public Boolean renameNX(byte[] oldName, byte[] newName) { try { - return jredis.renamenx(oldName, newName); + return jredis.renamenx(JredisUtils.convert(charset, oldName), JredisUtils.convert(charset, newName)); } catch (RedisException ex) { throw JredisUtils.convertJredisAccessException(ex); } @@ -177,18 +177,18 @@ public class JredisConnection implements RedisConnection { } @Override - public Integer ttl(String key) { + public Integer ttl(byte[] key) { try { - return Integer.valueOf((int) jredis.ttl(key)); + return Integer.valueOf((int) jredis.ttl(JredisUtils.convert(charset, key))); } catch (RedisException ex) { throw JredisUtils.convertJredisAccessException(ex); } } @Override - public DataType type(String key) { + public DataType type(byte[] key) { try { - return JredisUtils.convertDataType(jredis.type(key)); + return JredisUtils.convertDataType(jredis.type(JredisUtils.convert(charset, key))); } catch (RedisException ex) { throw JredisUtils.convertJredisAccessException(ex); } @@ -200,7 +200,7 @@ public class JredisConnection implements RedisConnection { } @Override - public void watch(String... keys) { + public void watch(byte[]... keys) { throw new UnsupportedOperationException(); } @@ -209,123 +209,122 @@ public class JredisConnection implements RedisConnection { // @Override - public String get(String key) { + public byte[] get(byte[] key) { try { - return JredisUtils.convertToString(jredis.get(key), encoding); + return jredis.get(JredisUtils.convert(charset, key)); } catch (RedisException ex) { throw JredisUtils.convertJredisAccessException(ex); } } @Override - public void set(String key, String value) { + public void set(byte[] key, byte[] value) { try { - jredis.set(key, value); + jredis.set(JredisUtils.convert(charset, key), value); } catch (RedisException ex) { throw JredisUtils.convertJredisAccessException(ex); } } @Override - public String getSet(String key, String value) { + public byte[] getSet(byte[] key, byte[] value) { try { - return JredisUtils.convertToString(jredis.getset(key, value), encoding); - } catch (RedisException ex) { - throw JredisUtils.convertJredisAccessException(ex); - } - } - - - @Override - public Integer append(String key, String value) { - try { - return Integer.valueOf((int) jredis.append(key, value)); + return jredis.getset(JredisUtils.convert(charset, key), value); } catch (RedisException ex) { throw JredisUtils.convertJredisAccessException(ex); } } @Override - public List mGet(String... keys) { + public Integer append(byte[] key, byte[] value) { try { - return JredisUtils.convertToStringCollection(jredis.mget(keys), encoding, List.class); + return Integer.valueOf((int) jredis.append(JredisUtils.convert(charset, key), value)); } catch (RedisException ex) { throw JredisUtils.convertJredisAccessException(ex); } } @Override - public void mSet(String[] keys, String[] values) { + public List mGet(byte[]... keys) { try { - jredis.mset(JredisUtils.convert(keys, values)); + return jredis.mget(JredisUtils.convertMultiple(charset, keys)); } catch (RedisException ex) { throw JredisUtils.convertJredisAccessException(ex); } } @Override - public void mSetNX(String[] keys, String[] values) { + public void mSet(Map tuple) { try { - jredis.msetnx(JredisUtils.convert(keys, values)); + jredis.mset(JredisUtils.convert(charset, tuple)); } catch (RedisException ex) { throw JredisUtils.convertJredisAccessException(ex); } } @Override - public void setEx(String key, int seconds, String value) { + public void mSetNX(Map tuple) { + try { + jredis.msetnx(JredisUtils.convert(charset, tuple)); + } catch (RedisException ex) { + throw JredisUtils.convertJredisAccessException(ex); + } + } + + @Override + public void setEx(byte[] key, int seconds, byte[] value) { throw new UnsupportedOperationException(); } @Override - public Boolean setNX(String key, String value) { + public Boolean setNX(byte[] key, byte[] value) { try { - return jredis.setnx(key, value); + return jredis.setnx(JredisUtils.convert(charset, key), value); } catch (RedisException ex) { throw JredisUtils.convertJredisAccessException(ex); } } @Override - public String substr(String key, int start, int end) { + public byte[] substr(byte[] key, int start, int end) { try { - return JredisUtils.convertToString(jredis.substr(key, (long) start, (long) end), encoding); + return jredis.substr(JredisUtils.convert(charset, key), (long) start, (long) end); } catch (RedisException ex) { throw JredisUtils.convertJredisAccessException(ex); } } @Override - public Integer decr(String key) { + public Integer decr(byte[] key) { try { - return (int) jredis.decr(key); + return (int) jredis.decr(JredisUtils.convert(charset, key)); } catch (RedisException ex) { throw JredisUtils.convertJredisAccessException(ex); } } @Override - public Integer decrBy(String key, int value) { + public Integer decrBy(byte[] key, int value) { try { - return (int) jredis.decrby(key, value); + return (int) jredis.decrby(JredisUtils.convert(charset, key), value); } catch (RedisException ex) { throw JredisUtils.convertJredisAccessException(ex); } } @Override - public Integer incr(String key) { + public Integer incr(byte[] key) { try { - return (int) jredis.incr(key); + return (int) jredis.incr(JredisUtils.convert(charset, key)); } catch (RedisException ex) { throw JredisUtils.convertJredisAccessException(ex); } } @Override - public Integer incrBy(String key, int value) { + public Integer incrBy(byte[] key, int value) { try { - return (int) jredis.incrby(key, value); + return (int) jredis.incrby(JredisUtils.convert(charset, key), value); } catch (RedisException ex) { throw JredisUtils.convertJredisAccessException(ex); } @@ -336,46 +335,46 @@ public class JredisConnection implements RedisConnection { // @Override - public List bLPop(int timeout, String... keys) { + public List bLPop(int timeout, byte[]... keys) { throw new UnsupportedOperationException(); } @Override - public List bRPop(int timeout, String... keys) { + public List bRPop(int timeout, byte[]... keys) { throw new UnsupportedOperationException(); } @Override - public String lIndex(String key, int index) { + public byte[] lIndex(byte[] key, int index) { try { - return JredisUtils.convertToString(jredis.lindex(key, (long) index), encoding); + return jredis.lindex(JredisUtils.convert(charset, key), (long) index); } catch (RedisException ex) { throw JredisUtils.convertJredisAccessException(ex); } } @Override - public Integer lLen(String key) { + public Integer lLen(byte[] key) { try { - return Integer.valueOf((int) jredis.llen(key)); + return Integer.valueOf((int) jredis.llen(JredisUtils.convert(charset, key))); } catch (RedisException ex) { throw JredisUtils.convertJredisAccessException(ex); } } @Override - public String lPop(String key) { + public byte[] lPop(byte[] key) { try { - return JredisUtils.convertToString(jredis.lpop(key), encoding); + return jredis.lpop(JredisUtils.convert(charset, key)); } catch (RedisException ex) { throw JredisUtils.convertJredisAccessException(ex); } } @Override - public Integer lPush(String key, String value) { + public Integer lPush(byte[] key, byte[] value) { try { - jredis.lpush(key, value); + jredis.lpush(JredisUtils.convert(charset, key), value); return null; } catch (RedisException ex) { throw JredisUtils.convertJredisAccessException(ex); @@ -383,66 +382,65 @@ public class JredisConnection implements RedisConnection { } @Override - public List lRange(String key, int start, int end) { + public List lRange(byte[] key, int start, int end) { try { - List lrange = jredis.lrange(key, start, end); + List lrange = jredis.lrange(JredisUtils.convert(charset, key), start, end); - return JredisUtils.convertToStringCollection(lrange, encoding, List.class); + return lrange; } catch (RedisException ex) { throw JredisUtils.convertJredisAccessException(ex); } } @Override - public Integer lRem(String key, int count, String value) { + public Integer lRem(byte[] key, int count, byte[] value) { try { - Integer.valueOf((int) jredis.lrem(key, value, count)); - return null; + return Integer.valueOf((int) jredis.lrem(JredisUtils.convert(charset, key), value, count)); } catch (RedisException ex) { throw JredisUtils.convertJredisAccessException(ex); } } @Override - public void lSet(String key, int index, String value) { + public void lSet(byte[] key, int index, byte[] value) { try { - jredis.lset(key, index, value); + jredis.lset(JredisUtils.convert(charset, key), index, value); } catch (RedisException ex) { throw JredisUtils.convertJredisAccessException(ex); } } @Override - public void lTrim(String key, int start, int end) { + public void lTrim(byte[] key, int start, int end) { try { - jredis.ltrim(key, start, end); + jredis.ltrim(JredisUtils.convert(charset, key), start, end); } catch (RedisException ex) { throw JredisUtils.convertJredisAccessException(ex); } } @Override - public String rPop(String key) { + public byte[] rPop(byte[] key) { try { - return JredisUtils.convertToString(jredis.rpop(key), encoding); + return jredis.rpop(JredisUtils.convert(charset, key)); } catch (RedisException ex) { throw JredisUtils.convertJredisAccessException(ex); } } @Override - public String rPopLPush(String srcKey, String dstKey) { + public byte[] rPopLPush(byte[] srcKey, byte[] dstKey) { try { - return JredisUtils.convertToString(jredis.rpoplpush(srcKey, dstKey), encoding); + return jredis.rpoplpush(JredisUtils.convert(charset, srcKey), JredisUtils.convert(charset, dstKey)); } catch (RedisException ex) { throw JredisUtils.convertJredisAccessException(ex); } } @Override - public Integer rPush(String key, String value) { + public Integer rPush(byte[] key, byte[] value) { try { - jredis.rpush(key, value); + jredis.rpush(JredisUtils.convert(charset, key), value); return null; } catch (RedisException ex) { throw JredisUtils.convertJredisAccessException(ex); @@ -454,40 +452,40 @@ public class JredisConnection implements RedisConnection { // @Override - public Boolean sAdd(String key, String value) { + public Boolean sAdd(byte[] key, byte[] value) { try { - return jredis.sadd(key, value); + return jredis.sadd(JredisUtils.convert(charset, key), value); } catch (RedisException ex) { throw JredisUtils.convertJredisAccessException(ex); } } @Override - public Integer sCard(String key) { + public Integer sCard(byte[] key) { try { - return Integer.valueOf((int) jredis.scard(key)); + return Integer.valueOf((int) jredis.scard(JredisUtils.convert(charset, key))); } catch (RedisException ex) { throw JredisUtils.convertJredisAccessException(ex); } } @Override - public Set sDiff(String... keys) { - String set1 = keys[0]; - String[] sets = Arrays.copyOfRange(keys, 1, keys.length); + public Set sDiff(byte[]... keys) { + String set1 = JredisUtils.convert(charset, keys[0]); + String[] sets = JredisUtils.convertMultiple(charset, Arrays.copyOfRange(keys, 1, keys.length)); try { List result = jredis.sdiff(set1, sets); - return JredisUtils.convertToStringCollection(result, encoding, Set.class); + return new LinkedHashSet(result); } catch (RedisException ex) { throw JredisUtils.convertJredisAccessException(ex); } } @Override - public void sDiffStore(String destKey, String... keys) { - String set1 = keys[0]; - String[] sets = Arrays.copyOfRange(keys, 1, keys.length); + public void sDiffStore(byte[] destKey, byte[]... keys) { + String set1 = JredisUtils.convert(charset, keys[0]); + String[] sets = JredisUtils.convertMultiple(charset, Arrays.copyOfRange(keys, 1, keys.length)); try { jredis.sdiffstore(set1, sets); @@ -497,22 +495,22 @@ public class JredisConnection implements RedisConnection { } @Override - public Set sInter(String... keys) { - String set1 = keys[0]; - String[] sets = Arrays.copyOfRange(keys, 1, keys.length); + public Set sInter(byte[]... keys) { + String set1 = JredisUtils.convert(charset, keys[0]); + String[] sets = JredisUtils.convertMultiple(charset, Arrays.copyOfRange(keys, 1, keys.length)); try { List result = jredis.sinter(set1, sets); - return JredisUtils.convertToStringCollection(result, encoding, Set.class); + return new LinkedHashSet(result); } catch (RedisException ex) { throw JredisUtils.convertJredisAccessException(ex); } } @Override - public void sInterStore(String destKey, String... keys) { - String set1 = keys[0]; - String[] sets = Arrays.copyOfRange(keys, 1, keys.length); + public void sInterStore(byte[] destKey, byte[]... keys) { + String set1 = JredisUtils.convert(charset, keys[0]); + String[] sets = JredisUtils.convertMultiple(charset, Arrays.copyOfRange(keys, 1, keys.length)); try { jredis.sinterstore(set1, sets); @@ -522,76 +520,75 @@ public class JredisConnection implements RedisConnection { } @Override - public Boolean sIsMember(String key, String value) { + public Boolean sIsMember(byte[] key, byte[] value) { try { - return jredis.sismember(key, value); + return jredis.sismember(JredisUtils.convert(charset, key), value); } catch (RedisException ex) { throw JredisUtils.convertJredisAccessException(ex); } } @Override - public Set sMembers(String key) { + public Set sMembers(byte[] key) { try { - return JredisUtils.convertToStringCollection(jredis.smembers(key), encoding, Set.class); + return new LinkedHashSet(jredis.smembers(JredisUtils.convert(charset, key))); } catch (RedisException ex) { throw JredisUtils.convertJredisAccessException(ex); } } @Override - public Boolean sMove(String srcKey, String destKey, String value) { + public Boolean sMove(byte[] srcKey, byte[] destKey, byte[] value) { try { - return jredis.smove(srcKey, destKey, value); + return jredis.smove(JredisUtils.convert(charset, srcKey), JredisUtils.convert(charset, destKey), value); } catch (RedisException ex) { throw JredisUtils.convertJredisAccessException(ex); } } @Override - public String sPop(String key) { + public byte[] sPop(byte[] key) { try { - return JredisUtils.convertToString(jredis.spop(key), encoding); + return jredis.spop(JredisUtils.convert(charset, key)); } catch (RedisException ex) { throw JredisUtils.convertJredisAccessException(ex); } } @Override - public String sRandMember(String key) { + public byte[] sRandMember(byte[] key) { try { - return JredisUtils.convertToString(jredis.srandmember(key), encoding); + return jredis.srandmember(JredisUtils.convert(charset, key)); } catch (RedisException ex) { throw JredisUtils.convertJredisAccessException(ex); } } @Override - public Boolean sRem(String key, String value) { + public Boolean sRem(byte[] key, byte[] value) { try { - return jredis.srem(key, value); + return jredis.srem(JredisUtils.convert(charset, key), value); } catch (RedisException ex) { throw JredisUtils.convertJredisAccessException(ex); } } @Override - public Set sUnion(String... keys) { - String set1 = keys[0]; - String[] sets = Arrays.copyOfRange(keys, 1, keys.length); + public Set sUnion(byte[]... keys) { + String set1 = JredisUtils.convert(charset, keys[0]); + String[] sets = JredisUtils.convertMultiple(charset, Arrays.copyOfRange(keys, 1, keys.length)); try { - List result = jredis.sunion(set1, sets); - return JredisUtils.convertToStringCollection(result, encoding, Set.class); + return new LinkedHashSet(jredis.sunion(set1, sets)); } catch (RedisException ex) { throw JredisUtils.convertJredisAccessException(ex); } } @Override - public void sUnionStore(String destKey, String... keys) { - String set1 = keys[0]; - String[] sets = Arrays.copyOfRange(keys, 1, keys.length); + public void sUnionStore(byte[] destKey, byte[]... keys) { + String set1 = JredisUtils.convert(charset, keys[0]); + String[] sets = JredisUtils.convertMultiple(charset, Arrays.copyOfRange(keys, 1, keys.length)); try { jredis.sunionstore(set1, sets); @@ -606,154 +603,153 @@ public class JredisConnection implements RedisConnection { // @Override - public Boolean zAdd(String key, double score, String value) { + public Boolean zAdd(byte[] key, double score, byte[] value) { try { - return jredis.zadd(key, score, value); + return jredis.zadd(JredisUtils.convert(charset, key), score, value); } catch (RedisException ex) { throw JredisUtils.convertJredisAccessException(ex); } } @Override - public Integer zCard(String key) { + public Integer zCard(byte[] key) { try { - return Integer.valueOf((int) jredis.zcard(key)); + return Integer.valueOf((int) jredis.zcard(JredisUtils.convert(charset, key))); } catch (RedisException ex) { throw JredisUtils.convertJredisAccessException(ex); } } @Override - public Integer zCount(String key, double min, double max) { + public Integer zCount(byte[] key, double min, double max) { try { - return Integer.valueOf((int) jredis.zcount(key, min, max)); + return Integer.valueOf((int) jredis.zcount(JredisUtils.convert(charset, key), min, max)); } catch (RedisException ex) { throw JredisUtils.convertJredisAccessException(ex); } } @Override - public Double zIncrBy(String key, double increment, String value) { + public Double zIncrBy(byte[] key, double increment, byte[] value) { try { - return jredis.zincrby(key, increment, value); + return jredis.zincrby(JredisUtils.convert(charset, key), increment, value); } catch (RedisException ex) { throw JredisUtils.convertJredisAccessException(ex); } } @Override - public Integer zInterStore(String destKey, Aggregate aggregate, int[] weights, String... sets) { + public Integer zInterStore(byte[] destKey, Aggregate aggregate, int[] weights, byte[]... sets) { throw new UnsupportedOperationException(); } @Override - public Integer zInterStore(String destKey, String... sets) { + public Integer zInterStore(byte[] destKey, byte[]... sets) { throw new UnsupportedOperationException(); } @Override - public Set zRange(String key, int start, int end) { + public Set zRange(byte[] key, int start, int end) { try { - return JredisUtils.convertToStringCollection(jredis.zrange(key, (long) start, (long) end), encoding, - Set.class); + return new LinkedHashSet(jredis.zrange(JredisUtils.convert(charset, key), (long) start, (long) end)); } catch (RedisException ex) { throw JredisUtils.convertJredisAccessException(ex); } } @Override - public Set zRangeWithScore(String key, int start, int end) { + public Set zRangeWithScore(byte[] key, int start, int end) { throw new UnsupportedOperationException(); } @Override - public Set zRangeByScore(String key, double min, double max) { + public Set zRangeByScore(byte[] key, double min, double max) { try { - return JredisUtils.convertToStringCollection(jredis.zrangebyscore(key, min, max), encoding, Set.class); + return new LinkedHashSet(jredis.zrangebyscore(JredisUtils.convert(charset, key), min, max)); } catch (RedisException ex) { throw JredisUtils.convertJredisAccessException(ex); } } @Override - public Set zRangeByScoreWithScore(String key, double min, double max) { + public Set zRangeByScoreWithScore(byte[] key, double min, double max) { throw new UnsupportedOperationException(); } @Override - public Set zRangeByScore(String key, double min, double max, int offset, int count) { + public Set zRangeByScore(byte[] key, double min, double max, int offset, int count) { throw new UnsupportedOperationException(); } @Override - public Set zRangeByScoreWithScore(String key, double min, double max, int offset, int count) { + public Set zRangeByScoreWithScore(byte[] key, double min, double max, int offset, int count) { throw new UnsupportedOperationException(); } @Override - public Integer zRank(String key, String value) { + public Integer zRank(byte[] key, byte[] value) { try { - return Integer.valueOf((int) jredis.zrank(key, value)); + return Integer.valueOf((int) jredis.zrank(JredisUtils.convert(charset, key), value)); } catch (RedisException ex) { throw JredisUtils.convertJredisAccessException(ex); } } @Override - public Boolean zRem(String key, String value) { + public Boolean zRem(byte[] key, byte[] value) { try { - return jredis.zrem(key, value); + return jredis.zrem(JredisUtils.convert(charset, key), value); } catch (RedisException ex) { throw JredisUtils.convertJredisAccessException(ex); } } @Override - public Integer zRemRange(String key, int start, int end) { + public Integer zRemRange(byte[] key, int start, int end) { try { - return Integer.valueOf((int) jredis.zremrangebyrank(key, start, end)); + return Integer.valueOf((int) jredis.zremrangebyrank(JredisUtils.convert(charset, key), start, end)); } catch (RedisException ex) { throw JredisUtils.convertJredisAccessException(ex); } } @Override - public Integer zRemRangeByScore(String key, double min, double max) { + public Integer zRemRangeByScore(byte[] key, double min, double max) { try { - return Integer.valueOf((int) jredis.zremrangebyscore(key, min, max)); + return Integer.valueOf((int) jredis.zremrangebyscore(JredisUtils.convert(charset, key), min, max)); } catch (RedisException ex) { throw JredisUtils.convertJredisAccessException(ex); } } @Override - public Set zRevRange(String key, int start, int end) { + public Set zRevRange(byte[] key, int start, int end) { try { - return JredisUtils.convertToStringCollection(jredis.zrevrange(key, start, end), encoding, Set.class); + return new LinkedHashSet(jredis.zrevrange(JredisUtils.convert(charset, key), start, end)); } catch (RedisException ex) { throw JredisUtils.convertJredisAccessException(ex); } } @Override - public Set zRevRangeWithScore(String key, int start, int end) { + public Set zRevRangeWithScore(byte[] key, int start, int end) { throw new UnsupportedOperationException(); } @Override - public Integer zRevRank(String key, String value) { + public Integer zRevRank(byte[] key, byte[] value) { try { - return Integer.valueOf((int) jredis.zrevrank(key, value)); + return Integer.valueOf((int) jredis.zrevrank(JredisUtils.convert(charset, key), value)); } catch (RedisException ex) { throw JredisUtils.convertJredisAccessException(ex); } } @Override - public Double zScore(String key, String value) { + public Double zScore(byte[] key, byte[] value) { try { - return jredis.zscore(key, value); + return jredis.zscore(JredisUtils.convert(charset, key), value); } catch (RedisException ex) { throw JredisUtils.convertJredisAccessException(ex); } @@ -765,102 +761,103 @@ public class JredisConnection implements RedisConnection { // @Override - public Integer zUnionStore(String destKey, Aggregate aggregate, int[] weights, String... sets) { + public Integer zUnionStore(byte[] destKey, Aggregate aggregate, int[] weights, byte[]... sets) { throw new UnsupportedOperationException(); } @Override - public Integer zUnionStore(String destKey, String... sets) { + public Integer zUnionStore(byte[] destKey, byte[]... sets) { throw new UnsupportedOperationException(); } @Override - public Boolean hDel(String key, String field) { + public Boolean hDel(byte[] key, byte[] field) { try { - return jredis.hdel(key, field); + return jredis.hdel(JredisUtils.convert(charset, key), JredisUtils.convert(charset, field)); } catch (RedisException ex) { throw JredisUtils.convertJredisAccessException(ex); } } @Override - public Boolean hExists(String key, String field) { + public Boolean hExists(byte[] key, byte[] field) { try { - return jredis.hexists(key, field); + return jredis.hexists(JredisUtils.convert(charset, key), JredisUtils.convert(charset, field)); } catch (RedisException ex) { throw JredisUtils.convertJredisAccessException(ex); } } @Override - public String hGet(String key, String field) { + public byte[] hGet(byte[] key, byte[] field) { try { - return JredisUtils.convertToString(jredis.hget(key, field), encoding); + return jredis.hget(JredisUtils.convert(charset, key), JredisUtils.convert(charset, field)); } catch (RedisException ex) { throw JredisUtils.convertJredisAccessException(ex); } } @Override - public Set hGetAll(String key) { + public Map hGetAll(byte[] key) { try { - return JredisUtils.convert(jredis.hgetall(key), encoding); + return JredisUtils.convertMap(charset, jredis.hgetall(JredisUtils.convert(charset, key))); } catch (RedisException ex) { throw JredisUtils.convertJredisAccessException(ex); } } @Override - public Integer hIncrBy(String key, String field, int delta) { + public Integer hIncrBy(byte[] key, byte[] field, int delta) { throw new UnsupportedOperationException(); } @Override - public Set hKeys(String key) { + public Set hKeys(byte[] key) { try { - return new LinkedHashSet(jredis.hkeys(key)); + return new LinkedHashSet(JredisUtils.convert(charset, + jredis.hkeys(JredisUtils.convert(charset, key)))); } catch (RedisException ex) { throw JredisUtils.convertJredisAccessException(ex); } } @Override - public Integer hLen(String key) { + public Integer hLen(byte[] key) { try { - return Integer.valueOf((int) jredis.hlen(key)); + return Integer.valueOf((int) jredis.hlen(JredisUtils.convert(charset, key))); } catch (RedisException ex) { throw JredisUtils.convertJredisAccessException(ex); } } @Override - public List hMGet(String key, String... fields) { + public List hMGet(byte[] key, byte[]... fields) { throw new UnsupportedOperationException(); } @Override - public void hMSet(String key, String[] fields, String[] values) { + public void hMSet(byte[] key, Map values) { throw new UnsupportedOperationException(); } @Override - public Boolean hSet(String key, String field, String value) { + public Boolean hSet(byte[] key, byte[] field, byte[] value) { try { - return jredis.hset(key, field, value); + return jredis.hset(JredisUtils.convert(charset, key), JredisUtils.convert(charset, field), value); } catch (RedisException ex) { throw JredisUtils.convertJredisAccessException(ex); } } @Override - public Boolean hSetNX(String key, String field, String value) { + public Boolean hSetNX(byte[] key, byte[] field, byte[] value) { throw new UnsupportedOperationException(); } @Override - public List hVals(String key) { + public List hVals(byte[] key) { try { - return JredisUtils.convertToStringCollection(jredis.hvals(key), encoding, List.class); + return jredis.hvals(JredisUtils.convert(charset, key)); } catch (RedisException ex) { throw JredisUtils.convertJredisAccessException(ex); } diff --git a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/connection/jredis/JredisConnectionFactory.java b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/connection/jredis/JredisConnectionFactory.java index 015d36793..4037c0783 100644 --- a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/connection/jredis/JredisConnectionFactory.java +++ b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/connection/jredis/JredisConnectionFactory.java @@ -15,6 +15,8 @@ */ package org.springframework.datastore.redis.connection.jredis; +import java.nio.charset.Charset; + import org.jredis.JRedis; import org.jredis.connector.ConnectionSpec; import org.jredis.connector.Connection.Socket.Property; @@ -36,7 +38,6 @@ import org.springframework.util.StringUtils; */ public class JredisConnectionFactory implements InitializingBean, DisposableBean, RedisConnectionFactory { - private String encoding = "UTF-8"; private ConnectionSpec connectionSpec; private String password; @@ -49,6 +50,9 @@ public class JredisConnectionFactory implements InitializingBean, DisposableBean private int poolSize = 5; + private Charset charset = Charset.forName("UTF8"); + + /** * Constructs a new JredisConnectionFactory instance. */ @@ -88,7 +92,6 @@ public class JredisConnectionFactory implements InitializingBean, DisposableBean this.connectionSpec = connectionSpec; } - @Override public void afterPropertiesSet() { if (StringUtils.hasLength(password)) { @@ -117,7 +120,7 @@ public class JredisConnectionFactory implements InitializingBean, DisposableBean @Override public RedisConnection getConnection() { - return new JredisConnection((usePool ? pool : new JRedisClient(connectionSpec)), getEncoding()); + return new JredisConnection((usePool ? pool : new JRedisClient(connectionSpec)), charset); } @@ -126,22 +129,6 @@ public class JredisConnectionFactory implements InitializingBean, DisposableBean return null; } - /** - * Returns the encoding. - * - * @return Returns the encoding - */ - public String getEncoding() { - return encoding; - } - - /** - * @param encoding The encoding to set. - */ - public void setEncoding(String encoding) { - this.encoding = encoding; - } - /** * @return the password */ @@ -191,4 +178,21 @@ public class JredisConnectionFactory implements InitializingBean, DisposableBean this.poolSize = poolSize; usePool = true; } + + + /** + * + * @return + */ + public Charset getCharset() { + return charset; + } + + + /** + * @param charset + */ + public void setCharset(Charset charset) { + this.charset = charset; + } } \ No newline at end of file diff --git a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/connection/jredis/JredisUtils.java b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/connection/jredis/JredisUtils.java index 8bb44a9b3..38a5e73b6 100644 --- a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/connection/jredis/JredisUtils.java +++ b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/connection/jredis/JredisUtils.java @@ -16,23 +16,18 @@ package org.springframework.datastore.redis.connection.jredis; -import java.io.UnsupportedEncodingException; +import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Collection; import java.util.LinkedHashMap; -import java.util.LinkedHashSet; import java.util.List; import java.util.Map; -import java.util.Set; import org.jredis.RedisException; import org.jredis.RedisType; import org.springframework.dao.DataAccessException; -import org.springframework.dao.DataRetrievalFailureException; import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.datastore.redis.connection.DataType; -import org.springframework.datastore.redis.connection.DefaultEntry; -import org.springframework.datastore.redis.connection.RedisHashCommands.Entry; /** * Helper class featuring methods for JRedis connection handling, providing support for exception translation. @@ -45,27 +40,16 @@ public abstract class JredisUtils { return new InvalidDataAccessApiUsageException(ex.getMessage(), ex); } - static String convertToString(byte[] bytes, String encoding) { - try { - return new String(bytes, encoding); - } catch (UnsupportedEncodingException ex) { - throw new DataRetrievalFailureException("Unsupported encoding " + encoding, ex); - } + static String convert(Charset charset, byte[] bytes) { + return new String(bytes, charset); } - static > T convertToStringCollection(List bytes, String encoding, Class collectionType) { - - Collection col = (List.class.isAssignableFrom(collectionType) ? new ArrayList(bytes.size()) - : new LinkedHashSet(bytes.size())); - - try { - for (byte[] bs : bytes) { - col.add(new String(bs, encoding)); - } - return (T) col; - } catch (UnsupportedEncodingException ex) { - throw new DataRetrievalFailureException("Unsupported encoding " + encoding, ex); + static String[] convertMultiple(Charset charset, byte[]... bytes) { + String[] result = new String[bytes.length]; + for (int i = 0; i < bytes.length; i++) { + result[i] = new String(bytes[i], charset); } + return result; } static DataType convertDataType(RedisType type) { @@ -87,23 +71,31 @@ public abstract class JredisUtils { return null; } - static Set convert(Map map, String encoding) { - Set entries = new LinkedHashSet(map.size()); - try { - for (Map.Entry entry : map.entrySet()) { - entries.add(new DefaultEntry(entry.getKey(), new String(entry.getValue(), encoding))); - } - } catch (UnsupportedEncodingException ex) { - throw new DataRetrievalFailureException("Unsupported encoding " + encoding, ex); + static Map convertMap(Charset charset, Map map) { + Map result = new LinkedHashMap(map.size()); + for (Map.Entry entry : map.entrySet()) { + result.put(entry.getKey().getBytes(charset), entry.getValue()); } - return entries; + return result; } - static Map convert(String[] keys, String[] values) { - Map result = new LinkedHashMap(keys.length); + static Collection convert(Charset charset, List keys) { + Collection list = new ArrayList(keys.size()); - for (int i = 0; i < values.length; i++) { - result.put(keys[i], values[i].getBytes()); + for (String string : keys) { + list.add(string.getBytes(charset)); + } + return list; + } + + static byte[] convert(Charset charset, String string) { + return string.getBytes(charset); + } + + static Map convert(Charset charset, Map tuple) { + Map result = new LinkedHashMap(tuple.size()); + for (Map.Entry entry : tuple.entrySet()) { + result.put(new String(entry.getKey(), charset), entry.getValue()); } return result; } diff --git a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/core/BoundListOperations.java b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/core/BoundListOperations.java new file mode 100644 index 000000000..1c1e330c3 --- /dev/null +++ b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/core/BoundListOperations.java @@ -0,0 +1,44 @@ +/* + * Copyright 2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.springframework.datastore.redis.core; + +import java.util.List; + +/** + * List operations bound to a certain key. + * + * @author Costin Leau + */ +public interface BoundListOperations extends KeyBound { + + List range(int start, int end); + + void trim(int start, int end); + + Integer length(); + + Integer leftPush(V value); + + Integer rightPush(V value); + + V leftPop(); + + V rightPop(); + + Integer remove(int i, Object value); + + V index(int index); +} diff --git a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/core/BoundSetOperations.java b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/core/BoundSetOperations.java new file mode 100644 index 000000000..c1afe7f4a --- /dev/null +++ b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/core/BoundSetOperations.java @@ -0,0 +1,51 @@ +/* + * Copyright 2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.springframework.datastore.redis.core; + +import java.util.Set; + +/** + * Set operations bound to a certain key. + * + * @author Costin Leau + */ +public interface BoundSetOperations extends KeyBound { + + Set diff(K... keys); + + void diffAndStore(K destKey, K... keys); + + RedisOperations getOperations(); + + Set intersect(K... keys); + + void intersectAndStore(K destKey, K... keys); + + Set union(K... keys); + + void unionAndStore(K destKey, K... keys); + + Boolean add(V value); + + boolean isMember(Object o); + + Set members(); + + boolean remove(Object o); + + int size(); +} diff --git a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/core/BoundZSetOperations.java b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/core/BoundZSetOperations.java new file mode 100644 index 000000000..72d1e2dcd --- /dev/null +++ b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/core/BoundZSetOperations.java @@ -0,0 +1,52 @@ +/* + * Copyright 2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.springframework.datastore.redis.core; + +import java.util.Set; + + +/** + * ZSet (or SortedSet) operations bound to a certain key. + * + * @author Costin Leau + */ +public interface BoundZSetOperations extends KeyBound { + + RedisOperations getOperations(); + + void intersectAndStore(K destKey, K... keys); + + Set range(int start, int end); + + Set rangeByScore(double min, double max); + + void removeRange(int start, int end); + + void removeRangeByScore(double min, double max); + + void unionAndStore(K destKey, K... keys); + + boolean add(V value, double score); + + Integer rank(Object o); + + boolean remove(Object o); + + int size(); + + Set reverseRange(int start, int end); +} diff --git a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/core/DefaultBoundListOperations.java b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/core/DefaultBoundListOperations.java new file mode 100644 index 000000000..82ebaf363 --- /dev/null +++ b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/core/DefaultBoundListOperations.java @@ -0,0 +1,79 @@ +/* + * Copyright 2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.springframework.datastore.redis.core; + +import java.util.List; + + +/** + * Default implementation for {@link BoundListOperations}. + * + * @author Costin Leau + */ +public class DefaultBoundListOperations extends DefaultKeyBound implements BoundListOperations { + + private final ListOperations ops; + + public DefaultBoundListOperations(K key, RedisTemplate template) { + super(key); + this.ops = template.listOps(); + } + + @Override + public V index(int index) { + throw new UnsupportedOperationException(); + } + + @Override + public V leftPop() { + throw new UnsupportedOperationException(); + } + + @Override + public Integer leftPush(V value) { + throw new UnsupportedOperationException(); + } + + @Override + public Integer length() { + throw new UnsupportedOperationException(); + } + + @Override + public List range(int start, int end) { + throw new UnsupportedOperationException(); + } + + @Override + public Integer remove(int i, Object value) { + throw new UnsupportedOperationException(); + } + + @Override + public V rightPop() { + throw new UnsupportedOperationException(); + } + + @Override + public Integer rightPush(V value) { + throw new UnsupportedOperationException(); + } + + @Override + public void trim(int start, int end) { + throw new UnsupportedOperationException(); + } +} \ No newline at end of file diff --git a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/core/DefaultBoundSetOperations.java b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/core/DefaultBoundSetOperations.java new file mode 100644 index 000000000..ff9a529ef --- /dev/null +++ b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/core/DefaultBoundSetOperations.java @@ -0,0 +1,95 @@ +/* + * Copyright 2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.springframework.datastore.redis.core; + +import java.util.Set; + +/** + * Default implementation for {@link BoundSetOperations}. + * + * @author Costin Leau + */ +class DefaultBoundSetOperations extends DefaultKeyBound implements BoundSetOperations { + + private final SetOperations ops; + + + DefaultBoundSetOperations(K key, RedisTemplate template) { + super(key); + this.ops = template.setOps(); + } + + @Override + public Boolean add(V value) { + return ops.add(getKey(), value); + } + + @Override + public Set diff(K... keys) { + return ops.diff(getKey(), keys); + } + + @Override + public void diffAndStore(K destKey, K... keys) { + ops.diffAndStore(getKey(), destKey, keys); + } + + @Override + public RedisOperations getOperations() { + return ops.getOperations(); + } + + @Override + public Set intersect(K... keys) { + return ops.intersect(getKey(), keys); + } + + @Override + public void intersectAndStore(K destKey, K... keys) { + ops.intersectAndStore(getKey(), destKey, keys); + } + + @Override + public boolean isMember(Object o) { + return ops.isMember(getKey(), o); + } + + @Override + public Set members() { + return ops.members(getKey()); + } + + @Override + public boolean remove(Object o) { + return ops.remove(getKey(), o); + } + + @Override + public int size() { + return ops.size(getKey()); + } + + @Override + public Set union(K... keys) { + return ops.union(getKey(), keys); + } + + @Override + public void unionAndStore(K destKey, K... keys) { + ops.unionAndStore(getKey(), destKey, keys); + } +} \ No newline at end of file diff --git a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/core/DefaultBoundZSetOperations.java b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/core/DefaultBoundZSetOperations.java new file mode 100644 index 000000000..8b3fe5c6f --- /dev/null +++ b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/core/DefaultBoundZSetOperations.java @@ -0,0 +1,94 @@ +/* + * Copyright 2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.springframework.datastore.redis.core; + +import java.util.Set; + +/** + * Default implementation for {@link BoundZSetOperations}. + * + * @author Costin Leau + */ +class DefaultBoundZSetOperations extends DefaultKeyBound implements BoundZSetOperations { + + private final ZSetOperations ops; + + public DefaultBoundZSetOperations(K key, RedisTemplate template) { + super(key); + this.ops = template.zSetOps(); + } + + @Override + public boolean add(V value, double score) { + return ops.add(getKey(), value, score); + } + + @Override + public RedisOperations getOperations() { + return ops.getOperations(); + } + + @Override + public void intersectAndStore(K destKey, K... keys) { + ops.intersectAndStore(getKey(), destKey, keys); + } + + @Override + public Set range(int start, int end) { + return ops.range(getKey(), start, end); + } + + @Override + public Set rangeByScore(double min, double max) { + return ops.rangeByScore(getKey(), min, max); + } + + @Override + public Integer rank(Object o) { + return ops.rank(getKey(), o); + } + + @Override + public boolean remove(Object o) { + return ops.remove(getKey(), o); + } + + @Override + public void removeRange(int start, int end) { + ops.removeRange(getKey(), start, end); + } + + @Override + public void removeRangeByScore(double min, double max) { + ops.removeRangeByScore(getKey(), min, max); + } + + @Override + public Set reverseRange(int start, int end) { + return ops.reverseRange(getKey(), start, end); + } + + @Override + public int size() { + return ops.size(getKey()); + } + + @Override + public void unionAndStore(K destKey, K... keys) { + ops.unionAndStore(getKey(), destKey, keys); + } +} \ No newline at end of file diff --git a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/connection/DefaultEntry.java b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/core/DefaultKeyBound.java similarity index 58% rename from spring-datastore-redis/src/main/java/org/springframework/datastore/redis/connection/DefaultEntry.java rename to spring-datastore-redis/src/main/java/org/springframework/datastore/redis/core/DefaultKeyBound.java index db174291e..6c2dd57cc 100644 --- a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/connection/DefaultEntry.java +++ b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/core/DefaultKeyBound.java @@ -13,33 +13,24 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.datastore.redis.connection; +package org.springframework.datastore.redis.core; -import org.springframework.datastore.redis.connection.RedisHashCommands.Entry; /** - * Default {@link Entry} implementation. + * Default {@link KeyBound} implementation. * * @author Costin Leau */ -public class DefaultEntry implements Entry { +public class DefaultKeyBound implements KeyBound { - private final String field; - private final String value; + private final K key; - public DefaultEntry(String field, String value) { - this.field = field; - this.value = value; + public DefaultKeyBound(K key) { + this.key = key; } @Override - public String getField() { - return null; + public K getKey() { + return key; } - - @Override - public String getValue() { - return null; - } - } diff --git a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/core/KeyBound.java b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/core/KeyBound.java new file mode 100644 index 000000000..29f336b7d --- /dev/null +++ b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/core/KeyBound.java @@ -0,0 +1,31 @@ +/* + * Copyright 2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.springframework.datastore.redis.core; + +/** + * Redis store for a certain key. Useful for creating views into Redis 'collection' types. + * + * @author Costin Leau + */ +public interface KeyBound { + + /** + * Returns the key associated with this store. + * + * @return + */ + K getKey(); +} diff --git a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/core/ListOperations.java b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/core/ListOperations.java new file mode 100644 index 000000000..930466d6b --- /dev/null +++ b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/core/ListOperations.java @@ -0,0 +1,50 @@ +/* + * Copyright 2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.springframework.datastore.redis.core; + +import java.util.List; + +/** + * Redis, list specific operations. + * + * @author Costin Leau + */ +public interface ListOperations { + + List range(K key, int start, int end); + + void trim(K key, int start, int end); + + Integer length(K key); + + Integer leftPush(K key, V value); + + Integer rightPush(K key, V value); + + void set(K key, int index, V value); + + Integer remove(K key, int i, Object value); + + V index(K key, int index); + + V leftPop(K key); + + V rightPop(K key); + + List blockingLeftPop(int timeout, K... keys); + + List blockingRightPop(int timeout, K... keys); +} diff --git a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/core/RedisConnectionUtils.java b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/core/RedisConnectionUtils.java index bbaa8a88e..f5344e3f8 100644 --- a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/core/RedisConnectionUtils.java +++ b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/core/RedisConnectionUtils.java @@ -46,6 +46,10 @@ public abstract class RedisConnectionUtils { if (connHolder != null) return connHolder.getConnection(); + if (!allowCreate) { + throw new IllegalArgumentException("No connection found and allowCreate = false"); + } + if (log.isDebugEnabled()) log.debug("Opening RedisConnection"); @@ -56,10 +60,9 @@ public abstract class RedisConnectionUtils { TransactionSynchronizationManager.registerSynchronization(new RedisConnectionSynchronization(connHolder, factory, true)); TransactionSynchronizationManager.bindResource(factory, connHolder); - + return connHolder.getConnection(); } - return connHolder.getConnection(); - + return conn; } public static void releaseConnection(RedisConnection conn, RedisConnectionFactory factory) { diff --git a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/core/RedisOperations.java b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/core/RedisOperations.java index 7d6b8ea0e..52a4d5a89 100644 --- a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/core/RedisOperations.java +++ b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/core/RedisOperations.java @@ -15,12 +15,39 @@ */ package org.springframework.datastore.redis.core; + /** * Basic set of Redis operations, implemented by {@link RedisTemplate}. * * @author Costin Leau */ -public interface RedisOperations { +public interface RedisOperations { + void set(K key, V value); + V get(K key); + + V getAndSet(K key, V newValue); + + void watch(K... keys); + + void multi(); + + Object exec(); + + Integer increment(K key, int delta); + + void delete(K... keys); + + ListOperations listOps(); + + BoundListOperations forList(K key); + + SetOperations setOps(); + + BoundSetOperations forSet(K key); + + ZSetOperations zSetOps(); + + BoundZSetOperations forZSet(K key); } diff --git a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/core/RedisTemplate.java b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/core/RedisTemplate.java index 3cfa23777..97db2af7e 100644 --- a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/core/RedisTemplate.java +++ b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/core/RedisTemplate.java @@ -19,11 +19,17 @@ import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Proxy; +import java.util.ArrayList; +import java.util.Collection; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; import org.springframework.datastore.redis.connection.RedisConnection; import org.springframework.datastore.redis.connection.RedisConnectionFactory; import org.springframework.datastore.redis.serializer.RedisSerializer; import org.springframework.datastore.redis.serializer.SimpleRedisSerializer; +import org.springframework.datastore.redis.serializer.StringRedisSerializer; import org.springframework.transaction.support.TransactionSynchronizationManager; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; @@ -43,10 +49,12 @@ import org.springframework.util.ClassUtils; * * @author Costin Leau */ -public class RedisTemplate extends RedisAccessor { +public class RedisTemplate extends RedisAccessor implements RedisOperations { private boolean exposeConnection = false; - private RedisSerializer converter = new SimpleRedisSerializer(); + private RedisSerializer keySerializer = new StringRedisSerializer(); + private RedisSerializer valueSerializer = new SimpleRedisSerializer(); + private RedisSerializer defaultSerializer = new SimpleRedisSerializer(); public RedisTemplate() { } @@ -60,7 +68,7 @@ public class RedisTemplate extends RedisAccessor { execute(new RedisCallback() { @Override public Object doInRedis(RedisConnection connection) throws Exception { - connection.del(redisKey); + connection.del(keySerializer.serialize(redisKey)); return null; } }); @@ -72,6 +80,10 @@ public class RedisTemplate extends RedisAccessor { } public T execute(RedisCallback action, boolean exposeConnection) { + return execute(action, isExposeConnection(), defaultSerializer); + } + + public T execute(RedisCallback action, boolean exposeConnection, RedisSerializer returnSerializer) { Assert.notNull(action, "Callback object must not be null"); RedisConnectionFactory factory = getConnectionFactory(); @@ -122,8 +134,16 @@ public class RedisTemplate extends RedisAccessor { this.exposeConnection = exposeConnection; } - public void setRedisConverter(RedisSerializer converter) { - this.converter = converter; + public void setKeySerializer(RedisSerializer serializer) { + this.keySerializer = serializer; + } + + public void setValueSerializer(RedisSerializer serializer) { + this.valueSerializer = serializer; + } + + public void setDefaultSerializer(RedisSerializer serializer) { + this.defaultSerializer = serializer; } /** @@ -164,4 +184,642 @@ public class RedisTemplate extends RedisAccessor { } } } + + private byte[] rawKey(K key) { + return (key != null ? keySerializer.serialize(key) : null); + } + + private byte[] rawValue(T value) { + return (value != null ? valueSerializer.serialize(value) : null); + } + + private byte[][] rawKeys(K... keys) { + final byte[][] rawKeys = new byte[keys.length][]; + + for (int i = 0; i < keys.length; i++) { + rawKeys[i] = rawKey(keys[i]); + } + + return rawKeys; + } + + @SuppressWarnings("unchecked") + private > T values(Collection rawValues, Class type) { + Collection values = (List.class.isAssignableFrom(type) ? new ArrayList(rawValues.size()) + : new LinkedHashSet(rawValues.size())); + for (byte[] bs : rawValues) { + values.add((V) valueSerializer.deserialize(bs)); + } + + return (T) values; + } + + // utility methods for the template internal methods + private abstract class ValueDeserializingRedisCallback implements RedisCallback { + private K key; + + public ValueDeserializingRedisCallback() { + this(null); + + } + + public ValueDeserializingRedisCallback(K key) { + this.key = key; + } + + @SuppressWarnings("unchecked") + @Override + public final V doInRedis(RedisConnection connection) throws Exception { + byte[] result = inRedis(rawKey(key), connection); + if (result != null) { + return (V) valueSerializer.deserialize(result); + } + return null; + } + + protected abstract byte[] inRedis(byte[] rawKey, RedisConnection connection); + } + + + // + // RedisOperations + // + + @Override + public Object exec() { + throw new UnsupportedOperationException(); + } + + @Override + public BoundListOperations forList(K key) { + return new DefaultBoundListOperations(key, this); + } + + @Override + public V get(final K key) { + return execute(new ValueDeserializingRedisCallback(key) { + @Override + protected byte[] inRedis(byte[] rawKey, RedisConnection connection) { + return connection.get(rawKey); + } + }, false); + } + + @Override + public V getAndSet(K key, V newValue) { + final byte[] rawValue = rawValue(newValue); + return execute(new ValueDeserializingRedisCallback(key) { + @Override + protected byte[] inRedis(byte[] rawKey, RedisConnection connection) { + return connection.getSet(rawKey, rawValue); + } + }, false); + } + + @Override + public Integer increment(K key, final int delta) { + final byte[] rawKey = rawKey(key); + return execute(new RedisCallback() { + @Override + public Integer doInRedis(RedisConnection connection) throws Exception { + if (delta == 1) { + return connection.incr(rawKey); + } + + if (delta == -1) { + return connection.decr(rawKey); + } + + if (delta < 0) { + return connection.decrBy(rawKey, delta); + } + + return connection.incrBy(rawKey, delta); + } + }, false); + } + + @Override + public ListOperations listOps() { + return new DefaultListOperations(); + } + + @Override + public void multi() { + throw new UnsupportedOperationException(); + } + + @Override + public void set(K key, V value) { + final byte[] rawValue = rawValue(value); + execute(new ValueDeserializingRedisCallback(key) { + @Override + protected byte[] inRedis(byte[] rawKey, RedisConnection connection) { + connection.set(rawKey, rawValue); + return null; + } + }, false); + } + + @Override + public void watch(K... keys) { + final byte[][] rawKeys = rawKeys(keys); + + execute(new RedisCallback() { + @Override + public Object doInRedis(RedisConnection connection) throws Exception { + connection.watch(rawKeys); + return null; + } + }, false); + } + + @Override + public void delete(K... keys) { + final byte[][] rawKeys = rawKeys(keys); + + execute(new RedisCallback() { + @Override + public Object doInRedis(RedisConnection connection) throws Exception { + connection.del(rawKeys); + return null; + } + }, false); + } + + // + // List operations + // + + private class DefaultListOperations implements ListOperations { + + @Override + public List blockingLeftPop(final int timeout, K... keys) { + final byte[][] rawKeys = rawKeys(keys); + + return execute(new RedisCallback>() { + @Override + public List doInRedis(RedisConnection connection) throws Exception { + return values(connection.bLPop(timeout, rawKeys), List.class); + } + }, false); + } + + @Override + public List blockingRightPop(final int timeout, K... keys) { + final byte[][] rawKeys = rawKeys(keys); + return execute(new RedisCallback>() { + @Override + public List doInRedis(RedisConnection connection) throws Exception { + return values(connection.bRPop(timeout, rawKeys), List.class); + } + }, false); + } + + @Override + public V index(K key, final int index) { + return execute(new ValueDeserializingRedisCallback(key) { + @Override + protected byte[] inRedis(byte[] rawKey, RedisConnection connection) { + return connection.lIndex(rawKey, index); + } + }, false); + } + + @Override + public V leftPop(K key) { + return execute(new ValueDeserializingRedisCallback(key) { + @Override + protected byte[] inRedis(byte[] rawKey, RedisConnection connection) { + return connection.lPop(rawKey); + } + }, false); + } + + @Override + public Integer leftPush(K key, V value) { + final byte[] rawKey = rawKey(key); + final byte[] rawValue = rawValue(value); + return execute(new RedisCallback() { + @Override + public Integer doInRedis(RedisConnection connection) throws Exception { + return connection.lPush(rawKey, rawValue); + } + }, false); + } + + @Override + public Integer length(K key) { + final byte[] rawKey = rawKey(key); + return execute(new RedisCallback() { + @Override + public Integer doInRedis(RedisConnection connection) throws Exception { + return connection.lLen(rawKey); + } + }, false); + } + + @Override + public List range(K key, final int start, final int end) { + final byte[] rawKey = rawKey(key); + return execute(new RedisCallback>() { + @Override + public List doInRedis(RedisConnection connection) throws Exception { + return values(connection.lRange(rawKey, start, end), List.class); + } + }, false); + } + + @Override + public Integer remove(K key, final int count, Object value) { + final byte[] rawKey = rawKey(key); + final byte[] rawValue = rawValue(value); + return execute(new RedisCallback() { + @Override + public Integer doInRedis(RedisConnection connection) throws Exception { + return connection.lRem(rawKey, count, rawValue); + } + }, false); + } + + @Override + public V rightPop(K key) { + return execute(new ValueDeserializingRedisCallback(key) { + @Override + protected byte[] inRedis(byte[] rawKey, RedisConnection connection) { + return connection.rPop(rawKey); + } + }, false); + } + + @Override + public Integer rightPush(K key, V value) { + final byte[] rawKey = rawKey(key); + final byte[] rawValue = rawValue(value); + return execute(new RedisCallback() { + @Override + public Integer doInRedis(RedisConnection connection) throws Exception { + return connection.rPush(rawKey, rawValue); + } + }, false); + } + + @Override + public void set(K key, final int index, V value) { + final byte[] rawValue = rawValue(value); + execute(new ValueDeserializingRedisCallback(key) { + @Override + protected byte[] inRedis(byte[] rawKey, RedisConnection connection) { + connection.lSet(rawKey, index, rawValue); + return null; + } + }, false); + } + + @Override + public void trim(K key, final int start, final int end) { + execute(new ValueDeserializingRedisCallback(key) { + @Override + protected byte[] inRedis(byte[] rawKey, RedisConnection connection) { + connection.lTrim(rawKey, start, end); + return null; + } + }, false); + } + } + + // + // Set operations + // + + private K[] aggregateKeys(K key, K... keys) { + Object[] aggregate = new Object[keys.length + 1]; + aggregate[0] = key; + for (int i = 0; i < keys.length; i++) { + aggregate[i + 1] = keys[i]; + } + + return (K[]) aggregate; + } + + @Override + public BoundSetOperations forSet(K key) { + return new DefaultBoundSetOperations(key, this); + } + + @Override + public SetOperations setOps() { + return new DefaultSetOperations(); + } + + private class DefaultSetOperations implements SetOperations { + + @Override + public Boolean add(K key, V value) { + final byte[] rawKey = rawKey(key); + final byte[] rawValue = rawValue(value); + return execute(new RedisCallback() { + @Override + public Boolean doInRedis(RedisConnection connection) throws Exception { + return connection.sAdd(rawKey, rawValue); + } + }, false); + } + + @Override + public Set diff(final K key, final K... keys) { + final byte[][] rawKeys = rawKeys(aggregateKeys(key, keys)); + Set rawValues = execute(new RedisCallback>() { + @Override + public Set doInRedis(RedisConnection connection) throws Exception { + return connection.sDiff(rawKeys); + } + }, false); + + return values(rawValues, Set.class); + } + + @Override + public void diffAndStore(K destKey, final K key, final K... keys) { + final byte[][] rawKeys = rawKeys(aggregateKeys(key, keys)); + final byte[] rawDestKey = rawKey(destKey); + Object rawValues = execute(new RedisCallback() { + @Override + public Object doInRedis(RedisConnection connection) throws Exception { + connection.sDiffStore(rawDestKey, rawKeys); + return null; + } + }, false); + } + + @Override + public RedisOperations getOperations() { + return RedisTemplate.this; + } + + @Override + public Set intersect(K key, K... keys) { + final byte[][] rawKeys = rawKeys(aggregateKeys(key, keys)); + Set rawValues = execute(new RedisCallback>() { + @Override + public Set doInRedis(RedisConnection connection) throws Exception { + return connection.sInter(rawKeys); + } + }, false); + + return values(rawValues, Set.class); + } + + @Override + public void intersectAndStore(K key, K destKey, K... keys) { + final byte[][] rawKeys = rawKeys(aggregateKeys(key, keys)); + final byte[] rawDestKey = rawKey(destKey); + Object rawValues = execute(new RedisCallback() { + @Override + public Object doInRedis(RedisConnection connection) throws Exception { + connection.sInterStore(rawDestKey, rawKeys); + return null; + } + }, false); + } + + @Override + public boolean isMember(K key, Object o) { + final byte[] rawKey = rawKey(key); + final byte[] rawValue = rawValue(o); + return execute(new RedisCallback() { + @Override + public Boolean doInRedis(RedisConnection connection) throws Exception { + return connection.sIsMember(rawKey, rawValue); + } + }, false); + } + + @Override + public Set members(K key) { + final byte[] rawKey = rawKey(key); + Set rawValues = execute(new RedisCallback>() { + @Override + public Set doInRedis(RedisConnection connection) throws Exception { + return connection.sMembers(rawKey); + } + }, false); + + return values(rawValues, Set.class); + } + + @Override + public boolean remove(K key, Object o) { + final byte[] rawKey = rawKey(key); + final byte[] rawValue = rawValue(o); + return execute(new RedisCallback() { + @Override + public Boolean doInRedis(RedisConnection connection) throws Exception { + return connection.sRem(rawKey, rawValue); + } + }, false); + } + + @Override + public int size(K key) { + final byte[] rawKey = rawKey(key); + return execute(new RedisCallback() { + @Override + public Integer doInRedis(RedisConnection connection) throws Exception { + return connection.sCard(rawKey); + } + }, false); + } + + @Override + public Set union(K key, K... keys) { + final byte[][] rawKeys = rawKeys(aggregateKeys(key, keys)); + Set rawValues = execute(new RedisCallback>() { + @Override + public Set doInRedis(RedisConnection connection) throws Exception { + return connection.sUnion(rawKeys); + } + }, false); + + return values(rawValues, Set.class); + } + + @Override + public void unionAndStore(K key, K destKey, K... keys) { + final byte[][] rawKeys = rawKeys(aggregateKeys(key, keys)); + final byte[] rawDestKey = rawKey(destKey); + execute(new RedisCallback() { + @Override + public Object doInRedis(RedisConnection connection) throws Exception { + connection.sUnionStore(rawDestKey, rawKeys); + return null; + } + }, false); + } + } + + // + // ZSet operations + // + + @Override + public BoundZSetOperations forZSet(K key) { + return new DefaultBoundZSetOperations(key, this); + } + + @Override + public ZSetOperations zSetOps() { + return new DefaultZSetOperations(); + } + + private class DefaultZSetOperations implements ZSetOperations { + + @Override + public boolean add(final K key, final V value, final double score) { + final byte[] rawKey = rawKey(key); + final byte[] rawValue = rawValue(value); + + return execute(new RedisCallback() { + @Override + public Boolean doInRedis(RedisConnection connection) throws Exception { + return connection.zAdd(rawKey, score, rawValue); + } + }, false); + } + + @Override + public RedisOperations getOperations() { + return RedisTemplate.this; + } + + @Override + public void intersectAndStore(K key, K destKey, K... keys) { + final byte[][] rawKeys = rawKeys(aggregateKeys(key, keys)); + final byte[] rawDestKey = rawKey(destKey); + execute(new RedisCallback() { + @Override + public Object doInRedis(RedisConnection connection) throws Exception { + connection.zInterStore(rawDestKey, rawKeys); + return null; + } + }, false); + } + + @Override + public Set range(K key, final int start, final int end) { + final byte[] rawKey = rawKey(key); + + Set rawValues = execute(new RedisCallback>() { + @Override + public Set doInRedis(RedisConnection connection) throws Exception { + return connection.zRange(rawKey, start, end); + } + }, false); + + return values(rawValues, Set.class); + } + + @Override + public Set rangeByScore(K key, final double min, final double max) { + final byte[] rawKey = rawKey(key); + + Set rawValues = execute(new RedisCallback>() { + @Override + public Set doInRedis(RedisConnection connection) throws Exception { + return connection.zRangeByScore(rawKey, min, max); + } + }, false); + + return values(rawValues, Set.class); + } + + @Override + public Integer rank(K key, Object o) { + final byte[] rawKey = rawKey(key); + final byte[] rawValue = rawValue(o); + + return execute(new RedisCallback() { + @Override + public Integer doInRedis(RedisConnection connection) throws Exception { + return connection.zRank(rawKey, rawValue); + } + }, false); + } + + @Override + public boolean remove(K key, Object o) { + final byte[] rawKey = rawKey(key); + final byte[] rawValue = rawValue(o); + + return execute(new RedisCallback() { + @Override + public Boolean doInRedis(RedisConnection connection) throws Exception { + return connection.zRem(rawKey, rawValue); + } + }, false); + } + + @Override + public void removeRange(K key, final int start, final int end) { + final byte[] rawKey = rawKey(key); + execute(new RedisCallback() { + @Override + public Object doInRedis(RedisConnection connection) throws Exception { + connection.zRemRange(rawKey, start, end); + return null; + } + }, false); + } + + @Override + public void removeRangeByScore(K key, final double min, final double max) { + final byte[] rawKey = rawKey(key); + execute(new RedisCallback() { + @Override + public Object doInRedis(RedisConnection connection) throws Exception { + connection.zRemRangeByScore(rawKey, min, max); + return null; + } + }, false); + } + + @Override + public Set reverseRange(K key, final int start, final int end) { + final byte[] rawKey = rawKey(key); + + Set rawValues = execute(new RedisCallback>() { + @Override + public Set doInRedis(RedisConnection connection) throws Exception { + return connection.zRevRange(rawKey, start, end); + } + }, false); + + return values(rawValues, Set.class); + } + + @Override + public int size(K key) { + final byte[] rawKey = rawKey(key); + + return execute(new RedisCallback() { + @Override + public Integer doInRedis(RedisConnection connection) throws Exception { + return connection.zCard(rawKey); + } + }, false); + } + + @Override + public void unionAndStore(K key, K destKey, K... keys) { + final byte[][] rawKeys = rawKeys(aggregateKeys(key, keys)); + final byte[] rawDestKey = rawKey(destKey); + execute(new RedisCallback() { + @Override + public Object doInRedis(RedisConnection connection) throws Exception { + connection.zUnionStore(rawDestKey, rawKeys); + return null; + } + }, false); + } + } } \ No newline at end of file diff --git a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/core/SetOperations.java b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/core/SetOperations.java new file mode 100644 index 000000000..34dc6e7d4 --- /dev/null +++ b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/core/SetOperations.java @@ -0,0 +1,52 @@ +/* + * Copyright 2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.springframework.datastore.redis.core; + +import java.util.Set; + +/** + * Redis set specific operations. + * + * @author Costin Leau + */ +public interface SetOperations { + + Set diff(K key, K... keys); + + void diffAndStore(K key, K destKey, K... keys); + + RedisOperations getOperations(); + + Set intersect(K key, K... keys); + + void intersectAndStore(K key, K destKey, K... keys); + + Set union(K key, K... keys); + + void unionAndStore(K key, K destKey, K... keys); + + Boolean add(K key, V value); + + boolean isMember(K key, Object o); + + Set members(K key); + + boolean remove(K key, Object o); + + int size(K key); + +} diff --git a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/core/ZSetOperations.java b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/core/ZSetOperations.java new file mode 100644 index 000000000..0dc9d01c4 --- /dev/null +++ b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/core/ZSetOperations.java @@ -0,0 +1,51 @@ +/* + * Copyright 2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.springframework.datastore.redis.core; + +import java.util.Set; + +/** + * Redis ZSet/sorted set specific operations. + * + * @author Costin Leau + */ +public interface ZSetOperations { + + void intersectAndStore(K key, K destKey, K... keys); + + Set range(K key, int start, int end); + + Set rangeByScore(K key, double min, double max); + + void removeRange(K key, int start, int end); + + void removeRangeByScore(K key, double min, double max); + + void unionAndStore(K key, K destKey, K... keys); + + boolean add(K key, V value, double score); + + Integer rank(K key, Object o); + + boolean remove(K key, Object o); + + int size(K key); + + Set reverseRange(K key, int start, int end); + + RedisOperations getOperations(); +} diff --git a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/serializer/RedisSerializer.java b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/serializer/RedisSerializer.java index 486155e26..5b10e4f16 100644 --- a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/serializer/RedisSerializer.java +++ b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/serializer/RedisSerializer.java @@ -23,7 +23,7 @@ package org.springframework.datastore.redis.serializer; */ public interface RedisSerializer { - byte[] serialize(T object); + byte[] serialize(T t); T deserialize(byte[] bytes); } diff --git a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/serializer/SimpleRedisSerializer.java b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/serializer/SimpleRedisSerializer.java index 308f2e33f..143cc7f90 100644 --- a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/serializer/SimpleRedisSerializer.java +++ b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/serializer/SimpleRedisSerializer.java @@ -18,6 +18,7 @@ package org.springframework.datastore.redis.serializer; import org.springframework.core.convert.converter.Converter; import org.springframework.core.serializer.support.DeserializingConverter; import org.springframework.core.serializer.support.SerializingConverter; +import org.springframework.datastore.redis.UncategorizedRedisException; /** * Simple Redis serializer delegating to the default serializer in Spring 3. @@ -25,18 +26,30 @@ import org.springframework.core.serializer.support.SerializingConverter; * @author Mark Pollack * @author Costin Leau */ -public class SimpleRedisSerializer implements RedisSerializer { +public class SimpleRedisSerializer implements RedisSerializer { private Converter serializer = new SerializingConverter(); private Converter deserializer = new DeserializingConverter(); + private sun.misc.BASE64Encoder encoder = new sun.misc.BASE64Encoder(); + private sun.misc.BASE64Decoder decoder = new sun.misc.BASE64Decoder(); + + @SuppressWarnings("unchecked") @Override - public T deserialize(byte[] bytes) { - return (T) deserializer.convert(bytes); + public Object deserialize(byte[] bytes) { + try { + return deserializer.convert(bytes); + } catch (Exception ex) { + throw new UncategorizedRedisException("Cannot deserialize", ex); + } } @Override - public byte[] serialize(T object) { - return serializer.convert(object); + public byte[] serialize(Object object) { + try { + return serializer.convert(object); + } catch (Exception ex) { + throw new UncategorizedRedisException("Cannot serialize", ex); + } } -} +} \ No newline at end of file diff --git a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/serializer/StringRedisSerializer.java b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/serializer/StringRedisSerializer.java new file mode 100644 index 000000000..2caaf6899 --- /dev/null +++ b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/serializer/StringRedisSerializer.java @@ -0,0 +1,47 @@ +/* + * Copyright 2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.springframework.datastore.redis.serializer; + +import java.nio.charset.Charset; + +/** + * Simple String to byte[] (and back) serializer. Relies on the specified charset + * to properly convert the String into bytes and vice-versa. + * + * @author Costin Leau + */ +public class StringRedisSerializer implements RedisSerializer { + + private final Charset charset; + + public StringRedisSerializer() { + this(Charset.forName("UTF8")); + } + + public StringRedisSerializer(Charset charset) { + this.charset = charset; + } + + @Override + public String deserialize(byte[] bytes) { + return new String(bytes, charset); + } + + @Override + public byte[] serialize(String object) { + return object.toString().getBytes(charset); + } +} diff --git a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/util/AbstractRedisCollection.java b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/util/AbstractRedisCollection.java index c9b7ffa1b..b765048d9 100644 --- a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/util/AbstractRedisCollection.java +++ b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/util/AbstractRedisCollection.java @@ -18,21 +18,23 @@ package org.springframework.datastore.redis.util; import java.util.AbstractCollection; import java.util.Collection; -import org.springframework.datastore.redis.connection.RedisCommands; +import org.springframework.datastore.redis.core.RedisOperations; /** * Base implementation for Redis collections. * * @author Costin Leau */ -public abstract class AbstractRedisCollection extends AbstractCollection implements RedisStore { +public abstract class AbstractRedisCollection extends AbstractCollection implements RedisStore { + + public static final String ENCODING = "UTF-8"; protected final String key; - protected final RedisCommands commands; + protected final RedisOperations operations; - public AbstractRedisCollection(String key, RedisCommands commands) { + public AbstractRedisCollection(String key, RedisOperations operations) { this.key = key; - this.commands = commands; + this.operations = operations; } @Override @@ -41,15 +43,20 @@ public abstract class AbstractRedisCollection extends AbstractCollection } @Override - public boolean addAll(Collection c) { + public RedisOperations getOperations() { + return operations; + } + + @Override + public boolean addAll(Collection c) { boolean modified = false; - for (String string : c) { - modified |= add(string); + for (E e : c) { + modified |= add(e); } return modified; } - public abstract boolean add(String e); + public abstract boolean add(E e); public abstract void clear(); @@ -78,4 +85,34 @@ public abstract class AbstractRedisCollection extends AbstractCollection throw new UnsupportedOperationException(); } + @Override + public boolean equals(Object o) { + if (o == this) + return true; + + if (o instanceof RedisStore) { + return key.equals(((RedisStore) o).getKey()); + } + if (o instanceof AbstractRedisCollection) { + return o.hashCode() == hashCode(); + } + + return false; + } + + @Override + public int hashCode() { + int result = 17 + getClass().hashCode(); + result = result * 31 + key.hashCode(); + return result; + } + + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("RedisStore for key:"); + sb.append(getKey()); + return sb.toString(); + } } \ No newline at end of file diff --git a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/util/CollectionUtils.java b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/util/CollectionUtils.java new file mode 100644 index 000000000..9bc9815e8 --- /dev/null +++ b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/util/CollectionUtils.java @@ -0,0 +1,39 @@ +/* + * Copyright 2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.springframework.datastore.redis.util; + +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +/** + * Utility class used mainly for type conversion by the default collection implementations. + * + * @author Costin Leau + */ +abstract class CollectionUtils { + + @SuppressWarnings("unchecked") + static Collection reverse(Collection c) { + Object[] reverse = new Object[c.size()]; + int index = c.size(); + for (E e : c) { + reverse[--index] = e; + } + + return (List) Arrays.asList(reverse); + } +} diff --git a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/util/DefaultRedisList.java b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/util/DefaultRedisList.java index 4226dd581..bb4c58542 100644 --- a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/util/DefaultRedisList.java +++ b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/util/DefaultRedisList.java @@ -21,98 +21,133 @@ import java.util.List; import java.util.ListIterator; import java.util.NoSuchElementException; -import org.springframework.datastore.redis.connection.RedisCommands; +import org.springframework.datastore.redis.core.ListOperations; +import org.springframework.datastore.redis.core.RedisOperations; /** * Default implementation for {@link RedisList}. * * @author Costin Leau */ -public class DefaultRedisList extends AbstractRedisCollection implements RedisList { +public class DefaultRedisList extends AbstractRedisCollection implements RedisList { - private class DefaultRedisListIterator extends RedisIterator { + private final ListOperations listOps; - public DefaultRedisListIterator(Iterator delegate) { + private class DefaultRedisListIterator extends RedisIterator { + + public DefaultRedisListIterator(Iterator delegate) { super(delegate); } @Override - protected void removeFromRedisStorage(String item) { + protected void removeFromRedisStorage(E item) { DefaultRedisList.this.remove(item); } } - public DefaultRedisList(String key, RedisCommands commands) { - super(key, commands); + public DefaultRedisList(String key, RedisOperations operations) { + super(key, operations); + listOps = operations.listOps(); } @Override - public List range(int start, int end) { - return commands.lRange(key, start, end); + public List range(int start, int end) { + return listOps.range(key, start, end); } @Override - public RedisList trim(int start, int end) { - commands.lTrim(key, start, end); + public RedisList trim(int start, int end) { + listOps.trim(key, start, end); return this; } - private List content() { - return commands.lRange(key, 0, -1); + private List content() { + return listOps.range(key, 0, -1); } @Override - public Iterator iterator() { + public Iterator iterator() { return content().iterator(); } @Override public int size() { - return commands.lLen(key); + return listOps.length(key); } @Override - public boolean add(String value) { - commands.rPush(key, value); + public boolean add(E value) { + listOps.rightPush(key, value); return true; } @Override public void clear() { - commands.lTrim(key, 0, -1); + listOps.trim(key, size() + 1, 0); } @Override public boolean remove(Object o) { - Integer result = commands.lRem(key, 0, o.toString()); + Integer result = listOps.remove(key, 0, o); return (result != null && result.intValue() > 0); } @Override - public void add(int index, String element) { + public void add(int index, E element) { if (index == 0) { - commands.lPush(key, element); + listOps.leftPush(key, element); + return; } - else if (index == size()) { - commands.rPush(key, element); + + int size = size(); + + if (index == size()) { + listOps.rightPush(key, element); + return; + } + + if (index < 0 || index > size) { + throw new IndexOutOfBoundsException(); } throw new IllegalArgumentException("Redis supports insertion only at the beginning or the end of the list"); } @Override - public boolean addAll(int index, Collection c) { - for (String string : c) { - add(index, string); + public boolean addAll(int index, Collection c) { + // insert collection in reverse + if (index == 0) { + Collection reverseC = CollectionUtils.reverse(c); + + for (E e : reverseC) { + listOps.leftPush(key, e); + } + return true; } - return true; + int size = size(); + + if (index == size()) { + for (E e : c) { + listOps.rightPush(key, e); + } + return true; + } + + if (index < 0 || index > size) { + throw new IndexOutOfBoundsException(); + } + + throw new IllegalArgumentException("Redis supports insertion only at the beginning or the end of the list"); } @Override - public String get(int index) { - return commands.lIndex(key, index); + public E get(int index) { + if (index < 0 || index > size()) { + throw new IndexOutOfBoundsException(); + } + return listOps.index(key, index); } @Override @@ -126,37 +161,37 @@ public class DefaultRedisList extends AbstractRedisCollection implements RedisLi } @Override - public ListIterator listIterator() { + public ListIterator listIterator() { throw new UnsupportedOperationException(); } @Override - public ListIterator listIterator(int index) { + public ListIterator listIterator(int index) { throw new UnsupportedOperationException(); } @Override - public String remove(int index) { + public E remove(int index) { throw new UnsupportedOperationException(); } @Override - public String set(int index, String element) { - String object = get(index); - commands.lSet(key, index, element); + public E set(int index, E e) { + E object = get(index); + listOps.set(key, index, e); return object; } @Override - public List subList(int fromIndex, int toIndex) { + public List subList(int fromIndex, int toIndex) { throw new UnsupportedOperationException(); } @Override - public String element() { - String value = peek(); + public E element() { + E value = peek(); if (value == null) throw new NoSuchElementException(); @@ -165,27 +200,29 @@ public class DefaultRedisList extends AbstractRedisCollection implements RedisLi @Override - public boolean offer(String e) { - commands.lPush(key, e); + public boolean offer(E e) { + listOps.leftPush(key, e); return true; } @Override - public String peek() { - return commands.lIndex(key, 0); + public E peek() { + E element = listOps.index(key, 0); + return (element == null ? null : element); } @Override - public String poll() { - return commands.lPop(key); + public E poll() { + E element = listOps.leftPop(key); + return (element == null ? null : element); } @Override - public String remove() { - String value = poll(); + public E remove() { + E value = poll(); if (value == null) throw new NoSuchElementException(); diff --git a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/util/DefaultRedisMap.java b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/util/DefaultRedisMap similarity index 86% rename from spring-datastore-redis/src/main/java/org/springframework/datastore/redis/util/DefaultRedisMap.java rename to spring-datastore-redis/src/main/java/org/springframework/datastore/redis/util/DefaultRedisMap index da3e23ef3..2cb9c6bed 100644 --- a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/util/DefaultRedisMap.java +++ b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/util/DefaultRedisMap @@ -21,13 +21,14 @@ import java.util.Map; import java.util.Set; import org.springframework.datastore.redis.connection.RedisCommands; +import org.springframework.datastore.redis.core.RedisOperations; /** * Default {@link RedisMap} implementation. * * @author Costin Leau */ -public class DefaultRedisMap implements RedisMap { +public class DefaultRedisMap implements RedisMap { private class DefaultRedisMapEntry implements Map.Entry { @@ -60,17 +61,25 @@ public class DefaultRedisMap implements RedisMap { } protected final String redisKey; - protected final RedisCommands commands; + protected final RedisOperations operations; + private final MapOperations mapOps; + /** * Constructs a new DefaultRedisMap instance. * * @param key - * @param commands + * @param operations */ - public DefaultRedisMap(String key, RedisCommands commands) { + public DefaultRedisMap(String key, RedisOperations operations) { this.redisKey = key; - this.commands = commands; + this.operations = operations; + this.maps = operations.forMap(key); + } + + public DefaultRedisList(String key, RedisOperations operations) { + super(key, operations); + listOps = operations.listOps(); } @Override @@ -88,6 +97,11 @@ public class DefaultRedisMap implements RedisMap { return redisKey; } + @Override + public RedisCommands getOperations() { + return commands; + } + @Override public void clear() { throw new UnsupportedOperationException(); diff --git a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/util/DefaultRedisSet.java b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/util/DefaultRedisSet.java index 6dcbf749e..cb5c9a75a 100644 --- a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/util/DefaultRedisSet.java +++ b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/util/DefaultRedisSet.java @@ -18,23 +18,26 @@ package org.springframework.datastore.redis.util; import java.util.Iterator; import java.util.Set; -import org.springframework.datastore.redis.connection.RedisCommands; +import org.springframework.datastore.redis.core.BoundSetOperations; +import org.springframework.datastore.redis.core.RedisOperations; /** * Default implementation for {@link RedisSet}. * * @author Costin Leau */ -public class DefaultRedisSet extends AbstractRedisCollection implements RedisSet { +public class DefaultRedisSet extends AbstractRedisCollection implements RedisSet { - private class DefaultRedisSetIterator extends RedisIterator { + private final BoundSetOperations boundSetOps; - public DefaultRedisSetIterator(Iterator delegate) { + private class DefaultRedisSetIterator extends RedisIterator { + + public DefaultRedisSetIterator(Iterator delegate) { super(delegate); } @Override - protected void removeFromRedisStorage(String item) { + protected void removeFromRedisStorage(E item) { DefaultRedisSet.this.remove(item); } } @@ -43,82 +46,92 @@ public class DefaultRedisSet extends AbstractRedisCollection implements RedisSet * Constructs a new DefaultRedisSet instance. * * @param key - * @param commands + * @param operations */ - public DefaultRedisSet(String key, RedisCommands commands) { - super(key, commands); + public DefaultRedisSet(String key, RedisOperations operations) { + super(key, operations); + boundSetOps = operations.forSet(key); + } + + /** + * Constructs a new DefaultRedisSet instance. + * + * @param boundOps + */ + public DefaultRedisSet(BoundSetOperations boundOps) { + super(boundOps.getKey(), boundOps.getOperations()); + this.boundSetOps = boundOps; } @Override - public Set diff(RedisSet... sets) { - return commands.sDiff(extractKeys(sets)); + public Set diff(RedisSet... sets) { + return boundSetOps.diff(extractKeys(sets)); } @Override - public RedisSet diffAndStore(String destKey, RedisSet... sets) { - commands.sDiffStore(destKey, extractKeys(sets)); - return new DefaultRedisSet(destKey, commands); + public RedisSet diffAndStore(String destKey, RedisSet... sets) { + boundSetOps.diffAndStore(destKey, extractKeys(sets)); + return new DefaultRedisSet(boundSetOps.getOperations().forSet(destKey)); } @Override - public Set intersect(RedisSet... sets) { - return commands.sInter(extractKeys(sets)); + public Set intersect(RedisSet... sets) { + return boundSetOps.intersect(extractKeys(sets)); } @Override - public RedisSet intersectAndStore(String destKey, RedisSet... sets) { - commands.sInterStore(destKey, extractKeys(sets)); - return new DefaultRedisSet(destKey, commands); + public RedisSet intersectAndStore(String destKey, RedisSet... sets) { + boundSetOps.intersectAndStore(destKey, extractKeys(sets)); + return new DefaultRedisSet(boundSetOps.getOperations().forSet(destKey)); } @Override - public Set union(RedisSet... sets) { - return commands.sUnion(extractKeys(sets)); + public Set union(RedisSet... sets) { + return boundSetOps.union(extractKeys(sets)); } @Override - public RedisSet unionAndStore(String destKey, RedisSet... sets) { - commands.sUnionStore(destKey, extractKeys(sets)); - return new DefaultRedisSet(destKey, commands); + public RedisSet unionAndStore(String destKey, RedisSet... sets) { + boundSetOps.unionAndStore(destKey, extractKeys(sets)); + return new DefaultRedisSet(boundSetOps.getOperations().forSet(destKey)); } @Override - public boolean add(String e) { - return commands.sAdd(key, e); + public boolean add(E e) { + return boundSetOps.add(e); } @Override public void clear() { // intersect the set with a non existing one // TODO: find a safer way to clean the set - commands.sInterStore(key, key, "NON-EXISTING"); + boundSetOps.intersectAndStore(key, "NON-EXISTING"); } @Override public boolean contains(Object o) { - return commands.sIsMember(key, o.toString()); + return boundSetOps.isMember(o); } @Override - public Iterator iterator() { - return new DefaultRedisSetIterator(commands.sMembers(key).iterator()); + public Iterator iterator() { + return new DefaultRedisSetIterator(boundSetOps.members().iterator()); } @Override public boolean remove(Object o) { - return commands.sRem(key, o.toString()); + return boundSetOps.remove(o); } @Override public int size() { - return commands.sCard(key); + return boundSetOps.size(); } - private String[] extractKeys(RedisSet... sets) { + private String[] extractKeys(RedisSet... sets) { String[] keys = new String[sets.length + 1]; - keys[0] = key; for (int i = 0; i < keys.length; i++) { - keys[i + 1] = sets[i].getKey(); + keys[i] = sets[i].getKey(); } return keys; diff --git a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/util/DefaultRedisSortedSet.java b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/util/DefaultRedisSortedSet.java index 4343b8b1d..2f937f942 100644 --- a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/util/DefaultRedisSortedSet.java +++ b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/util/DefaultRedisSortedSet.java @@ -20,126 +20,142 @@ import java.util.Iterator; import java.util.Set; import java.util.SortedSet; -import org.springframework.datastore.redis.connection.RedisCommands; +import org.springframework.datastore.redis.core.BoundZSetOperations; +import org.springframework.datastore.redis.core.RedisOperations; /** * Default implementation for {@link RedisSortedSet}. * * @author Costin Leau */ -class DefaultRedisSortedSet extends AbstractRedisCollection implements RedisSortedSet { +class DefaultRedisSortedSet extends AbstractRedisCollection implements RedisSortedSet { - private class DefaultRedisSortedSetIterator extends RedisIterator { + private final BoundZSetOperations boundZSetOps; + + private class DefaultRedisSortedSetIterator extends RedisIterator { - public DefaultRedisSortedSetIterator(Iterator delegate) { + public DefaultRedisSortedSetIterator(Iterator delegate) { super(delegate); } @Override - protected void removeFromRedisStorage(String item) { + protected void removeFromRedisStorage(E item) { DefaultRedisSortedSet.this.remove(item); } } - public DefaultRedisSortedSet(String key, RedisCommands commands) { - super(key, commands); + /** + * Constructs a new DefaultRedisSortedSet instance. + * + * @param key + * @param operations + */ + public DefaultRedisSortedSet(String key, RedisOperations operations) { + super(key, operations); + boundZSetOps = operations.forZSet(key); + } + + + public DefaultRedisSortedSet(BoundZSetOperations boundOps) { + super(boundOps.getKey(), boundOps.getOperations()); + this.boundZSetOps = boundOps; } @Override - public RedisSortedSet intersectAndStore(String destKey, RedisSortedSet... sets) { - commands.zInterStore(destKey, extractKeys(sets)); - return new DefaultRedisSortedSet(destKey, commands); + public RedisSortedSet intersectAndStore(String destKey, RedisSortedSet... sets) { + boundZSetOps.intersectAndStore(destKey, extractKeys(sets)); + return new DefaultRedisSortedSet(boundZSetOps.getOperations().forZSet(destKey)); } @Override - public Set range(int start, int end) { - return commands.zRange(key, start, end); + public Set range(int start, int end) { + return boundZSetOps.range(start, end); } @Override - public Set rangeByScore(double min, double max) { - return commands.zRangeByScore(key, min, max); + public Set rangeByScore(double min, double max) { + return boundZSetOps.rangeByScore(min, max); } @Override - public RedisSortedSet remove(int start, int end) { - commands.zRemRange(key, start, end); + public RedisSortedSet remove(int start, int end) { + boundZSetOps.removeRange(start, end); return this; } @Override - public RedisSortedSet removeByScore(double min, double max) { - commands.zRemRangeByScore(key, min, max); + public RedisSortedSet removeByScore(double min, double max) { + boundZSetOps.removeRangeByScore(min, max); return this; } @Override - public RedisSortedSet unionAndStore(String destKey, RedisSortedSet... sets) { - commands.zUnionStore(destKey, extractKeys(sets)); - return new DefaultRedisSortedSet(destKey, commands); + public RedisSortedSet unionAndStore(String destKey, RedisSortedSet... sets) { + boundZSetOps.unionAndStore(destKey, extractKeys(sets)); + return new DefaultRedisSortedSet(boundZSetOps.getOperations().forZSet(destKey)); } @Override - public boolean add(String e) { - return commands.zAdd(key, 0, e); + public boolean add(E e) { + return boundZSetOps.add(e, 0); } @Override public void clear() { - commands.zRemRange(key, 0, -1); + boundZSetOps.removeRange(0, -1); } @Override public boolean contains(Object o) { - return (commands.zRank(key, o.toString()) != null); + return (boundZSetOps.rank(o) != null); } @Override - public Iterator iterator() { - return new DefaultRedisSortedSetIterator(commands.zRange(key, 0, -1).iterator()); + public Iterator iterator() { + return new DefaultRedisSortedSetIterator(boundZSetOps.range(0, -1).iterator()); } @Override public boolean remove(Object o) { - return commands.zRem(key, o.toString()); + return boundZSetOps.remove(o); } @Override public int size() { - return commands.zCard(key); + return boundZSetOps.size(); } @Override - public Comparator comparator() { + public Comparator comparator() { return null; } @Override - public String first() { - return commands.zRange(key, 0, 0).iterator().next(); + public E first() { + return boundZSetOps.range(0, 0).iterator().next(); } @Override - public SortedSet headSet(String toElement) { + public SortedSet headSet(E toElement) { throw new UnsupportedOperationException(); } @Override - public String last() { - return commands.zRevRange(key, 0, 0).iterator().next(); + public E last() { + return boundZSetOps.reverseRange(0, 0).iterator().next(); } @Override - public SortedSet subSet(String fromElement, String toElement) { + public SortedSet subSet(E fromElement, E toElement) { throw new UnsupportedOperationException(); } @Override - public SortedSet tailSet(String fromElement) { + public SortedSet tailSet(E fromElement) { throw new UnsupportedOperationException(); } - private String[] extractKeys(RedisSortedSet... sets) { + private String[] extractKeys(RedisSortedSet... sets) { String[] keys = new String[sets.length + 1]; keys[0] = key; for (int i = 0; i < keys.length; i++) { diff --git a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/util/RedisAtomicInteger.java b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/util/RedisAtomicInteger.java index 185ae4ea7..fc2153ebc 100644 --- a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/util/RedisAtomicInteger.java +++ b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/util/RedisAtomicInteger.java @@ -17,43 +17,41 @@ package org.springframework.datastore.redis.util; import java.io.Serializable; -import org.springframework.datastore.redis.connection.RedisCommands; +import org.springframework.datastore.redis.core.RedisOperations; /** * Atomic integer backed by Redis. - * Uses Redis atomic increment/decrement and watch/multi/exec commands for CAS operations. + * Uses Redis atomic increment/decrement and watch/multi/exec operations for CAS operations. * * @see java.util.concurrent.atomic.AtomicInteger * @author Costin Leau */ public class RedisAtomicInteger extends Number implements Serializable { - private static final long serialVersionUID = 5984507176128031015L; - private final String key; - private RedisCommands commands; + private RedisOperations operations; /** * Constructs a new RedisAtomicInteger instance with an initial value of zero. * * @param redisCounter - * @param commands + * @param operations */ - public RedisAtomicInteger(String redisCounter, RedisCommands commands) { - this(redisCounter, commands, 0); + public RedisAtomicInteger(String redisCounter, RedisOperations operations) { + this(redisCounter, operations, 0); } /** * Constructs a new RedisAtomicInteger instance with the given initial value. * * @param redisCounter - * @param commands + * @param operations * @param initialValue */ - public RedisAtomicInteger(String redisCounter, RedisCommands commands, int initialValue) { + public RedisAtomicInteger(String redisCounter, RedisOperations operations, int initialValue) { this.key = redisCounter; - this.commands = commands; - commands.set(redisCounter, Integer.toString(initialValue)); + this.operations = operations; + operations.set(redisCounter, initialValue); } /** @@ -62,7 +60,7 @@ public class RedisAtomicInteger extends Number implements Serializable { * @return the current value */ public int get() { - return Integer.valueOf(commands.get(key)); + return Integer.valueOf(operations.get(key)); } /** @@ -71,7 +69,7 @@ public class RedisAtomicInteger extends Number implements Serializable { * @param newValue the new value */ public void set(int newValue) { - commands.set(key, Integer.toString(newValue)); + operations.set(key, newValue); } /** @@ -81,7 +79,7 @@ public class RedisAtomicInteger extends Number implements Serializable { * @return the previous value */ public int getAndSet(int newValue) { - return Integer.valueOf(commands.getSet(key, Integer.toString(newValue))); + return operations.getAndSet(key, newValue); } /** @@ -94,11 +92,11 @@ public class RedisAtomicInteger extends Number implements Serializable { */ public boolean compareAndSet(int expect, int update) { for (;;) { - commands.watch(key); + operations.watch(key); if (expect == get()) { - commands.multi(); + operations.multi(); set(update); - if (commands.exec() != null) { + if (operations.exec() != null) { return true; } } @@ -112,11 +110,11 @@ public class RedisAtomicInteger extends Number implements Serializable { */ public int getAndIncrement() { for (;;) { - commands.watch(key); + operations.watch(key); int value = get(); - commands.multi(); - commands.incr(key); - if (commands.exec() != null) { + operations.multi(); + operations.increment(key, 1); + if (operations.exec() != null) { return value; } } @@ -129,11 +127,11 @@ public class RedisAtomicInteger extends Number implements Serializable { */ public int getAndDecrement() { for (;;) { - commands.watch(key); + operations.watch(key); int value = get(); - commands.multi(); - commands.decr(key); - if (commands.exec() != null) { + operations.multi(); + operations.increment(key, -1); + if (operations.exec() != null) { return value; } } @@ -147,11 +145,11 @@ public class RedisAtomicInteger extends Number implements Serializable { */ public int getAndAdd(int delta) { for (;;) { - commands.watch(key); + operations.watch(key); int value = get(); - commands.multi(); + operations.multi(); set(value + delta); - if (commands.exec() != null) { + if (operations.exec() != null) { return value; } } @@ -162,7 +160,7 @@ public class RedisAtomicInteger extends Number implements Serializable { * @return the updated value */ public int incrementAndGet() { - return commands.incr(key); + return operations.increment(key, 1); } /** @@ -170,7 +168,7 @@ public class RedisAtomicInteger extends Number implements Serializable { * @return the updated value */ public int decrementAndGet() { - return commands.decr(key); + return operations.increment(key, -1); } @@ -180,7 +178,7 @@ public class RedisAtomicInteger extends Number implements Serializable { * @return the updated value */ public int addAndGet(int delta) { - return commands.incrBy(key, delta); + return operations.increment(key, delta); } /** diff --git a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/util/RedisAtomicLong.java b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/util/RedisAtomicLong.java index 64775e673..8b736681b 100644 --- a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/util/RedisAtomicLong.java +++ b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/util/RedisAtomicLong.java @@ -17,11 +17,11 @@ package org.springframework.datastore.redis.util; import java.io.Serializable; -import org.springframework.datastore.redis.connection.RedisCommands; +import org.springframework.datastore.redis.core.RedisOperations; /** * Atomic long backed by Redis. - * Uses Redis atomic increment/decrement and watch/multi/exec commands for CAS operations. + * Uses Redis atomic increment/decrement and watch/multi/exec operations for CAS operations. * * @see java.util.concurrent.atomic.AtomicLong * @author Costin Leau @@ -29,29 +29,29 @@ import org.springframework.datastore.redis.connection.RedisCommands; public class RedisAtomicLong extends Number implements Serializable { private final String key; - private RedisCommands commands; + private RedisOperations operations; /** * Constructs a new RedisAtomicLong instance with an initial value of zero. * * @param redisCounter - * @param commands + * @param operations */ - public RedisAtomicLong(String redisCounter, RedisCommands commands) { - this(redisCounter, commands, 0); + public RedisAtomicLong(String redisCounter, RedisOperations operations) { + this(redisCounter, operations, 0); } /** * Constructs a new RedisAtomicLong instance with the given initial value. * * @param redisCounter - * @param commands + * @param operations * @param initialValue */ - public RedisAtomicLong(String redisCounter, RedisCommands commands, long initialValue) { + public RedisAtomicLong(String redisCounter, RedisOperations operations, long initialValue) { this.key = redisCounter; - this.commands = commands; - commands.set(redisCounter, Long.toString(initialValue)); + this.operations = operations; + operations.set(redisCounter, initialValue); } /** @@ -60,7 +60,7 @@ public class RedisAtomicLong extends Number implements Serializable { * @return the current value */ public long get() { - return Long.valueOf(commands.get(key)); + return operations.get(key); } /** @@ -69,7 +69,7 @@ public class RedisAtomicLong extends Number implements Serializable { * @param newValue the new value */ public void set(long newValue) { - commands.set(key, Long.toString(newValue)); + operations.set(key, newValue); } /** @@ -79,7 +79,7 @@ public class RedisAtomicLong extends Number implements Serializable { * @return the previous value */ public long getAndSet(long newValue) { - return Long.valueOf(commands.getSet(key, Long.toString(newValue))); + return operations.getAndSet(key, newValue); } /** @@ -93,11 +93,11 @@ public class RedisAtomicLong extends Number implements Serializable { */ public boolean compareAndSet(long expect, long update) { for (;;) { - commands.watch(key); + operations.watch(key); if (expect == get()) { - commands.multi(); + operations.multi(); set(update); - if (commands.exec() != null) { + if (operations.exec() != null) { return true; } } @@ -112,11 +112,11 @@ public class RedisAtomicLong extends Number implements Serializable { */ public long getAndIncrement() { for (;;) { - commands.watch(key); + operations.watch(key); long value = get(); - commands.multi(); - commands.incr(key); - if (commands.exec() != null) { + operations.multi(); + operations.increment(key, 1); + if (operations.exec() != null) { return value; } } @@ -129,11 +129,11 @@ public class RedisAtomicLong extends Number implements Serializable { */ public long getAndDecrement() { for (;;) { - commands.watch(key); + operations.watch(key); long value = get(); - commands.multi(); - commands.decr(key); - if (commands.exec() != null) { + operations.multi(); + operations.increment(key, -1); + if (operations.exec() != null) { return value; } } @@ -147,11 +147,11 @@ public class RedisAtomicLong extends Number implements Serializable { */ public long getAndAdd(long delta) { for (;;) { - commands.watch(key); + operations.watch(key); long value = get(); - commands.multi(); + operations.multi(); set(value + delta); - if (commands.exec() != null) { + if (operations.exec() != null) { return value; } } @@ -163,7 +163,7 @@ public class RedisAtomicLong extends Number implements Serializable { * @return the updated value */ public long incrementAndGet() { - return commands.incr(key); + return operations.increment(key, 1); } /** @@ -172,7 +172,7 @@ public class RedisAtomicLong extends Number implements Serializable { * @return the updated value */ public long decrementAndGet() { - return commands.decr(key); + return operations.increment(key, -1); } /** @@ -183,11 +183,12 @@ public class RedisAtomicLong extends Number implements Serializable { */ public long addAndGet(long delta) { // TODO: is this really safe - return commands.incrBy(key, (int) delta); + return operations.increment(key, (int) delta); } /** * Returns the String representation of the current value. + * * @return the String representation of the current value. */ public String toString() { diff --git a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/util/RedisIterator.java b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/util/RedisIterator.java index ae22f2e28..a65a4fa8c 100644 --- a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/util/RedisIterator.java +++ b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/util/RedisIterator.java @@ -22,18 +22,18 @@ import java.util.Iterator; * * @author Costin Leau */ -abstract class RedisIterator implements Iterator { +abstract class RedisIterator implements Iterator { - private final Iterator delegate; + private final Iterator delegate; - private String item; + private E item; /** * Constructs a new RedisIterator instance. * * @param delegate */ - RedisIterator(Iterator delegate) { + RedisIterator(Iterator delegate) { this.delegate = delegate; } @@ -49,7 +49,7 @@ abstract class RedisIterator implements Iterator { * @return * @see java.util.Iterator#next() */ - public String next() { + public E next() { item = delegate.next(); return item; } @@ -64,5 +64,5 @@ abstract class RedisIterator implements Iterator { item = null; } - protected abstract void removeFromRedisStorage(String item); + protected abstract void removeFromRedisStorage(E item); } \ No newline at end of file diff --git a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/util/RedisList.java b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/util/RedisList.java index 82baa0f89..c49ec8ad2 100644 --- a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/util/RedisList.java +++ b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/util/RedisList.java @@ -20,13 +20,13 @@ import java.util.Queue; /** * Redis extension for the {@link List} contract. Supports {@link List} specific - * operations backed by Redis commands. + * operations backed by Redis operations. * * @author Costin Leau */ -public interface RedisList extends RedisStore, List, Queue { +public interface RedisList extends RedisStore, List, Queue { - List range(int start, int end); + List range(int start, int end); - RedisList trim(int start, int end); + RedisList trim(int start, int end); } diff --git a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/util/RedisMap.java b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/util/RedisMap.java index 8ad2956aa..48d70a9e5 100644 --- a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/util/RedisMap.java +++ b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/util/RedisMap.java @@ -22,9 +22,9 @@ import java.util.Map; * * @author Costin Leau */ -public interface RedisMap extends RedisStore, Map { +public interface RedisMap extends RedisStore, Map { - boolean putIfAbsent(String key, String value); - - Integer increment(String key, int delta); + boolean putIfAbsent(K key, V value); + + Integer increment(K key, int delta); } diff --git a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/util/RedisSet.java b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/util/RedisSet.java index a3e32202d..76ecf3fa4 100644 --- a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/util/RedisSet.java +++ b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/util/RedisSet.java @@ -1,39 +1,39 @@ -/* - * Copyright 2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES 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.springframework.datastore.redis.util; - -import java.util.Set; - -/** - * Redis extension for the {@link Set} contract. Supports {@link Set} specific - * operations backed by Redis commands. - * - * @author Costin Leau - */ -public interface RedisSet extends RedisStore, Set { - - Set intersect(RedisSet... sets); - - Set union(RedisSet... sets); - - Set diff(RedisSet... sets); - - RedisSet intersectAndStore(String destKey, RedisSet... sets); - - RedisSet unionAndStore(String destKey, RedisSet... sets); - - RedisSet diffAndStore(String destKey, RedisSet... sets); -} +/* + * Copyright 2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.springframework.datastore.redis.util; + +import java.util.Set; + +/** + * Redis extension for the {@link Set} contract. Supports {@link Set} specific + * operations backed by Redis operations. + * + * @author Costin Leau + */ +public interface RedisSet extends RedisStore, Set { + + Set intersect(RedisSet... sets); + + Set union(RedisSet... sets); + + Set diff(RedisSet... sets); + + RedisSet intersectAndStore(String destKey, RedisSet... sets); + + RedisSet unionAndStore(String destKey, RedisSet... sets); + + RedisSet diffAndStore(String destKey, RedisSet... sets); +} diff --git a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/util/RedisSortedSet.java b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/util/RedisSortedSet.java index b38baebd2..480f3f4a5 100644 --- a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/util/RedisSortedSet.java +++ b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/util/RedisSortedSet.java @@ -20,21 +20,21 @@ import java.util.SortedSet; /** * Redis extension for the {@link SortedSet} contract. Supports {@link SortedSet} specific - * operations backed by Redis commands. + * operations backed by Redis operations. * * @author Costin Leau */ -public interface RedisSortedSet extends RedisStore, SortedSet { +public interface RedisSortedSet extends RedisStore, SortedSet { - RedisSortedSet intersectAndStore(String destKey, RedisSortedSet... sets); + RedisSortedSet intersectAndStore(String destKey, RedisSortedSet... sets); - RedisSortedSet unionAndStore(String destKey, RedisSortedSet... sets); + RedisSortedSet unionAndStore(String destKey, RedisSortedSet... sets); - Set range(int start, int end); + Set range(int start, int end); - Set rangeByScore(double min, double max); + Set rangeByScore(double min, double max); - RedisSortedSet remove(int start, int end); + RedisSortedSet remove(int start, int end); - RedisSortedSet removeByScore(double min, double max); + RedisSortedSet removeByScore(double min, double max); } diff --git a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/util/RedisStore.java b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/util/RedisStore.java index 1d0a64492..384b31e74 100644 --- a/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/util/RedisStore.java +++ b/spring-datastore-redis/src/main/java/org/springframework/datastore/redis/util/RedisStore.java @@ -15,18 +15,27 @@ */ package org.springframework.datastore.redis.util; +import org.springframework.datastore.redis.core.RedisOperations; + /** * Basic interface for Redis-based collections. * * @author Costin Leau */ -public interface RedisStore { +public interface RedisStore { /** * Returns the key used by the backing Redis store for this collection. * * @return Redis key */ - String getKey(); + K getKey(); + + /** + * Returns the underlying Redis operations used by the backing implementation. + * + * @return operations + */ + RedisOperations getOperations(); } diff --git a/spring-datastore-redis/src/test/java/org/springframework/datastore/redis/Address.java b/spring-datastore-redis/src/test/java/org/springframework/datastore/redis/Address.java new file mode 100644 index 000000000..81bbd685a --- /dev/null +++ b/spring-datastore-redis/src/test/java/org/springframework/datastore/redis/Address.java @@ -0,0 +1,77 @@ +/* + * Copyright 2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.springframework.datastore.redis; + +import java.io.Serializable; + +/** + * Simple serializable class. + * + * @author Costin Leau + */ +public class Address implements Serializable { + + private static final long serialVersionUID = 4924045450477798779L; + + private String street; + + private Integer number; + + /** + * Constructs a new Address instance. + * + * @param street + * @param number + */ + public Address(String street, int number) { + super(); + this.street = street; + this.number = number; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((number == null) ? 0 : number.hashCode()); + result = prime * result + ((street == null) ? 0 : street.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (!(obj instanceof Address)) + return false; + Address other = (Address) obj; + if (number == null) { + if (other.number != null) + return false; + } + else if (!number.equals(other.number)) + return false; + if (street == null) { + if (other.street != null) + return false; + } + else if (!street.equals(other.street)) + return false; + return true; + } +} \ No newline at end of file diff --git a/spring-datastore-redis/src/test/java/org/springframework/datastore/redis/core/Person.java b/spring-datastore-redis/src/test/java/org/springframework/datastore/redis/Person.java similarity index 58% rename from spring-datastore-redis/src/test/java/org/springframework/datastore/redis/core/Person.java rename to spring-datastore-redis/src/test/java/org/springframework/datastore/redis/Person.java index 48396bc17..c071ff183 100644 --- a/spring-datastore-redis/src/test/java/org/springframework/datastore/redis/core/Person.java +++ b/spring-datastore-redis/src/test/java/org/springframework/datastore/redis/Person.java @@ -13,17 +13,40 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.datastore.redis.core; +package org.springframework.datastore.redis; import java.io.Serializable; +/** + * Simple serializable class. + * + * @author Mark Pollack + * @author Costin Leau + */ public class Person implements Serializable { + private static final long serialVersionUID = 92633004015631981L; + private String firstName; - private String lastName; - - private int age; + + private Integer age; + private Address address; + + public Person() { + } + + public Person(String firstName, String lastName, int age) { + this(firstName, lastName, age, null); + } + + public Person(String firstName, String lastName, int age, Address address) { + super(); + this.firstName = firstName; + this.lastName = lastName; + this.age = age; + this.address = address; + } public String getFirstName() { return firstName; @@ -49,22 +72,22 @@ public class Person implements Serializable { this.age = age; } - public Person(String firstName, String lastName, int age) { - super(); - this.firstName = firstName; - this.lastName = lastName; - this.age = age; + public Address getAddress() { + return address; + } + + public void setAddress(Address address) { + this.address = address; } @Override public int hashCode() { final int prime = 31; int result = 1; - result = prime * result + age; - result = prime * result - + ((firstName == null) ? 0 : firstName.hashCode()); - result = prime * result - + ((lastName == null) ? 0 : lastName.hashCode()); + result = prime * result + ((address == null) ? 0 : address.hashCode()); + result = prime * result + ((age == null) ? 0 : age.hashCode()); + result = prime * result + ((firstName == null) ? 0 : firstName.hashCode()); + result = prime * result + ((lastName == null) ? 0 : lastName.hashCode()); return result; } @@ -74,22 +97,33 @@ public class Person implements Serializable { return true; if (obj == null) return false; - if (getClass() != obj.getClass()) + if (!(obj instanceof Person)) return false; Person other = (Person) obj; - if (age != other.age) + if (address == null) { + if (other.address != null) + return false; + } + else if (!address.equals(other.address)) + return false; + if (age == null) { + if (other.age != null) + return false; + } + else if (!age.equals(other.age)) return false; if (firstName == null) { if (other.firstName != null) return false; - } else if (!firstName.equals(other.firstName)) + } + else if (!firstName.equals(other.firstName)) return false; if (lastName == null) { if (other.lastName != null) return false; - } else if (!lastName.equals(other.lastName)) + } + else if (!lastName.equals(other.lastName)) return false; return true; } - -} +} \ No newline at end of file diff --git a/spring-datastore-redis/src/test/java/org/springframework/datastore/redis/connection/AbstractConnectionIntegrationTests.java b/spring-datastore-redis/src/test/java/org/springframework/datastore/redis/connection/AbstractConnectionIntegrationTests.java index f42513c35..2410a0cd6 100644 --- a/spring-datastore-redis/src/test/java/org/springframework/datastore/redis/connection/AbstractConnectionIntegrationTests.java +++ b/spring-datastore-redis/src/test/java/org/springframework/datastore/redis/connection/AbstractConnectionIntegrationTests.java @@ -16,15 +16,13 @@ package org.springframework.datastore.redis.connection; -import static org.junit.Assert.assertEquals; -import junit.framework.Assert; +import static org.junit.Assert.*; +import static org.junit.Assume.*; import org.junit.After; import org.junit.Before; import org.junit.Test; -import org.springframework.datastore.redis.connection.RedisConnection; -import org.springframework.datastore.redis.connection.RedisConnectionFactory; -import org.springframework.datastore.redis.core.Person; +import org.springframework.datastore.redis.Person; public abstract class AbstractConnectionIntegrationTests { @@ -46,20 +44,24 @@ public abstract class AbstractConnectionIntegrationTests { @Test public void testLPush() throws Exception { - Integer index = connection.lPush(listName, "bar"); + Integer index = connection.lPush(listName.getBytes(), "bar".getBytes()); if (index != null) { - assertEquals((Integer) (index + 1), connection.lPush(listName, "bar")); + assertEquals((Integer) (index + 1), connection.lPush(listName.getBytes(), "bar".getBytes())); } } @Test public void testSetAndGet() { - connection.set("foo", "blah blah"); - String value = connection.get("foo"); - Assert.assertEquals("blah blah", value); + assumeTrue(!isJredis()); + connection.set("foo".getBytes(), "blahblah".getBytes()); + assertEquals("blahblah", new String(connection.get("foo".getBytes()))); } + private boolean isJredis() { + return connection.getClass().getSimpleName().startsWith("Jredis"); + } + public void conversions() { Person p = new Person("Joe", "Trader", 33); } diff --git a/spring-datastore-redis/src/test/java/org/springframework/datastore/redis/core/RedisTemplateIntegrationTests.java b/spring-datastore-redis/src/test/java/org/springframework/datastore/redis/core/RedisTemplateIntegrationTests.java index b569ed59e..a3c9ce377 100644 --- a/spring-datastore-redis/src/test/java/org/springframework/datastore/redis/core/RedisTemplateIntegrationTests.java +++ b/spring-datastore-redis/src/test/java/org/springframework/datastore/redis/core/RedisTemplateIntegrationTests.java @@ -18,6 +18,7 @@ package org.springframework.datastore.redis.core; import org.junit.Before; import org.junit.Test; +import org.springframework.datastore.redis.Person; public class RedisTemplateIntegrationTests { diff --git a/spring-datastore-redis/src/test/java/org/springframework/datastore/redis/serializer/SimpleRedisSerializerTests.java b/spring-datastore-redis/src/test/java/org/springframework/datastore/redis/serializer/SimpleRedisSerializerTests.java new file mode 100644 index 000000000..cbe1f2538 --- /dev/null +++ b/spring-datastore-redis/src/test/java/org/springframework/datastore/redis/serializer/SimpleRedisSerializerTests.java @@ -0,0 +1,140 @@ +/* + * Copyright 2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.springframework.datastore.redis.serializer; + +import static org.junit.Assert.*; + +import java.io.Serializable; +import java.util.UUID; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.springframework.datastore.redis.Address; +import org.springframework.datastore.redis.Person; + + +public class SimpleRedisSerializerTests { + + private static class A implements Serializable { + private Integer value = Integer.valueOf(30); + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((value == null) ? 0 : value.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + A other = (A) obj; + if (value == null) { + if (other.value != null) + return false; + } + else if (!value.equals(other.value)) + return false; + return true; + } + } + + private static class B implements Serializable { + private String name = getClass().getName(); + private A a = new A(); + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((a == null) ? 0 : a.hashCode()); + result = prime * result + ((name == null) ? 0 : name.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + B other = (B) obj; + if (a == null) { + if (other.a != null) + return false; + } + else if (!a.equals(other.a)) + return false; + if (name == null) { + if (other.name != null) + return false; + } + else if (!name.equals(other.name)) + return false; + return true; + } + } + + private RedisSerializer serializer; + + @Before + public void setUp() { + serializer = new SimpleRedisSerializer(); + } + + @After + public void tearDown() { + serializer = null; + } + + @Test + public void testBasicSerializationRoundtrip() throws Exception { + Integer integer = new Integer(300); + verifySerializedObjects(new Integer(300), new Double(200), new B()); + } + + private void verifySerializedObjects(Object... objects) { + for (Object object : objects) { + assertEquals("Incorrectly (de)serialized object " + object, object, + serializer.deserialize(serializer.serialize(object))); + } + } + + @Test + public void testStringEncodedSerialization() { + String value = UUID.randomUUID().toString(); + assertEquals(value, serializer.deserialize(serializer.serialize(value))); + assertEquals(value, serializer.deserialize(serializer.serialize(value))); + assertEquals(value, serializer.deserialize(serializer.serialize(value))); + } + + @Test + public void testPersonSerialization() throws Exception { + String value = UUID.randomUUID().toString(); + Person p1 = new Person(value, value, 1, new Address(value, 2)); + assertEquals(p1, serializer.deserialize(serializer.serialize(p1))); + assertEquals(p1, serializer.deserialize(serializer.serialize(p1))); + } +} \ No newline at end of file diff --git a/spring-datastore-redis/src/test/java/org/springframework/datastore/redis/util/AbstractRedisCollectionTests.java b/spring-datastore-redis/src/test/java/org/springframework/datastore/redis/util/AbstractRedisCollectionTests.java new file mode 100644 index 000000000..1365996f2 --- /dev/null +++ b/spring-datastore-redis/src/test/java/org/springframework/datastore/redis/util/AbstractRedisCollectionTests.java @@ -0,0 +1,265 @@ +/* + * Copyright 2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.springframework.datastore.redis.util; + + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.not; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; +import static org.junit.matchers.JUnitMatchers.hasItem; +import static org.junit.matchers.JUnitMatchers.hasItems; + +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + + +/** + * Base test for Redis collections. + * + * @author Costin Leau + */ +public abstract class AbstractRedisCollectionTests { + + protected AbstractRedisCollection collection; + + @Before + public void setUp() throws Exception { + collection = createCollection(); + } + + abstract AbstractRedisCollection createCollection(); + + abstract void destroyCollection(); + + abstract RedisStore copyStore(RedisStore store); + + + /** + * Return a new instance of T + * @return + */ + abstract T getT(); + + @After + public void tearDown() throws Exception { + // remove the collection entirely since clear() doesn't always work + collection.getOperations().delete(collection.getKey()); + destroyCollection(); + } + + @Test + public void testAdd() { + T t1 = getT(); + assertThat(collection.add(t1), is(true)); + assertThat(collection, hasItem(t1)); + assertEquals(1, collection.size()); + } + + @SuppressWarnings("unchecked") + @Test + public void testAddAll() { + T t1 = getT(); + T t2 = getT(); + T t3 = getT(); + + List list = Arrays.asList(t1, t2, t3); + + assertThat(collection.addAll(list), is(true)); + assertThat(collection, hasItem(t1)); + assertThat(collection, hasItem(t2)); + assertThat(collection, hasItem(t3)); + assertEquals(collection.size(), 3); + } + + @Test + public void testClear() { + T t1 = getT(); + assertEquals(0, collection.size()); + collection.add(t1); + assertEquals(1, collection.size()); + collection.clear(); + assertEquals(0, collection.size()); + } + + @Test + public void containsObject() { + T t1 = getT(); + assertThat(collection, not(hasItem(t1))); + assertThat(collection.add(t1), is(true)); + assertThat(collection, hasItem(t1)); + } + + @SuppressWarnings("unchecked") + @Test + public void containsAll() { + T t1 = getT(); + T t2 = getT(); + T t3 = getT(); + + List list = Arrays.asList(t1, t2, t3); + + assertThat(collection.addAll(list), is(true)); + assertThat(collection.containsAll(list), is(true)); + assertThat(collection, hasItems(t1, t2, t3)); + } + + @Test + public void testEquals() { + //assertEquals(collection, copyStore(collection)); + } + + @Test + public void testHashCode() { + assertThat(collection.hashCode(), not(equalTo(collection.getKey().hashCode()))); + } + + @Test + public void testIsEmpty() { + assertEquals(0, collection.size()); + assertTrue(collection.isEmpty()); + collection.add(getT()); + assertEquals(1, collection.size()); + assertFalse(collection.isEmpty()); + collection.clear(); + assertTrue(collection.isEmpty()); + } + + @Test + public void testIterator() { + T t1 = getT(); + T t2 = getT(); + T t3 = getT(); + + List list = Arrays.asList(t1, t2, t3); + + assertThat(collection.addAll(list), is(true)); + Iterator iterator = collection.iterator(); + + assertEquals(t1, iterator.next()); + assertEquals(t2, iterator.next()); + assertEquals(t3, iterator.next()); + assertFalse(iterator.hasNext()); + } + + @Test + public void testRemoveObject() { + T t1 = getT(); + T t2 = getT(); + T t3 = getT(); + + assertEquals(0, collection.size()); + assertThat(collection.add(t1), is(true)); + assertThat(collection.add(t2), is(true)); + assertEquals(2, collection.size()); + assertThat(collection.remove(t3), is(false)); + assertThat(collection.remove(t2), is(true)); + assertThat(collection.remove(t2), is(false)); + assertEquals(1, collection.size()); + assertThat(collection.remove(t1), is(true)); + assertEquals(0, collection.size()); + } + + @Test + public void removeAll() { + T t1 = getT(); + T t2 = getT(); + T t3 = getT(); + + List list = Arrays.asList(t1, t2, t3); + + assertThat(collection.addAll(list), is(true)); + assertThat(collection.containsAll(list), is(true)); + assertThat(collection, hasItems(t1, t2, t3)); + + List newList = Arrays.asList(getT(), getT()); + List partialList = Arrays.asList(getT(), t1, getT()); + + assertThat(collection.removeAll(newList), is(false)); + assertThat(collection.removeAll(partialList), is(true)); + assertThat(collection, not(hasItem(t1))); + assertThat(collection, hasItems(t2, t3)); + assertThat(collection.removeAll(list), is(true)); + assertThat(collection, not(hasItems(t2, t3))); + } + + @Test(expected = UnsupportedOperationException.class) + public void testRetainAll() { + T t1 = getT(); + T t2 = getT(); + T t3 = getT(); + + List list = Arrays.asList(t1, t2); + List newList = Arrays.asList(t2, t3); + + assertThat(collection.addAll(list), is(true)); + assertThat(collection, hasItems(t1, t2)); + assertThat(collection.retainAll(newList), is(true)); + assertThat(collection, not(hasItem(t1))); + assertThat(collection, hasItem(t2)); + } + + @Test + public void testSize() { + assertEquals(0, collection.size()); + assertTrue(collection.isEmpty()); + collection.add(getT()); + assertEquals(1, collection.size()); + collection.add(getT()); + collection.add(getT()); + assertEquals(3, collection.size()); + } + + @SuppressWarnings("unchecked") + @Test + public void testToArray() { + Object[] expectedArray = new Object[] { getT(), getT(), getT() }; + List list = (List) Arrays.asList(expectedArray); + + assertThat(collection.addAll(list), is(true)); + + Object[] array = collection.toArray(); + assertArrayEquals(expectedArray, array); + } + + @SuppressWarnings("unchecked") + @Test + public void testToArrayWithGenerics() { + Object[] expectedArray = new Object[] { getT(), getT(), getT() }; + List list = (List) Arrays.asList(expectedArray); + + assertThat(collection.addAll(list), is(true)); + + Object[] array = collection.toArray(new Object[expectedArray.length]); + assertArrayEquals(expectedArray, array); + } + + @Test + public void testToString() { + String name = collection.toString(); + collection.add(getT()); + assertEquals(name, collection.toString()); + } +} \ No newline at end of file diff --git a/spring-datastore-redis/src/test/java/org/springframework/datastore/redis/util/AbstractRedisListTests.java b/spring-datastore-redis/src/test/java/org/springframework/datastore/redis/util/AbstractRedisListTests.java new file mode 100644 index 000000000..9f4f135ac --- /dev/null +++ b/spring-datastore-redis/src/test/java/org/springframework/datastore/redis/util/AbstractRedisListTests.java @@ -0,0 +1,260 @@ +/* + * Copyright 2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.springframework.datastore.redis.util; + +import static org.junit.Assert.*; + +import java.util.Arrays; +import java.util.List; +import java.util.NoSuchElementException; + +import org.junit.Before; +import org.junit.Test; + +/** + * Integration test for RedisList + * + * @author Costin Leau + */ +public abstract class AbstractRedisListTests extends AbstractRedisCollectionTests { + + protected RedisList list; + + @SuppressWarnings("unchecked") + @Before + public void setUp() throws Exception { + super.setUp(); + list = (RedisList) collection; + } + + @Test + public void testAddIndexObjectHead() { + T t1 = getT(); + T t2 = getT(); + T t3 = getT(); + + list.add(t1); + list.add(t2); + + assertEquals(t1, list.get(0)); + list.add(0, t3); + assertEquals(t3, list.get(0)); + } + + @Test + public void testAddIndexObjectTail() { + T t1 = getT(); + T t2 = getT(); + T t3 = getT(); + + list.add(t1); + list.add(t2); + + assertEquals(t2, list.get(1)); + list.add(2, t3); + assertEquals(t3, list.get(2)); + } + + @Test(expected = IllegalArgumentException.class) + public void testAddIndexObjectMiddle() { + T t1 = getT(); + T t2 = getT(); + T t3 = getT(); + + list.add(t1); + list.add(t2); + + assertEquals(t1, list.get(0)); + list.add(1, t3); + } + + @Test + public void addAllIndexCollectionHead() { + T t1 = getT(); + T t2 = getT(); + T t3 = getT(); + T t4 = getT(); + + list.add(t1); + list.add(t2); + + List asList = Arrays.asList(t3, t4); + + assertEquals(t1, list.get(0)); + list.addAll(0, asList); + // verify insertion order + assertEquals(t3, list.get(0)); + assertEquals(t4, list.get(1)); + } + + @Test + public void addAllIndexCollectionTail() { + T t1 = getT(); + T t2 = getT(); + T t3 = getT(); + T t4 = getT(); + + list.add(t1); + list.add(t2); + + List asList = Arrays.asList(t3, t4); + + assertEquals(t1, list.get(0)); + assertTrue(list.addAll(2, asList)); + + // verify insertion order + assertEquals(t3, list.get(2)); + assertEquals(t4, list.get(3)); + } + + @Test(expected = IllegalArgumentException.class) + public void addAllIndexCollectionMiddle() { + T t1 = getT(); + T t2 = getT(); + T t3 = getT(); + T t4 = getT(); + + list.add(t1); + list.add(t2); + + List asList = Arrays.asList(t3, t4); + + assertEquals(t1, list.get(0)); + assertTrue(list.addAll(1, asList)); + } + + @Test(expected = UnsupportedOperationException.class) + public void testIndexOfObject() { + T t1 = getT(); + T t2 = getT(); + + assertEquals(-1, list.indexOf(t1)); + list.add(t1); + assertEquals(0, list.indexOf(t1)); + + assertEquals(-1, list.indexOf(t2)); + list.add(t2); + assertEquals(1, list.indexOf(t1)); + } + + @Test + public void testOffer() { + T t1 = getT(); + + assertTrue(list.offer(t1)); + assertTrue(list.contains(t1)); + } + + @Test + public void testPeek() { + assertNull(list.peek()); + T t1 = getT(); + list.add(t1); + assertEquals(t1, list.peek()); + list.clear(); + assertNull(list.peek()); + } + + @Test + public void testElement() { + try { + list.element(); + fail(); + } catch (NoSuchElementException nse) { + // expected + } + + T t1 = getT(); + list.add(t1); + assertEquals(t1, list.element()); + list.clear(); + try { + list.element(); + fail(); + } catch (NoSuchElementException nse) { + // expected + } + } + + @Test + public void testPoll() { + assertNull(list.poll()); + T t1 = getT(); + list.add(t1); + assertEquals(t1, list.poll()); + assertNull(list.poll()); + } + + @Test + public void testRemove() { + try { + list.remove(); + fail(); + } catch (NoSuchElementException nse) { + // expected + } + + T t1 = getT(); + list.add(t1); + assertEquals(t1, list.remove()); + try { + list.remove(); + fail(); + } catch (NoSuchElementException nse) { + // expected + } + } + + @Test + public void testRange() { + T t1 = getT(); + T t2 = getT(); + + assertTrue(list.range(0, -1).isEmpty()); + list.add(t1); + list.add(t2); + assertEquals(2, list.range(0, -1).size()); + assertEquals(t1, list.range(0, 0).get(0)); + assertEquals(t2, list.range(1, 1).get(0)); + } + + @Test(expected = UnsupportedOperationException.class) + public void testRemoveIndex() { + T t1 = getT(); + T t2 = getT(); + + assertNull(list.remove(0)); + list.add(t1); + list.add(t2); + assertNull(list.remove(2)); + assertEquals(t2, list.remove(1)); + assertEquals(t1, list.remove(0)); + } + + @Test + public void testTrim() { + T t1 = getT(); + T t2 = getT(); + + assertTrue(list.trim(0, 0).isEmpty()); + list.add(t1); + list.add(t2); + assertEquals(2, list.size()); + assertEquals(1, list.trim(0, 0).size()); + assertEquals(1, list.size()); + assertEquals(t1, list.get(0)); + } +} \ No newline at end of file diff --git a/spring-datastore-redis/src/test/java/org/springframework/datastore/redis/util/PersonRedisListTests.java b/spring-datastore-redis/src/test/java/org/springframework/datastore/redis/util/PersonRedisListTests.java new file mode 100644 index 000000000..4feeffdb5 --- /dev/null +++ b/spring-datastore-redis/src/test/java/org/springframework/datastore/redis/util/PersonRedisListTests.java @@ -0,0 +1,64 @@ +/* + * Copyright 2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.springframework.datastore.redis.util; + +import java.util.UUID; + +import org.springframework.datastore.redis.Address; +import org.springframework.datastore.redis.Person; +import org.springframework.datastore.redis.connection.jedis.JedisConnectionFactory; +import org.springframework.datastore.redis.core.RedisTemplate; + + +/** + * Person-based Redis List test. + * + * @author Costin Leau + */ +public class PersonRedisListTests extends AbstractRedisListTests { + + private JedisConnectionFactory factory; + private int counter = 0; + + @Override + AbstractRedisCollection createCollection() { + String redisName = getClass().getName(); + factory = new JedisConnectionFactory(); + factory.setPooling(false); + factory.afterPropertiesSet(); + + RedisTemplate template = new RedisTemplate(factory); + return new DefaultRedisList(redisName, template); + } + + @Override + void destroyCollection() { + factory.destroy(); + } + + @Override + RedisStore copyStore(RedisStore store) { + //return new DefaultRedisList(store.getKey(), (RedisOperations) store.getOperations()); + return null; + } + + @Override + Person getT() { + String uuid = UUID.randomUUID().toString(); + return new Person(uuid, uuid, ++counter, new Address(uuid, counter)); + } +} + diff --git a/spring-datastore-redis/src/test/java/org/springframework/datastore/redis/util/StringRedisListTests.java b/spring-datastore-redis/src/test/java/org/springframework/datastore/redis/util/StringRedisListTests.java new file mode 100644 index 000000000..b0a907c41 --- /dev/null +++ b/spring-datastore-redis/src/test/java/org/springframework/datastore/redis/util/StringRedisListTests.java @@ -0,0 +1,60 @@ +/* + * Copyright 2010 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES 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.springframework.datastore.redis.util; + +import java.util.UUID; + +import org.springframework.datastore.redis.connection.jedis.JedisConnectionFactory; +import org.springframework.datastore.redis.core.RedisOperations; +import org.springframework.datastore.redis.core.RedisTemplate; + + +/** + * String-based Redis List test. + * + * @author Costin Leau + */ +public class StringRedisListTests extends AbstractRedisListTests { + + private JedisConnectionFactory factory; + + @Override + AbstractRedisCollection createCollection() { + String redisName = getClass().getName(); + factory = new JedisConnectionFactory(); + factory.setPooling(false); + factory.afterPropertiesSet(); + + RedisTemplate template = new RedisTemplate(factory); + return new DefaultRedisList(redisName, template); + } + + @Override + void destroyCollection() { + factory.destroy(); + } + + @Override + RedisStore copyStore(RedisStore store) { + return new DefaultRedisList(store.getKey(), (RedisOperations) store.getOperations()); + } + + @Override + String getT() { + return UUID.randomUUID().toString(); + } +} +