All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.impetus.client.cassandra.thrift.ThriftClient Maven / Gradle / Ivy

There is a newer version: 3.13
Show newest version
/**
 * 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.cassandra.thrift;

import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.persistence.PersistenceException;
import javax.persistence.metamodel.EntityType;

import net.dataforte.cassandra.pool.ConnectionPool;

import org.apache.cassandra.db.marshal.UTF8Type;
import org.apache.cassandra.thrift.Cassandra;
import org.apache.cassandra.thrift.Column;
import org.apache.cassandra.thrift.ColumnOrSuperColumn;
import org.apache.cassandra.thrift.ColumnParent;
import org.apache.cassandra.thrift.ColumnPath;
import org.apache.cassandra.thrift.CounterColumn;
import org.apache.cassandra.thrift.CounterSuperColumn;
import org.apache.cassandra.thrift.IndexClause;
import org.apache.cassandra.thrift.IndexExpression;
import org.apache.cassandra.thrift.IndexOperator;
import org.apache.cassandra.thrift.InvalidRequestException;
import org.apache.cassandra.thrift.KeyRange;
import org.apache.cassandra.thrift.KeySlice;
import org.apache.cassandra.thrift.Mutation;
import org.apache.cassandra.thrift.SlicePredicate;
import org.apache.cassandra.thrift.SliceRange;
import org.apache.cassandra.thrift.SuperColumn;
import org.apache.cassandra.thrift.TimedOutException;
import org.apache.cassandra.thrift.UnavailableException;
import org.apache.cassandra.utils.ByteBufferUtil;
import org.apache.thrift.TException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.impetus.client.cassandra.CassandraClientBase;
import com.impetus.client.cassandra.CassandraIdGenerator;
import com.impetus.client.cassandra.common.CassandraConstants;
import com.impetus.client.cassandra.common.CassandraUtilities;
import com.impetus.client.cassandra.datahandler.CassandraDataHandler;
import com.impetus.client.cassandra.index.InvertedIndexHandler;
import com.impetus.client.cassandra.query.CassQuery;
import com.impetus.client.cassandra.thrift.ThriftClientFactory.Connection;
import com.impetus.client.cassandra.thrift.ThriftDataResultHelper.ColumnFamilyType;
import com.impetus.kundera.Constants;
import com.impetus.kundera.KunderaException;
import com.impetus.kundera.client.Client;
import com.impetus.kundera.client.EnhanceEntity;
import com.impetus.kundera.db.RelationHolder;
import com.impetus.kundera.db.SearchResult;
import com.impetus.kundera.generator.AutoGenerator;
import com.impetus.kundera.generator.Generator;
import com.impetus.kundera.generator.TableGenerator;
import com.impetus.kundera.graph.Node;
import com.impetus.kundera.index.IndexManager;
import com.impetus.kundera.metadata.KunderaMetadataManager;
import com.impetus.kundera.metadata.MetadataUtils;
import com.impetus.kundera.metadata.model.EntityMetadata;
import com.impetus.kundera.metadata.model.MetamodelImpl;
import com.impetus.kundera.metadata.model.TableGeneratorDiscriptor;
import com.impetus.kundera.metadata.model.EntityMetadata.Type;
import com.impetus.kundera.metadata.model.annotation.DefaultEntityAnnotationProcessor;
import com.impetus.kundera.metadata.model.type.AbstractManagedType;
import com.impetus.kundera.persistence.EntityManagerFactoryImpl.KunderaMetadata;
import com.impetus.kundera.persistence.EntityReader;
import com.impetus.kundera.persistence.EntityReaderException;
import com.impetus.kundera.persistence.api.Batcher;
import com.impetus.kundera.persistence.context.jointable.JoinTableData;
import com.impetus.kundera.property.PropertyAccessor;
import com.impetus.kundera.property.PropertyAccessorFactory;
import com.impetus.kundera.property.PropertyAccessorHelper;
import com.impetus.kundera.utils.KunderaCoreUtils;
import com.impetus.kundera.utils.TimestampGenerator;

/**
 * Kundera Client implementation for Cassandra using Thrift library.
 * 
 * @author amresh.singh
 */
public class ThriftClient extends CassandraClientBase implements Client, Batcher

{

    /** log for this class. */
    private static Logger log = LoggerFactory.getLogger(ThriftClient.class);

    /** The data handler. */
    private final ThriftDataHandler dataHandler;

    /** Handler for Inverted indexing. */
    private final InvertedIndexHandler invertedIndexHandler;

    /** The reader. */
    private final EntityReader reader;

    /** The client factory. */
    private final ThriftClientFactory clientFactory;

    /** The pool. */
    private final ConnectionPool pool;

