
com.bluejeans.redis.client.RedisCollectionClient Maven / Gradle / Ivy
The newest version!
/**
*
*/
package com.bluejeans.redis.client;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;
import org.apache.commons.lang.SerializationUtils;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.Pipeline;
import redis.clients.jedis.Protocol;
/**
* Redis client implementing collections operations
*
* @author Dinesh Ilindra
*/
@Resource
public class RedisCollectionClient {
private static final String[] EMPTY_STRING_ARRAY = new String[0];
public static class CollEntry {
private final String coll, id;
private final T value;
private String parentColl;
private String parentId;
private final boolean indexId;
private final long score;
private long expiryMillis = 0;
/**
* @param coll
* @param id
* @param value
* @param score
*/
public CollEntry(final String coll, final String id, final long score, final T value) {
this(coll, id, score, value, coll, id, true);
}
/**
* @param coll
* @param id
* @param value
* @param score
* @param indexId
*/
public CollEntry(final String coll, final String id, final long score, final T value, final boolean indexId) {
super();
this.coll = coll;
this.id = id;
this.value = value;
this.score = score;
this.indexId = indexId;
}
/**
* @param coll
* @param id
* @param value
* @param parentColl
* @param parentId
* @param score
*/
public CollEntry(final String coll, final String id, final long score, final T value, final String parentColl,
final String parentId) {
this(coll, id, score, value, parentColl, parentId, true);
}
/**
* @param coll
* @param id
* @param value
* @param parentColl
* @param parentId
* @param score
* @param indexId
*/
public CollEntry(final String coll, final String id, final long score, final T value, final String parentColl,
final String parentId, final boolean indexId) {
super();
this.coll = coll;
this.id = id;
this.value = value;
this.parentColl = parentColl;
this.parentId = parentId;
this.score = score;
this.indexId = indexId;
}
public String getColl() {
return coll;
}
public String getId() {
return id;
}
public T getValue() {
return value;
}
public long getScore() {
return score;
}
public String getParentColl() {
return parentColl;
}
public String getParentId() {
return parentId;
}
public boolean isIndexId() {
return indexId;
}
/**
* @return the expiryMillis
*/
public long getExpiryMillis() {
return expiryMillis;
}
public CollEntry withExpiry(final long millis) {
this.expiryMillis = millis;
return this;
}
}
private JedisPool writePool = null;
private JedisPool readPool = null;
private String primaryHost = null;
private String replicaHost = null;
private GenericObjectPoolConfig poolConfig;
private String delim = ":";
private String password, clientName;
private int database = Protocol.DEFAULT_DATABASE;
private int connectionTimeout = Protocol.DEFAULT_TIMEOUT;
private int soTimeout = Protocol.DEFAULT_TIMEOUT;
private Class> dataType;
private String valueOfMethod = "valueOf";
@PostConstruct
public void init() {
if (poolConfig == null) {
poolConfig = new GenericObjectPoolConfig();
}
if (dataType == null) {
dataType = String.class;
}
if (primaryHost != null) {
writePool = createPool(primaryHost);
}
if (replicaHost != null) {
readPool = createPool(replicaHost);
} else {
readPool = writePool;
}
}
@PreDestroy
public void destroy() {
if (writePool != null) {
writePool.destroy();
}
if (readPool != null) {
readPool.destroy();
}
}
private JedisPool createPool(final String redisHost) {
String host = redisHost;
int port = Protocol.DEFAULT_PORT;
if (redisHost.indexOf(':') > 0) {
final String[] info = redisHost.split(":");
host = info[0];
port = Integer.parseInt(info[1]);
}
return new JedisPool(poolConfig, host, port, connectionTimeout, soTimeout, password, database, clientName);
}
public String _get(final String key) {
try (Jedis jedis = readPool.getResource()) {
return jedis.get(key);
}
}
public byte[] _get(final byte[] key) {
try (Jedis jedis = readPool.getResource()) {
return jedis.get(key);
}
}
public List _get(final String... keys) {
if (keys.length > 0) {
try (Jedis jedis = readPool.getResource()) {
return smget(jedis.mget(keys));
}
} else {
return new ArrayList<>();
}
}
public List _get(final byte[]... keys) {
if (keys.length > 0) {
try (Jedis jedis = readPool.getResource()) {
return bmget(jedis.mget(keys));
}
} else {
return new ArrayList<>();
}
}
public void _set(final String key, final String value) {
try (Jedis jedis = writePool.getResource()) {
jedis.set(key, value);
}
}
public void _set(final byte[] key, final byte[] value) {
try (Jedis jedis = writePool.getResource()) {
jedis.set(key, value);
}
}
public void _set(final String key, final long expiryMillis, final String value) {
try (Jedis jedis = writePool.getResource()) {
jedis.set(key, value);
jedis.pexpire(key, expiryMillis);
}
}
public void _set(final byte[] key, final long expiryMillis, final byte[] value) {
try (Jedis jedis = writePool.getResource()) {
jedis.set(key, value);
jedis.pexpire(key, expiryMillis);
}
}
public void _set(final Map data) {
if (!data.isEmpty()) {
final T sample = data.keySet().iterator().next();
try (Jedis jedis = writePool.getResource()) {
final Pipeline pipe = jedis.pipelined();
pipe.multi();
if (sample instanceof byte[]) {
data.forEach((key, value) -> pipe.set((byte[]) key, (byte[]) value));
} else {
data.forEach((key, value) -> pipe.set(key.toString(), value.toString()));
}
pipe.exec();
pipe.sync();
}
}
}
public void _expire(final String key, final long expiryMillis) {
try (Jedis jedis = writePool.getResource()) {
jedis.pexpire(key, expiryMillis);
}
}
public void _expire(final byte[] key, final long expiryMillis) {
try (Jedis jedis = writePool.getResource()) {
jedis.pexpire(key, expiryMillis);
}
}
public void _delete(final String... keys) {
if (keys.length > 0) {
try (Jedis jedis = writePool.getResource()) {
jedis.del(keys);
}
}
}
public void _delete(final byte[]... keys) {
if (keys.length > 0) {
try (Jedis jedis = writePool.getResource()) {
jedis.del(keys);
}
}
}
public void delete(final List keys) {
if (!keys.isEmpty()) {
try (Jedis jedis = writePool.getResource()) {
jedis.del(keys.toArray(EMPTY_STRING_ARRAY));
}
}
}
@SuppressWarnings("unchecked")
private T convert(final byte[] value) {
if (value == null) {
return null;
}
return (T) SerializationUtils.deserialize(value);
}
public T get(final String coll, final String id) {
return get(coll + delim + id);
}
@SuppressWarnings("unchecked")
public T get(final String key) {
try (Jedis jedis = readPool.getResource()) {
if (dataType == byte[].class) {
return (T) jedis.get(key.getBytes());
} else if (dataType == String.class) {
return (T) jedis.get(key);
} else {
return convert(jedis.get(key.getBytes()));
}
}
}
public List smget(final List list) {
list.removeAll(Collections.singleton(null));
return list;
}
public List bmget(final List list) {
list.removeAll(Collections.singleton(null));
return list;
}
public List tmget(final List list) {
list.removeAll(Collections.singleton(null));
return list;
}
@SuppressWarnings("unchecked")
public List get(final List keys) {
if (!keys.isEmpty()) {
try (Jedis jedis = readPool.getResource()) {
if (dataType == byte[].class) {
return (List) bmget(jedis.mget(keys.stream().map(k -> k.getBytes()).toArray(byte[][]::new)));
} else if (dataType == String.class) {
return (List) smget(jedis.mget(keys.toArray(EMPTY_STRING_ARRAY)));
} else {
return tmget(jedis.mget(keys.stream().map(k -> k.getBytes()).toArray(byte[][]::new)).stream()
.map(v -> convert(v)).collect(Collectors.toList()));
}
}
} else {
return new ArrayList<>();
}
}
@SuppressWarnings("unchecked")
public List getMulti(final String coll, final String... ids) {
if (ids.length > 0) {
try (Jedis jedis = readPool.getResource()) {
if (dataType == byte[].class) {
final byte[][] byteKeys = new byte[ids.length][];
for (int index = 0; index < byteKeys.length; index++) {
byteKeys[index] = (coll + delim + ids[index]).getBytes();
}
return (List) bmget(jedis.mget(byteKeys));
} else if (dataType == String.class) {
final String[] keys = new String[ids.length];
for (int index = 0; index < keys.length; index++) {
keys[index] = coll + delim + ids[index];
}
return (List) smget(jedis.mget(keys));
} else {
final byte[][] keys = new byte[ids.length][];
for (int index = 0; index < keys.length; index++) {
keys[index] = (coll + delim + ids[index]).getBytes();
}
return tmget(jedis.mget(keys).stream().map(v -> convert(v)).collect(Collectors.toList()));
}
}
} else {
return new ArrayList<>();
}
}
public List getMulti(final String coll, final List ids) {
return getMulti(coll, ids.toArray(EMPTY_STRING_ARRAY));
}
public void expire(final String coll, final String id, final long expiryMillis) {
_expire(toKey(coll, id), expiryMillis);
}
public String set(final String coll, final String id, final long score, final T value) {
return set(coll, id, score, value, true);
}
public String set(final String coll, final String id, final long score, final T value, final boolean indexId) {
try (Jedis jedis = writePool.getResource()) {
final String key = coll + delim + id;
if (dataType == byte[].class) {
jedis.set(key.getBytes(), (byte[]) value);
} else if (dataType == String.class) {
jedis.set(key, String.valueOf(value));
} else {
jedis.set(key.getBytes(), SerializationUtils.serialize(value));
}
if (indexId) {
jedis.zadd(coll + "_ids", score, id);
}
return key;
}
}
public void setParent(final String coll, final String id, final long score, final String parentColl,
final String parentId) {
try (Jedis jedis = writePool.getResource()) {
jedis.sadd(parentColl + "_childs", coll);
jedis.sadd(coll + "_parents", parentColl);
jedis.zadd(parentColl + "_children" + delim + parentId + delim + coll, score, id);
jedis.set(coll + "_parent" + delim + id + delim + parentColl, parentId);
}
}
public List set(final List> data) {
try (Jedis jedis = writePool.getResource()) {
final List keys = new ArrayList<>();
final Pipeline pipe = jedis.pipelined();
pipe.multi();
for (final CollEntry ce : data) {
final String key = ce.coll + delim + ce.id;
keys.add(key);
if (ce.value instanceof byte[]) {
pipe.set(key.getBytes(), (byte[]) ce.value);
} else if (ce.value instanceof String) {
pipe.set(key, String.valueOf(ce.value));
} else {
pipe.set(key.getBytes(), SerializationUtils.serialize(ce.value));
}
if (ce.indexId) {
pipe.zadd(ce.coll + "_ids", ce.score, ce.id);
}
if (ce.getParentColl() != null) {
pipe.sadd(ce.parentColl + "_childs", ce.coll);
pipe.sadd(ce.coll + "_parents", ce.parentColl);
pipe.zadd(ce.parentColl + "_children" + delim + ce.parentId + delim + ce.coll, ce.score, ce.id);
pipe.set(ce.coll + "_parent" + delim + ce.id + delim + ce.parentColl, ce.parentId);
}
if (ce.expiryMillis > 0) {
pipe.pexpire(key, ce.expiryMillis);
}
}
pipe.exec();
pipe.sync();
return keys;
}
}
public String set(final String coll, final String id, final long score, final T value, final String parentColl,
final String parentId) {
return set(coll, id, score, value, parentColl, parentId, true);
}
public String set(final String coll, final String id, final long score, final T value, final String parentColl,
final String parentId, final boolean indexId) {
setParent(coll, id, score, parentColl, parentId);
return set(coll, id, score, value, indexId);
}
public long getCount(final String coll) {
try (Jedis jedis = readPool.getResource()) {
return jedis.zcard(coll + "_ids");
}
}
public List getAll(final String coll, final int offset, final int limit) {
return getAll(coll, offset, limit, false);
}
public List getAll(final String coll, final int offset, final int limit, final boolean desc) {
return get(getAllIds(coll, offset, limit, desc, true));
}
public List getAllIds(final String coll, final int offset, final int limit) {
return getAllIds(coll, offset, limit, false, false);
}
public List getAllIds(final String coll, final int offset, final int limit, final boolean desc,
final boolean withCollNames) {
int end = offset + limit - 1;
if (limit < 0) {
end = -1;
}
try (Jedis jedis = readPool.getResource()) {
Set ids = null;
if (desc) {
ids = jedis.zrevrange(coll + "_ids", offset, end);
} else {
ids = jedis.zrange(coll + "_ids", offset, end);
}
if (ids.isEmpty()) {
return new ArrayList();
}
return ids.stream().map(id -> withCollNames ? coll + delim + id : id).collect(Collectors.toList());
}
}
public String getParentId(final String coll, final String id, final String parentColl) {
try (Jedis jedis = readPool.getResource()) {
return jedis.get(coll + "_parent" + delim + id + delim + parentColl);
}
}
@SuppressWarnings("unchecked")
public T getParent(final String coll, final String id, final String parentColl) {
try (Jedis jedis = readPool.getResource()) {
if (dataType == byte[].class) {
return (T) jedis.get((parentColl + delim + getParentId(coll, id, parentColl)).getBytes());
} else if (dataType == String.class) {
return (T) jedis.get(parentColl + delim + getParentId(coll, id, parentColl));
} else {
return convert(jedis.get(parentColl + delim + getParentId(coll, id, parentColl)).getBytes());
}
}
}
public Set getParentColls(final String coll) {
try (Jedis jedis = readPool.getResource()) {
return jedis.zrange(coll + "_parents", 0, -1);
}
}
public Set getChildColls(final String coll) {
try (Jedis jedis = readPool.getResource()) {
return jedis.zrange(coll + "_childs", 0, -1);
}
}
public long getChildCount(final String coll, final String childColl, final String id) {
try (Jedis jedis = readPool.getResource()) {
return jedis.zcard(coll + "_children" + delim + id + delim + childColl);
}
}
public List getChilds(final String parentColl, final String childColl, final String parentId, final int offset,
final int limit) {
return getChilds(parentColl, childColl, parentId, offset, limit, false);
}
public List getChilds(final String parentColl, final String childColl, final String parentId, final int offset,
final int limit, final boolean desc) {
return get(getChildIds(parentColl, childColl, parentId, offset, limit, desc));
}
public List getChildIds(final String parentColl, final String childColl, final String parentId,
final int offset, final int limit) {
return getChildIds(parentColl, childColl, parentId, offset, limit, false);
}
public List getChildIds(final String parentColl, final String childColl, final String parentId,
final int offset, final int limit, final boolean desc) {
int end = offset + limit - 1;
if (limit < 0) {
end = -1;
}
try (Jedis jedis = readPool.getResource()) {
Set ids = null;
if (desc) {
ids = jedis.zrevrange(parentColl + "_children" + delim + parentId + delim + childColl, offset, end);
} else {
ids = jedis.zrange(parentColl + "_children" + delim + parentId + delim + childColl, offset, end);
}
if (ids.isEmpty()) {
return new ArrayList();
}
return ids.stream().map(id -> childColl + delim + id).collect(Collectors.toList());
}
}
public void delete(final String coll, final String id) {
delete(coll, id, false);
}
public void delete(final String coll, final String id, final long expireMillis) {
delete(coll, id, false, expireMillis);
}
public void delete(final String coll, final String id, final boolean deleteChildren) {
delete(coll, id, deleteChildren, -1);
}
public void delete(final String coll, final String id, final boolean deleteChildren, final long expireMillis) {
try (Jedis jedis = writePool.getResource()) {
if (expireMillis <= 0) {
jedis.del(coll + delim + id);
} else {
jedis.pexpire(coll + delim + id, expireMillis);
}
jedis.zrem(coll + "_ids", id);
final Set parentColls = jedis.smembers(coll + "_parents");
parentColls.forEach(parentColl -> jedis
.zrem(parentColl + "_children" + delim + getParentId(coll, id, parentColl) + delim + coll, id));
parentColls.forEach(parentColl -> jedis.del(coll + "_parent" + delim + id + delim + parentColl));
final Set childColls = jedis.smembers(coll + "_childs");
if (deleteChildren) {
delete(childColls.stream()
.map(childColl -> jedis.zrange(coll + "_children" + delim + id + delim + childColl, 0, -1)
.stream().map(cid -> childColl + delim + cid))
.flatMap(x -> x).collect(Collectors.toList()));
childColls.forEach(childColl -> jedis.zrem(childColl + "_ids",
jedis.zrange(coll + "_children" + delim + id + delim + childColl, 0, -1)
.toArray(EMPTY_STRING_ARRAY)));
delete(childColls.stream().map(childColl -> coll + "_children" + delim + id + delim + childColl)
.collect(Collectors.toList()));
}
}
}
public void clear(final String coll) {
delete(getAllIds(coll, 0, -1));
}
public String toKey(final String coll, final String id) {
return coll + delim + id;
}
public String[] fromKey(final String key) {
return key.split(delim, 2);
}
/**
* @return the primaryHost
*/
public String getPrimaryHost() {
return primaryHost;
}
/**
* @param primaryHost
* the primaryHost to set
*/
public void setPrimaryHost(final String primaryHost) {
this.primaryHost = primaryHost;
}
/**
* @return the replicaHost
*/
public String getReplicaHost() {
return replicaHost;
}
/**
* @param replicaHost
* the replicaHost to set
*/
public void setReplicaHost(final String replicaHost) {
this.replicaHost = replicaHost;
}
public GenericObjectPoolConfig getPoolConfig() {
return poolConfig;
}
public void setPoolConfig(final GenericObjectPoolConfig poolConfig) {
this.poolConfig = poolConfig;
}
public String getDelim() {
return delim;
}
public void setDelim(final String delim) {
this.delim = delim;
}
public JedisPool getPool() {
return writePool;
}
public String getPassword() {
return password;
}
public void setPassword(final String password) {
this.password = password;
}
public String getClientName() {
return clientName;
}
public void setClientName(final String clientName) {
this.clientName = clientName;
}
public int getDatabase() {
return database;
}
public void setDatabase(final int database) {
this.database = database;
}
public int getConnectionTimeout() {
return connectionTimeout;
}
public void setConnectionTimeout(final int connectionTimeout) {
this.connectionTimeout = connectionTimeout;
}
public int getSoTimeout() {
return soTimeout;
}
public void setSoTimeout(final int soTimeout) {
this.soTimeout = soTimeout;
}
public Class> getDataType() {
return dataType;
}
public void setDataType(final Class> dataType) {
this.dataType = dataType;
}
public String getValueOfMethod() {
return valueOfMethod;
}
public void setValueOfMethod(final String valueOfMethod) {
this.valueOfMethod = valueOfMethod;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy