migrating old spring-keyvalue-redis repository

This commit is contained in:
Mark Pollack
2010-10-07 16:54:43 -04:00
parent c58fcc2244
commit b1387fadac
41 changed files with 3385 additions and 3 deletions

View File

@@ -88,7 +88,7 @@
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>1.0.0-RC3</version>
<version>1.1.1</version>
<scope>compile</scope>
</dependency>
@@ -98,6 +98,13 @@
<version>a.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.commons</groupId>
<artifactId>spring-commons-serializer</artifactId>
<version>1.0.0.BUILD-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>

View File

@@ -0,0 +1,37 @@
/*
* Copyright 2002-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 org.springframework.dao.DataAccessResourceFailureException;
/**
* Fatal exception thrown when we can't connect to Redis.
* @author Mark Pollack
*
*/
public class CannotGetRedisConnectionException extends
DataAccessResourceFailureException {
public CannotGetRedisConnectionException(String msg) {
super(msg);
}
public CannotGetRedisConnectionException(String msg, Throwable cause) {
super(msg, cause);
}
}

View File

@@ -0,0 +1,66 @@
/*
* Copyright 2002-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.io.UnsupportedEncodingException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.dao.InvalidDataAccessApiUsageException;
/**
* Common base class for RedisClient implementations
* @author Mark Pollack
*
*/
public abstract class AbstractRedisClient implements RedisClient {
protected final Log logger = LogFactory.getLog(this.getClass());
public static final String DEFAULT_CHARSET = "UTF-8";
private volatile String defaultCharset = DEFAULT_CHARSET;
/**
* Specify the default charset to use when converting to or from text-based
* Message body content. If not specified, the charset will be "UTF-8".
*/
public void setDefaultCharset(String defaultCharset) {
this.defaultCharset = (defaultCharset != null) ? defaultCharset : DEFAULT_CHARSET;
}
public String getDefaultCharset() {
return defaultCharset;
}
protected byte[] stringToByte(String string) throws InvalidDataAccessApiUsageException {
try {
return string.getBytes(this.defaultCharset);
} catch (UnsupportedEncodingException e) {
throw new InvalidDataAccessApiUsageException(defaultCharset
+ " encoding not supported.", e);
}
}
protected String byteToString(byte[] value) throws InvalidDataAccessApiUsageException {
try {
return new String(value, defaultCharset);
} catch (UnsupportedEncodingException e) {
throw new InvalidDataAccessApiUsageException(defaultCharset
+ " encoding not supported.", e);
}
}
}

View File

@@ -0,0 +1,102 @@
/*
* Copyright 2002-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.net.InetAddress;
import java.net.UnknownHostException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.datastore.redis.support.RedisPersistenceExceptionTranslator;
/**
* Common base class for RedisClientFactories
* @author Mark Pollack
*
*/
public abstract class AbstractRedisClientFactory implements RedisClientFactory {
protected final Log logger = LogFactory.getLog(getClass());
private String hostName;
private int port;
private String password;
public int getPort() {
return port;
}
protected void setPort(int port) {
this.port = port;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getHostName() {
return hostName;
}
protected void setHostName(String hostName) {
this.hostName = hostName;
}
public RedisClient createClient() {
return doGetClient();
}
public abstract RedisClient doGetClient();
public abstract RedisPersistenceExceptionTranslator getExceptionTranslator();
protected String getDefaultHostName() {
String temp;
try {
InetAddress localMachine = InetAddress.getLocalHost();
temp = localMachine.getHostName();
logger.debug("Using hostname [" + temp + "] for hostname.");
}
catch (UnknownHostException e) {
logger.warn("Could not get host name, using 'localhost' as default value", e);
temp = "localhost";
}
return temp;
}
/*
public void closeClient() {
if (logger.isDebugEnabled()) {
logger.debug("Closing Redis Client: " + this.client);
}
try {
client.close();
}
catch (Throwable ex) {
logger.debug("Could not close Redis Client", ex);
}
}*/
}

View File

@@ -0,0 +1,42 @@
/*
* Copyright 2002-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.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class DefaultServerOperations implements ServerOperations {
protected final Log logger = LogFactory.getLog(getClass());
private RedisOperations redisOperations;
public DefaultServerOperations(RedisOperations redisOperations) {
this.redisOperations = redisOperations;
}
public Map<String, String> getServerInfo() {
return redisOperations.execute(new RedisCallback<Map<String,String>>() {
public Map<String, String> doInRedis(RedisClient redisClient)
throws Exception {
return redisClient.info();
}
});
}
}

View File

@@ -0,0 +1,126 @@
/*
* Copyright 2002-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;
import java.util.Map;
/**
* Key value operations with 'friendly' names instead of using command names for methods.
* Additional helper methods for working with keys and values
*
* @author Mark Pollack
*
*/
public interface KeyValueOperations {
// Set and Set with expiry operations
void set(String key, String value);
void set(String key, String value, long expiryInMillis);
void setAsBytes(String key, byte[] value);
void setAsBytes(String key, byte[] value, long expiryInMillis);
void convertAndSet(String key, Object value);
void convertAndSet(String key, Object value, long expiryInMillis);
// Get operations
String get(String key);
byte[] getAsBytes(String key);
<T> T getAndConvert(String key, Class<T> requiredType);
// Get and Set operations
String getAndSet(String key, String value);
byte[] getAndSetBytes(String key, byte[] value);
<T> T getAndSetObject(String key, T value, Class<T> requiredType);
// Multi-get operations
List<String> getValues(List<String> keys);
<T> List<T> getAndConvertValues(List<String> keys, Class<T> requiredType);
// Set if non-existent operations
void setIfKeyNonExistent(String key, String value);
void setIfKeyNonExistent(String key, byte[] value);
void convertAndSetIfKeyNonExistent(String key, Object value);
// Multiple key-value set
void setMultiple(Map<String, String> keysAndValues);
void setMultipleAsBytes(Map<String, byte[]> keysAndValues);
<T> void convertAndSetMultiple(Map<String, T> keysAndValues);
// Multiple key-value set if non-existent
void setMultipleIfKeysNonExistent(Map<String, String> keysAndValues);
void setMultipleAsBytesIfKeysNonExistent(Map<String, byte[]> keysAndValues);
<T> void convertAndSetMultipleIfKeysNonExistent(Map<String, T> keysAndValues);
// Append
int append(String key, String value);
// Increment
int increment(String key);
int incrementBy(String key, int value);
// Decrement
int decrement(String key);
int decrementBy(String key, int value);
// Substring
String getSubString(String key, int fromIndex, int toIndex);
boolean containsKey(String key);
boolean deleteKeys(String... keys);
}

View File

@@ -0,0 +1,29 @@
/*
* Copyright 2002-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;
/**
* List operations with 'friendly' names instead of using Redis command names for methods.
*
* May also include List specific helper methods from redis recipies.
* @author Mark Pollack
*
*/
public interface ListOperations {
//ListRecipies getListRecipies();
}

View File

@@ -0,0 +1,68 @@
/*
* Copyright 2002-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 org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
/**
* Base class for {@link RedisTemplate} and
* other Redis-accessing DAO helpers, defining common properties such as
* RedisClientFactory.
*
* @author Mark Pollack
*
*/
public class RedisAccessor implements InitializingBean {
/** Logger available to subclasses */
protected final Log logger = LogFactory.getLog(getClass());
private volatile RedisClientFactory redisClientFactory;
/**
* Set the RedisClientFactory to use for obtaining Redis {@link RedisClient clients}.
*/
public void setRedisClientFactory(RedisClientFactory redisClientFactory) {
this.redisClientFactory = redisClientFactory;
}
/**
* Return the RedisClientFactory that this accessor uses for obtaining
* Redis {@link RedisClient Clients}.
*/
public RedisClientFactory getRedisClientFactory() {
return this.redisClientFactory;
}
/**
* Create a Redis Client
* @return the new Redis Client
* @throws TODO
*/
protected RedisClient createClient() {
return this.redisClientFactory.createClient();
}
public void afterPropertiesSet() {
Assert.notNull(getRedisClientFactory(), "RedisClientfactory is required");
}
}

View File

@@ -0,0 +1,31 @@
/*
* Copyright 2002-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;
/**
* Basic callback for use in RedisTemplate
* @author Mark Pollack
*
* @param <T> TODO
*/
public interface RedisCallback<T> {
/**
* Execute any number of operations against the supplied RedisClient
* {@link RedicClient}, possibly returning a result.
*/
T doInRedis(RedisClient redisClient) throws Exception;
}

View File

@@ -0,0 +1,220 @@
/*
* Copyright 2002-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.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* An interface that is a one to one mapping to Redis commands to method names
* that is portable across various Redis driver libraries.
*
* @author Mark Pollack
*
*/
public interface RedisClient {
// Connection Management
void disconnect() throws IOException;
// Database control commands
String save();
String bgsave();
String bgrewriteaof();
Integer lastsave();
String shutdown();
Map<String, String> info();
//bulk reply callback - monitor
String slaveof(String host, int port);
String slaveofNoOne();
String select(int index);
String flushDb();
String flushAll();
Integer move(String key, int dbIndex);
String auth(String password);
Integer dbSize();
// Note: JRedis and the SMA client do not return the response code for set, would probably have to catch exception.
// Commands operating on string values "StringOperations" or "Operations"
/**
* Set the string value as value of the key. The string can't be longer than 1073741824 bytes (1 GB).
* <p>Time complexity: O(1)</p>
* <p>Corresponds to Redis command "SET key value"</p>
* @see <a href="http://code.google.com/p/redis/wiki/SetCommand">setCommand</a>
* @param key key whose associated value is to be returned
* @param value value to be associated with the specified key
*/
void set(String key, String value);
void set(String key, byte[] value);
String get(String key);
byte[] getAsBytes(String key);
String getSet(String key, String value);
List<String> mget(String... keys);
//TODO mgetAsBytes? Best to have byte[] overloads somewhere else?
/**
* SETNX works exactly like SET with the only difference that if the key already exists no operation is performed.
* SETNX actually means "SET if Not eXists".
* <p>Time complexity: O(1)</p>
* <p>Corresponds to command "SETNX key value"</p>
* @see <a href="http://code.google.com/p/redis/wiki/SetnxCommand">SetnxCommand</a>
* @param key key whose associated value is to be set
* @param value value to be associated with the specified key
* @return 1 if the key was set, 0 if the key was not set
*/
Integer setnx(String key, String value);
/**
* The command is exactly equivalent to the following group of commands:
* <p>SET key value
* EXPIRE key time
* </p>
* <p>Time complexity: O(1)</p>
* @see <a href="http://code.google.com/p/redis/wiki/SetexCommand">SetexCommand</a>
* @param key key whose associated value is to be set
* @param seconds timeout on the specified key. After the timeout the key will automatically be deleted by the server
* @param value timeout in seconds
* @return Status reply code, OK is success
*/
String setex(String key, int seconds, String value);
/**
* Set the the respective keys to the respective values.
* <p>Time complexity: O(1) to set every key</p>
* <p>Corresponds to the command "MSET key1 value1 key2 value2 ... keyN valueN"</p>
* @see <a href="http://code.google.com/p/redis/wiki/MsetCommand">MsetCommand</a>
* @param keysvalues key value sequence
* @return OK as MSET can't fail.
*/
//TODO Consider Map<string,string> here or in template? Map<string, byte> ?
String mset(String... keysvalues);
Integer msetnx(String... keysvalues);
Integer incrBy(String key, int increment);
Integer incr(String key);
Integer decr(String key);
Integer decrBy(String key, int decrement);
//TODO incrementByOne,decrementByOne in template
/**
* If the key already exists and is a string, this command appends the provided value at the
* end of the string. If the key does not exist it is created and set as an empty string,
* so APPEND will be very similar to SET in this special case.
* @see <a href="http://code.google.com/p/redis/wiki/AppendCommand">AppendCommand</a>
* @param key key whose associated value is to be appended
* @param value value to be appended to end of current value associated with the specified key
* @return the total length of the string after the append operation.
*/
Integer append(String key, String value);
String substr(String key, int start, int end);
// Commands operating on all value types "KeySpaceOperations"
Integer exists(String key);
Integer del(String... keys);
String type(String key);
List<String> keys(String pattern);
String randomKey();
String rename(String oldkey, String newkey);
Integer renamenx(String oldkey, String newkey);
Integer expire(String key, int seconds);
Integer expireAt(String key, long unixTime);
Integer ttl(String key);
Integer persist(String key);
// Probably not possible to abstract at this level across different providers....
// T sendCommand(String commandName, ReplyTypeMapper mapper, String... commandArgs);
// Commands operating on Sets
Integer sadd(String key, String member);
Set<String> smembers(String key);
Integer srem(String key, String member);
String spop(String key);
Integer smove(String srckey, String dstkey, String member);
Integer scard(String key);
Integer sismember(String key, String member);
Set<String> sinter(String... keys);
Integer sinterstore(String dstkey, String... keys);
Set<String> sunion(String... keys);
Integer sunionstore(String dstkey, String... keys);
Set<String> sdiff(String... keys);
Integer sdiffstore(String dstkey, String... keys);
String srandmember(String key);
}

View File

@@ -0,0 +1,34 @@
/*
* Copyright 2002-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 org.springframework.datastore.redis.support.RedisPersistenceExceptionTranslator;
/**
* An interface based ConnectionFactory for creating {@link RedisClient}s.
*
* @author Mark Pollack
*
*/
public interface RedisClientFactory {
RedisClient createClient();
void setPassword(String password);
RedisPersistenceExceptionTranslator getExceptionTranslator();
}

View File

@@ -0,0 +1,42 @@
/*
* Copyright 2002-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;
import org.springframework.dao.DataAccessException;
/**
* Interface specifying a set of Redis operations.
* Implemented by {@link RedisTemplate}.
*
* @author Mark Pollack
*
*/
public interface RedisOperations extends KeyValueOperations {
<T> T execute(RedisCallback<T> action) throws DataAccessException;
ServerOperations getServerOperations();
ListOperations getListOperations();
SetOperations getSetOperations();
}

View File

@@ -0,0 +1,293 @@
/*
* Copyright 2002-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;
import java.util.Map;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataRetrievalFailureException;
import org.springframework.datastore.redis.support.RedisUtils;
import org.springframework.datastore.redis.support.converter.DefaultRedisConverter;
import org.springframework.datastore.redis.support.converter.RedisConverter;
import org.springframework.util.Assert;
/**
* <b>This is the central class in the Redis core package.</b>
* It simplifies the use of Redis and helps to avoid common errors.
*
* @author Mark Pollack
*
*/
public class RedisTemplate extends RedisAccessor implements RedisOperations {
// TODO perform validation to see if value size > 1GB
// TODO perform validation to see if key contains space, newline or whitespace.
// TODO warning on key size being large > 1024 bytes?
private RedisConverter redisConverter = new DefaultRedisConverter();
private ServerOperations serverOperations;
public RedisTemplate() {
initDefaults();
}
public RedisTemplate(RedisClientFactory redisClientFactory) {
this();
this.setRedisClientFactory(redisClientFactory);
afterPropertiesSet();
}
public void setRedisConverter(RedisConverter redisConverter) {
this.redisConverter = redisConverter;
}
protected void initDefaults() {
serverOperations = new DefaultServerOperations(this);
}
public <T> T execute(RedisCallback<T> action) {
Assert.notNull(action, "Callback object must not be null");
RedisClient clientToClose = null;
try {
RedisClient clientToUse = null; //ConnectionFactoryUtils.doGetTransacxtionChannel(getConnectionFactory, this.transactionResourceFactory);
if (clientToUse == null) {
clientToClose = createClient();
clientToUse = clientToClose;
}
if (logger.isDebugEnabled()) {
logger.debug("Executing callback on Redis Client: " + clientToUse);
}
return action.doInRedis(clientToUse);
}
catch (Exception e) {
throw convertRedisAccessException(e);
} finally {
RedisUtils.closeClient(clientToClose);
}
}
protected DataAccessException convertRedisAccessException(Exception ex) {
//TODO
return null;
}
public ServerOperations getServerOperations() {
return serverOperations;
}
public ListOperations getListOperations() {
// TODO Auto-generated method stub
throw new RuntimeException("unimplemented");
}
// Key Value Operations
public String get(final String key) {
return execute(new RedisCallback<String>() {
public String doInRedis(RedisClient redisClient) throws Exception {
return redisClient.get(key);
}
});
}
public byte[] getAsBytes(final String key) {
return execute(new RedisCallback<byte[]>() {
public byte[] doInRedis(RedisClient redisClient) throws Exception {
return redisClient.getAsBytes(key);
}
});
}
public <T> T getAndConvert(String key, Class<T> requiredType) {
//TODO deserializer exceptions need to be under DAO exception hierarchy.
Object object = redisConverter.deserialize(getAsBytes(key));
if (requiredType != null && object != null && !requiredType.isAssignableFrom(object.getClass())) {
throw new DataRetrievalFailureException("Can not assign from " + requiredType + " to " + object.getClass());
}
return (T) object;
}
public String getAndSet(String key, String value) {
// TODO Auto-generated method stub
throw new RuntimeException("unimplemented");
}
public byte[] getAndSetBytes(String key, byte[] value) {
// TODO Auto-generated method stub
throw new RuntimeException("unimplemented");
}
public <T> T getAndSetObject(String key, T value, Class<T> requiredType) {
// TODO Auto-generated method stub
throw new RuntimeException("unimplemented");
}
public void set(final String key, final String value) {
execute(new RedisCallback<Void>() {
public Void doInRedis(RedisClient redisClient) throws Exception {
redisClient.set(key, value);
return null;
}
});
}
public void set(String key, String value, long expiryInMillis) {
// TODO Auto-generated method stub
}
public void setAsBytes(final String key, final byte[] value) {
execute(new RedisCallback<Void>() {
public Void doInRedis(RedisClient redisClient) throws Exception {
redisClient.set(key, value);
return null;
}
});
}
public void setAsBytes(String key, byte[] value, long expiryInMillis) {
// TODO Auto-generated method stub
throw new RuntimeException("unimplemented");
}
public void setIfKeyNonExistent(String key, String value) {
// TODO Auto-generated method stub
throw new RuntimeException("unimplemented");
}
public void setIfKeyNonExistent(String key, byte[] value) {
// TODO Auto-generated method stub
throw new RuntimeException("unimplemented");
}
public void setMultiple(Map<String, String> keysAndValues) {
// TODO Auto-generated method stub
throw new RuntimeException("unimplemented");
}
public void setMultipleAsBytes(Map<String, byte[]> keysAndValues) {
// TODO Auto-generated method stub
throw new RuntimeException("unimplemented");
}
public void setMultipleAsBytesIfKeysNonExistent(
Map<String, byte[]> keysAndValues) {
// TODO Auto-generated method stub
throw new RuntimeException("unimplemented");
}
public void setMultipleIfKeysNonExistent(Map<String, String> keysAndValues) {
// TODO Auto-generated method stub
throw new RuntimeException("unimplemented");
}
public int append(String key, String value) {
throw new RuntimeException("unimplemented");
}
public void convertAndSet(String key, Object value) {
setAsBytes(key, this.redisConverter.serialize(value));
}
public void convertAndSet(String key, Object value, long expiryInMillis) {
// TODO Auto-generated method stub
throw new RuntimeException("unimplemented");
}
public void convertAndSetIfKeyNonExistent(String key, Object value) {
// TODO Auto-generated method stub
throw new RuntimeException("unimplemented");
}
public <T> void convertAndSetMultiple(Map<String, T> keysAndValues) {
// TODO Auto-generated method stub
throw new RuntimeException("unimplemented");
}
public <T> void convertAndSetMultipleIfKeysNonExistent(
Map<String, T> keysAndValues) {
// TODO Auto-generated method stub
throw new RuntimeException("unimplemented");
}
public int decrement(String key) {
// TODO Auto-generated method stub
throw new RuntimeException("unimplemented");
}
public int decrementBy(String key, int value) {
// TODO Auto-generated method stub
throw new RuntimeException("unimplemented");
}
public List<String> getValues(List<String> keys) {
// TODO Auto-generated method stub
throw new RuntimeException("unimplemented");
}
public int increment(String key) {
// TODO Auto-generated method stub
throw new RuntimeException("unimplemented");
}
public int incrementBy(String key, int value) {
// TODO Auto-generated method stub
throw new RuntimeException("unimplemented");
}
public String subString(String key, int fromIndex, int toIndex) {
// TODO Auto-generated method stub
throw new RuntimeException("unimplemented");
}
public <T> List<T> getAndConvertValues(List<String> keys,
Class<T> requiredType) {
// TODO Auto-generated method stub
return null;
}
public String getSubString(String key, int fromIndex, int toIndex) {
// TODO Auto-generated method stub
return null;
}
public boolean containsKey(String key) {
// TODO Auto-generated method stub
return false;
}
public boolean deleteKeys(final String... keys) {
return execute(new RedisCallback<Boolean>() {
public Boolean doInRedis(RedisClient redisClient) throws Exception {
Integer intVal = redisClient.del(keys);
return (intVal == 0) ? false : true;
}
});
}
public SetOperations getSetOperations() {
// TODO Auto-generated method stub
return null;
}
}

View File

@@ -0,0 +1,44 @@
/*
* Copyright 2002-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.Map;
/**
* Server operations for Redis
*
* @author Mark Pollack
*
*/
public interface ServerOperations {
// Connection handling
/**
* Calls the Redis 'info' command that returns different information and statistics about the server.
* The reply is parsed into a Map for easy programmatic access.
* Corresponds to the Redis InfoCommand INFO
* @see <a href="http://code.google.com/p/redis/wiki/InfoCommand">InfoCommand</a>
* @return
*/
Map<String,String> getServerInfo();
// TODO Commands Monitor, SlaveOf, Config
}

View File

@@ -0,0 +1,35 @@
package org.springframework.datastore.redis.core;
import java.util.Set;
public interface SetOperations {
boolean add(String key, String member);
Set<String> getAll(String key);
boolean remove(String key, String member);
boolean removeRandom(String key);
boolean moveBetweenSets(String srckey, String dstkey, String member);
int size(String key);
boolean contains(String key, String member);
Set<String> getIntersectionOfSets(String... keys);
void storeIntersectionOfSets(String dstkey, String... keys);
Set<String> getUnionOfSets(String... keys);
void storeUnionOfSets(String dstkey, String... keys);
Set<String> getDifferenceBetweenSets(String... keys);
void storeDifferenceBetweenSets(String dstkey, String... keys);
String getRandom(String key);
}

View File

@@ -0,0 +1,111 @@
/*
* Copyright 2002-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.jedis;
import java.util.concurrent.TimeoutException;
import org.springframework.datastore.redis.CannotGetRedisConnectionException;
import org.springframework.datastore.redis.core.AbstractRedisClientFactory;
import org.springframework.datastore.redis.core.RedisClient;
import org.springframework.datastore.redis.support.RedisPersistenceExceptionTranslator;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
/**
* A RedisClientFactory implementation that uses Jedis's native connection/client
* caching features.
*
* @author Mark Pollack
*
*/
public class CachingJedisClientFactory extends AbstractRedisClientFactory {
private JedisPool pool;
private int timeout;
private int clientCacheSize;
private long maxWaitTime;
/**
*
* @param clientCacheSize
*/
public CachingJedisClientFactory(int clientCacheSize) {
this.clientCacheSize = clientCacheSize;
}
public CachingJedisClientFactory(JedisPool pool) {
this.pool = pool;
}
public int getClientCacheSize() {
return this.clientCacheSize;
}
public JedisPool getJedisPool() {
return this.pool;
}
public int getTimeout() {
return timeout;
}
protected void setTimeout(int timeout) {
this.timeout = timeout;
}
public long getMaxWaitTime() {
return this.maxWaitTime;
}
/**
* Sets the maximum amount of time (in milliseconds) the getResource() method
* should block before throwing an TimeoutException.
* @param maxWaitTime The maximum time you would like to wait for the resource.
*/
public void setMaxWaitTime(long maxWaitTime) {
this.maxWaitTime = maxWaitTime;
}
@Override
public RedisClient doGetClient() {
Jedis jedis;
if (getClientCacheSize() != 0) {
pool = new JedisPool(getHostName(), getPort(), getTimeout());
pool.setResourcesNumber(getClientCacheSize());
}
try {
if (getMaxWaitTime() != 0)
jedis = pool.getResource(getMaxWaitTime());
else {
jedis = pool.getResource();
}
} catch (TimeoutException e) {
throw new CannotGetRedisConnectionException(
"Timed out. Could not get Redis Connection", e);
}
return new JedisClient(jedis, getExceptionTranslator() );
}
@Override
public RedisPersistenceExceptionTranslator getExceptionTranslator() {
return new JedisPersistenceExceptionTranslator();
}
}

View File

@@ -0,0 +1,535 @@
/*
* Copyright 2002-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.jedis;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.springframework.dao.DataAccessException;
import org.springframework.datastore.redis.core.AbstractRedisClient;
import org.springframework.datastore.redis.support.RedisPersistenceExceptionTranslator;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import redis.clients.jedis.Jedis;
/**
* Jedis based implementation of Spring's RedisClient interface. Presents a low
* level API where method names map onto Redis commands.
*
* @author Mark Pollack
*
*/
public class JedisClient extends AbstractRedisClient {
private Jedis _jedis;
private RedisPersistenceExceptionTranslator exceptionTranslator;
public JedisClient(Jedis jedis,
RedisPersistenceExceptionTranslator exceptionTranslator) {
this._jedis = jedis;
this.exceptionTranslator = exceptionTranslator;
}
public <T> T execute(JedisClientCallback<T> action) {
Assert.notNull(action, "Callback object must not be null");
// TODO jredisClient resource mgmt.
try {
if (logger.isDebugEnabled()) {
logger.debug("Executing callback on Jedis : " + _jedis);
}
return action.doInJedis(_jedis);
} catch (Exception e) {
throw convertJedisAccessException(e);
}
}
protected DataAccessException convertJedisAccessException(Exception ex) {
return exceptionTranslator.translateException(ex);
}
public void disconnect() throws IOException {
execute(new JedisClientCallback<Object>() {
public Object doInJedis(Jedis jedis) throws Exception {
jedis.disconnect();
return null;
}
});
}
// Database control commands
public String save() {
return execute(new JedisClientCallback<String>() {
public String doInJedis(Jedis jedis) throws Exception {
return jedis.save();
}
});
}
public String bgsave() {
return execute(new JedisClientCallback<String>() {
public String doInJedis(Jedis jedis) throws Exception {
return jedis.bgsave();
}
});
}
public String bgrewriteaof() {
return execute(new JedisClientCallback<String>() {
public String doInJedis(Jedis jedis) throws Exception {
return jedis.bgrewriteaof();
}
});
}
public Integer lastsave() {
return execute(new JedisClientCallback<Integer>() {
public Integer doInJedis(Jedis jedis) throws Exception {
return jedis.lastsave();
}
});
}
public String shutdown() {
return execute(new JedisClientCallback<String>() {
public String doInJedis(Jedis jedis) throws Exception {
return jedis.shutdown();
}
});
}
public Map<String, String> info() {
return execute(new JedisClientCallback<Map<String, String>>() {
public Map<String, String> doInJedis(Jedis jedis) throws Exception {
String[] response = StringUtils.delimitedListToStringArray(
jedis.info(), "\r\n");
Map<String, String> responseMap = new HashMap<String, String>();
for (String responseLine : response) {
if (!responseLine.isEmpty()) {
String[] keyValue = StringUtils
.split(responseLine, ":");
if (keyValue == null) {
logger.warn("Could not parse info reponse line ["
+ responseLine + "]");
continue;
}
responseMap.put(keyValue[0], keyValue[1]);
}
}
return responseMap;
}
});
}
public String slaveof(final String host, final int port) {
return execute(new JedisClientCallback<String>() {
public String doInJedis(Jedis jedis) throws Exception {
return jedis.slaveof(host, port);
}
});
}
public String slaveofNoOne() {
return execute(new JedisClientCallback<String>() {
public String doInJedis(Jedis jedis) throws Exception {
return jedis.slaveofNoOne();
}
});
}
public String select(final int index) {
return execute(new JedisClientCallback<String>() {
public String doInJedis(Jedis jedis) throws Exception {
return jedis.select(index);
}
});
}
public String flushDb() {
return execute(new JedisClientCallback<String>() {
public String doInJedis(Jedis jedis) throws Exception {
return jedis.flushDB();
}
});
}
public String flushAll() {
return execute(new JedisClientCallback<String>() {
public String doInJedis(Jedis jedis) throws Exception {
return jedis.flushAll();
}
});
}
public Integer move(final String key, final int dbIndex) {
return execute(new JedisClientCallback<Integer>() {
public Integer doInJedis(Jedis jedis) throws Exception {
return jedis.move(key, dbIndex);
}
});
}
public String auth(final String password) {
return execute(new JedisClientCallback<String>() {
public String doInJedis(Jedis jedis) throws Exception {
return jedis.auth(password);
}
});
}
public Integer dbSize() {
return execute(new JedisClientCallback<Integer>() {
public Integer doInJedis(Jedis jedis) throws Exception {
return jedis.dbSize();
}
});
}
// Commands operating on string value types "StringOperations" or
// "Operations"
public void set(final String key, final String value) {
execute(new JedisClientCallback<String>() {
public String doInJedis(Jedis jedis) throws Exception {
return jedis.set(key, value);
}
});
}
public void set(String key, byte[] value) {
set(key, byteToString(value));
}
public String get(final String key) {
return execute(new JedisClientCallback<String>() {
public String doInJedis(Jedis jedis) throws Exception {
return jedis.get(key);
}
});
}
public byte[] getAsBytes(String key) {
return stringToByte(get(key));
}
public String getSet(final String key, final String value) {
return execute(new JedisClientCallback<String>() {
public String doInJedis(Jedis jedis) throws Exception {
return jedis.getSet(key, value);
}
});
}
public List<String> mget(final String... keys) {
return execute(new JedisClientCallback<List<String>>() {
public List<String> doInJedis(Jedis jedis) throws Exception {
return jedis.mget(keys);
}
});
}
public Integer setnx(final String key, final String value) {
return execute(new JedisClientCallback<Integer>() {
public Integer doInJedis(Jedis jedis) throws Exception {
return jedis.setnx(key, value);
}
});
}
public String setex(final String key, final int seconds, final String value) {
return execute(new JedisClientCallback<String>() {
public String doInJedis(Jedis jedis) throws Exception {
return jedis.setex(key, seconds, value);
}
});
}
public String mset(final String... keysvalues) {
return execute(new JedisClientCallback<String>() {
public String doInJedis(Jedis jedis) throws Exception {
return jedis.mset(keysvalues);
}
});
}
public Integer msetnx(final String... keysvalues) {
return execute(new JedisClientCallback<Integer>() {
public Integer doInJedis(Jedis jedis) throws Exception {
return jedis.msetnx(keysvalues);
}
});
}
public Integer incrBy(final String key, final int increment) {
return execute(new JedisClientCallback<Integer>() {
public Integer doInJedis(Jedis jedis) throws Exception {
return jedis.incrBy(key, increment);
}
});
}
public Integer incr(final String key) {
return execute(new JedisClientCallback<Integer>() {
public Integer doInJedis(Jedis jedis) throws Exception {
return jedis.incr(key);
}
});
}
public Integer decr(final String key) {
return execute(new JedisClientCallback<Integer>() {
public Integer doInJedis(Jedis jedis) throws Exception {
return jedis.decr(key);
}
});
}
public Integer decrBy(final String key, final int increment) {
return execute(new JedisClientCallback<Integer>() {
public Integer doInJedis(Jedis jedis) throws Exception {
return jedis.decrBy(key, increment);
}
});
}
public Integer append(final String key, final String value) {
return execute(new JedisClientCallback<Integer>() {
public Integer doInJedis(Jedis jedis) throws Exception {
return jedis.append(key, value);
}
});
}
public String substr(final String key, final int start, final int end) {
return execute(new JedisClientCallback<String>() {
public String doInJedis(Jedis jedis) throws Exception {
return jedis.substr(key, start, end);
}
});
}
// Commands operating on all value types "KeySpaceOperations"
public Integer exists(final String key) {
return execute(new JedisClientCallback<Integer>() {
public Integer doInJedis(Jedis jedis) throws Exception {
return jedis.exists(key);
}
});
}
public Integer del(final String... keys) {
return execute(new JedisClientCallback<Integer>() {
public Integer doInJedis(Jedis jedis) throws Exception {
return jedis.del(keys);
}
});
}
public String type(final String key) {
return execute(new JedisClientCallback<String>() {
public String doInJedis(Jedis jedis) throws Exception {
return jedis.type(key);
}
});
}
public List<String> keys(final String pattern) {
return execute(new JedisClientCallback<List<String>>() {
public List<String> doInJedis(Jedis jedis) throws Exception {
return jedis.keys(pattern);
}
});
}
public String randomKey() {
return execute(new JedisClientCallback<String>() {
public String doInJedis(Jedis jedis) throws Exception {
return jedis.randomKey();
}
});
}
public String rename(final String oldkey, final String newkey) {
return execute(new JedisClientCallback<String>() {
public String doInJedis(Jedis jedis) throws Exception {
return jedis.rename(oldkey, newkey);
}
});
}
public Integer renamenx(final String oldkey, final String newkey) {
return execute(new JedisClientCallback<Integer>() {
public Integer doInJedis(Jedis jedis) throws Exception {
return jedis.renamenx(oldkey, newkey);
}
});
}
public Integer expire(final String key, final int seconds) {
return execute(new JedisClientCallback<Integer>() {
public Integer doInJedis(Jedis jedis) throws Exception {
return jedis.expire(key, seconds);
}
});
}
public Integer expireAt(final String key, final long unixTime) {
return execute(new JedisClientCallback<Integer>() {
public Integer doInJedis(Jedis jedis) throws Exception {
return jedis.expireAt(key, unixTime);
}
});
}
public Integer ttl(final String key) {
return execute(new JedisClientCallback<Integer>() {
public Integer doInJedis(Jedis jedis) throws Exception {
return jedis.ttl(key);
}
});
}
public Integer persist(final String key) {
return execute(new JedisClientCallback<Integer>() {
public Integer doInJedis(Jedis jedis) throws Exception {
return jedis.persist(key);
}
});
}
// Commands operating on Sets
public Integer sadd(final String key, final String member) {
return execute(new JedisClientCallback<Integer>() {
public Integer doInJedis(Jedis jedis) throws Exception {
return jedis.sadd(key, member);
}
});
}
public Set<String> smembers(final String key) {
return execute(new JedisClientCallback<Set<String>>() {
public Set<String> doInJedis(Jedis jedis) throws Exception {
return jedis.smembers(key);
}
});
}
public Integer srem(final String key, final String member) {
return execute(new JedisClientCallback<Integer>() {
public Integer doInJedis(Jedis jedis) throws Exception {
return jedis.srem(key, member);
}
});
}
public String spop(final String key) {
return execute(new JedisClientCallback<String>() {
public String doInJedis(Jedis jedis) throws Exception {
return jedis.spop(key);
}
});
}
public Integer smove(final String srckey, final String dstkey,
final String member) {
return execute(new JedisClientCallback<Integer>() {
public Integer doInJedis(Jedis jedis) throws Exception {
return jedis.smove(srckey, dstkey, member);
}
});
}
public Integer scard(final String key) {
return execute(new JedisClientCallback<Integer>() {
public Integer doInJedis(Jedis jedis) throws Exception {
return jedis.scard(key);
}
});
}
public Integer sismember(final String key, final String member) {
return execute(new JedisClientCallback<Integer>() {
public Integer doInJedis(Jedis jedis) throws Exception {
return jedis.sismember(key, member);
}
});
}
public Set<String> sinter(final String... keys) {
return execute(new JedisClientCallback<Set<String>>() {
public Set<String> doInJedis(Jedis jedis) throws Exception {
return jedis.sinter(keys);
}
});
}
public Integer sinterstore(final String dstkey, final String... keys) {
return execute(new JedisClientCallback<Integer>() {
public Integer doInJedis(Jedis jedis) throws Exception {
return jedis.sinterstore(dstkey, keys);
}
});
}
public Set<String> sunion(final String... keys) {
return execute(new JedisClientCallback<Set<String>>() {
public Set<String> doInJedis(Jedis jedis) throws Exception {
return jedis.sunion(keys);
}
});
}
public Integer sunionstore(final String dstkey, final String... keys) {
return execute(new JedisClientCallback<Integer>() {
public Integer doInJedis(Jedis jedis) throws Exception {
return jedis.sunionstore(dstkey, keys);
}
});
}
public Set<String> sdiff(final String... keys) {
return execute(new JedisClientCallback<Set<String>>() {
public Set<String> doInJedis(Jedis jedis) throws Exception {
return jedis.sdiff(keys);
}
});
}
public Integer sdiffstore(final String dstkey, final String... keys) {
return execute(new JedisClientCallback<Integer>() {
public Integer doInJedis(Jedis jedis) throws Exception {
return jedis.sdiffstore(dstkey, keys);
}
});
}
public String srandmember(final String key) {
return execute(new JedisClientCallback<String>() {
public String doInJedis(Jedis jedis) throws Exception {
return jedis.srandmember(key);
}
});
}
}

View File

@@ -0,0 +1,33 @@
/*
* Copyright 2002-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.jedis;
import redis.clients.jedis.Jedis;
/**
* Basic callback for use in JedisClient
* @author Mark Pollack
*
* @param <T> TODO
*/
public interface JedisClientCallback<T> {
/**
* Execute any number of operations against the supplied Jedis
* {@link Jedis}, possibly returning a result.
*/
T doInJedis(Jedis jedis) throws Exception;
}

View File

@@ -0,0 +1,122 @@
/*
* Copyright 2002-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.jedis;
import java.io.IOException;
import java.net.UnknownHostException;
import org.springframework.datastore.redis.CannotGetRedisConnectionException;
import org.springframework.datastore.redis.core.AbstractRedisClientFactory;
import org.springframework.datastore.redis.core.RedisClient;
import org.springframework.datastore.redis.core.RedisClientFactory;
import org.springframework.datastore.redis.core.jredis.JRedisPersistenceExceptionTranslator;
import org.springframework.datastore.redis.support.RedisPersistenceExceptionTranslator;
import redis.clients.jedis.Jedis;
import redis.clients.util.ShardInfo;
/**
* A {@link RedisClientFactory} implementation that returns a new instance of a
* Jedis backed RedisClient from call {@link #createClient()} calls.
*
* @author Mark Pollack
*
*/
public class JedisClientFactory extends AbstractRedisClientFactory {
private ShardInfo shardInfo;
private int timeout;
private RedisPersistenceExceptionTranslator exceptionTranslator = new JRedisPersistenceExceptionTranslator();
public JedisClientFactory() {
setHostName(getDefaultHostName());
}
public JedisClientFactory(String hostname) {
setHostName(hostname);
}
public JedisClientFactory(String hostname, int port)
{
setHostName(hostname);
setPort(port);
}
public JedisClientFactory(String hostname, int port, int timeout)
{
setHostName(hostname);
setPort(port);
setTimeout(timeout);
}
public JedisClientFactory(ShardInfo shardInfo) {
this.shardInfo = shardInfo;
}
protected ShardInfo getShardInfo() {
return this.shardInfo;
}
public int getTimeout() {
return timeout;
}
protected void setTimeout(int timeout) {
this.timeout = timeout;
}
@Override
public RedisClient doGetClient() {
Jedis jedis;
if (getShardInfo() != null) {
jedis = new Jedis(getShardInfo());
}
if (getPort() != 0 && getTimeout() != 0) {
jedis = new Jedis(getHostName(), getPort(), getTimeout());
} else if (getPort() != 0) {
jedis = new Jedis(getHostName(), getPort());
} else {
jedis = new Jedis(getHostName());
}
try {
jedis.connect();
if (getPassword() != null) {
jedis.auth(getPassword());
}
} catch (UnknownHostException e) {
throw new CannotGetRedisConnectionException(
"Could not get Redis Connection", e);
} catch (IOException e) {
throw new CannotGetRedisConnectionException(
"Could not get Redis Connection", e);
}
return new JedisClient(jedis, getExceptionTranslator());
}
@Override
public RedisPersistenceExceptionTranslator getExceptionTranslator() {
return exceptionTranslator;
}
public void setExceptionTranslator(
RedisPersistenceExceptionTranslator exceptionTranslator) {
this.exceptionTranslator = exceptionTranslator;
}
}

View File

@@ -0,0 +1,35 @@
/*
* Copyright 2002-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.jedis;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.datastore.redis.support.RedisPersistenceExceptionTranslator;
/**
* Translates error messages from Jedis to Spring's Data Access exception class hierarchy
*
* @author Mark Pollack
*
*/
public class JedisPersistenceExceptionTranslator implements
RedisPersistenceExceptionTranslator {
public DataAccessException translateException(Exception ex) {
return new InvalidDataAccessApiUsageException(ex.getMessage(), ex);
}
}

View File

@@ -0,0 +1,33 @@
/*
* Copyright 2002-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.jredis;
import org.jredis.ri.alphazero.JRedisClient;
/**
* Basic callback for use in JRedisClient
* @author Mark Pollack
*
* @param <T> TODO
*/
public interface JRedisClientCallback<T> {
/**
* Execute any number of operations against the supplied RedisClient
* {@link RedicClient}, possibly returning a result.
*/
T doInJRedis(JRedisClient jredisClient) throws Exception;
}

View File

@@ -0,0 +1,111 @@
/*
* Copyright 2002-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.jredis;
import java.io.UnsupportedEncodingException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import org.jredis.ClientRuntimeException;
import org.jredis.connector.ConnectionSpec;
import org.jredis.ri.alphazero.JRedisClient;
import org.jredis.ri.alphazero.connection.DefaultConnectionSpec;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.datastore.redis.core.AbstractRedisClientFactory;
import org.springframework.datastore.redis.core.RedisClient;
import org.springframework.datastore.redis.support.RedisPersistenceExceptionTranslator;
public class JRedisClientFactory extends AbstractRedisClientFactory {
public static final String DEFAULT_CHARSET = "UTF-8";
private volatile String defaultCharset = DEFAULT_CHARSET;
private RedisPersistenceExceptionTranslator exceptionTranslator;
private ConnectionSpec connectionSpec;
public JRedisClientFactory() {
setHostName(getDefaultHostName());
exceptionTranslator = new JRedisPersistenceExceptionTranslator();
}
public JRedisClientFactory(ConnectionSpec connectionSpec) {
this.connectionSpec = connectionSpec;
}
@Override
public RedisClient doGetClient() {
JRedisClient jredis;
if (connectionSpec == null) {
connectionSpec = DefaultConnectionSpec.newSpec();
InetAddress address;
try {
address = InetAddress.getByName(getHostName());
} catch (UnknownHostException e) {
throw new ClientRuntimeException("unknown host: "
+ getHostName(), e);
}
connectionSpec.setAddress(address);
if (getPort() != 0) {
connectionSpec.setPort(getPort());
}
if (getPassword() != null) {
connectionSpec.setCredentials(stringToByte(getPassword()));
}
}
jredis = new JRedisClient(connectionSpec);
return new JRedisSpringClient(jredis, getExceptionTranslator());
}
protected byte[] stringToByte(String string) throws InvalidDataAccessApiUsageException {
try {
return string.getBytes(this.defaultCharset);
} catch (UnsupportedEncodingException e) {
throw new InvalidDataAccessApiUsageException(defaultCharset
+ " encoding not supported.", e);
}
}
/**
* Specify the default charset to use when converting to or from text-based
* Message body content. If not specified, the charset will be "UTF-8".
*/
public void setDefaultCharset(String defaultCharset) {
this.defaultCharset = (defaultCharset != null) ? defaultCharset : DEFAULT_CHARSET;
}
public String getDefaultCharset() {
return defaultCharset;
}
@Override
public RedisPersistenceExceptionTranslator getExceptionTranslator() {
return exceptionTranslator;
}
public void setExceptionTranslator(
RedisPersistenceExceptionTranslator exceptionTranslator) {
this.exceptionTranslator = exceptionTranslator;
}
}

View File

@@ -0,0 +1,29 @@
/*
* Copyright 2002-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.jredis;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.datastore.redis.support.RedisPersistenceExceptionTranslator;
public class JRedisPersistenceExceptionTranslator implements
RedisPersistenceExceptionTranslator {
public DataAccessException translateException(Exception ex) {
return new InvalidDataAccessApiUsageException(ex.getMessage(), ex);
}
}

View File

@@ -0,0 +1,494 @@
/*
* Copyright 2002-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.jredis;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jredis.ri.alphazero.JRedisClient;
import org.jredis.ri.alphazero.support.DefaultCodec;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataRetrievalFailureException;
import org.springframework.datastore.redis.core.AbstractRedisClient;
import org.springframework.datastore.redis.support.RedisPersistenceExceptionTranslator;
import org.springframework.util.Assert;
/**
* JRedis implementation of RedisClient. Name has 'Spring' in it to avoid naming
* conflict with classes in JRedis itself.
*
* @author Mark Pollack
*
*/
public class JRedisSpringClient extends AbstractRedisClient {
/** Logger available to subclasses */
protected final Log logger = LogFactory.getLog(getClass());
private JRedisClient _jredisClient;
private RedisPersistenceExceptionTranslator exceptionTranslator;
public JRedisSpringClient(JRedisClient jredisClient,
RedisPersistenceExceptionTranslator exceptionTransator) {
this._jredisClient = jredisClient;
this.exceptionTranslator = exceptionTransator;
this.setDefaultCharset(DefaultCodec.SUPPORTED_CHARSET_NAME);
}
protected Integer convertToInteger(long longTime) {
if (longTime < Integer.MIN_VALUE
|| longTime > Integer.MAX_VALUE) {
throw new DataRetrievalFailureException(
longTime
+ " cannot be cast to int without changing its value.");
}
return (int) longTime;
}
public <T> T execute(JRedisClientCallback<T> action) {
Assert.notNull(action, "Callback object must not be null");
// TODO jredisClient resource mgmt.
try {
if (logger.isDebugEnabled()) {
logger.debug("Executing callback on JRedisClient : "
+ _jredisClient);
}
return action.doInJRedis(_jredisClient);
} catch (Exception e) {
throw convertJRedisAccessException(e);
}
}
protected DataAccessException convertJRedisAccessException(Exception ex) {
return exceptionTranslator.translateException(ex);
}
public void disconnect() {
// TODO look at disconnect exception translation
execute(new JRedisClientCallback<Object>() {
public Object doInJRedis(JRedisClient jredisClient)
throws Exception {
jredisClient.quit();
return null;
}
});
}
public String get(final String key) {
return execute(new JRedisClientCallback<String>() {
public String doInJRedis(JRedisClient jredisClient)
throws Exception {
return byteToString(jredisClient.get(key));
}
});
}
public byte[] getAsBytes(final String key) {
return execute(new JRedisClientCallback<byte[]>() {
public byte[] doInJRedis(JRedisClient jredisClient)
throws Exception {
return jredisClient.get(key);
}
});
}
public void set(final String key, final String value) {
execute(new JRedisClientCallback<Object>() {
public String doInJRedis(JRedisClient jredisClient)
throws Exception {
jredisClient.set(key, value);
return null;
}
});
}
public void set(final String key, final byte[] value) {
execute(new JRedisClientCallback<Object>() {
public String doInJRedis(JRedisClient jredisClient)
throws Exception {
jredisClient.set(key, value);
return null;
}
});
}
public String save() {
return execute(new JRedisClientCallback<String>() {
public String doInJRedis(JRedisClient jredisClient)
throws Exception {
jredisClient.save();
return "OK";
}
});
}
public String bgsave() {
return execute(new JRedisClientCallback<String>() {
public String doInJRedis(JRedisClient jredisClient)
throws Exception {
jredisClient.bgsave();
return "Background saving started";
}
});
}
public String bgrewriteaof() {
return execute(new JRedisClientCallback<String>() {
public String doInJRedis(JRedisClient jredisClient)
throws Exception {
jredisClient.bgrewriteaof();
return "Background append only file rewriting started";
}
});
}
public Integer lastsave() {
return execute(new JRedisClientCallback<Integer>() {
public Integer doInJRedis(JRedisClient jredisClient)
throws Exception {
long longTime = jredisClient.lastsave();
// odd that JRedis return long when the Redis command spec says
// int.
return convertToInteger(longTime);
}
});
}
public String shutdown() {
return execute(new JRedisClientCallback<String>() {
public String doInJRedis(JRedisClient jredisClient)
throws Exception {
throw new UnsupportedOperationException("JRedis does not implement SHUTDOWN command");
}
});
}
public Map<String, String> info() {
return execute(new JRedisClientCallback<Map<String, String>>() {
public Map<String, String> doInJRedis(JRedisClient jredisClient)
throws Exception {
return jredisClient.info();
}
});
}
public String slaveof(final String host, final int port) {
return execute(new JRedisClientCallback<String>() {
public String doInJRedis(JRedisClient jredisClient)
throws Exception {
jredisClient.slaveof(host,port);
return "TODO - EXTRACT CORRECT STRING RESPONSE FROM REDIS FOR COMMAND SLAVEOF";
}
});
}
public String slaveofNoOne() {
return execute(new JRedisClientCallback<String>() {
public String doInJRedis(JRedisClient jredisClient)
throws Exception {
jredisClient.slaveofnone();
return "TODO - EXTRACT CORRECT STRING RESPONSE FROM REDIS FOR COMMAND SLAVEOF NO ONE";
}
});
}
public String select(int index) {
return execute(new JRedisClientCallback<String>() {
public String doInJRedis(JRedisClient jredisClient)
throws Exception {
throw new UnsupportedOperationException("JRedis does not implement SELECT command");
}
});
}
public String flushDb() {
return execute(new JRedisClientCallback<String>() {
public String doInJRedis(JRedisClient jredisClient)
throws Exception {
jredisClient.flushdb();
//TODO why does flushdb() return JRedis interface?
return "OK";
}
});
}
public String flushAll() {
return execute(new JRedisClientCallback<String>() {
public String doInJRedis(JRedisClient jredisClient)
throws Exception {
jredisClient.flushall();
//TODO why does flushdb() return JRedis interface?
return "OK";
}
});
}
public Integer move(final String key, final int dbIndex) {
return execute(new JRedisClientCallback<Integer>() {
public Integer doInJRedis(JRedisClient jredisClient)
throws Exception {
return jredisClient.move(key, dbIndex) ? 1 : 0;
}
});
}
public String auth(String password) {
return execute(new JRedisClientCallback<String>() {
public String doInJRedis(JRedisClient jredisClient)
throws Exception {
throw new UnsupportedOperationException("JRedis does not implement AUTH command");
}
});
}
public Integer dbSize() {
return execute(new JRedisClientCallback<Integer>() {
public Integer doInJRedis(JRedisClient jredisClient)
throws Exception {
return convertToInteger(jredisClient.dbsize());
}
});
}
public String getSet(String key, String value) {
// TODO Auto-generated method stub
return null;
}
public List<String> mget(String... keys) {
// TODO Auto-generated method stub
return null;
}
public Integer setnx(String key, String value) {
// TODO Auto-generated method stub
return null;
}
public String setex(String key, int seconds, String value) {
// TODO Auto-generated method stub
return null;
}
public String mset(String... keysvalues) {
// TODO Auto-generated method stub
return null;
}
public Integer msetnx(String... keysvalues) {
// TODO Auto-generated method stub
return null;
}
public Integer incrBy(String key, int increment) {
// TODO Auto-generated method stub
return null;
}
public Integer incr(String key) {
// TODO Auto-generated method stub
return null;
}
public Integer decr(String key) {
// TODO Auto-generated method stub
return null;
}
public Integer decrBy(String key, int decrement) {
// TODO Auto-generated method stub
return null;
}
public Integer append(String key, String value) {
// TODO Auto-generated method stub
return null;
}
public String substr(String key, int start, int end) {
// TODO Auto-generated method stub
return null;
}
public Integer exists(String key) {
// TODO Auto-generated method stub
return null;
}
public Integer del(String... keys) {
// TODO Auto-generated method stub
return null;
}
public String type(String key) {
// TODO Auto-generated method stub
return null;
}
public List<String> keys(String pattern) {
// TODO Auto-generated method stub
return null;
}
public String randomKey() {
// TODO Auto-generated method stub
return null;
}
public String rename(String oldkey, String newkey) {
// TODO Auto-generated method stub
return null;
}
public Integer renamenx(String oldkey, String newkey) {
// TODO Auto-generated method stub
return null;
}
public Integer expire(String key, int seconds) {
// TODO Auto-generated method stub
return null;
}
public Integer expireAt(String key, long unixTime) {
// TODO Auto-generated method stub
return null;
}
public Integer ttl(String key) {
// TODO Auto-generated method stub
return null;
}
public Integer persist(String key) {
// TODO Auto-generated method stub
return null;
}
public Integer sadd(String key, String member) {
// TODO Auto-generated method stub
return null;
}
public Set<String> smembers(String key) {
// TODO Auto-generated method stub
return null;
}
public Integer srem(String key, String member) {
// TODO Auto-generated method stub
return null;
}
public String spop(String key) {
// TODO Auto-generated method stub
return null;
}
public Integer smove(String srckey, String dstkey, String member) {
// TODO Auto-generated method stub
return null;
}
public Integer scard(String key) {
// TODO Auto-generated method stub
return null;
}
public Integer sismember(String key, String member) {
// TODO Auto-generated method stub
return null;
}
public Set<String> sinter(String... keys) {
// TODO Auto-generated method stub
return null;
}
public Integer sinterstore(String dstkey, String... keys) {
// TODO Auto-generated method stub
return null;
}
public Set<String> sunion(String... keys) {
// TODO Auto-generated method stub
return null;
}
public Integer sunionstore(String dstkey, String... keys) {
// TODO Auto-generated method stub
return null;
}
public Set<String> sdiff(String... keys) {
// TODO Auto-generated method stub
return null;
}
public Integer sdiffstore(String dstkey, String... keys) {
// TODO Auto-generated method stub
return null;
}
public String srandmember(String key) {
// TODO Auto-generated method stub
return null;
}
}

View File

@@ -0,0 +1,33 @@
/*
* Copyright 2002-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.support;
import org.springframework.dao.DataAccessException;
/**
* Interface implemented by Spring integrations with Redis for drivers
* that throw runtime and checked exceptions.
*
* @author Mark Pollack
*
*/
public interface RedisPersistenceExceptionTranslator {
//NOTE some client libraries throw checked exceptions.
DataAccessException translateException(Exception ex);
}

View File

@@ -0,0 +1,54 @@
/*
* Copyright 2002-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.support;
import java.io.IOException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.datastore.redis.core.RedisClient;
/**
* Generic utility methods for working with Redis. Mainly for internal use
* within the framework.
* @author Mark Pollack
*
*/
public class RedisUtils {
private static final Log logger = LogFactory.getLog(RedisUtils.class);
/**
* Close the given Redis Client and ignore any thrown exception.
* This is useful for typical <code>finally</code> blocks in manual Redis code.
* @param channel the RabbitMQ Channel to close (may be <code>null</code>)
*/
public static void closeClient(RedisClient redisClient) {
if (redisClient != null) {
try {
redisClient.disconnect();
}
catch (IOException ex) {
logger.debug("Could not close Redis Channel", ex);
}
catch (Throwable ex) {
logger.debug("Unexpected exception on closing Redis Client", ex);
}
}
}
}

