+ connection implementations mainly finished

+ aggregated cached vs non-cached jedis strategies
+ added more exception translations
This commit is contained in:
Costin Leau
2010-11-03 18:21:54 +02:00
parent e63ce9115c
commit 20dc9566ad
14 changed files with 695 additions and 883 deletions

View File

@@ -1,35 +1,35 @@
/*
* 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 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);
}
}
/*
* 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 org.springframework.dao.DataAccessResourceFailureException;
/**
* Fatal exception thrown when the Redis connection fails completely.
*
* @author Mark Pollack
*/
public class RedisConnectionFailureException extends DataAccessResourceFailureException {
public RedisConnectionFailureException(String msg) {
super(msg);
}
public RedisConnectionFailureException(String msg, Throwable cause) {
super(msg, cause);
}
}

View File

@@ -0,0 +1,56 @@
/*
* 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.connection;
import java.util.EnumSet;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* Enumeration of the Redis data types.
*
* @author Costin Leau
*/
public enum DataType {
NONE("none"), STRING("string"), LIST("list"), SET("set"), ZSET("zset"), HASH("hash");
private static final Map<String, DataType> codeLookup = new ConcurrentHashMap<String, DataType>(6);
static {
for (DataType type : EnumSet.allOf(DataType.class))
codeLookup.put(type.code, type);
}
private final String code;
DataType(String name) {
this.code = name;
}
public String code() {
return code;
}
public static DataType fromCode(String code) {
DataType data = codeLookup.get(code);
if (data == null)
throw new IllegalArgumentException("unknown data type code");
return data;
}
}

View File

