Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.impetus.client.redis.RedisClient Maven / Gradle / Ivy
/*******************************************************************************
* * Copyright 2012 Impetus Infotech.
* *
* * 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 com.impetus.client.redis;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import javax.persistence.PersistenceException;
import javax.persistence.metamodel.Attribute;
import javax.persistence.metamodel.EmbeddableType;
import javax.persistence.metamodel.EntityType;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Pipeline;
import redis.clients.jedis.Response;
import redis.clients.jedis.Transaction;
import redis.clients.jedis.exceptions.JedisConnectionException;
import com.impetus.client.redis.RedisQueryInterpreter.Clause;
import com.impetus.kundera.Constants;
import com.impetus.kundera.PersistenceProperties;
import com.impetus.kundera.client.Client;
import com.impetus.kundera.client.ClientBase;
import com.impetus.kundera.client.ClientPropertiesSetter;
import com.impetus.kundera.client.EnhanceEntity;
import com.impetus.kundera.db.RelationHolder;
import com.impetus.kundera.generator.SequenceGenerator;
import com.impetus.kundera.graph.Node;
import com.impetus.kundera.lifecycle.states.RemovedState;
import com.impetus.kundera.metadata.KunderaMetadataManager;
import com.impetus.kundera.metadata.model.EntityMetadata;
import com.impetus.kundera.metadata.model.KunderaMetadata;
import com.impetus.kundera.metadata.model.MetamodelImpl;
import com.impetus.kundera.metadata.model.PersistenceUnitMetadata;
import com.impetus.kundera.metadata.model.SequenceGeneratorDiscriptor;
import com.impetus.kundera.metadata.model.attributes.AbstractAttribute;
import com.impetus.kundera.persistence.EntityReader;
import com.impetus.kundera.persistence.KunderaTransactionException;
import com.impetus.kundera.persistence.TransactionBinder;
import com.impetus.kundera.persistence.TransactionResource;
import com.impetus.kundera.persistence.api.Batcher;
import com.impetus.kundera.persistence.context.jointable.JoinTableData;
import com.impetus.kundera.property.PropertyAccessorFactory;
import com.impetus.kundera.property.PropertyAccessorHelper;
import com.impetus.kundera.property.accessor.ObjectAccessor;
import com.impetus.kundera.utils.KunderaCoreUtils;
/**
* Redis client implementation for REDIS.
*
* @author vivek.mishra
*/
public class RedisClient extends ClientBase implements Client, Batcher, ClientPropertiesSetter,
TransactionBinder, SequenceGenerator
{
/**
* Reference to redis client factory.
*/
private RedisClientFactory factory;
private EntityReader reader;
private Map settings;
/** list of nodes for batch processing. */
private List nodes = new ArrayList();
private TransactionResource resource;
/** batch size. */
private int batchSize;
/** The logger. */
private static Logger logger = LoggerFactory.getLogger(RedisClient.class);
private static final String COMPOSITE_KEY_SEPERATOR = "\001";
private Jedis connection;
RedisClient(final RedisClientFactory factory, final String persistenceUnit)
{
this.factory = factory;
reader = new RedisEntityReader();
this.indexManager = factory.getIndexManager();
this.persistenceUnit = persistenceUnit;
this.clientMetadata = factory.getClientMetadata();
setBatchSize(persistenceUnit, factory.getOverridenProperties());
}
/*
* (non-Javadoc)
*
* @see
* com.impetus.kundera.client.ClientBase#onPersist(com.impetus.kundera.metadata
* .model.EntityMetadata, java.lang.Object, java.lang.Object,
* java.util.List)
*/
@Override
protected void onPersist(EntityMetadata entityMetadata, Object entity, Object id, List rlHolders)
{
Object connection = getConnection();
// Create a hashset and populate data into it
//
Pipeline pipeLine = null;
try
{
if (resource == null)
{
pipeLine = ((Jedis) connection).pipelined();
onPersist(entityMetadata, entity, id, rlHolders, pipeLine);
}
else
{
onPersist(entityMetadata, entity, id, rlHolders, connection);
}
}
finally
{
//
if (pipeLine != null)
{
pipeLine.sync(); // send I/O.. as persist call. so no need to
// read
} // response?
onCleanup(connection);
}
}
private double getDouble(String valueAsStr)
{
return StringUtils.isNumeric(valueAsStr) ? Double.parseDouble(valueAsStr) : Double
.parseDouble(((Integer) valueAsStr.hashCode()).toString());
}
@Override
public Object find(Class entityClass, Object key)
{
Object result = null;
Object connection = getConnection();
try
{
result = fetch(entityClass, key, connection, null);
}
catch (InstantiationException e)
{
logger.error("Error during find by key:", e);
throw new PersistenceException(e);
}
catch (IllegalAccessException e)
{
logger.error("Error during find by key:", e);
throw new PersistenceException(e);
}
finally
{
onCleanup(connection);
}
return result;
}
/**
* Retrieves entity instance of given class,row key and specific fields.
*
* @param clazz
* entity class
* @param key
* row key
* @param connection
* connection instance.
* @param fields
* fields.
* @return entity instance.
* @throws InstantiationException
* throws in case of runtime exception
* @throws IllegalAccessException
* throws in case of runtime exception
*/
private Object fetch(Class clazz, Object key, Object connection, byte[][] fields) throws InstantiationException,
IllegalAccessException
{
Object result = null;
EntityMetadata entityMetadata = KunderaMetadataManager.getEntityMetadata(clazz);
MetamodelImpl metaModel = (MetamodelImpl) KunderaMetadata.INSTANCE.getApplicationMetadata().getMetamodel(
entityMetadata.getPersistenceUnit());
String rowKey = null;
if (metaModel.isEmbeddable(entityMetadata.getIdAttribute().getBindableJavaType()))
{
rowKey = KunderaCoreUtils.prepareCompositeKey(entityMetadata, metaModel, key);
}
else
{
ObjectAccessor accessor = new ObjectAccessor();
rowKey = accessor.toString(key);/*
* PropertyAccessorHelper.getString(key
* );
*/
}
String hashKey = getHashKey(entityMetadata.getTableName(), rowKey);
try
{
Map columns = new HashMap();
// IF it is for selective columns
if (fields != null)
{
List fieldValues = null;
if (resource != null && resource.isActive())
{
Response response = ((Transaction) connection).hmget(getEncodedBytes(hashKey), fields);
((Transaction) connection).exec();
fieldValues = (List) response.get();
}
else
{
fieldValues = ((Jedis) connection).hmget(getEncodedBytes(hashKey), fields);
}
if (fieldValues != null && !fieldValues.isEmpty())
{
for (int i = 0; i < fields.length; i++)
{
columns.put(fields[i], fieldValues.get(i));
}
}
}
else
{
columns = getColumns(connection, hashKey, columns);
}
// Map
result = unwrap(entityMetadata, columns, key);
}
catch (JedisConnectionException jedex)
{
// Jedis is throwing runtime exception in case of no result
// found!!!!
return null;
}
return result;
}
private Map getColumns(Object connection, String hashKey, Map columns)
{
if (resource != null && resource.isActive())
{
// Why transaction API returns response in byte[] format/?
Response response = ((Transaction) connection).hgetAll(getEncodedBytes(hashKey));
((Transaction) connection).exec();
Map cols = (Map) response.get();
if (cols != null)
{
for (String name : cols.keySet())
{
columns.put(getEncodedBytes(name), getEncodedBytes(cols.get(name)));
}
}
}
else
{
columns = ((Jedis) connection).hgetAll(getEncodedBytes(hashKey));
}
return columns;
}
/*
* (non-Javadoc)
*
* @see com.impetus.kundera.client.Client#findAll(java.lang.Class,
* java.lang.Object[])
*/
@Override
public List findAll(Class entityClass, String[] columnsToSelect, Object... keys)
{
Object connection = getConnection();
List results = new ArrayList();
try
{
for (Object key : keys)
{
Object result = fetch(entityClass, key, connection, null);
if (result != null)
{
results.add(result);
}
}
}
catch (InstantiationException e)
{
logger.error("Error during find by key:", e);
throw new PersistenceException(e);
}
catch (IllegalAccessException e)
{
logger.error("Error during find by key:", e);
throw new PersistenceException(e);
}
return results;
}
@Override
public List find(Class entityClass, Map embeddedColumnMap)
{
throw new UnsupportedOperationException("Method not supported!");
}
@Override
public void close()
{
if (settings != null)
{
settings.clear();
settings = null;
}
if (connection != null)
{
connection.disconnect();
connection = null;
}
reader = null;
}
/*
* (non-Javadoc)
*
* @see com.impetus.kundera.client.Client#delete(java.lang.Object,
* java.lang.Object)
*/
@Override
public void delete(Object entity, Object pKey)
{
Object connection = getConnection();
Pipeline pipeLine = null;
try
{
if (resource == null)
{
pipeLine = ((Jedis) connection).pipelined();
onDelete(entity, pKey, pipeLine);
}
else
{
onDelete(entity, pKey, connection);
}
}
finally
{
if (pipeLine != null)
{
pipeLine.sync();
}
onCleanup(connection);
}
}
/**
* On delete relation.
*
* @param connection
* connection instance.
* @param entityMetadata
* entity metadata.
* @param rowKey
* row key.
* @param relationHolders
*/
private void deleteRelation(Object connection, EntityMetadata entityMetadata, String rowKey)
{
List relations = entityMetadata.getRelationNames();
if (relations != null)
{
for (String relation : relations)
{
if (resource != null && resource.isActive())
{
((Transaction) connection).hdel(getHashKey(entityMetadata.getTableName(), rowKey), relation);
}
else
{
((Pipeline) connection).hdel(getHashKey(entityMetadata.getTableName(), rowKey), relation);
}
}
}
/*
* Response> fields = null; if (resource != null &&
* resource.isActive()) { fields = ((Transaction)
* connection).hgetAll(getHashKey(entityMetadata.getTableName(),
* rowKey)); if (connection != null) { ((Pipeline) connection).sync(); }
* for (String field : fields.get().keySet()) { ((Transaction)
* connection).hdel(getHashKey(entityMetadata.getTableName(), rowKey),
* field); } } else { fields = ((Pipeline)
* connection).hgetAll(getHashKey(entityMetadata.getTableName(),
* rowKey)); if (connection != null) { ((Pipeline) connection).sync(); }
* for (String field : fields.get().keySet()) { ((Pipeline)
* connection).hdel(getHashKey(entityMetadata.getTableName(), rowKey),
* field); } }
*/
}
@Override
public void persistJoinTable(JoinTableData joinTableData)
{
String tableName = joinTableData.getJoinTableName();
String inverseJoinColumn = joinTableData.getInverseJoinColumnName();
String joinColumn = joinTableData.getJoinColumnName();
Map> joinTableRecords = joinTableData.getJoinTableRecords();
Object connection = null;
Pipeline pipeline = null;
/**
* Example: join table : PERSON_ADDRESS join column : PERSON_ID (1_p)
* inverse join column : ADDRESS_ID (1_a) store in REDIS:
* PERSON_ADDRESS:1_p_1_a PERSON_ID 1_p ADDRESS_ID 1_a
*/
// String rowKey =
try
{
connection = getConnection();
if (resource == null)
{
pipeline = ((Jedis) connection).pipelined();
}
Set joinKeys = joinTableRecords.keySet();
for (Object joinKey : joinKeys)
{
String joinKeyAsStr = PropertyAccessorHelper.getString(joinKey);
Set inverseKeys = joinTableRecords.get(joinKey);
for (Object inverseKey : inverseKeys)
{
Map redisFields = new HashMap(1);
String inverseJoinKeyAsStr = PropertyAccessorHelper.getString(inverseKey);
String redisKey = getHashKey(tableName, joinKeyAsStr + "_" + inverseJoinKeyAsStr);
redisFields.put(getEncodedBytes(joinColumn), getEncodedBytes(joinKeyAsStr)); // put
// join
// column
// field.
redisFields.put(getEncodedBytes(inverseJoinColumn), getEncodedBytes(inverseJoinKeyAsStr)); // put
// inverse
// join
// column
// field
// add to hash table.
if (resource != null && resource.isActive())
{
((Transaction) connection).hmset(getEncodedBytes(redisKey), redisFields);
// add index
((Transaction) connection).zadd(getHashKey(tableName, inverseJoinKeyAsStr),
getDouble(inverseJoinKeyAsStr), redisKey);
((Transaction) connection).zadd(getHashKey(tableName, joinKeyAsStr), getDouble(joinKeyAsStr),
redisKey);
}
else
{
((Jedis) connection).hmset(getEncodedBytes(redisKey), redisFields);
// add index
((Jedis) connection).zadd(getHashKey(tableName, inverseJoinKeyAsStr),
getDouble(inverseJoinKeyAsStr), redisKey);
((Jedis) connection).zadd(getHashKey(tableName, joinKeyAsStr), getDouble(joinKeyAsStr),
redisKey);
}
redisFields.clear();
}
}
}
finally
{
if (pipeline != null)
{
pipeline.sync();
}
onCleanup(connection);
}
}
/**
* Returns collection of column values for given join table. TODO: Method is
* very much tightly coupled with Join table implementation and does not
* serve purpose as it is meant for.
*/
@Override
public List getColumnsById(String schemaName, String tableName, String pKeyColumnName, String columnName,
Object pKeyColumnValue, Class columnJavaType)
{
Object connection = null;
List results = new ArrayList();
try
{
connection = getConnection();
String valueAsStr = PropertyAccessorHelper.getString(pKeyColumnValue);
Double score = getDouble(valueAsStr);
Set resultKeys = null;
if (resource != null && resource.isActive())
{
Response response = ((Transaction) connection).zrangeByScore(getHashKey(tableName, valueAsStr), score,
score);
((Transaction) connection).exec();
// ((Transaction)
// connection).zrangeByScore(getHashKey(tableName, valueAsStr),
// score, score);
resultKeys = (Set) response.get();
}
else
{
resultKeys = ((Jedis) connection).zrangeByScore(getHashKey(tableName, valueAsStr), score, score);
}
results= fetchColumn(columnName, connection, results, resultKeys);
// return connection.hmget(getEncodedBytes(redisKey),
// getEncodedBytes(columnName));
return results;
}
finally
{
onCleanup(connection);
}
}
/**
* @param columnName
* @param connection
* @param results
* @param resultKeys
*/
private List fetchColumn(String columnName, Object connection, List results, Set resultKeys)
{
for (String hashKey : resultKeys)
{
List columnValues = null;
if (resource != null && resource.isActive())
{
Response response = ((Transaction) connection).hmget(hashKey, columnName);
((Transaction) connection).exec();
columnValues = (List) response.get();
}
else
{
columnValues = ((Jedis) connection).hmget(hashKey, columnName);
}
if (columnValues != null && !columnValues.isEmpty())
{
results.addAll(columnValues); // Currently returning list of
// string as known issue
// with
// joint table concept!
}
}
return results;
}
@Override
public Object[] findIdsByColumn(String schemaName, String tableName, String pKeyName, String columnName,
Object columnValue, Class entityClazz)
{
Object connection = null;
try
{
connection = getConnection();
String valueAsStr = PropertyAccessorHelper.getString(columnValue);
Set results = null;
if (resource != null && resource.isActive())
{
Response response = ((Transaction) connection).zrangeByScore(getHashKey(tableName, valueAsStr),
getDouble(valueAsStr), getDouble(valueAsStr));
((Transaction) connection).exec();
results = (Set) response.get();
}
else
{
results = ((Jedis) connection).zrangeByScore(getHashKey(tableName, valueAsStr), getDouble(valueAsStr),
getDouble(valueAsStr));
}
List returnResults = new ArrayList();
returnResults = fetchColumn(pKeyName, connection, returnResults, results);
if (returnResults != null)
{
return returnResults.toArray(new Object[0]);
}
}
finally
{
onCleanup(connection);
}
return null;
}
@Override
public void deleteByColumn(String schemaName, String tableName, String columnName, Object columnValue)
{
Object connection = null;
Pipeline pipeLine = null;
try
{
connection = getConnection();
if (resource == null)
{
pipeLine = ((Jedis) connection).pipelined();
}
String valueAsStr = PropertyAccessorHelper.getString(columnValue);
Double score = getDouble(valueAsStr);
Set results = null;
if (resource != null && resource.isActive())
{
Response response = ((Transaction) connection).zrangeByScore(getHashKey(tableName, valueAsStr), score,
score);
((Transaction) connection).exec();
results = (Set) response.get();
}
else
{
results = ((Jedis) connection).zrangeByScore(getHashKey(tableName, valueAsStr), score, score);
}
// Set results =
// connection.zrangeByScore(getHashKey(tableName, valueAsStr),
// score, score);
if (results != null)
{
for (String rowKey : results)
{
// byte[] hashKey = getEncodedBytes(getHashKey(tableName,
// rowKey));
Map columns = null;
columns = getColumns(connection, rowKey, columns);
for (byte[] column : columns.keySet()) // delete each
// column(e.g.
// field)
{
// connection.get(key)
String colName = PropertyAccessorFactory.STRING.fromBytes(String.class, columns.get(column));
if (resource != null && resource.isActive())
{
((Transaction) connection).hdel(getEncodedBytes(rowKey), column); // delete
// record
((Transaction) connection).zrem(getHashKey(tableName, colName), rowKey); // delete
// inverted
// index.
}
else
{
((Jedis) connection).hdel(getEncodedBytes(rowKey), column); // delete
// record
((Jedis) connection).zrem(getHashKey(tableName, colName), rowKey); // delete
// inverted
// index.
}
}
}
}
}
finally
{
if (pipeLine != null)
{
pipeLine.sync();
}
onCleanup(connection);
}
}
@Override
public List findByRelation(String colName, Object colValue, Class entityClazz)
{
EntityMetadata entityMetadata = KunderaMetadataManager.getEntityMetadata(entityClazz);
Object[] ids = findIdsByColumn(entityMetadata.getTableName(), colName, colValue);
List resultSet = new ArrayList();
if (ids != null)
{
// just to insure uniqueness.
for (Object id : new HashSet(Arrays.asList(ids)))
{
resultSet.add(find(entityClazz, id));
}
}
return resultSet;
}
@Override
public EntityReader getReader()
{
return reader;
}
@Override
public Class getQueryImplementor()
{
return RedisQuery.class;
}
/**
* To supply configurations for jedis connection.
*/
public void setConfig(Map configurations)
{
this.settings = configurations;
}
/*
* (non-Javadoc)
*
* @see
* com.impetus.kundera.persistence.api.Batcher#addBatch(com.impetus.kundera
* .graph.Node)
*/
@Override
public void addBatch(Node node)
{
if (node != null)
{
nodes.add(node);
}
onBatchLimit();
}
/*
* (non-Javadoc)
*
* @see com.impetus.kundera.persistence.api.Batcher#executeBatch()
*/
@Override
public int executeBatch()
{
Object connection = getConnection();
// Create a hashset and populate data into it
Pipeline pipeLine = null;
if (resource == null)
{
pipeLine = ((Jedis) connection).pipelined();
}
try
{
for (Node node : nodes)
{
if (node.isDirty())
{
node.handlePreEvent();
// delete can not be executed in batch
if (node.isInState(RemovedState.class))
{
onDelete(node.getData(), node.getEntityId(), pipeLine != null ? pipeLine : connection);
}
else
{
List relationHolders = getRelationHolders(node);
EntityMetadata metadata = KunderaMetadataManager.getEntityMetadata(node.getDataClass());
onPersist(metadata, node.getData(), node.getEntityId(), relationHolders,
pipeLine != null ? pipeLine : connection);
}
node.handlePostEvent();
}
}
}
finally
{
//
if (pipeLine != null)
{
pipeLine.sync(); // send I/O.. as persist call. so no need to
// read
// response?
}
onCleanup(connection);
}
return nodes.size();
}
/*
* (non-Javadoc)
*
* @see com.impetus.kundera.persistence.api.Batcher#getBatchSize()
*/
@Override
public int getBatchSize()
{
return batchSize;
}
/*
* (non-Javadoc)
*
* @see com.impetus.kundera.persistence.api.Batcher#clear()
*/
@Override
public void clear()
{
if (nodes != null)
{
nodes.clear();
nodes = null;
nodes = new ArrayList();
}
}
private Object[] findIdsByColumn(String tableName, String columnName, Object columnValue)
{
Object connection = null;
try
{
connection = getConnection();
String valueAsStr = PropertyAccessorHelper.getString(columnValue);
Set results = null;
if (resource != null && resource.isActive())
{
Response response = ((Transaction) connection).zrangeByScore(getHashKey(tableName, columnName),
getDouble(valueAsStr), getDouble(valueAsStr));
((Transaction) connection).exec();
results = (Set) response.get();
}
else
{
results = ((Jedis) connection).zrangeByScore(getHashKey(tableName, columnName), getDouble(valueAsStr),
getDouble(valueAsStr));
}
if (results != null)
{
return results.toArray(new Object[0]);
}
}
finally
{
onCleanup(connection);
}
return null;
}
/**
* Check on batch limit.
*/
private void onBatchLimit()
{
if (batchSize > 0 && batchSize == nodes.size())
{
executeBatch();
nodes.clear();
}
}
/**
* Attribute wrapper.
*
* @author vivek.mishra
*
*/
private class AttributeWrapper
{
private Map columns;
private Map indexes;
private AttributeWrapper()
{
columns = new HashMap();
indexes = new HashMap();
}
/**
* @param columns
* @param indexes
*/
AttributeWrapper(int size)
{
columns = new HashMap(size);
indexes = new HashMap(size);
}
private void addColumn(byte[] key, byte[] value)
{
columns.put(key, value);
}
private void addIndex(String key, Double score)
{
indexes.put(key, score);
}
Map getColumns()
{
return columns;
}
Map getIndexes()
{
return indexes;
}
}
/**
* Returns hash key.
*
* @param tableName
* table name
* @param rowKey
* row key
* @return concatenated hash key
*/
private String getHashKey(final String tableName, final String rowKey)
{
StringBuilder builder = new StringBuilder(tableName);
builder.append(":");
builder.append(rowKey);
return builder.toString();
}
/**
* Returns encoded bytes.
*
* @param name
* field name.
* @return encoded byte array.
*/
private byte[] getEncodedBytes(final String name)
{
try
{
if (name != null)
{
return name.getBytes(Constants.CHARSET_UTF8);
}
}
catch (UnsupportedEncodingException e)
{
logger.error("Error during persist, Caused by:", e);
throw new PersistenceException(e);
}
return null;
}
/**
* Add inverted index in sorted set.
*
* @param connection
* redis connection instance
* @param wrapper
* attribute wrapper.
* @param rowKey
* row key to be stor
*/
private void addIndex(final Object connection, final AttributeWrapper wrapper, final String rowKey)
{
Set indexKeys = wrapper.getIndexes().keySet();
for (String idx_Name : indexKeys)
{
if (resource != null && resource.isActive())
{
((Transaction) connection).zadd(idx_Name, wrapper.getIndexes().get(idx_Name), rowKey);
}
else
{
((Pipeline) connection).zadd(idx_Name, wrapper.getIndexes().get(idx_Name), rowKey);
}
}
}
/**
* Deletes inverted indexes from redis.
*
* @param connection
* redis instance.
* @param wrapper
* attribute wrapper
* @param member
* sorted set member name.
*/
private void unIndex(final Object connection, final AttributeWrapper wrapper, final String member)
{
Set keys = wrapper.getIndexes().keySet();
for (String key : keys)
{
if (resource != null && resource.isActive())
{
((Transaction) connection).zrem(key, member);
}
else
{
((Pipeline) connection).zrem(key, member);
}
}
}
/**
* On release connection.
*
* @param connection
* redis connection instance.
*/
private void onCleanup(Object connection)
{
if (resource == null && connection != null)
{
if (settings != null)
{
((Jedis) connection).configResetStat();
}
factory.releaseConnection((Jedis) connection);
}
}
/* *//**
* Prepares composite key as a redis key.
*
* @param m
* entity metadata
* @param metaModel
* meta model.
* @param compositeKey
* composite key instance
* @return redis key
*//*
private String prepareCompositeKey(final EntityMetadata m, final MetamodelImpl metaModel, final Object compositeKey)
{
// EmbeddableType keyObject =
// metaModel.embeddable(m.getIdAttribute().getBindableJavaType());
Field[] fields = m.getIdAttribute().getBindableJavaType().getDeclaredFields();
StringBuilder stringBuilder = new StringBuilder();
for (Field f : fields)
{
if (!ReflectUtils.isTransientOrStatic(f))
{
// Attribute compositeColumn =
// keyObject.getAttribute(f.getName());
try
{
String fieldValue = PropertyAccessorHelper.getString(compositeKey, f); // field
// value
stringBuilder.append(fieldValue);
stringBuilder.append(COMPOSITE_KEY_SEPERATOR);
}
catch (IllegalArgumentException e)
{
logger.error("Error during persist, Caused by:", e);
throw new PersistenceException(e);
}
}
}
if (stringBuilder.length() > 0)
{
stringBuilder.deleteCharAt(stringBuilder.lastIndexOf(COMPOSITE_KEY_SEPERATOR));
}
return stringBuilder.toString();
}
*/
/**
* Wraps entity attributes into byte[] and return instance of attribute
* wrapper.
*
* @param entityMetadata
* @param entity
* @return
*/
private AttributeWrapper wrap(EntityMetadata entityMetadata, Object entity)
{
MetamodelImpl metaModel = (MetamodelImpl) KunderaMetadata.INSTANCE.getApplicationMetadata().getMetamodel(
entityMetadata.getPersistenceUnit());
EntityType entityType = metaModel.entity(entityMetadata.getEntityClazz());
Set attributes = entityType.getAttributes();
// attributes can be null??? i guess NO
AttributeWrapper wrapper = new AttributeWrapper(attributes.size());
List relationNames = entityMetadata.getRelationNames();
// PropertyAccessorHelper.get(entity,
for (Attribute attr : attributes)
{
if (!entityMetadata.getIdAttribute().equals(attr) && !attr.isAssociation())
{
if (metaModel.isEmbeddable(((AbstractAttribute) attr).getBindableJavaType()))
{
EmbeddableType embeddableAttribute = metaModel.embeddable(((AbstractAttribute) attr)
.getBindableJavaType());
Object embeddedObject = PropertyAccessorHelper.getObject(entity, (Field) attr.getJavaMember());
Set embeddedAttributes = embeddableAttribute.getAttributes();
for (Attribute attrib : embeddedAttributes)
{
addToWrapper(entityMetadata, wrapper, embeddedObject, attrib, attr);
}
}
else
{
addToWrapper(entityMetadata, wrapper, entity, attr);
}
}
else if (attributes.size() == 1) // means it is only a key! weird
// but possible negative
// scenario
{
byte[] value = PropertyAccessorHelper.get(entity, (Field) attr.getJavaMember());
byte[] name;
name = getEncodedBytes(((AbstractAttribute) attr).getJPAColumnName());
// add column name as key and value as value
wrapper.addColumn(name, value);
}
}
return wrapper;
}
/**
* Adds field to wrapper.
*
* @param entityMetadata
* @param wrapper
* @param resultedObject
* @param attrib
*/
private void addToWrapper(EntityMetadata entityMetadata, AttributeWrapper wrapper, Object resultedObject,
Attribute attrib)
{
addToWrapper(entityMetadata, wrapper, resultedObject, attrib, null);
}
/**
* Wraps entity attributes into redis format byte[]
*
* @param entityMetadata
* @param wrapper
* @param embeddedObject
* @param attrib
* @param embeddedAttrib
*/
private void addToWrapper(EntityMetadata entityMetadata, AttributeWrapper wrapper, Object embeddedObject,
Attribute attrib, Attribute embeddedAttrib)
{
byte[] value = PropertyAccessorHelper.get(embeddedObject, (Field) attrib.getJavaMember());
String valueAsStr = PropertyAccessorHelper.getString(embeddedObject, (Field) attrib.getJavaMember());
byte[] name;
if (value != null)
{
if (embeddedAttrib == null)
{
name = getEncodedBytes(((AbstractAttribute) attrib).getJPAColumnName());
}
else
{
name = getEncodedBytes(getHashKey(embeddedAttrib.getName(),
((AbstractAttribute) attrib).getJPAColumnName()));
}
// add column name as key and value as value
wrapper.addColumn(name, value);
// // {tablename:columnname,hashcode} for value
wrapper.addIndex(
getHashKey(entityMetadata.getTableName(), ((AbstractAttribute) attrib).getJPAColumnName()),
getDouble(valueAsStr));
wrapper.addIndex(
getHashKey(entityMetadata.getTableName(),
getHashKey(((AbstractAttribute) attrib).getJPAColumnName(), valueAsStr)),
getDouble(valueAsStr));
}
}
/**
* Unwraps redis results into entity.
*
* @param entityMetadata
* @param results
* @param key
* @return
* @throws InstantiationException
* @throws IllegalAccessException
*/
private Object unwrap(EntityMetadata entityMetadata, Map results, Object key)
throws InstantiationException, IllegalAccessException
{
MetamodelImpl metaModel = (MetamodelImpl) KunderaMetadata.INSTANCE.getApplicationMetadata().getMetamodel(
entityMetadata.getPersistenceUnit());
List relationNames = entityMetadata.getRelationNames();
EntityType entityType = metaModel.entity(entityMetadata.getEntityClazz());
Map relations = new HashMap();
Object entity = null;
// Set attributes = entityType.getAttributes();
Set columnNames = results.keySet();
for (byte[] nameInByte : columnNames)
{
if (entity == null)
{
entity = entityMetadata.getEntityClazz().newInstance();
}
String columnName = PropertyAccessorFactory.STRING.fromBytes(String.class, nameInByte);
byte[] value = results.get(nameInByte);
String fieldName = entityMetadata.getFieldName(columnName);
if (fieldName != null)
{
Attribute attribute = entityType.getAttribute(fieldName);
if (relationNames != null && relationNames.contains(columnName))
{
Field field = (Field) attribute.getJavaMember();
EntityMetadata associationMetadata = KunderaMetadataManager
.getEntityMetadata(((AbstractAttribute) attribute).getBindableJavaType());
relations.put(columnName, PropertyAccessorHelper.getObject(associationMetadata.getIdAttribute()
.getBindableJavaType(), value));
}
else
{
PropertyAccessorHelper.set(entity, (Field) attribute.getJavaMember(), value);
}
}
else
{
// means it might be an embeddable field, if not simply omit
// this field.
if (StringUtils.contains(columnName, ":"))
{
StringTokenizer tokenizer = new StringTokenizer(columnName, ":");
while (tokenizer.hasMoreTokens())
{
String embeddedFieldName = tokenizer.nextToken();
String embeddedColumnName = tokenizer.nextToken();
Map embeddables = metaModel.getEmbeddables(entityMetadata
.getEntityClazz());
EmbeddableType embeddableAttribute = embeddables.get(embeddedFieldName);
Attribute attrib = embeddableAttribute.getAttribute(embeddedColumnName);
Object embeddedObject = PropertyAccessorHelper.getObject(entity, (Field) entityType
.getAttribute(embeddedFieldName).getJavaMember());
if (embeddedObject == null)
{
embeddedObject = ((AbstractAttribute) entityType.getAttribute(embeddedFieldName))
.getBindableJavaType().newInstance();
PropertyAccessorHelper.set(entity, (Field) entityType.getAttribute(embeddedFieldName)
.getJavaMember(), embeddedObject);
}
PropertyAccessorHelper.set(embeddedObject, (Field) attrib.getJavaMember(), value);
// PropertyAccessorHelper.
}
}
// It might be a case of embeddable attribute.
}
}
if (entity != null)
{
Class javaType = entityMetadata.getIdAttribute().getJavaType();
if (!metaModel.isEmbeddable(entityMetadata.getIdAttribute().getBindableJavaType()))
{
key = PropertyAccessorFactory.getPropertyAccessor(javaType).fromString(javaType, key.toString());
}
PropertyAccessorHelper.set(entity, (Field) entityMetadata.getIdAttribute().getJavaMember(), key);
}
if (!relations.isEmpty())
{
return new EnhanceEntity(entity, key, relations);
}
return entity;
}
List onExecuteQuery(RedisQueryInterpreter queryParameter, Class entityClazz)
{
/**
* Find a list of id's and then call findById for each!
*/
Object connection = null;
List results = new ArrayList();
try
{
connection = getConnection();
Set rowKeys = new HashSet();
EntityMetadata entityMetadata = KunderaMetadataManager.getEntityMetadata(entityClazz);
if (queryParameter.getClause() != null && !queryParameter.isByRange())
{
String destStore = entityClazz.getSimpleName() + System.currentTimeMillis();
Map fieldSets = queryParameter.getFields();
Set keySets = new HashSet(fieldSets.size());
// byte[][] keys = new byte[][fieldSets.size()];
for (String column : fieldSets.keySet())
{
String valueAsStr = PropertyAccessorHelper.getString(fieldSets.get(column));
String key = getHashKey(entityMetadata.getTableName(), getHashKey(column, valueAsStr));
keySets.add(key);
}
if (queryParameter.getClause().equals(Clause.INTERSECT))
{
if (resource != null && resource.isActive())
{
((Transaction) connection).zinterstore(destStore, keySets.toArray(new String[] {}));
}
else
{
((Jedis) connection).zinterstore(destStore, keySets.toArray(new String[] {}));
}
}
else
{
if (resource != null && resource.isActive())
{
((Transaction) connection).zunionstore(destStore, keySets.toArray(new String[] {}));
}
else
{
((Jedis) connection).zunionstore(destStore, keySets.toArray(new String[] {}));
}
}
if (resource != null && resource.isActive())
{
Response response = ((Transaction) connection).zrange(destStore, 0, -1);
((Transaction) connection).exec();
rowKeys = (Set) response.get();
//
// ((Transaction) connection).del(destStore);
}
else
{
rowKeys = ((Jedis) connection).zrange(destStore, 0, -1);
((Jedis) connection).del(destStore);
}
// delete intermediate store after find.
//
// means it is a query over sorted set.
}
else if (queryParameter.isByRange())
{
// means query over a single sorted set with range
Map minimum = queryParameter.getMin();
Map maximum = queryParameter.getMax();
String column = minimum.keySet().iterator().next();
if (resource != null && resource.isActive())
{
Response response = ((Transaction) connection)
.zrangeByScore(getHashKey(entityMetadata.getTableName(), column), minimum.get(column),
maximum.get(column));
((Transaction) connection).exec();
rowKeys = (Set) response.get();
}
else
{
rowKeys = ((Jedis) connection).zrangeByScore(getHashKey(entityMetadata.getTableName(), column),
minimum.get(column), maximum.get(column));
}
}
else if (queryParameter.isById())
{
Map fieldSets = queryParameter.getFields();
results = findAllColumns(entityClazz, (byte[][]) (queryParameter.getColumns() != null ? queryParameter
.getColumns().toArray() : null), fieldSets.values().toArray());
return results;
}
else if (queryParameter.getFields() != null)
{
Set columns = queryParameter.getFields().keySet();
for (String column : columns)
{
// ideally it will always be 1 value in map, else it will go
// it queryParameter.getClause() will not be null!
Double value = getDouble(PropertyAccessorHelper.getString(queryParameter.getFields().get(column)));
if (resource != null && resource.isActive())
{
Response response = ((Transaction) connection).zrangeByScore(
getHashKey(entityMetadata.getTableName(), column), value, value);
((Transaction) connection).exec();
rowKeys = (Set) response.get();
}
else
{
rowKeys = ((Jedis) connection).zrangeByScore(getHashKey(entityMetadata.getTableName(), column),
value, value);
}
}
}
else
{
if (resource != null && resource.isActive())
{
Response response = ((Transaction) connection).zrange(
getHashKey(entityMetadata.getTableName(),
((AbstractAttribute) entityMetadata.getIdAttribute()).getJPAColumnName()), 0, -1);
((Transaction) connection).exec();
rowKeys = new HashSet((Collection extends String>) response.get());
}
else
{
rowKeys = new HashSet(((Jedis) connection).zrange(
getHashKey(entityMetadata.getTableName(),
((AbstractAttribute) entityMetadata.getIdAttribute()).getJPAColumnName()), 0, -1));
}
}
// fetch fr
for (String k : rowKeys)
{
Object record = fetch(entityClazz, k, connection, (queryParameter.getColumns() != null ? queryParameter
.getColumns().toArray(new byte[][] {}) : null));
if (record != null)
{
results.add(record);
}
}
}
catch (InstantiationException e)
{
logger.error("Error during persist, Caused by:", e);
throw new PersistenceException(e);
}
catch (IllegalAccessException e)
{
logger.error("Error during persist, Caused by:", e);
throw new PersistenceException(e);
}
finally
{
onCleanup(connection);
}
return results;
}
private List findAllColumns(Class entityClass, byte[][] columns, Object... keys)
{
Object connection = getConnection();
// connection.co
List results = new ArrayList();
try
{
for (Object key : keys)
{
Object result = fetch(entityClass, key, connection, columns);
if (result != null)
{
results.add(result);
}
}
}
catch (InstantiationException e)
{
logger.error("Error during find by key:", e);
throw new PersistenceException(e);
}
catch (IllegalAccessException e)
{
logger.error("Error during find by key:", e);
throw new PersistenceException(e);
}
return results;
}
/*
* (non-Javadoc)
*
* @see
* com.impetus.kundera.client.ClientPropertiesSetter#populateClientProperties
* (com.impetus.kundera.client.Client, java.util.Map)
*/
@Override
public void populateClientProperties(Client client, Map properties)
{
setConfig(properties);
}
@Override
public void bind(TransactionResource resource)
{
// Not checking for type of TransactionRes
if (resource != null && resource instanceof RedisTransaction)
{
this.resource = resource;
}
else
{
throw new KunderaTransactionException("Invalid transaction resource provided:" + resource
+ " Should have been an instance of :" + RedisTransaction.class);
}
}
/**
* Returns jedis connection.
*
* @return jedis resource.
*/
private Object getConnection()
{
/*
* Jedis connection = factory.getConnection();
*
* // If resource is not null means a transaction in progress.
*
* if (settings != null) { for (String key : settings.keySet()) {
* connection.configSet(key, settings.get(key).toString()); } }
*
* if (resource != null && resource.isActive()) { return
* ((RedisTransaction) resource).bindResource(connection); } else {
* return connection; }
*/
if (resource == null && this.connection != null)
{
return this.connection;
}
Jedis conn = factory.getConnection();
// If resource is not null means a transaction in progress.
if (settings != null)
{
for (String key : settings.keySet())
{
conn.configSet(key, settings.get(key).toString());
}
}
if (resource != null && resource.isActive())
{
return ((RedisTransaction) resource).bindResource(conn);
}
else
{
this.connection = conn;
return conn;
}
}
/**
* @param persistenceUnit
* @param puProperties
*/
private void setBatchSize(String persistenceUnit, Map puProperties)
{
String batch_Size = null;
if (puProperties != null)
{
batch_Size = puProperties != null ? (String) puProperties.get(PersistenceProperties.KUNDERA_BATCH_SIZE)
: null;
if (batch_Size != null)
{
batchSize = Integer.valueOf(batch_Size);
if (batchSize == 0)
{
throw new IllegalArgumentException("kundera.batch.size property must be numeric and > 0");
}
}
}
else if (batch_Size == null)
{
PersistenceUnitMetadata puMetadata = KunderaMetadataManager.getPersistenceUnitMetadata(persistenceUnit);
batchSize = puMetadata.getBatchSize();
}
}
private void onPersist(EntityMetadata entityMetadata, Object entity, Object id, List rlHolders,
Object connection)
{
// first open a pipeline
AttributeWrapper wrapper = wrap(entityMetadata, entity);
// add relations.
if (rlHolders != null)
{
for (RelationHolder relation : rlHolders)
{
String name = relation.getRelationName();
Object value = relation.getRelationValue();
byte[] valueInBytes = PropertyAccessorHelper.getBytes(value);
byte[] nameInBytes = getEncodedBytes(name);
String valueAsStr = PropertyAccessorHelper.getString(value);
wrapper.addColumn(nameInBytes, valueInBytes);
wrapper.addIndex(getHashKey(entityMetadata.getTableName(), name), getDouble(valueAsStr));
// this index is required to work for UNION/INTERSECT
// support.
wrapper.addIndex(getHashKey(entityMetadata.getTableName(), getHashKey(name, valueAsStr)),
getDouble(valueAsStr));
}
}
// prepareCompositeKey
MetamodelImpl metaModel = (MetamodelImpl) KunderaMetadata.INSTANCE.getApplicationMetadata().getMetamodel(
entityMetadata.getPersistenceUnit());
String rowKey = null;
if (metaModel.isEmbeddable(entityMetadata.getIdAttribute().getBindableJavaType()))
{
rowKey = KunderaCoreUtils.prepareCompositeKey(entityMetadata, metaModel, id);
}
else
{
ObjectAccessor accessor = new ObjectAccessor();
rowKey = accessor.toString(id);
// rowKey = /*PropertyAccessorHelper.getString(entity, (Field)
// entityMetadata.getIdAttribute().getJavaMember())*/ ;
}
String hashKey = getHashKey(entityMetadata.getTableName(), rowKey);
// Add row key to list(Required for wild search over table).
if (resource != null && resource.isActive())
{
((Transaction) connection).hmset(getEncodedBytes(hashKey), wrapper.getColumns());
((Transaction) connection).zadd(
getHashKey(entityMetadata.getTableName(),
((AbstractAttribute) entityMetadata.getIdAttribute()).getJPAColumnName()),
getDouble(rowKey), rowKey);
// Add row-key as inverted index as well needed for multiple clause
// search with key and non row key.
((Transaction) connection)
.zadd(getHashKey(
entityMetadata.getTableName(),
getHashKey(((AbstractAttribute) entityMetadata.getIdAttribute()).getJPAColumnName(), rowKey)),
getDouble(rowKey), rowKey);
}
else
{
((Pipeline) connection).hmset(getEncodedBytes(hashKey), wrapper.getColumns());
((Pipeline) connection).zadd(
getHashKey(entityMetadata.getTableName(),
((AbstractAttribute) entityMetadata.getIdAttribute()).getJPAColumnName()),
getDouble(rowKey), rowKey);
// Add row-key as inverted index as well needed for multiple clause
// search with key and non row key.
((Pipeline) connection)
.zadd(getHashKey(
entityMetadata.getTableName(),
getHashKey(((AbstractAttribute) entityMetadata.getIdAttribute()).getJPAColumnName(), rowKey)),
getDouble(rowKey), rowKey);
}
// Add inverted indexes for column based search.
addIndex(connection, wrapper, rowKey);
}
private void onDelete(Object entity, Object pKey, Object connection)
{
EntityMetadata entityMetadata = KunderaMetadataManager.getEntityMetadata(entity.getClass());
AttributeWrapper wrapper = wrap(entityMetadata, entity);
Set columnNames = wrapper.columns.keySet();
String rowKey = null;
MetamodelImpl metaModel = (MetamodelImpl) KunderaMetadata.INSTANCE.getApplicationMetadata().getMetamodel(
entityMetadata.getPersistenceUnit());
if (metaModel.isEmbeddable(entityMetadata.getIdAttribute().getBindableJavaType()))
{
rowKey = KunderaCoreUtils.prepareCompositeKey(entityMetadata, metaModel, pKey);
}
else
{
rowKey = PropertyAccessorHelper.getString(entity, (Field) entityMetadata.getIdAttribute().getJavaMember());
}
for (byte[] name : columnNames)
{
if (resource != null && resource.isActive())
{
((Transaction) connection).hdel(getHashKey(entityMetadata.getTableName(), rowKey),
PropertyAccessorFactory.STRING.fromBytes(String.class, name));
}
else
{
((Pipeline) connection).hdel(getHashKey(entityMetadata.getTableName(), rowKey),
PropertyAccessorFactory.STRING.fromBytes(String.class, name));
}
}
// Delete relation values.
deleteRelation(connection, entityMetadata, rowKey);
// Delete inverted indexes.
unIndex(connection, wrapper, rowKey);
if (resource != null && resource.isActive())
{
((Transaction) connection).zrem(
getHashKey(entityMetadata.getTableName(),
((AbstractAttribute) entityMetadata.getIdAttribute()).getJPAColumnName()), rowKey);
}
else
{
((Pipeline) connection).zrem(
getHashKey(entityMetadata.getTableName(),
((AbstractAttribute) entityMetadata.getIdAttribute()).getJPAColumnName()), rowKey);
}
}
@Override
public Object generate(SequenceGeneratorDiscriptor discriptor)
{
Jedis jedis = factory.getConnection();
Long latestCount = jedis.incr(getEncodedBytes(discriptor.getSequenceName()));
if (latestCount == 1)
{
return discriptor.getInitialValue();
}
else
{
return (latestCount - 1) * discriptor.getAllocationSize();
}
}
}