View File

@@ -0,0 +1,42 @@
/*
* Copyright 2002-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.support.converter;
import org.springframework.commons.serializer.DefaultDeserializer;
import org.springframework.commons.serializer.DefaultSerializer;
import org.springframework.commons.serializer.DeserializingConverter;
import org.springframework.commons.serializer.SerializingConverter;
/**
* Implementation using Java Serialization
*
* @author Mark Pollack
*
*/
public class DefaultRedisConverter implements RedisConverter {
private DeserializingConverter fromBytes = new DeserializingConverter(new DefaultDeserializer());
private SerializingConverter toBytes = new SerializingConverter(new DefaultSerializer());
public Object deserialize(byte[] bytes) {
return fromBytes.convert(bytes);
}
public byte[] serialize(Object object) {
return toBytes.convert(object);
}
}

View File

@@ -0,0 +1,28 @@
/*
* Copyright 2002-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.support.converter;
/**
* Basic interface serialization and deserialization from object to byte[]. Nothing is specifc to Redis
* @author Mark Pollack
*
*/
public interface RedisConverter {
byte[] serialize(Object object);
Object deserialize(byte[] bytes);
}

View File

@@ -0,0 +1,83 @@
package org.springframework.datastore.redis.util;
import java.util.Collection;
import java.util.Iterator;
import org.springframework.datastore.redis.core.RedisTemplate;
public abstract class AbstractRedisCollection implements RedisCollection {
protected RedisTemplate redisTemplate;
protected String redisKey;
public AbstractRedisCollection(RedisTemplate redisTemplate, String redisKey) {
this.redisTemplate = redisTemplate;
this.redisKey = redisKey;
}
/**
* They key used by the collection
*
* @return The redis key
*/
public String getRedisKey() {
return redisKey;
}
public void clear() {
redisTemplate.deleteKeys(redisKey);
}
public boolean isEmpty() {
return size() == 0;
}
public Object[] toArray() {
return new Object[0];
}
public boolean containsAll(Collection c) {
for (Object o : c) {
if(!contains(o)) return false;
}
return true;
}
public boolean addAll(Collection c) {
boolean changed = false;
for (Object e : c) {
boolean elChange = add(e);
if(elChange && !changed) changed = true;
}
return changed;
}
public boolean retainAll(Collection c) {
Iterator i = iterator();
boolean changed = false;
while (i.hasNext()) {
Object o = i.next();
if(!c.contains(o)) {
i.remove();
changed = true;
}
}
return changed;
}
public boolean removeAll(Collection c) {
boolean changed = false;
for (Object e : c) {
boolean elChange = remove(e);
if(elChange && !changed) changed = true;
}
return changed;
}
public Object[] toArray(Object[] array) {
return new Object[0];
}
}