    /**
     * Instantiates a new thrift client.
     * 
     * @param clientFactory
     *            the client factory
     * @param indexManager
     *            the index manager
     * @param reader
     *            the reader
     * @param persistenceUnit
     *            the persistence unit
     * @param pool
     *            the pool
     * @param externalProperties
     *            the external properties
     * @param kunderaMetadata
     *            the kundera metadata
     * @param generator
     *            the generator
     */
    public ThriftClient(ThriftClientFactory clientFactory, IndexManager indexManager, EntityReader reader,
            String persistenceUnit, ConnectionPool pool, Map externalProperties,
            final KunderaMetadata kunderaMetadata, final TimestampGenerator generator)
    {
        super(persistenceUnit, externalProperties, kunderaMetadata, generator);
        this.clientFactory = clientFactory;
        this.indexManager = indexManager;
        this.dataHandler = new ThriftDataHandler(this, kunderaMetadata, generator);
        this.reader = reader;
        this.clientMetadata = clientFactory.getClientMetadata();
        this.invertedIndexHandler = new ThriftInvertedIndexHandler(this,
                MetadataUtils.useSecondryIndex(clientMetadata), generator);
        this.pool = pool;
    }

    /**
     * Persists and indexes a {@link Node} to database.
     * 
     * @param node
     *            the node
     */
    @Override
    public void persist(Node node)
    {
        super.persist(node);
    }

    /**
     * Persists a {@link Node} to database.
     * 
     * @param entityMetadata
     *            the entity metadata
     * @param entity
     *            the entity
     * @param id
     *            the id
     * @param rlHolders
     *            the rl holders
     */
    @Override
    protected void onPersist(EntityMetadata entityMetadata, Object entity, Object id, List rlHolders)
    {
        Connection conn = getConnection();
        try
        {
            // if entity is embeddable...call cql translator to get cql string!
            // use thrift client to execute cql query.

            if (isCql3Enabled(entityMetadata))
            {
                cqlClient.persist(entityMetadata, entity, conn.getClient(), rlHolders,
                        getTtlValues().get(entityMetadata.getTableName()));
            }
            else
            {
                Map>> mutationMap = new HashMap>>();
                prepareMutation(entityMetadata, entity, id, rlHolders, mutationMap);
                // Write Mutation map to database
                conn.getClient().batch_mutate(mutationMap, getConsistencyLevel());

                mutationMap.clear();
                mutationMap = null;
            }

        }
        catch (InvalidRequestException e)
        {
            log.error("Error while persisting record, Caused by: .", e);
            throw new KunderaException(e);
        }
        catch (TException e)
        {
            log.error("Error while persisting record, Caused by: .", e);
            throw new KunderaException(e);
        }
        catch (UnsupportedEncodingException e)
        {
            log.error("Error while persisting record, Caused by: .", e);
            throw new KunderaException(e);
        }
        finally
        {
            releaseConnection(conn);

            if (isTtlPerRequest())
            {
                getTtlValues().clear();
            }
        }
    }

    /**
     * Persists a Join table record set into database.
     * 
     * @param joinTableData
     *            the join table data
     */
    @Override
    public void persistJoinTable(JoinTableData joinTableData)
    {
        String joinTableName = joinTableData.getJoinTableName();
        String invJoinColumnName = joinTableData.getInverseJoinColumnName();
        Map> joinTableRecords = joinTableData.getJoinTableRecords();

        EntityMetadata entityMetadata = KunderaMetadataManager.getEntityMetadata(kunderaMetadata,
                joinTableData.getEntityClass());

        Connection conn = null;
        try
        {

            conn = getConnection();

            if (isCql3Enabled(entityMetadata))
            {
                persistJoinTableByCql(joinTableData, conn.getClient());
            }
            else
            {
                KunderaCoreUtils.printQuery("Persist join table:" + joinTableName, showQuery);
                for (Object key : joinTableRecords.keySet())
                {
                    PropertyAccessor accessor = PropertyAccessorFactory.getPropertyAccessor((Field) entityMetadata
                            .getIdAttribute().getJavaMember());
                    byte[] rowKey = accessor.toBytes(key);

                    Set values = joinTableRecords.get(key);
                    List columns = new ArrayList();

                    // Create Insertion List
                    List insertionList = new ArrayList();
                    Class columnType = null;
                    for (Object value : values)
                    {
                        Column column = new Column();
                        column.setName(PropertyAccessorFactory.STRING.toBytes(invJoinColumnName
                                + Constants.JOIN_COLUMN_NAME_SEPARATOR + value));
                        column.setValue(PropertyAccessorHelper.getBytes(value));

                        column.setTimestamp(generator.getTimestamp());
                        columnType = value.getClass();
                        columns.add(column);

                        Mutation mut = new Mutation();
                        mut.setColumn_or_supercolumn(new ColumnOrSuperColumn().setColumn(column));
                        insertionList.add(mut);
                    }
                    createIndexesOnColumns(entityMetadata, joinTableName, columns, columnType);
                    // Create Mutation Map
                    Map> columnFamilyValues = new HashMap>();
                    columnFamilyValues.put(joinTableName, insertionList);
                    Map>> mulationMap = new HashMap>>();
                    mulationMap.put(ByteBuffer.wrap(rowKey), columnFamilyValues);

                    // Write Mutation map to database

                    conn.getClient().set_keyspace(entityMetadata.getSchema());

                    conn.getClient().batch_mutate(mulationMap, getConsistencyLevel());
                }
            }
        }
        catch (InvalidRequestException e)
        {
            log.error("Error while inserting record into join table, Caused by: .", e);
            throw new PersistenceException(e);
        }
        catch (TException e)
        {
            log.error("Error while inserting record into join table, Caused by: .", e);
            throw new PersistenceException(e);
        }
        finally
        {
            releaseConnection(conn);
        }
    }

    /**
     * Indexes a {@link Node} to database.
     * 
     * @param node
     *            the node
     * @param entityMetadata
     *            the entity metadata
     */
    @Override
    protected void indexNode(Node node, EntityMetadata entityMetadata)
    {
        super.indexNode(node, entityMetadata);

        // Write to inverted index table if applicable
        invertedIndexHandler.write(node, entityMetadata, getPersistenceUnit(), getConsistencyLevel(), dataHandler);
    }

    /**
     * Finds an entity from database.
     * 
     * @param entityClass
     *            the entity class
     * @param key
     *            the key
     * @return the object
     */
    @Override
    public Object find(Class entityClass, Object key)
    {
        return super.find(entityClass, key);
    }

    /**
     * Finds a {@link List} of entities from database.
     * 
     * @param 
     *            the element type
     * @param entityClass
     *            the entity class
     * @param columnsToSelect
     *            the columns to select
     * @param keys
     *            the keys
     * @return the list
     */
    @Override
    public  List findAll(Class entityClass, String[] columnsToSelect, Object... keys)
    {
        return super.findAll(entityClass, columnsToSelect, keys);
    }

    /**
     * Finds a {@link List} of entities from database.
     * 
     * @param entityClass
     *            the entity class
     * @param relationNames
     *            the relation names
     * @param isWrapReq
     *            the is wrap req
     * @param metadata
     *            the metadata
     * @param rowIds
     *            the row ids
     * @return the list
     */
    @Override
    public final List find(Class entityClass, List relationNames, boolean isWrapReq, EntityMetadata metadata,
            Object... rowIds)
    {
        if (!isOpen())
        {
            throw new PersistenceException("ThriftClient is closed.");
        }
        return findByRowKeys(entityClass, relationNames, isWrapReq, metadata, rowIds);
    }

    /**
     * Finds a {@link List} of entities from database for given super columns.
     * 
     * @param 
     *            the element type
     * @param entityClass
     *            the entity class
     * @param embeddedColumnMap
     *            the embedded column map
     * @return the list
     */
    @Override
    public  List find(Class entityClass, Map embeddedColumnMap)
    {
        return super.find(entityClass, embeddedColumnMap, dataHandler);
    }

    /**
     * Loads super columns from database.
     * 
     * @param keyspace
     *            the keyspace
     * @param columnFamily
     *            the column family
     * @param rowId
     *            the row id
     * @param superColumnNames
     *            the super column names
     * @return the list
     */
    @Override
    protected final List loadSuperColumns(String keyspace, String columnFamily, String rowId,
            String... superColumnNames)
    {
        // TODO::: super column abstract entity and discriminator column
        if (!isOpen())
            throw new PersistenceException("ThriftClient is closed.");

        byte[] rowKey = rowId.getBytes();

        SlicePredicate predicate = new SlicePredicate();
        List columnNames = new ArrayList();
        for (String superColumnName : superColumnNames)
        {
            KunderaCoreUtils.printQuery("Fetch superColumn:" + superColumnName, showQuery);
            columnNames.add(ByteBuffer.wrap(superColumnName.getBytes()));
        }

        predicate.setColumn_names(columnNames);

        ColumnParent parent = new ColumnParent(columnFamily);
        List coscList;
        Connection conn = null;
        try
        {
            conn = getConnection();

            coscList = conn.getClient().get_slice(ByteBuffer.wrap(rowKey), parent, predicate, getConsistencyLevel());

        }
        catch (InvalidRequestException e)
        {
            log.error("Error while getting super columns for row Key {} , Caused by: .", rowId, e);
            throw new EntityReaderException(e);
        }
        catch (UnavailableException e)
        {
            log.error("Error while getting super columns for row Key {} , Caused by: .", rowId, e);
            throw new EntityReaderException(e);
        }
        catch (TimedOutException e)
        {
            log.error("Error while getting super columns for row Key {} , Caused by: .", rowId, e);
            throw new EntityReaderException(e);
        }
        catch (TException e)
        {
            log.error("Error while getting super columns for row Key {} , Caused by: .", rowId, e);
            throw new EntityReaderException(e);
        }
        finally
        {

            releaseConnection(conn);
        }

        List superColumns = ThriftDataResultHelper.transformThriftResult(coscList,
                ColumnFamilyType.SUPER_COLUMN, null);
        return superColumns;
    }

    /**
     * Retrieves column for a given primary key.
     * 
     * @param 
     *            the element type
     * @param schemaName
     *            the schema name
     * @param tableName
     *            the table name
     * @param pKeyColumnName
     *            the key column name
     * @param columnName
     *            the column name
     * @param pKeyColumnValue
     *            the key column value
     * @param columnJavaType
     *            the column java type
     * @return the columns by id
     */
    @Override
    public  List getColumnsById(String schemaName, String tableName, String pKeyColumnName, String columnName,
            Object pKeyColumnValue, Class columnJavaType)
    {
        List foreignKeys = new ArrayList();

        if (getCqlVersion().equalsIgnoreCase(CassandraConstants.CQL_VERSION_3_0))
        {
            foreignKeys = getColumnsByIdUsingCql(schemaName, tableName, pKeyColumnName, columnName, pKeyColumnValue,
                    columnJavaType);
        }
        else
        {
            byte[] rowKey = CassandraUtilities.toBytes(pKeyColumnValue);

            if (rowKey != null)
            {
                SlicePredicate predicate = new SlicePredicate();
                SliceRange sliceRange = new SliceRange();
                sliceRange.setStart(new byte[0]);
                sliceRange.setFinish(new byte[0]);
                predicate.setSlice_range(sliceRange);

                ColumnParent parent = new ColumnParent(tableName);
                List results;
                Connection conn = null;
                try
                {
                    conn = getConnection();
                    results = conn.getClient().get_slice(ByteBuffer.wrap(rowKey), parent, predicate,
                            getConsistencyLevel());
                }
                catch (InvalidRequestException e)
                {
                    log.error("Error while getting columns for row Key {} , Caused by: .", pKeyColumnValue, e);
                    throw new EntityReaderException(e);
                }
                catch (UnavailableException e)
                {
                    log.error("Error while getting columns for row Key {} , Caused by: .", pKeyColumnValue, e);
                    throw new EntityReaderException(e);
                }
                catch (TimedOutException e)
                {
                    log.error("Error while getting columns for row Key {} , Caused by: .", pKeyColumnValue, e);
                    throw new EntityReaderException(e);
                }
                catch (TException e)
                {
                    log.error("Error while getting columns for row Key {} , Caused by: .", pKeyColumnValue, e);
                    throw new EntityReaderException(e);
                }
                finally
                {
                    releaseConnection(conn);
                }

                List columns = ThriftDataResultHelper.transformThriftResult(results, ColumnFamilyType.COLUMN,
                        null);

                foreignKeys = dataHandler.getForeignKeysFromJoinTable(columnName, columns, columnJavaType);
            }
        }
        return (List) foreignKeys;
    }

    /**
     * Retrieves IDs for a given column.
     * 
     * @param schemaName
     *            the schema name
     * @param tableName
     *            the table name
     * @param pKeyName
     *            the key name
     * @param columnName
     *            the column name
     * @param columnValue
     *            the column value
     * @param entityClazz
     *            the entity clazz
     * @return the object[]
     */
    @Override
    public Object[] findIdsByColumn(String schemaName, String tableName, String pKeyName, String columnName,
            Object columnValue, Class entityClazz)
    {
        List rowKeys = new ArrayList();

        if (getCqlVersion().equalsIgnoreCase(CassandraConstants.CQL_VERSION_3_0))
        {
            rowKeys = findIdsByColumnUsingCql(schemaName, tableName, pKeyName, columnName, columnValue, entityClazz);
        }
        else
        {
            EntityMetadata metadata = KunderaMetadataManager.getEntityMetadata(kunderaMetadata, entityClazz);
            SlicePredicate slicePredicate = new SlicePredicate();

            slicePredicate.setSlice_range(new SliceRange(ByteBufferUtil.EMPTY_BYTE_BUFFER,
                    ByteBufferUtil.EMPTY_BYTE_BUFFER, false, Integer.MAX_VALUE));

            String childIdStr = PropertyAccessorHelper.getString(columnValue);
            IndexExpression ie = new IndexExpression(UTF8Type.instance.decompose(columnName
                    + Constants.JOIN_COLUMN_NAME_SEPARATOR + childIdStr), IndexOperator.EQ,
                    UTF8Type.instance.decompose(childIdStr));

            List expressions = new ArrayList();
            expressions.add(ie);

            IndexClause ix = new IndexClause();
            ix.setStart_key(ByteBufferUtil.EMPTY_BYTE_BUFFER);
            ix.setCount(Integer.MAX_VALUE);
            ix.setExpressions(expressions);

            ColumnParent columnParent = new ColumnParent(tableName);
            Connection conn = null;
            try
            {
                conn = getConnection();
                List keySlices = conn.getClient().get_indexed_slices(columnParent, ix, slicePredicate,
                        getConsistencyLevel());

                rowKeys = ThriftDataResultHelper.getRowKeys(keySlices, metadata);
            }
            catch (InvalidRequestException e)
            {
                log.error("Error while fetching key slices of column family {} for column name {} , Caused by: .",
                        tableName, columnName, e);
                throw new KunderaException(e);
            }
            catch (UnavailableException e)
            {
                log.error("Error while fetching key slices of column family {} for column name {} , Caused by: .",
                        tableName, columnName, e);
                throw new KunderaException(e);
            }
            catch (TimedOutException e)
            {
                log.error("Error while fetching key slices of column family {} for column name {} , Caused by: .",
                        tableName, columnName, e);
                throw new KunderaException(e);
            }
            catch (TException e)
            {
                log.error("Error while fetching key slices of column family {} for column name {} , Caused by: .",
                        tableName, columnName, e);
                throw new KunderaException(e);
            }
            finally
            {
                releaseConnection(conn);
            }
        }
        if (rowKeys != null && !rowKeys.isEmpty())
        {
            return rowKeys.toArray(new Object[0]);
        }

        if (log.isInfoEnabled())
        {
            log.info("No record found!, returning null.");
        }
        return null;
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.impetus.kundera.client.Client#findByRelation(java.lang.String,
     * java.lang.Object, java.lang.Class)
     */
    @Override
    public List findByRelation(String colName, Object colValue, Class entityClazz)
    {
        EntityMetadata m = KunderaMetadataManager.getEntityMetadata(kunderaMetadata, entityClazz);
        List entities = null;

        if (isCql3Enabled(m))
        {
            entities = new ArrayList();

            MetamodelImpl metaModel = (MetamodelImpl) kunderaMetadata.getApplicationMetadata().getMetamodel(
                    m.getPersistenceUnit());

            EntityType entityType = metaModel.entity(m.getEntityClazz());

            List subManagedType = ((AbstractManagedType) entityType).getSubManagedType();

            if (subManagedType.isEmpty())
            {
                entities.addAll(findByRelationQuery(m, colName, colValue, entityClazz, dataHandler));
            }
            else
            {
                for (AbstractManagedType subEntity : subManagedType)
                {
                    EntityMetadata subEntityMetadata = KunderaMetadataManager.getEntityMetadata(kunderaMetadata,
                            subEntity.getJavaType());

                    entities.addAll(findByRelationQuery(subEntityMetadata, colName, colValue,
                            subEntityMetadata.getEntityClazz(), dataHandler));
                    // TODOO:: if(entities != null)
                }
            }

        }
        else
        {
            SlicePredicate slicePredicate = new SlicePredicate();
            slicePredicate.setSlice_range(new SliceRange(ByteBufferUtil.EMPTY_BYTE_BUFFER,
                    ByteBufferUtil.EMPTY_BYTE_BUFFER, false, Integer.MAX_VALUE));

            IndexExpression ie = new IndexExpression(UTF8Type.instance.decompose(colName), IndexOperator.EQ,
                    ByteBuffer.wrap(PropertyAccessorHelper.getBytes(colValue)));
            List expressions = new ArrayList();
            expressions.add(ie);

            IndexClause ix = new IndexClause();
            ix.setStart_key(ByteBufferUtil.EMPTY_BYTE_BUFFER);
            ix.setCount(Integer.MAX_VALUE);
            ix.setExpressions(expressions);
            ColumnParent columnParent = new ColumnParent(m.getTableName());

            List keySlices = null;
            Connection conn = null;

            try
            {
                conn = getConnection();
                if (!m.getType().equals(Type.SUPER_COLUMN_FAMILY))
                {
                    keySlices = conn.getClient().get_indexed_slices(columnParent, ix, slicePredicate,
                            getConsistencyLevel());
                }
            }
            catch (InvalidRequestException e)
            {
                if (e.why != null && e.why.contains("No indexed columns"))
                {
                    return entities;
                }
                else
                {
                    log.error("Error while finding relations for column family {} , Caused by: .", m.getTableName(), e);
                    throw new KunderaException(e);
                }
            }
            catch (UnavailableException e)
            {
                log.error("Error while finding relations for column family {} , Caused by: .", m.getTableName(), e);
                throw new KunderaException(e);
            }
            catch (TimedOutException e)
            {
                log.error("Error while finding relations for column family {} , Caused by: .", m.getTableName(), e);
                throw new KunderaException(e);
            }
            catch (TException e)
            {
                log.error("Error while finding relations for column family {} , Caused by: .", m.getTableName(), e);
                throw new KunderaException(e);
            }
            finally
            {
                releaseConnection(conn);
            }

            if (keySlices != null)
            {
                entities = new ArrayList(keySlices.size());

                MetamodelImpl metaModel = (MetamodelImpl) kunderaMetadata.getApplicationMetadata().getMetamodel(
                        m.getPersistenceUnit());

                EntityType entityType = metaModel.entity(m.getEntityClazz());

                List subManagedType = ((AbstractManagedType) entityType).getSubManagedType();

                if (subManagedType.isEmpty())
                {
                    entities = populateData(m, keySlices, entities, m.getRelationNames() != null, m.getRelationNames());
                }
                else
                {
                    for (AbstractManagedType subEntity : subManagedType)
                    {
                        EntityMetadata subEntityMetadata = KunderaMetadataManager.getEntityMetadata(kunderaMetadata,
                                subEntity.getJavaType());
                        entities = populateData(subEntityMetadata, keySlices, entities,
                                subEntityMetadata.getRelationNames() != null, subEntityMetadata.getRelationNames());
                        // TODOO:: if(entities != null)

                    }
                }
            }
        }
        return entities;
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * com.impetus.client.cassandra.CassandraClientBase#delete(java.lang.Object,
     * java.lang.Object)
     */
    @Override
    public void delete(Object entity, Object pKey)
    {
        if (!isOpen())
        {
            throw new PersistenceException("ThriftClient is closed.");
        }

        EntityMetadata metadata = KunderaMetadataManager.getEntityMetadata(kunderaMetadata, entity.getClass());
        Connection conn = null;
        try
        {
            conn = getConnection();
            MetamodelImpl metaModel = (MetamodelImpl) kunderaMetadata.getApplicationMetadata().getMetamodel(
                    metadata.getPersistenceUnit());

            AbstractManagedType managedType = (AbstractManagedType) metaModel.entity(metadata.getEntityClazz());
            // For secondary tables.
            List secondaryTables = ((DefaultEntityAnnotationProcessor) managedType.getEntityAnnotation())
                    .getSecondaryTablesName();
            secondaryTables.add(metadata.getTableName());

            for (String tableName : secondaryTables)
            {
                if (isCql3Enabled(metadata))
                {
                    String deleteQuery = onDeleteQuery(metadata, tableName, metaModel, pKey);
                    executeCQLQuery(deleteQuery, isCql3Enabled(metadata));

                }
                else
                {
                    if (metadata.isCounterColumnType())
                    {
                        deleteRecordFromCounterColumnFamily(pKey, tableName, metadata, getConsistencyLevel());
                    }
                    else
                    {
                        ColumnPath path = new ColumnPath(tableName);

                        conn.getClient().remove(
                                CassandraUtilities.toBytes(pKey, metadata.getIdAttribute().getJavaType()), path,
                                generator.getTimestamp(), getConsistencyLevel());
                    }
                }
            }
            getIndexManager().remove(metadata, entity, pKey);

            // Delete from Inverted Index if applicable
            invertedIndexHandler.delete(entity, metadata, getConsistencyLevel(), kunderaMetadata);
        }
        catch (InvalidRequestException e)
        {
            log.error("Error while deleting of column family {} for row key {}, Caused by: .", metadata.getTableName(),
                    pKey, e);
            throw new KunderaException(e);
        }
        catch (TException e)
        {
            log.error("Error while deleting of column family {} for row key {}, Caused by: .", metadata.getTableName(),
                    pKey, e);
            throw new KunderaException(e);
        }
        finally
        {
            releaseConnection(conn);
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.impetus.kundera.client.Client#deleteByColumn(java.lang.String,
     * java.lang.String, java.lang.String, java.lang.Object)
     */
    @Override
    public void deleteByColumn(String schemaName, String tableName, String columnName, Object columnValue)
    {
        if (!isOpen())
        {
            throw new PersistenceException("ThriftClient is closed.");
        }

        Connection conn = null;
        try
        {
            conn = getConnection();
            ColumnPath path = new ColumnPath(tableName);
            conn.getClient().remove(CassandraUtilities.toBytes(columnValue, columnValue.getClass()), path,
                    generator.getTimestamp(), getConsistencyLevel());

        }
        catch (InvalidRequestException e)
        {
            log.error("Error while deleting of column family {} for row key {}, Caused by: .", tableName, columnValue,
                    e);
            throw new KunderaException(e);
        }
        catch (TException e)
        {
            log.error("Error while deleting of column family {} for row key {}, Caused by: .", tableName, columnValue,
                    e);
            throw new KunderaException(e);
        }
        finally
        {
            releaseConnection(conn);
        }

    }

    /*
     * (non-Javadoc)
     * 
     * @see com.impetus.kundera.client.Client#getReader()
     */
    @Override
    public EntityReader getReader()
    {
        return reader;
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.impetus.kundera.client.Client#getQueryImplementor()
     */
    @Override
    public Class getQueryImplementor()
    {
        return CassQuery.class;
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.impetus.kundera.client.ClientBase#getPersistenceUnit()
     */
    @Override
    public String getPersistenceUnit()
    {
        return super.getPersistenceUnit();
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * com.impetus.kundera.client.ClientBase#getRelationHolders(com.impetus.
     * kundera.graph.Node)
     */
    @Override
    protected List getRelationHolders(Node node)
    {
        return super.getRelationHolders(node);
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.impetus.client.cassandra.CassandraClientBase#close()
     */
    @Override
    public void close()
    {
        this.indexManager.flush();
        // this.dataHandler = null;
        // this.invertedIndexHandler = null;
        super.close();
    }

    /**
     * Populate data.
     * 
     * @param m
     *            the m
     * @param keySlices
     *            the key slices
     * @param entities
     *            the entities
     * @param isRelational
     *            the is relational
     * @param relationNames
     *            the relation names
     * @return the list
     */
    private List populateData(EntityMetadata m, List keySlices, List entities, boolean isRelational,
            List relationNames)
    {
        try
        {
            if (m.getType().isSuperColumnFamilyMetadata())
            {
                List rowKeys = ThriftDataResultHelper.getRowKeys(keySlices, m);

                Object[] rowIds = rowKeys.toArray();
                entities.addAll(findAll(m.getEntityClazz(), null, rowIds));
            }
            else
            {
                for (KeySlice keySlice : keySlices)
                {
                    byte[] key = keySlice.getKey();
                    List coscList = keySlice.getColumns();

                    List columns = ThriftDataResultHelper.transformThriftResult(coscList,
                            ColumnFamilyType.COLUMN, null);
                    Object e = null;
                    Object id = PropertyAccessorHelper.getObject(m.getIdAttribute().getJavaType(), key);
                    e = dataHandler.populateEntity(new ThriftRow(id, m.getTableName(), columns,
                            new ArrayList(0), new ArrayList(0),
                            new ArrayList(0)), m, KunderaCoreUtils.getEntity(e), relationNames,
                            isRelational);
                    entities.add(e);
                }
            }
        }
        catch (Exception e)
        {

            log.error("Error while populating data for relations of column family {}, Caused by: .", m.getTableName(),
                    e);
            throw new KunderaException(e);
        }
        return entities;
    }

    /**
     * Query related methods.
     * 
     * @param clazz
     *            the clazz
     * @param relationalField
     *            the relational field
     * @param isNative
     *            the is native
     * @param cqlQuery
     *            the cql query
     * @return the list
     */

    @Override
    public List executeQuery(Class clazz, List relationalField, boolean isNative, String cqlQuery)
    {
        if (clazz == null)
        {
            return super.executeScalarQuery(cqlQuery);
        }
        return super.executeSelectQuery(clazz, relationalField, dataHandler, isNative, cqlQuery);
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * com.impetus.client.cassandra.CassandraClientBase#find(java.util.List,
     * com.impetus.kundera.metadata.model.EntityMetadata, boolean,
     * java.util.List, int, java.util.List)
     */
    @Override
    public List find(List ixClause, EntityMetadata m, boolean isRelation, List relations,
            int maxResult, List columns)
    {
        List entities = new ArrayList();
        Connection conn = null;
        try
        {
            // ixClause can be 0,1 or more!
            SlicePredicate slicePredicate = new SlicePredicate();

            if (columns != null && !columns.isEmpty())
            {
                List asList = new ArrayList(32);
                for (String colName : columns)
                {
                    if (colName != null)
                    {
                        asList.add(UTF8Type.instance.decompose(colName));
                    }
                }
                slicePredicate.setColumn_names(asList);
            }
            else
            {
                SliceRange sliceRange = new SliceRange();
                sliceRange.setStart(ByteBufferUtil.EMPTY_BYTE_BUFFER);
                sliceRange.setFinish(ByteBufferUtil.EMPTY_BYTE_BUFFER);
                slicePredicate.setSlice_range(sliceRange);
            }
            conn = getConnection();

            if (ixClause.isEmpty())
            {
                KeyRange keyRange = new KeyRange(maxResult);
                keyRange.setStart_key(ByteBufferUtil.EMPTY_BYTE_BUFFER);
                keyRange.setEnd_key(ByteBufferUtil.EMPTY_BYTE_BUFFER);

                if (m.isCounterColumnType())
                {
                    List ks = conn.getClient().get_range_slices(new ColumnParent(m.getTableName()),
                            slicePredicate, keyRange, getConsistencyLevel());
                    entities = onCounterColumn(m, isRelation, relations, ks);

                }
                else
                {
                    List keySlices = conn.getClient().get_range_slices(new ColumnParent(m.getTableName()),
                            slicePredicate, keyRange, getConsistencyLevel());

                    if (m.getType().isSuperColumnFamilyMetadata())
                    {
                        Map> qResults = ThriftDataResultHelper.transformThriftResult(
                                ColumnFamilyType.SUPER_COLUMN, keySlices, null);
                        entities = new ArrayList(qResults.size());
                        computeEntityViaSuperColumns(m, isRelation, relations, entities, qResults);
                    }
                    else
                    {
                        Map> qResults = ThriftDataResultHelper.transformThriftResult(
                                ColumnFamilyType.COLUMN, keySlices, null);
                        entities = new ArrayList(qResults.size());
                        computeEntityViaColumns(m, isRelation, relations, entities, qResults);
                    }
                }
            }
            else
            {
                entities = new ArrayList();
                for (IndexClause ix : ixClause)
                {
                    List keySlices = conn.getClient().get_indexed_slices(new ColumnParent(m.getTableName()),
                            ix, slicePredicate, getConsistencyLevel());

                    Map> qResults = ThriftDataResultHelper.transformThriftResult(
                            ColumnFamilyType.COLUMN, keySlices, null);
                    // iterate through complete map and populate.
                    entities = new ArrayList(qResults.size());

                    computeEntityViaColumns(m, isRelation, relations, entities, qResults);
                }
            }
        }
        catch (InvalidRequestException irex)
        {
            log.error("Error during executing find of column family {}, Caused by: .", m.getTableName(), irex);
            throw new PersistenceException(irex);
        }
        catch (UnavailableException uex)
        {
            log.error("Error during executing find of column family {}, Caused by: .", m.getTableName(), uex);
            throw new PersistenceException(uex);
        }
        catch (TimedOutException tex)
        {
            log.error("Error during executing find of column family {}, Caused by: .", m.getTableName(), tex);
            throw new PersistenceException(tex);
        }
        catch (TException tex)
        {
            log.error("Error during executing find of column family {}, Caused by: .", m.getTableName(), tex);
            throw new PersistenceException(tex);
        }
        finally
        {

            releaseConnection(conn);
        }
        return entities;
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * com.impetus.client.cassandra.CassandraClientBase#find(com.impetus.kundera
     * .metadata.model.EntityMetadata, java.util.List, java.util.List, int,
     * java.util.List)
     */
    @Override
    public List find(EntityMetadata m, List relationNames, List conditions,
            int maxResult, List columns)
    {
        return (List) find(conditions, m, true, relationNames, maxResult, columns);
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.impetus.client.cassandra.CassandraClientBase#findByRange(byte[],
     * byte[], com.impetus.kundera.metadata.model.EntityMetadata, boolean,
     * java.util.List, java.util.List, java.util.List, int)
     */
    @Override
    public List findByRange(byte[] minVal, byte[] maxVal, EntityMetadata m, boolean isWrapReq, List relations,
            List columns, List conditions, int maxResults) throws Exception
    {
        SlicePredicate slicePredicate = new SlicePredicate();

        if (columns != null && !columns.isEmpty())
        {
            List asList = new ArrayList(32);
            for (String colName : columns)
            {
                if (colName != null)
                {
                    asList.add(UTF8Type.instance.decompose(colName));
                }
            }
            slicePredicate.setColumn_names(asList);
        }
        else
        {
            SliceRange sliceRange = new SliceRange();
            sliceRange.setStart(ByteBufferUtil.EMPTY_BYTE_BUFFER);
            sliceRange.setFinish(ByteBufferUtil.EMPTY_BYTE_BUFFER);
            slicePredicate.setSlice_range(sliceRange);
        }

        KeyRange keyRange = new KeyRange(maxResults);
        keyRange.setStart_key(minVal == null ? "".getBytes() : minVal);
        keyRange.setEnd_key(maxVal == null ? "".getBytes() : maxVal);
        ColumnParent cp = new ColumnParent(m.getTableName());

        if (conditions != null && !conditions.isEmpty())
        {
            keyRange.setRow_filter(conditions);
            keyRange.setRow_filterIsSet(true);
        }

        Connection conn = getConnection();

        List keys = conn.getClient().get_range_slices(cp, slicePredicate, keyRange, getConsistencyLevel());

        releaseConnection(conn);

        List results = null;
        if (keys != null)
        {
            results = populateEntitiesFromKeySlices(m, isWrapReq, relations, keys, dataHandler);
        }
        return results;
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * com.impetus.client.cassandra.CassandraClientBase#searchInInvertedIndex
     * (java.lang.String, com.impetus.kundera.metadata.model.EntityMetadata,
     * java.util.Map)
     */
    @Override
    public List searchInInvertedIndex(String columnFamilyName, EntityMetadata m,
            Map> indexClauseMap)
    {
        return invertedIndexHandler.search(m, getPersistenceUnit(), getConsistencyLevel(), indexClauseMap);
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.impetus.client.cassandra.CassandraClientBase#getDataHandler()
     */
    @Override
    protected CassandraDataHandler getDataHandler()
    {
        return dataHandler;
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.impetus.client.cassandra.CassandraClientBase#getConnection()
     */
    protected Connection getConnection()
    {
        Connection connection = clientFactory.getConnection(pool);
        return connection;
    }

    /**
     * Return cassandra client instance.
     * 
     * @param connection
     *            the connection
     * @return the connection
     */
    protected Cassandra.Client getConnection(Object connection)
    {
        if (connection != null)
        {
            return ((Connection) connection).getClient();
        }

        throw new KunderaException("Invalid configuration!, no available pooled connection found for:"
                + this.getClass().getSimpleName());
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * com.impetus.client.cassandra.CassandraClientBase#releaseConnection(java
     * .lang.Object)
     */
    protected void releaseConnection(Object conn)
    {
        clientFactory.releaseConnection(((Connection) conn).getPool(), ((Connection) conn).getClient());
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.impetus.kundera.client.Client#getIdGenerator()
     */
    @Override
    public Generator getIdGenerator()
    {
        return (Generator) KunderaCoreUtils.createNewInstance(ThriftIdGenerator.class);
    }
}