package org.ff4j.store;
import org.ff4j.exception.PropertyAlreadyExistException;
import org.ff4j.property.Property;
import org.ff4j.property.store.AbstractPropertyStore;
import org.ff4j.redis.RedisConnection;
import org.ff4j.utils.Util;
import org.ff4j.utils.json.PropertyJsonParser;
import redis.clients.jedis.Jedis;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import static org.ff4j.redis.RedisContants.KEY_PROPERTY;
import static org.ff4j.redis.RedisContants.KEY_PROPERTY_MAP;
/*
* #%L
* ff4j-store-redis
* %%
* Copyright (C) 2013 - 2016 FF4J
* %%
* 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.
* #L%
*/
/**
* Implementation of property store for REDIS.
*
* @author Cedrick Lunven (@clunven)</a>
* @author Shridhar Navanageri
*/
public class PropertyStoreRedis extends AbstractPropertyStore {
/**
* Wrapping of redis connection (isolation).
*/
private RedisConnection redisConnection;
/**
* Default Constructor.
*/
public PropertyStoreRedis() {
this(new RedisConnection());
}
/**
* Contact remote redis server.
*/
public PropertyStoreRedis(RedisConnection pRedisConnection) {
redisConnection = pRedisConnection;
}
/**
* Default Constructor.
*/
public PropertyStoreRedis(String xmlFeaturesfFile) {
this();
importPropertiesFromXmlFile(xmlFeaturesfFile);
}
/**
* Contact remote redis server.
*
* @param host target redis host
* @param port target redis port
*/
public PropertyStoreRedis(String host, int port) {
this(new RedisConnection(host, port));
}
/**
* Contact remote redis server.
*
* @param host target redis host
* @param port target redis port
*/
public PropertyStoreRedis(String host, int port, String password, String xmlFeaturesfFile) {
this(new RedisConnection(host, port, password));
importPropertiesFromXmlFile(xmlFeaturesfFile);
}
/**
* Contact remote redis server.
*
* @param host target redis host
* @param port target redis port
*/
public PropertyStoreRedis(String host, int port, String xmlFeaturesfFile) {
this(host, port);
importPropertiesFromXmlFile(xmlFeaturesfFile);
}
/**
* {@inheritDoc}
*/
public boolean existProperty(String name) {
Util.assertParamHasLength(name, "PropertyName identifier");
Jedis jedis = null;
try {
jedis = getJedis();
return jedis.exists(KEY_PROPERTY + name);
} finally {
if (jedis != null) {
jedis.close();
}
}
}
/**
* {@inheritDoc}
*/
public <T> void createProperty(Property<T> prop) {
Util.assertNotNull(prop);
if (existProperty(prop.getName())) {
throw new PropertyAlreadyExistException(prop.getName());
}
Jedis jedis = null;
try {
jedis = getJedis();
String name = prop.getName();
// Store the feature in the mapping bucket.
jedis.sadd(KEY_PROPERTY_MAP, name);
jedis.set(KEY_PROPERTY + name, prop.toJson());
jedis.persist(KEY_PROPERTY + name);
} finally {
if (jedis != null) {
jedis.close();
}
}
}
/**
* {@inheritDoc}
*/
public Property<?> readProperty(String name) {
assertPropertyExist(name);
Jedis jedis = null;
try {
jedis = getJedis();
return PropertyJsonParser.parseProperty(jedis.get(KEY_PROPERTY + name));
} finally {
if (jedis != null) {
jedis.close();
}
}
}
/**
* {@inheritDoc}
*/
public void deleteProperty(String name) {
assertPropertyExist(name);
Jedis jedis = null;
try {
jedis = getJedis();
jedis.srem(KEY_PROPERTY_MAP, name);
jedis.del(KEY_PROPERTY + name);
} finally {
if (jedis != null) {
jedis.close();
}
}
}
/**
* {@inheritDoc}
*/
public Map<String, Property<?>> readAllProperties() {
LinkedHashMap<String, Property<?>> mapP = new LinkedHashMap<String, Property<?>>();
Jedis jedis = null;
try {
jedis = getJedis();
Set<String> properties = jedis.smembers(KEY_PROPERTY_MAP);
if (properties != null) {
for (String key : properties) {
mapP.put(key, readProperty(key));
}
}
return mapP;
} finally {
if (jedis != null) {
jedis.close();
}
}
}
/**
* {@inheritDoc}
*/
public Set<String> listPropertyNames() {
Jedis jedis = null;
try {
jedis = getJedis();
Set<String> propertyNames = jedis.smembers(KEY_PROPERTY_MAP);
return propertyNames;
} finally {
if (jedis != null) {
jedis.close();
}
}
}
/**
* {@inheritDoc}
*/
public void clear() {
Jedis jedis = null;
try {
jedis = getJedis();
Set<String> myKeys = jedis.smembers(KEY_PROPERTY_MAP);
for (String key : myKeys) {
deleteProperty(key);
}
} finally {
if (jedis != null) {
jedis.close();
}
}
}
/**
* Getter accessor for attribute 'redisConnection'.
*
* @return current value of 'redisConnection'
*/
public RedisConnection getRedisConnection() {
return redisConnection;
}
/**
* Setter accessor for attribute 'redisConnection'.
*
* @param redisConnection new value for 'redisConnection '
*/
public void setRedisConnection(RedisConnection redisConnection) {
this.redisConnection = redisConnection;
}
/**
* Safe acces to Jedis, avoid JNPE.
*
* @return
*/
public Jedis getJedis() {
if (redisConnection == null) {
throw new IllegalArgumentException("Cannot found any redisConnection");
}
Jedis jedis = redisConnection.getJedis();
if (jedis == null) {
throw new IllegalArgumentException("Cannot found any jedis connection, please build connection");
}
return jedis;
}
}