View File

@@ -0,0 +1,21 @@
package org.springframework.datastore.redis.util;
import java.util.Collection;
import java.util.Set;
/**
*
* @author Graeme Rocher
*
*/
public interface RedisCollection extends Collection {
/**
* They key used by the collection
*
* @return The redis key
*/
String getRedisKey();
Set<String> members();
}

View File

@@ -0,0 +1,79 @@
package org.springframework.datastore.redis.util;
import java.util.Iterator;
import java.util.Set;
import org.springframework.datastore.redis.core.RedisTemplate;
/**
*
* @author Graeme Rocher
*
*/
public class RedisSet extends AbstractRedisCollection implements Set {
public RedisSet(RedisTemplate redisTemplate, String redisKey) {
super(redisTemplate, redisKey);
}
public int size() {
return redisTemplate.getSetOperations().size(redisKey);
}
public boolean contains(Object o) {
//TODO investigate cast
return redisTemplate.getSetOperations().contains(redisKey, (String)o);
}
public Iterator iterator() {
return redisTemplate.getSetOperations().getAll(redisKey).iterator();
}
public boolean add(Object o) {
//TODO investigate cast
return redisTemplate.getSetOperations().add(redisKey, (String)o);
}
public boolean remove(Object o) {
//TODO investigate cast
return redisTemplate.getSetOperations().remove(redisKey, (String)o);
}
public Set<String> members() {
return redisTemplate.getSetOperations().getAll(redisKey);
}
/*
public List<String> members(final int offset, final int max) {
return redisTemplate.sort(redisKey, redisTemplate.sortParams().limit(offset, max));
}*/
public String getRandom() {
return redisTemplate.getSetOperations().getRandom(redisKey);
}
public boolean removeRandom() {
return redisTemplate.getSetOperations().removeRandom(redisKey);
}
void intersection(RedisSet... redisSets) {
//storeIntersectionOfSets..
}
void union(RedisSet... redisSets) {
//storeUnionOfSets
}
void difference(RedisSet... redisSets) {
}
//consider methods in google collections such as
// cartesianProduct, filter, powerSet, symmetricDifference, newRedisSet
//TODO move to another set
//
}

View File

@@ -0,0 +1,18 @@
package org.springframework.datastore.redis.util;
import org.springframework.datastore.redis.core.RedisTemplate;
public class Sets {
protected RedisTemplate redisTemplate;
public Sets(RedisTemplate redisTemplate) {
this.redisTemplate = redisTemplate;
}
//TODO what key to assing?
}

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<description>Example configuration to get you started.</description>
<bean id="service" class="org.springframework.datastore.ExampleService" />
</beans>

View File

@@ -0,0 +1,105 @@
/*
* Copyright 2002-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 static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.io.IOException;
import java.util.Map;
import junit.framework.Assert;
import org.junit.After;
import org.junit.Test;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import redis.clients.jedis.JedisException;
public abstract class AbstractClientIntegrationTests {
protected RedisClient client;
@After
public void tearDown() throws IOException {
client.disconnect();
}
@Test
public void save() {
String status = client.save();
assertEquals("OK", status);
}
@Test
public void bgsave() {
try {
String status = client.bgsave();
assertEquals("Background saving started", status);
} catch (InvalidDataAccessApiUsageException e) {
assertEquals("ERR Background save already in progress",
e.getMessage());
}
}
@Test
public void bgrewriteaof() {
String status = client.bgrewriteaof();
assertEquals("Background append only file rewriting started", status);
}
@Test
public void lastsave() throws InterruptedException {
int before = client.lastsave();
String st = "";
while (!st.equals("OK")) {
try {
Thread.sleep(1000);
st = client.save();
} catch (JedisException e) {
}
}
int after = client.lastsave();
assertTrue((after - before) > 0);
}
@Test
public void info() {
Map<String,String> infoResponse = client.info();
Assert.assertNotNull(infoResponse);
Assert.assertTrue(infoResponse.containsKey("redis_version"));
//Map<String, String> infoResponse = client.info();
//Assert.assertTrue("Expected non empty map of info about the server.", infoResponse.size() > 0);
//Assert.assertTrue("Expected key 'redis_version' in map of info about the server.",
// infoResponse.containsKey("redis_version"));
}
@Test
public void setAndGet() {
client.set("foo", "blah blah");
String value = client.get("foo");
Assert.assertEquals("blah blah", value);
}
@Test
public void conversions() {
Person p = new Person("Joe", "Trader", 33);
}
}

View File

@@ -0,0 +1,96 @@
package org.springframework.datastore.redis.core;
/*
* Copyright 2002-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.
*/
import java.io.Serializable;
public class Person implements Serializable {
private String firstName;
private String lastName;
private int age;
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Person(String firstName, String lastName, int age) {
super();
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
}
@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());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Person other = (Person) obj;
if (age != other.age)
return false;
if (firstName == null) {
if (other.firstName != null)
return false;
} else if (!firstName.equals(other.firstName))
return false;
if (lastName == null) {
if (other.lastName != null)
return false;
} else if (!lastName.equals(other.lastName))
return false;
return true;
}
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright 2002-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 org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.springframework.datastore.redis.core.jredis.JRedisClientFactory;
public class RedisTemplateIntegrationTests {
RedisTemplate template;
@Before
public void setUp() {
template = new RedisTemplate(new JRedisClientFactory());
}
@Test
public void conversions() {
Person p = new Person("Joe", "Trader", 33);
template.convertAndSet("trader:1", p);
Person samePerson = template.getAndConvert("trader:1", Person.class);
Assert.assertEquals(p, samePerson);
}
}