@@ -29,7 +29,7 @@ public interface RedisCommands {
int del(String... keys);
DataTypes type(String key);
DataType type(String key);
Collection<String> keys(String pattern);

View File

@@ -24,7 +24,8 @@ import org.springframework.datastore.redis.UncategorizedRedisException;
*
* @author Costin Leau
*/
public interface RedisConnection extends RedisCommands {
public interface RedisConnection<T> extends RedisCommands, RedisHashCommands, RedisListCommands, RedisSetCommands,
RedisStringCommands, RedisZSetCommands {
/**
* Close (or quit) the connection.
@@ -35,5 +36,7 @@ public interface RedisConnection extends RedisCommands {
boolean isClosed();
<T> T getNativeConnection();
T getNativeConnection();
String getCharset();
}

View File

@@ -16,12 +16,15 @@
package org.springframework.datastore.redis.core.connection;
import org.springframework.dao.support.PersistenceExceptionTranslator;
/**
* Enumeration of the Redis data types.
* Thread-safe factory of Redis connections. Additionally performs exception translation
* between the underlying Redis client library and Spring DAO exceptions.
*
* @author Costin Leau
*/
public enum DataTypes {
public interface RedisConnectionFactory extends PersistenceExceptionTranslator {
NONE, STRING, LIST, SET, ZSET, HASH;
RedisConnection<?> getConnection();
}

View File

@@ -17,7 +17,7 @@
package org.springframework.datastore.redis.core.connection;
/**
* String specific commands supported by Redis .
* String specific commands supported by Redis.
*
* @author Costin Leau
*/

View File

@@ -0,0 +1,295 @@
/*
* 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.connection.jedis;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Collection;
import org.springframework.dao.DataAccessException;
import org.springframework.datastore.keyvalue.UncategorizedKeyvalueStoreException;
import org.springframework.datastore.redis.UncategorizedRedisException;
import org.springframework.datastore.redis.core.connection.DataType;
import org.springframework.datastore.redis.core.connection.RedisConnection;
import org.springframework.util.ReflectionUtils;
import redis.clients.jedis.Client;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisException;
/**
* Jedis based {@link RedisConnection}.
*
* @author Costin Leau
*/
public class JedisConnection implements RedisConnection<Jedis> {
private static final Field CLIENT_FIELD;
static {
CLIENT_FIELD = ReflectionUtils.findField(Jedis.class, "client", Client.class);
ReflectionUtils.makeAccessible(CLIENT_FIELD);
}
private final Jedis jedis;
private final Client client;
public JedisConnection(Jedis jedis) {
this.jedis = jedis;
// extract underlying client for batch operations
client = (Client) ReflectionUtils.getField(CLIENT_FIELD, jedis);
}
protected DataAccessException convertJedisAccessException(Exception ex) {
if (ex instanceof JedisException) {
return JedisUtils.convertJedisAccessException((JedisException) ex);
}
if (ex instanceof IOException) {
return JedisUtils.convertJedisAccessException((IOException) ex);
}
throw new UncategorizedKeyvalueStoreException("Unknown jedis exception", ex);
}
@Override
public void close() throws UncategorizedRedisException {
try {
jedis.disconnect();
jedis.quit();
} catch (Exception ex) {
throw convertJedisAccessException(ex);
}
}
@Override
public String getCharset() {
return "UTF-8";
}
@Override
public Jedis getNativeConnection() {
return jedis;
}
@Override
public boolean isClosed() {
try {
return !jedis.isConnected();
} catch (Exception ex) {
throw convertJedisAccessException(ex);
}
}
@Override
public int dbSize() {
try {
return jedis.dbSize();
} catch (Exception ex) {
throw convertJedisAccessException(ex);
}
}
@Override
public int del(String... keys) {
try {
return jedis.del(keys);
} catch (Exception ex) {
throw convertJedisAccessException(ex);
}
}
@Override
public void discard() {
try {
client.discard();
} catch (Exception ex) {
throw convertJedisAccessException(ex);
}
}
@Override
public void exec() {
try {
client.exec();
} catch (Exception ex) {
throw convertJedisAccessException(ex);
}
}
@Override
public boolean exists(String key) {
try {
return (jedis.exists(key) == 1);
} catch (Exception ex) {
throw convertJedisAccessException(ex);
}
}
@Override
public boolean expire(String key, long seconds) {
try {
return (jedis.expire(key, (int) seconds) == 1);
} catch (Exception ex) {
throw convertJedisAccessException(ex);
}
}
@Override
public Collection<String> keys(String pattern) {
try {
return (jedis.keys(pattern));
} catch (Exception ex) {
throw convertJedisAccessException(ex);
}
}
@Override
public void multi() {
try {
jedis.multi();
} catch (Exception ex) {
throw convertJedisAccessException(ex);
}
}
@Override
public boolean persist(String key) {
try {
return (jedis.persist(key) == 1);
} catch (Exception ex) {
throw convertJedisAccessException(ex);
}
}
@Override
public String randomKey() {
try {
return jedis.randomKey();
} catch (Exception ex) {
throw convertJedisAccessException(ex);
}
}
@Override
public boolean rename(String oldName, String newName) {
try {
return (JedisUtils.OK_CODE.equals(jedis.rename(oldName, newName)));
} catch (Exception ex) {
throw convertJedisAccessException(ex);
}
}
@Override
public boolean renameNx(String oldName, String newName) {
try {
return (JedisUtils.OK_CODE.equals(jedis.renamenx(oldName, newName)));
} catch (Exception ex) {
throw convertJedisAccessException(ex);
}
}
@Override
public void select(int dbIndex) {
try {
jedis.select(dbIndex);
} catch (Exception ex) {
throw convertJedisAccessException(ex);
}
}
@Override
public int ttl(String key) {
try {
return jedis.ttl(key);
} catch (Exception ex) {
throw convertJedisAccessException(ex);
}
}
@Override
public DataType type(String key) {
try {
return DataType.fromCode(jedis.type(key));
} catch (Exception ex) {
throw convertJedisAccessException(ex);
}
}
@Override
public void unwatch() {
try {
jedis.unwatch();
} catch (Exception ex) {
throw convertJedisAccessException(ex);
}
}
@Override
public void watch(String... keys) {
try {
for (String key : keys) {
jedis.watch(key);
}
} catch (Exception ex) {
throw convertJedisAccessException(ex);
}
}
@Override
public int hSet(String key, String field, String value) {
try {
return jedis.hset(key, field, value);
} catch (Exception ex) {
throw convertJedisAccessException(ex);
}
}
@Override
public int lPush(String key, String value) {
try {
return jedis.lpush(key, value);
} catch (Exception ex) {
throw convertJedisAccessException(ex);
}
}
@Override
public int rPush(String key, String value) {
try {
return jedis.rpush(key, value);
} catch (Exception ex) {
throw convertJedisAccessException(ex);
}
}
@Override
public String get(String key) {
try {
return jedis.get(key);
} catch (Exception ex) {
throw convertJedisAccessException(ex);
}
}
@Override
public void set(String key, String value) {
try {
jedis.set(key, value);
} catch (Exception ex) {
throw convertJedisAccessException(ex);
}
}
}

View File

@@ -0,0 +1,235 @@
/*
* 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.connection.jedis;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.concurrent.TimeoutException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.dao.DataAccessException;
import org.springframework.datastore.redis.core.connection.RedisConnection;
import org.springframework.datastore.redis.core.connection.RedisConnectionFactory;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisShardInfo;
/**
* Connection factory using Jedis underneath.
*
* @author Costin Leau
*/
public class JedisConnectionFactory implements InitializingBean, DisposableBean, RedisConnectionFactory {
private final static Log log = LogFactory.getLog(JedisConnectionFactory.class);
private JedisShardInfo shardInfo;
private String password;
private int timeout;
private boolean usePool = true;
private JedisPool pool = null;
// taken from Jedis code
private int poolSize = 10;
/**
* Constructs a new <code>JedisConnectionFactory</code> instance.
*/
public JedisConnectionFactory() {
this(getDefaultHostName());
}
/**
* Constructs a new <code>JedisConnectionFactory</code> instance.
*
* @param hostname
*/
public JedisConnectionFactory(String hostName) {
Assert.hasText(hostName);
shardInfo = new JedisShardInfo(hostName);
}
/**
* Constructs a new <code>JedisConnectionFactory</code> instance.
*
* @param hostname
* @param port
*/
public JedisConnectionFactory(String hostName, int port) {
shardInfo = new JedisShardInfo(hostName, port);
}
/**
* Constructs a new <code>JedisConnectionFactory</code> instance.
*
* @param shardInfo
*/
public JedisConnectionFactory(JedisShardInfo shardInfo) {
this.shardInfo = shardInfo;
}
/**
* Returns a Jedis instance to be used as a Redis connection.
* The instance can be newly created or retrieved from a pool.
*
* @return Jedis instance ready for wrapping into a {@link RedisConnection}.
*/
protected Jedis fetchJedisConnector() {
try {
if (usePool) {
return pool.getResource();
}
return new Jedis(getShardInfo());
} catch (TimeoutException ex) {
throw JedisUtils.convertJedisAccessException(ex);
}
}
public void afterPropertiesSet() {
if (StringUtils.hasLength(password)) {
shardInfo.setPassword(password);
}
if (timeout > 0) {
shardInfo.setTimeout(timeout);
}
if (usePool) {
int size = getPoolSize();
pool = new JedisPool(shardInfo);
pool.setResourcesNumber(size);
}
}
public void destroy() throws Exception {
// TODO: should this component do tracking of all returned connections
// normally not but then again we're the ones creating the connections
// so we end up behaving like a pool
}
public JedisConnection getConnection() {
return new JedisConnection(fetchJedisConnector());
}
@Override
public DataAccessException translateExceptionIfPossible(RuntimeException ex) {
return JedisUtils.convertJedisAccessException(ex);
}
private static String getDefaultHostName() {
String temp;
try {
InetAddress localMachine = InetAddress.getLocalHost();
temp = localMachine.getHostName();
if (log.isDebugEnabled())
log.debug("Using hostname [" + temp + "] for hostname.");
} catch (UnknownHostException e) {
log.warn("Could not get host name, using 'localhost' as default value", e);
temp = "localhost";
}
return temp;
}
/**
* @return the password
*/
public String getPassword() {
return password;
}
/**
* @param password the password to set
*/
public void setPassword(String password) {
this.password = password;
}
/**
* Returns the shardInfo.
*
* @return Returns the shardInfo
*/
public JedisShardInfo getShardInfo() {
return shardInfo;
}
/**
* @param shardInfo The shardInfo to set.
*/
public void setShardInfo(JedisShardInfo shardInfo) {
this.shardInfo = shardInfo;
}
/**
* Returns the timeout.
*
* @return Returns the timeout
*/
public int getTimeout() {
return timeout;
}
/**
* @param timeout The timeout to set.
*/
public void setTimeout(int timeout) {
this.timeout = timeout;
}
/**
* Indicates the use of a connection pool.
*
* @return Returns the use of connection pooling.
*/
public boolean isPooling() {
return usePool;
}
/**
* Turns on or off the use of connection pooling.
*
* @param usePool The usePool to set.
*/
public void setPooling(boolean usePool) {
this.usePool = usePool;
}
/**
* Returns the poolSize.
*
* @return Returns the poolSize
*/
public int getPoolSize() {
return poolSize;
}
/**
* @param poolSize The poolSize to set.
*/
public void setPoolSize(int poolSize) {
Assert.isTrue(poolSize > 0, "pool size needs to be bigger then zero");
this.poolSize = poolSize;
usePool = true;
}
}

View File

@@ -0,0 +1,61 @@
/*
* 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.connection.jedis;
import java.io.IOException;
import java.net.UnknownHostException;
import java.util.concurrent.TimeoutException;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.datastore.redis.RedisConnectionFailureException;
import org.springframework.datastore.redis.UncategorizedRedisException;
import redis.clients.jedis.JedisException;
/**
* Helper class featuring methods for Jedis connection handling, providing support for exception translation.
*
* @author Costin Leau
*/
public abstract class JedisUtils {
public static final String OK_CODE = "OK";
public static DataAccessException convertJedisAccessException(JedisException ex) {
return new InvalidDataAccessApiUsageException(ex.getMessage(), ex);
}
public static DataAccessException convertJedisAccessException(RuntimeException ex) {
if (ex instanceof JedisException) {
return convertJedisAccessException((JedisException) ex);
}
return new UncategorizedRedisException("Unknown exception", ex);
}
static DataAccessException convertJedisAccessException(IOException ex) {
if (ex instanceof UnknownHostException) {
return new RedisConnectionFailureException("Unknown host " + ex.getMessage(), ex);
}
return new RedisConnectionFailureException("Could not connect to Redis server", ex);
}
static DataAccessException convertJedisAccessException(TimeoutException ex) {
throw new RedisConnectionFailureException("Jedis pool timed out. Could not get Redis Connection", ex);
}
}

View File

@@ -1,111 +0,0 @@
/*
* 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.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

@@ -1,535 +0,0 @@
/*
* 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.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

@@ -1,33 +0,0 @@
/*
* 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.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

@@ -1,123 +0,0 @@
/*
* 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.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.jedis.JedisShardInfo;
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 JedisShardInfo 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(JedisShardInfo shardInfo) {
this.shardInfo = shardInfo;
}
protected JedisShardInfo 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

@@ -1,39 +0,0 @@
/*
* 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.jedis;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.dao.support.PersistenceExceptionTranslator;
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,
PersistenceExceptionTranslator {
public DataAccessException translateException(Exception ex) {
return new InvalidDataAccessApiUsageException(ex.getMessage(), ex);
}
public DataAccessException translateExceptionIfPossible(RuntimeException ex) {
return new InvalidDataAccessApiUsageException(ex.getMessage(), ex);
}
}