View File

@@ -0,0 +1,36 @@
/*
* Copyright 2002-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.jedis;
import org.junit.Before;
import org.springframework.datastore.redis.core.AbstractClientIntegrationTests;
import org.springframework.datastore.redis.core.RedisClientFactory;
public class JedisRedisClientIntegrationTests extends
AbstractClientIntegrationTests {
@Before
public void setUp() {
RedisClientFactory clientFactory = new JedisClientFactory();
clientFactory.setPassword("foobared");
client = clientFactory.createClient();
client.flushAll();
}
}

View File

@@ -0,0 +1,33 @@
/*
* Copyright 2002-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.jredis;
import org.junit.Before;
import org.springframework.datastore.redis.core.AbstractClientIntegrationTests;
import org.springframework.datastore.redis.core.RedisClientFactory;
public class JRedisClientIntegrationTests extends AbstractClientIntegrationTests {
@Before
public void setUp() {
RedisClientFactory clientFactory = new JRedisClientFactory();
clientFactory.setPassword("foobared");
client = clientFactory.createClient();
}
}

View File

@@ -0,0 +1,13 @@
log4j.rootCategory=INFO, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - <%m>%n
log4j.category.org.apache.activemq=ERROR
log4j.category.org.springframework.batch=DEBUG
log4j.category.org.springframework.transaction=INFO
log4j.category.org.hibernate.SQL=DEBUG
# for debugging datasource initialization
# log4j.category.test.jdbc=DEBUG

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<import resource="classpath:/META-INF/spring/app-context.xml"/>
</beans>

View File

@@ -11,10 +11,15 @@ Import-Template:
org.springframework.util.*;version="[3.0.0, 4.0.0)",
org.springframework.data.core.*;version="[1.0.0, 2.0.0)",
org.springframework.datastore.core.*;version="[1.0.0, 2.0.0)",
org.springframework.datastore.*;version="[1.0.0, 2.0.0)",
org.springframework.datastore.persistence.*;version="[1.0.0, 2.0.0)",
org.springframework.datastore.document.*;version="[1.0.0, 2.0.0)",
org.aopalliance.*;version="[1.0.0, 2.0.0)";resolution:=optional,
org.apache.commons.logging.*;version="[1.1.1, 2.0.0)",
org.w3c.dom.*;version="0"
org.w3c.dom.*;version="0",
org.jredis.*;version="[1.0.0, 2.0.0)",
org.jredis.ri.alphazero.*;version="[1.0.0, 2.0.0)",
org.springframework.commons.serializer.*;version="[1.0.0, 2.0.0)",
redis.clients.jedis.*;version="[1.0.0, 2.0.0)",
redis.clients.util.*;version="[1.0.0, 2.0.0)",