com.impetus.client.oraclenosql.OracleNoSQLClient.java Source code

Java tutorial

Introduction

Here is the source code for com.impetus.client.oraclenosql.OracleNoSQLClient.java

Source

/**
 * Copyright 2013 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.oraclenosql;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.concurrent.TimeUnit;

import javax.persistence.GenerationType;
import javax.persistence.PersistenceException;
import javax.persistence.metamodel.Attribute;
import javax.persistence.metamodel.EmbeddableType;
import javax.persistence.metamodel.EntityType;

import oracle.kv.Consistency;
import oracle.kv.Durability;
import oracle.kv.DurabilityException;
import oracle.kv.FaultException;
import oracle.kv.KVStore;
import oracle.kv.Key;
import oracle.kv.impl.api.table.TableImpl;
import oracle.kv.table.FieldDef;
import oracle.kv.table.FieldValue;
import oracle.kv.table.Index;
import oracle.kv.table.IndexKey;
import oracle.kv.table.PrimaryKey;
import oracle.kv.table.RecordValue;
import oracle.kv.table.ReturnRow.Choice;
import oracle.kv.table.Row;
import oracle.kv.table.Table;
import oracle.kv.table.TableAPI;
import oracle.kv.table.TableOpExecutionException;
import oracle.kv.table.TableOperation;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.impetus.client.oraclenosql.config.OracleNoSQLClientProperties;
import com.impetus.client.oraclenosql.query.OracleNoSQLQuery;
import com.impetus.client.oraclenosql.query.OracleNoSQLQueryInterpreter;
import com.impetus.kundera.KunderaException;
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.Generator;
import com.impetus.kundera.graph.Node;
import com.impetus.kundera.index.IndexManager;
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.MetamodelImpl;
import com.impetus.kundera.metadata.model.PersistenceUnitMetadata;
import com.impetus.kundera.metadata.model.Relation;
import com.impetus.kundera.metadata.model.Relation.ForeignKey;
import com.impetus.kundera.metadata.model.attributes.AbstractAttribute;
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.api.Batcher;
import com.impetus.kundera.persistence.context.jointable.JoinTableData;
import com.impetus.kundera.property.PropertyAccessorHelper;
import com.impetus.kundera.query.KunderaQuery.FilterClause;
import com.impetus.kundera.query.QueryHandlerException;
import com.impetus.kundera.utils.KunderaCoreUtils;

/**
 * Implementation of {@link Client} interface for Oracle NoSQL database.
 * 
 * @author vivek.mishra
 */
public class OracleNoSQLClient extends ClientBase
        implements Client<OracleNoSQLQuery>, Batcher, ClientPropertiesSetter {

    /** The Constant SEPERATOR. */
    private static final String SEPERATOR = "_";

    private static final String JOIN_TABLE_PRIMARY_KEY_NAME = "key";

    /** The kvstore db. */
    private KVStore kvStore;

    /** The factory. */
    private OracleNoSQLClientFactory factory;

    /** The handler. */
    private OracleNoSQLDataHandler handler;

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

    /** list of nodes for batch processing. */
    private List<Node> nodes = new ArrayList<Node>();

    /** batch size. */
    private int batchSize;

    // Configuration Parameter
    /** The timeout. */
    private int timeout = OracleNOSQLConstants.DEFAULT_WRITE_TIMEOUT_SECONDS;

    /** The durability. */
    private Durability durability = OracleNOSQLConstants.DEFAULT_DURABILITY;

    /** The time unit. */
    private TimeUnit timeUnit = OracleNOSQLConstants.DEFAULT_TIME_UNIT;

    /** The consistency. */
    private Consistency consistency = OracleNOSQLConstants.DEFAULT_CONSISTENCY;

    /** The table api. */
    private TableAPI tableAPI;

    /** The log. */
    private static Logger log = LoggerFactory.getLogger(OracleNoSQLClient.class);

    /**
     * Instantiates a new oracle no sqldb client.
     * 
     * @param factory
     *            the factory
     * @param reader
     *            the reader
     * @param indexManager
     *            the index manager
     * @param kvStore
     *            the kv store
     * @param puProperties
     *            the pu properties
     * @param persistenceUnit
     *            the persistence unit
     * @param kunderaMetadata
     *            the kundera metadata
     */
    OracleNoSQLClient(final OracleNoSQLClientFactory factory, EntityReader reader, IndexManager indexManager,
            final KVStore kvStore, Map<String, Object> puProperties, String persistenceUnit,
            final KunderaMetadata kunderaMetadata) {
        super(kunderaMetadata, puProperties, persistenceUnit);
        this.factory = factory;
        this.kvStore = kvStore;
        // this.handler = new OracleNoSQLDataHandler(this, kvStore,
        // persistenceUnit);
        this.reader = reader;
        this.indexManager = indexManager;
        this.clientMetadata = factory.getClientMetadata();
        this.tableAPI = kvStore.getTableAPI();
        setBatchSize(persistenceUnit, puProperties);
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.impetus.kundera.client.Client#find(java.lang.Class,
     * java.lang.Object)
     */

    @Override
    public Object find(Class entityClass, Object key) {
        return find(entityClass, key, null);
    }

    /**
     * Find by id.
     * 
     * @param entityClass
     *            entity class
     * @param key
     *            primary key
     * @param columnsToSelect
     *            columns to select
     * @return the object
     */
    private Object find(Class entityClass, Object key, List<String> columnsToSelect) {
        EntityMetadata entityMetadata = KunderaMetadataManager.getEntityMetadata(kunderaMetadata, entityClass);
        MetamodelImpl metamodel = (MetamodelImpl) KunderaMetadataManager.getMetamodel(kunderaMetadata,
                entityMetadata.getPersistenceUnit());

        String idColumnName = ((AbstractAttribute) entityMetadata.getIdAttribute()).getJPAColumnName();
        Table schemaTable = tableAPI.getTable(entityMetadata.getTableName());

        PrimaryKey rowKey = schemaTable.createPrimaryKey();
        if (metamodel.isEmbeddable(entityMetadata.getIdAttribute().getBindableJavaType())) {
            readEmbeddable(key, columnsToSelect, entityMetadata, metamodel, schemaTable, rowKey,
                    entityMetadata.getIdAttribute());
        } else {
            if (eligibleToFetch(columnsToSelect, idColumnName)) {
                NoSqlDBUtils.add(schemaTable.getField(idColumnName), rowKey, key, idColumnName);
            }
        }
        KunderaCoreUtils.printQuery("Fetch data from " + entityMetadata.getTableName() + " for PK " + key,
                showQuery);
        if (log.isDebugEnabled()) {
            log.debug("Fetching data from " + entityMetadata.getTableName() + " for PK " + key);
        }

        // Object entity = null;
        List entities = new ArrayList();
        Map<String, Object> relationMap = initialize(entityMetadata);

        try {
            Iterator<Row> rowsIter = tableAPI.tableIterator(rowKey, null, null);
            // iterator and build entity
            entities = scrollAndPopulate(key, entityMetadata, metamodel, schemaTable, rowsIter, relationMap,
                    columnsToSelect);
        } catch (Exception e) {
            log.error("Error while finding data for Key " + key + ", Caused By :" + e + ".");
            throw new PersistenceException(e);
        }

        return entities.isEmpty() ? null : entities.get(0);
    }

    /**
     * Read embeddable.
     * 
     * @param key
     *            the key
     * @param columnsToSelect
     *            the columns to select
     * @param entityMetadata
     *            the entity metadata
     * @param metamodel
     *            the metamodel
     * @param schemaTable
     *            the schema table
     * @param value
     *            the value
     * @param attribute
     *            the attribute
     */
    private void readEmbeddable(Object key, List<String> columnsToSelect, EntityMetadata entityMetadata,
            MetamodelImpl metamodel, Table schemaTable, RecordValue value, Attribute attribute) {
        EmbeddableType embeddableId = metamodel.embeddable(((AbstractAttribute) attribute).getBindableJavaType());
        Set<Attribute> embeddedAttributes = embeddableId.getAttributes();

        for (Attribute embeddedAttrib : embeddedAttributes) {
            String columnName = ((AbstractAttribute) embeddedAttrib).getJPAColumnName();
            Object embeddedColumn = PropertyAccessorHelper.getObject(key, (Field) embeddedAttrib.getJavaMember());

            // either null or empty or contains that column
            if (eligibleToFetch(columnsToSelect, columnName)) {
                NoSqlDBUtils.add(schemaTable.getField(columnName), value, embeddedColumn, columnName);
            }
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.impetus.kundera.client.Client#close()
     */
    @Override
    public void close() {
        this.handler = null;
        this.reader = null;

        nodes.clear();
    }

    /**
     * Delete by primary key.
     * 
     * @param entity
     *            the entity
     * @param pKey
     *            the key
     */
    @Override
    public void delete(Object entity, Object pKey) {
        EntityMetadata entityMetadata = KunderaMetadataManager.getEntityMetadata(kunderaMetadata,
                entity.getClass());
        MetamodelImpl metamodel = (MetamodelImpl) KunderaMetadataManager.getMetamodel(kunderaMetadata,
                entityMetadata.getPersistenceUnit());

        String idColumnName = ((AbstractAttribute) entityMetadata.getIdAttribute()).getJPAColumnName();

        Table schemaTable = tableAPI.getTable(entityMetadata.getTableName());

        PrimaryKey key = schemaTable.createPrimaryKey();

        if (metamodel.isEmbeddable(entityMetadata.getIdAttribute().getBindableJavaType())) {
            EmbeddableType embeddableId = metamodel
                    .embeddable(entityMetadata.getIdAttribute().getBindableJavaType());
            Set<Attribute> embeddedAttributes = embeddableId.getAttributes();

            for (Attribute embeddedAttrib : embeddedAttributes) {
                String columnName = ((AbstractAttribute) embeddedAttrib).getJPAColumnName();
                Object embeddedColumn = PropertyAccessorHelper.getObject(pKey,
                        (Field) embeddedAttrib.getJavaMember());

                NoSqlDBUtils.add(schemaTable.getField(columnName), key, embeddedColumn, columnName);
            }
        } else {
            NoSqlDBUtils.add(schemaTable.getField(idColumnName), key, pKey, idColumnName);
        }

        tableAPI.delete(key, null, null);
        KunderaCoreUtils.printQuery("Delete data from " + entityMetadata.getTableName() + " for PK " + pKey,
                showQuery);
    }

    /**
     * On persist.
     * 
     * @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<RelationHolder> rlHolders) {
        KunderaCoreUtils.printQuery("Persist data into " + entityMetadata.getSchema() + "."
                + entityMetadata.getTableName() + " for " + id, showQuery);
        Row row = createRow(entityMetadata, entity, id, rlHolders);
        // TODO:: handle case for putDate??????

        tableAPI.put(row, null, null);
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * com.impetus.kundera.client.Client#persistJoinTable(com.impetus.kundera
     * .persistence.context.jointable.JoinTableData)
     */
    @Override
    public void persistJoinTable(JoinTableData joinTableData) {
        String joinTableName = joinTableData.getJoinTableName();
        String joinColumnName = joinTableData.getJoinColumnName();
        String invJoinColumnName = joinTableData.getInverseJoinColumnName();
        Map<Key, List<TableOperation>> operations = new HashMap<Key, List<TableOperation>>();

        Table schemaTable = tableAPI.getTable(joinTableName);
        Row row = schemaTable.createRow();

        // String primaryKey = joinColumnName + SEPERATOR + invJoinColumnName;

        KunderaCoreUtils.printQuery("Persist Join Table:" + joinTableName, showQuery);
        Map<Object, Set<Object>> joinTableRecords = joinTableData.getJoinTableRecords();

        try {
            for (Object pk : joinTableRecords.keySet()) {
                // here pk is join column name and it's values would become
                // inverse join columns

                NoSqlDBUtils.add(schemaTable.getField(joinColumnName), row, pk, joinColumnName);
                Set<Object> values = joinTableRecords.get(pk);
                for (Object childId : values) {
                    // what if join or inverse join column is null? Not handling
                    // as ideally it should be handled in core itself!

                    NoSqlDBUtils.add(schemaTable.getField(invJoinColumnName), row, childId, invJoinColumnName);

                    NoSqlDBUtils.add(schemaTable.getField(JOIN_TABLE_PRIMARY_KEY_NAME), row,
                            pk.toString() + SEPERATOR + childId.toString(), JOIN_TABLE_PRIMARY_KEY_NAME);

                    addOps(operations, schemaTable, row);
                }
            }

            execute(operations);
        } finally {
            operations.clear();
            operations = null;
        }
    }

    /**
     * Adds the ops.
     * 
     * @param operations
     *            the operations
     * @param schemaTable
     *            the schema table
     * @param row
     *            the row
     */
    private void addOps(Map<Key, List<TableOperation>> operations, Table schemaTable, Row row) {
        Key key = ((TableImpl) schemaTable).createKey(row, false);

        TableOperation ops = tableAPI.getTableOperationFactory().createPut(row, Choice.NONE, true);

        if (operations.containsKey(key)) {
            operations.get(key).add(ops);

        } else {
            List<TableOperation> operation = new ArrayList<TableOperation>();
            operation.add(ops);
            operations.put(key, operation);
        }
    }

    /**
     * Execute.
     * 
     * @param batches
     *            the batches
     */
    private void execute(Map<Key, List<TableOperation>> batches) {
        if (batches != null && !batches.isEmpty()) {
            try {
                for (List<TableOperation> batch : batches.values()) {
                    tableAPI.execute(batch, null);
                }
            } catch (DurabilityException e) {
                log.error("Error while executing operations in OracleNOSQL, Caused by:" + e + ".");
                throw new PersistenceException("Error while Persisting data using batch", e);
            } catch (TableOpExecutionException e) {
                log.error("Error while executing operations in OracleNOSQL, Caused by:" + e + ".");
                throw new PersistenceException("Error while Persisting data using batch", e);
            } catch (FaultException e) {
                log.error("Error while executing operations in OracleNOSQL, Caused by:" + e + ".");
                throw new PersistenceException("Error while Persisting data using batch", e);
            } finally {
                batches.clear();
            }
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.impetus.kundera.client.Client#findAll(java.lang.Class,
     * java.lang.String[], java.lang.Object[])
     */
    @Override
    public <E> List<E> findAll(Class<E> entityClass, String[] columnsToSelect, Object... keys) {
        List<E> results = new ArrayList<E>();

        if (columnsToSelect == null) {
            columnsToSelect = new String[0];
        }

        if (keys == null) {
            EntityMetadata entityMetadata = KunderaMetadataManager.getEntityMetadata(kunderaMetadata, entityClass);
            MetamodelImpl metamodel = (MetamodelImpl) KunderaMetadataManager.getMetamodel(kunderaMetadata,
                    entityMetadata.getPersistenceUnit());

            EntityType entityType = metamodel.entity(entityMetadata.getEntityClazz());

            Table schemaTable = tableAPI.getTable(entityMetadata.getTableName());
            // KunderaCoreUtils.showQuery("Get all records for " +
            // entityMetadata.getTableName(), showQuery);
            Iterator<Row> rowsIter = tableAPI.tableIterator(schemaTable.createPrimaryKey(), null, null);

            Map<String, Object> relationMap = initialize(entityMetadata);

            try {
                results = scrollAndPopulate(null, entityMetadata, metamodel, schemaTable, rowsIter, relationMap,
                        Arrays.asList(columnsToSelect));
            } catch (Exception e) {
                log.error("Error while finding records , Caused By :" + e + ".");
                throw new PersistenceException(e);
            }
        } else {

            for (Object key : keys) {
                results.add((E) find(entityClass, key, Arrays.asList(columnsToSelect)));
            }
        }

        return results;
    }

    /**
     * On JPQL query execution.
     * 
     * @param <E>
     *            the element type
     * @param entityClass
     *            entity class.
     * @param interpreter
     *            query interpreter
     * @param primaryKeys
     *            set of primary keys. Empty if
     * @return the list
     */
    public <E> List<E> executeQuery(Class<E> entityClass, OracleNoSQLQueryInterpreter interpreter,
            Set<Object> primaryKeys) {

        EntityMetadata entityMetadata = KunderaMetadataManager.getEntityMetadata(kunderaMetadata, entityClass);
        MetamodelImpl metamodel = (MetamodelImpl) KunderaMetadataManager.getMetamodel(kunderaMetadata,
                entityMetadata.getPersistenceUnit());

        EntityType entityType = metamodel.entity(entityMetadata.getEntityClazz());

        List<E> results = new ArrayList<E>();

        if (interpreter.getClauseQueue().isEmpty()) // Select all query
        {
            // Select Query with where clause (requires search within inverted
            // index)
            return findAll(entityClass, interpreter.getSelectColumns(), null);
        } else if (interpreter.isFindById() && interpreter.getClauseQueue().size() == 1) {
            Object value = null;
            Object clause = interpreter.getClauseQueue().peek();
            if (clause.getClass().isAssignableFrom(FilterClause.class)) {
                value = interpreter.getRowKey();
            } else {
                throw new QueryHandlerException(
                        "Query with multiple AND/OR clause is not supported with oracle nosql db");
            }
            if (value != null) {
                Object output = find(entityClass, value, Arrays.asList(interpreter.getSelectColumns()));
                if (output != null) {
                    results.add((E) output);
                }
            }
        } else if (interpreter.getClauseQueue().size() >= 1) // query over index
        // keys.
        {
            return onIndexSearch(interpreter, entityMetadata, metamodel, results,
                    Arrays.asList(interpreter.getSelectColumns()));
        }
        return results;

        // throw new
        // UnsupportedOperationException("Query with where clause is not yet
        // supported");
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.impetus.kundera.client.Client#find(java.lang.Class,
     * java.util.Map)
     */
    @Override
    public <E> List<E> find(Class<E> entityClass, Map<String, String> embeddedColumnMap) {
        throw new UnsupportedOperationException("This operation is not supported for OracleNoSQL.");
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.impetus.kundera.client.Client#getColumnsById(java.lang.String,
     * java.lang.String, java.lang.String, java.lang.String, java.lang.Object,
     * java.lang.Class)
     */
    @Override
    public <E> List<E> getColumnsById(String schemaName, String tableName, String pKeyColumnName, String columnName,
            Object pKeyColumnValue, Class columnJavaType) {
        // search using index on pkey column
        List<E> foreignKeys = new ArrayList<E>();

        Table schemaTable = tableAPI.getTable(tableName);
        Index index = schemaTable.getIndex(pKeyColumnName);
        IndexKey indexKey = index.createIndexKey();

        // StringBuilder indexNamebuilder = new StringBuilder();
        NoSqlDBUtils.add(schemaTable.getField(pKeyColumnName), indexKey, pKeyColumnValue, pKeyColumnName);
        KunderaCoreUtils.printQuery("Get columns by id from:" + tableName + " for column:" + columnName
                + " where value:" + pKeyColumnValue, showQuery);
        Iterator<Row> rowsIter = tableAPI.tableIterator(indexKey, null, null);

        while (rowsIter.hasNext()) {
            Row row = rowsIter.next();
            FieldDef fieldMetadata = schemaTable.getField(columnName);
            FieldValue value = row.get(columnName);
            foreignKeys.add((E) NoSqlDBUtils.get(fieldMetadata, value, null));
        }

        return foreignKeys;

    }

    /*
     * (non-Javadoc)
     * 
     * @see com.impetus.kundera.client.Client#findIdsByColumn(java.lang.String,
     * java.lang.String, java.lang.String, java.lang.String, java.lang.Object,
     * java.lang.Class)
     */
    @Override
    public Object[] findIdsByColumn(String schemaName, String tableName, String pKeyName, String columnName,
            Object columnValue, Class entityClazz) {
        return getColumnsById(schemaName, tableName, columnName, pKeyName, columnValue, entityClazz).toArray();
    }

    /*
     * (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) {
        Table schemaTable = tableAPI.getTable(tableName);
        List<String> primaryKeys = schemaTable.getPrimaryKey();

        Object[] foundRecords = findIdsByColumn(schemaName, tableName, primaryKeys.get(0), columnName, columnValue,
                null);
        KunderaCoreUtils.printQuery("Delete columns by id from:" + tableName, showQuery);
        if (foundRecords != null) {
            for (Object key : foundRecords) {
                PrimaryKey primaryKey = schemaTable.createPrimaryKey();
                NoSqlDBUtils.add(schemaTable.getField(primaryKeys.get(0)), primaryKey, key, primaryKeys.get(0));
                KunderaCoreUtils.printQuery("  Delete for id:" + key, showQuery);
                tableAPI.delete(primaryKey, null, null);
            }
        }

    }

    /*
     * (non-Javadoc)
     * 
     * @see com.impetus.kundera.client.Client#findByRelation(java.lang.String,
     * java.lang.Object, java.lang.Class)
     */
    /**
     * Find by relational column name and value.
     * 
     * @param colName
     *            the col name
     * @param colValue
     *            the col value
     * @param entityClazz
     *            the entity clazz
     * @return the list
     */
    @Override
    public List<Object> findByRelation(String colName, Object colValue, Class entityClazz) {
        // find by relational value !

        EntityMetadata entityMetadata = KunderaMetadataManager.getEntityMetadata(kunderaMetadata, entityClazz);
        MetamodelImpl metamodel = (MetamodelImpl) KunderaMetadataManager.getMetamodel(kunderaMetadata,
                entityMetadata.getPersistenceUnit());

        EntityType entityType = metamodel.entity(entityMetadata.getEntityClazz());

        Table schemaTable = tableAPI.getTable(entityMetadata.getTableName());

        Iterator<Row> rowsIter = null;
        if (schemaTable.getPrimaryKey().contains(colName)) {
            PrimaryKey rowKey = schemaTable.createPrimaryKey();
            NoSqlDBUtils.add(schemaTable.getField(colName), rowKey, colValue, colName);
            rowsIter = tableAPI.tableIterator(rowKey, null, null);
        } else {
            Index index = schemaTable.getIndex(colName);
            IndexKey indexKey = index.createIndexKey();
            NoSqlDBUtils.add(schemaTable.getField(colName), indexKey, colValue, colName);
            rowsIter = tableAPI.tableIterator(indexKey, null, null);
        }

        try {
            Map<String, Object> relationMap = initialize(entityMetadata);

            return scrollAndPopulate(null, entityMetadata, metamodel, schemaTable, rowsIter, relationMap, null);
        } catch (Exception e) {
            log.error("Error while finding data for Key " + colName + ", Caused By :" + e + ".");
            throw new PersistenceException(e);
        }

    }

    /*
     * (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<OracleNoSQLQuery> getQueryImplementor() {
        return OracleNoSQLQuery.class;
    }

    /*
     * (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();
    }

    /**
     * Gets the handler.
     * 
     * @return the handler
     */
    public OracleNoSQLDataHandler getHandler() {
        return handler;
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.impetus.kundera.persistence.api.Batcher#executeBatch()
     */
    @Override
    public int executeBatch() {

        Map<Key, List<TableOperation>> operations = new HashMap<Key, List<TableOperation>>();
        for (Node node : nodes) {
            if (node.isDirty()) {
                node.handlePreEvent();
                // delete can not be executed in batch
                if (node.isInState(RemovedState.class)) {
                    delete(node.getData(), node.getEntityId());
                } else {
                    EntityMetadata metadata = KunderaMetadataManager.getEntityMetadata(kunderaMetadata,
                            node.getDataClass());
                    List<RelationHolder> relationHolders = getRelationHolders(node);
                    // KunderaCoreUtils.showQuery("Execute batch for" +
                    // metadata.getSchema() + "." + metadata.getTableName(),
                    // showQuery);
                    Row row = createRow(metadata, node.getData(), node.getEntityId(), relationHolders);

                    Table schemaTable = tableAPI.getTable(metadata.getTableName());

                    addOps(operations, schemaTable, row);
                }
                node.handlePostEvent();
            }
        }

        execute(operations);
        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 = new ArrayList<Node>();
        }
    }

    /**
     * Check on batch limit.
     */
    private void onBatchLimit() {
        if (batchSize > 0 && batchSize == nodes.size()) {
            executeBatch();
            nodes.clear();
        }
    }

    /**
     * Sets the batch size.
     * 
     * @param persistenceUnit
     *            the persistence unit
     * @param puProperties
     *            the pu properties
     */
    private void setBatchSize(String persistenceUnit, Map<String, Object> puProperties) {
        String batch_Size = null;
        if (puProperties != null) {
            batch_Size = puProperties != null ? (String) puProperties.get(PersistenceProperties.KUNDERA_BATCH_SIZE)
                    : null;
            if (batch_Size != null) {
                setBatchSize(Integer.valueOf(batch_Size));
            }
        } else if (batch_Size == null) {
            PersistenceUnitMetadata puMetadata = KunderaMetadataManager.getPersistenceUnitMetadata(kunderaMetadata,
                    persistenceUnit);
            setBatchSize(puMetadata.getBatchSize());
        }
    }

    /**
     * Sets the batch size.
     * 
     * @param batch_Size
     *            the new batch size
     */
    public void setBatchSize(int batch_Size) {
        this.batchSize = batch_Size;
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.impetus.kundera.client.ClientPropertiesSetter#
     * populateClientProperties (com.impetus.kundera.client.Client,
     * java.util.Map)
     */
    @Override
    public void populateClientProperties(Client client, Map<String, Object> properties) {

        new OracleNoSQLClientProperties().populateClientProperties(client, properties);
    }

    /**
     * Sets the timeout.
     * 
     * @param timeout
     *            the timeout to set
     */
    public void setTimeout(int timeout) {
        this.timeout = timeout;
    }

    /**
     * Sets the durability.
     * 
     * @param durability
     *            the durability to set
     */
    public void setDurability(Durability durability) {
        this.durability = durability;
    }

    /**
     * Sets the time unit.
     * 
     * @param timeUnit
     *            the timeUnit to set
     */
    public void setTimeUnit(TimeUnit timeUnit) {
        this.timeUnit = timeUnit;
    }

    /**
     * Sets the consistency.
     * 
     * @param consistency
     *            the consistency to set
     */
    public void setConsistency(Consistency consistency) {
        this.consistency = consistency;
    }

    /**
     * Gets the timeout.
     * 
     * @return the timeout
     */
    public int getTimeout() {
        return timeout;
    }

    /**
     * Gets the durability.
     * 
     * @return the durability
     */
    public Durability getDurability() {
        return durability;
    }

    /**
     * Gets the time unit.
     * 
     * @return the timeUnit
     */
    public TimeUnit getTimeUnit() {
        return timeUnit;
    }

    /**
     * Gets the consistency.
     * 
     * @return the consistency
     */
    public Consistency getConsistency() {
        return consistency;
    }

    /**
     * Iterate and store attributes.
     * 
     * @param entity
     *            JPA entity.
     * @param metamodel
     *            JPA meta model.
     * @param row
     *            kv row.
     * @param attributes
     *            JPA attributes.
     * @param schemaTable
     *            the schema table
     * @param metadata
     *            the metadata
     */
    private void process(Object entity, MetamodelImpl metamodel, Row row, Set<Attribute> attributes,
            Table schemaTable, EntityMetadata metadata) {

        for (Attribute attribute : attributes) {
            // by pass association.
            if (!attribute.isAssociation()) {
                // in case of embeddable id.
                if (attribute.equals(metadata.getIdAttribute())
                        && metamodel.isEmbeddable(((AbstractAttribute) attribute).getBindableJavaType())) {
                    processEmbeddableAttribute(entity, metamodel, row, schemaTable, metadata, attribute);
                } else {
                    if (metamodel.isEmbeddable(((AbstractAttribute) attribute).getBindableJavaType())) {
                        processEmbeddableAttribute(entity, metamodel, row, schemaTable, metadata, attribute);
                    } else {
                        setField(row, schemaTable, entity, attribute);
                    }
                }
            }
        }
    }

    /**
     * Process embeddable attribute.
     * 
     * @param entity
     *            the entity
     * @param metamodel
     *            the metamodel
     * @param row
     *            the row
     * @param schemaTable
     *            the schema table
     * @param metadata
     *            the metadata
     * @param attribute
     *            the attribute
     */
    private void processEmbeddableAttribute(Object entity, MetamodelImpl metamodel, Row row, Table schemaTable,
            EntityMetadata metadata, Attribute attribute) {
        // process on embeddables.
        EmbeddableType embeddable = metamodel.embeddable(((AbstractAttribute) attribute).getBindableJavaType());
        Set<Attribute> embeddedAttributes = embeddable.getAttributes();
        Object embeddedObject = PropertyAccessorHelper.getObject(entity, (Field) attribute.getJavaMember());

        for (Attribute embeddedAttrib : embeddedAttributes) {
            setField(row, schemaTable, embeddedObject, embeddedAttrib);
        }
    }

    /**
     * Process relational attributes.
     * 
     * @param rlHolders
     *            relation holders
     * @param row
     *            kv row object
     * @param schemaTable
     *            the schema table
     */
    private void onRelationalAttributes(List<RelationHolder> rlHolders, Row row, Table schemaTable) {
        // Iterate over relations
        if (rlHolders != null && !rlHolders.isEmpty()) {
            for (RelationHolder rh : rlHolders) {
                String relationName = rh.getRelationName();
                Object valueObj = rh.getRelationValue();

                if (!StringUtils.isEmpty(relationName) && valueObj != null) {
                    if (valueObj != null) {
                        NoSqlDBUtils.add(schemaTable.getField(relationName), row, valueObj, relationName);
                        KunderaCoreUtils.printQuery(
                                "Add relation: relation name:" + relationName + "relation value:" + valueObj,
                                showQuery);
                    }
                }
            }
        }
    }

    /**
     * Process discriminator columns.
     * 
     * @param row
     *            kv row object.
     * @param entityType
     *            metamodel attribute.
     * @param schemaTable
     *            the schema table
     */
    private void addDiscriminatorColumn(Row row, EntityType entityType, Table schemaTable) {
        String discrColumn = ((AbstractManagedType) entityType).getDiscriminatorColumn();
        String discrValue = ((AbstractManagedType) entityType).getDiscriminatorValue();

        // No need to check for empty or blank, as considering it as valid name
        // for nosql!
        if (discrColumn != null && discrValue != null) {
            // Key
            // Key key = Key.createKey(majorKeyComponent, discrColumn);

            byte[] valueInBytes = PropertyAccessorHelper.getBytes(discrValue);
            NoSqlDBUtils.add(schemaTable.getField(discrColumn), row, discrValue, discrColumn);

        }
    }

    /**
     * setter field.
     * 
     * @param row
     *            the row
     * @param schemaTable
     *            the schema table
     * @param embeddedObject
     *            the embedded object
     * @param embeddedAttrib
     *            the embedded attrib
     */
    private void setField(Row row, Table schemaTable, Object embeddedObject, Attribute embeddedAttrib) {
        Field field = (Field) embeddedAttrib.getJavaMember();
        FieldDef fieldDef = schemaTable.getField(((AbstractAttribute) embeddedAttrib).getJPAColumnName());

        Object valueObj = PropertyAccessorHelper.getObject(embeddedObject, field);

        if (valueObj != null)
            NoSqlDBUtils.add(fieldDef, row, valueObj, ((AbstractAttribute) embeddedAttrib).getJPAColumnName());

    }

    /**
     * Populate id.
     * 
     * @param entityMetadata
     *            the entity metadata
     * @param schemaTable
     *            the schema table
     * @param entity
     *            the entity
     * @param row
     *            the row
     */
    private void populateId(EntityMetadata entityMetadata, Table schemaTable, Object entity, Row row) {
        FieldDef fieldMetadata;
        FieldValue value;
        String idColumnName = ((AbstractAttribute) entityMetadata.getIdAttribute()).getJPAColumnName();

        fieldMetadata = schemaTable.getField(idColumnName);

        value = row.get(idColumnName);

        NoSqlDBUtils.get(fieldMetadata, value, entity, (Field) entityMetadata.getIdAttribute().getJavaMember());
    }

    /**
     * On embeddable id.
     * 
     * @param entityMetadata
     *            the entity metadata
     * @param metaModel
     *            the meta model
     * @param schemaTable
     *            the schema table
     * @param entity
     *            the entity
     * @param row
     *            the row
     * @throws InstantiationException
     *             the instantiation exception
     * @throws IllegalAccessException
     *             the illegal access exception
     */
    private void onEmbeddableId(EntityMetadata entityMetadata, MetamodelImpl metaModel, Table schemaTable,
            Object entity, Row row) throws InstantiationException, IllegalAccessException {
        FieldDef fieldMetadata;
        FieldValue value;
        EmbeddableType embeddableType = metaModel.embeddable(entityMetadata.getIdAttribute().getBindableJavaType());
        Set<Attribute> embeddedAttributes = embeddableType.getAttributes();

        Object embeddedObject = entityMetadata.getIdAttribute().getBindableJavaType().newInstance();
        for (Attribute attrib : embeddedAttributes) {

            String columnName = ((AbstractAttribute) attrib).getJPAColumnName();

            fieldMetadata = schemaTable.getField(columnName);
            value = row.get(columnName);
            NoSqlDBUtils.get(fieldMetadata, value, embeddedObject, (Field) attrib.getJavaMember());
        }

        PropertyAccessorHelper.set(entity, (Field) entityMetadata.getIdAttribute().getJavaMember(), embeddedObject);
    }

    /**
     * Initialize.
     * 
     * @param entityMetadata
     *            the entity metadata
     * @return the map
     */
    private Map<String, Object> initialize(EntityMetadata entityMetadata) {
        Map<String, Object> relationMap = null;
        if (entityMetadata.getRelationNames() != null && !entityMetadata.getRelationNames().isEmpty()) {
            relationMap = new HashMap<String, Object>();
        }
        return relationMap;
    }

    /**
     * Scroll and populate.
     * 
     * @param key
     *            the key
     * @param entityMetadata
     *            the entity metadata
     * @param metaModel
     *            the meta model
     * @param schemaTable
     *            the schema table
     * @param rowsIter
     *            the rows iter
     * @param relationMap
     *            the relation map
     * @param columnsToSelect
     *            the columns to select
     * @return the list
     * @throws InstantiationException
     *             the instantiation exception
     * @throws IllegalAccessException
     *             the illegal access exception
     */
    private List scrollAndPopulate(Object key, EntityMetadata entityMetadata, MetamodelImpl metaModel,
            Table schemaTable, Iterator<Row> rowsIter, Map<String, Object> relationMap,
            List<String> columnsToSelect) throws InstantiationException, IllegalAccessException {
        List results = new ArrayList();
        Object entity = null;
        EntityType entityType = metaModel.entity(entityMetadata.getEntityClazz());
        // here
        while (rowsIter.hasNext()) {
            relationMap = new HashMap<String, Object>();
            entity = initializeEntity(key, entityMetadata);

            Row row = rowsIter.next();

            List<String> fields = row.getTable().getFields();
            FieldDef fieldMetadata = null;
            FieldValue value = null;
            String idColumnName = ((AbstractAttribute) entityMetadata.getIdAttribute()).getJPAColumnName();
            if (/* eligibleToFetch(columnsToSelect, idColumnName) && */!metaModel
                    .isEmbeddable(entityMetadata.getIdAttribute().getBindableJavaType())) {
                populateId(entityMetadata, schemaTable, entity, row);
            } else {
                onEmbeddableId(entityMetadata, metaModel, schemaTable, entity, row);
            }

            Iterator<String> fieldIter = fields.iterator();

            Set<Attribute> attributes = entityType.getAttributes();
            for (Attribute attribute : attributes) {
                String jpaColumnName = ((AbstractAttribute) attribute).getJPAColumnName();
                if (eligibleToFetch(columnsToSelect, jpaColumnName)
                        && !attribute.getName().equals(entityMetadata.getIdAttribute().getName())) {
                    if (metaModel.isEmbeddable(((AbstractAttribute) attribute).getBindableJavaType())) {
                        // readEmbeddable(value, columnsToSelect,
                        // entityMetadata, metaModel, schemaTable, value,
                        // attribute);
                        EmbeddableType embeddableId = metaModel
                                .embeddable(((AbstractAttribute) attribute).getBindableJavaType());
                        Set<Attribute> embeddedAttributes = embeddableId.getAttributes();
                        Object embeddedObject = ((AbstractAttribute) attribute).getBindableJavaType().newInstance();
                        for (Attribute embeddedAttrib : embeddedAttributes) {
                            String embeddedColumnName = ((AbstractAttribute) embeddedAttrib).getJPAColumnName();

                            fieldMetadata = schemaTable.getField(embeddedColumnName);
                            value = row.get(embeddedColumnName);
                            NoSqlDBUtils.get(fieldMetadata, value, embeddedObject,
                                    (Field) embeddedAttrib.getJavaMember());
                        }
                        PropertyAccessorHelper.set(entity, (Field) attribute.getJavaMember(), embeddedObject);

                    } else {
                        fieldMetadata = schemaTable.getField(jpaColumnName);
                        value = row.get(jpaColumnName);

                        if (!attribute.isAssociation() && value != null) {
                            NoSqlDBUtils.get(fieldMetadata, value, entity, (Field) attribute.getJavaMember());
                        } else if (attribute.isAssociation() && value != null) {
                            Relation relation = entityMetadata.getRelation(attribute.getName());

                            if (relation != null) {
                                EntityMetadata associationMetadata = KunderaMetadataManager
                                        .getEntityMetadata(kunderaMetadata, relation.getTargetEntity());
                                if (!relation.getType().equals(ForeignKey.MANY_TO_MANY)) {
                                    relationMap.put(jpaColumnName, NoSqlDBUtils.get(fieldMetadata, value,
                                            (Field) associationMetadata.getIdAttribute().getJavaMember()));
                                }
                            }
                        }
                    }
                }
            }

            if (entity != null) {
                results.add(relationMap.isEmpty() ? entity
                        : new EnhanceEntity(entity,
                                key != null ? key : PropertyAccessorHelper.getId(entity, entityMetadata),
                                relationMap));
            }
        }
        return results;
    }

    /**
     * Initialize entity.
     * 
     * @param key
     *            the key
     * @param entityMetadata
     *            the entity metadata
     * @return the object
     * @throws InstantiationException
     *             the instantiation exception
     * @throws IllegalAccessException
     *             the illegal access exception
     */
    private Object initializeEntity(Object key, EntityMetadata entityMetadata)
            throws InstantiationException, IllegalAccessException {
        Object entity = null;
        entity = entityMetadata.getEntityClazz().newInstance();
        if (key != null) {
            PropertyAccessorHelper.setId(entity, entityMetadata, key);
        }
        return entity;
    }

    /**
     * On index search.
     * 
     * @param <E>
     *            the element type
     * @param interpreter
     *            the interpreter
     * @param entityMetadata
     *            the entity metadata
     * @param metamodel
     *            the metamodel
     * @param results
     *            the results
     * @param columnsToSelect
     *            the columns to select
     * @return the list
     */
    private <E> List<E> onIndexSearch(OracleNoSQLQueryInterpreter interpreter, EntityMetadata entityMetadata,
            MetamodelImpl metamodel, List<E> results, List<String> columnsToSelect) {
        Map<String, List> indexes = new HashMap<String, List>();
        StringBuilder indexNamebuilder = new StringBuilder();

        for (Object clause : interpreter.getClauseQueue()) {
            if (clause.getClass().isAssignableFrom(FilterClause.class)) {
                String fieldName = null;

                String clauseName = ((FilterClause) clause).getProperty();
                StringTokenizer stringTokenizer = new StringTokenizer(clauseName, ".");
                // if need to select embedded columns
                if (stringTokenizer.countTokens() > 1) {
                    fieldName = stringTokenizer.nextToken();
                }

                fieldName = stringTokenizer.nextToken();
                Object value = ((FilterClause) clause).getValue();
                if (!indexes.containsKey(fieldName)) {
                    indexNamebuilder.append(fieldName);
                    indexNamebuilder.append(",");
                }
                indexes.put(fieldName, (List) value);
            } else {
                if (clause.toString().equalsIgnoreCase("OR")) {
                    throw new QueryHandlerException("OR clause is not supported with oracle nosql db");
                }
            }
        }

        // prepare index name and value.
        Table schemaTable = tableAPI.getTable(entityMetadata.getTableName());
        String indexKeyName = indexNamebuilder.deleteCharAt(indexNamebuilder.length() - 1).toString();
        Index index = schemaTable.getIndex(entityMetadata.getIndexProperties().get(indexKeyName).getName());
        IndexKey indexKey = index.createIndexKey();

        // StringBuilder indexNamebuilder = new StringBuilder();
        for (String indexName : indexes.keySet()) {
            NoSqlDBUtils.add(schemaTable.getField(indexName), indexKey, indexes.get(indexName).get(0), indexName);
        }

        Iterator<Row> rowsIter = tableAPI.tableIterator(indexKey, null, null);

        Map<String, Object> relationMap = initialize(entityMetadata);

        try {
            results = scrollAndPopulate(null, entityMetadata, metamodel, schemaTable, rowsIter, relationMap,
                    columnsToSelect);
            KunderaCoreUtils.printQueryWithFilterClause(interpreter.getClauseQueue(),
                    entityMetadata.getTableName());
        } catch (Exception e) {
            log.error("Error while finding records , Caused By :" + e + ".");
            throw new PersistenceException(e);
        }

        return results;
    }

    /**
     * Creates the row.
     * 
     * @param entityMetadata
     *            the entity metadata
     * @param entity
     *            the entity
     * @param id
     *            the id
     * @param rlHolders
     *            the rl holders
     * @return the row
     */
    private Row createRow(EntityMetadata entityMetadata, Object entity, Object id, List<RelationHolder> rlHolders) {
        String schema = entityMetadata.getSchema(); // Irrelevant for this
        // datastore
        String table = entityMetadata.getTableName();

        MetamodelImpl metamodel = (MetamodelImpl) KunderaMetadataManager.getMetamodel(kunderaMetadata,
                entityMetadata.getPersistenceUnit());

        Table schemaTable = null;

        try {
            schemaTable = tableAPI.getTable(table);

            if (schemaTable == null) {
                log.error("No table found for " + table);
                throw new KunderaException("No table found for " + table);
            }
        } catch (FaultException ex) {
            log.error("Error while getting table " + table + ". Caused By: ", ex);
            throw new KunderaException("Error while getting table " + table + ". Caused By: ", ex);
        }

        Row row = schemaTable.createRow();

        if (log.isDebugEnabled()) {
            log.debug("Persisting data into " + schema + "." + table + " for " + id);
        }

        EntityType entityType = metamodel.entity(entityMetadata.getEntityClazz());

        Set<Attribute> attributes = entityType.getAttributes();

        // process entity attributes.
        process(entity, metamodel, row, attributes, schemaTable, entityMetadata);
        // on relational attributes.
        onRelationalAttributes(rlHolders, row, schemaTable);
        // add discriminator column(if present)
        addDiscriminatorColumn(row, entityType, schemaTable);
        return row;
    }

    /**
     * Eligible to fetch.
     * 
     * @param columnsToSelect
     *            the columns to select
     * @param columnName
     *            the column name
     * @return true, if successful
     */
    private boolean eligibleToFetch(List<String> columnsToSelect, String columnName) {
        return (columnsToSelect != null && !columnsToSelect.isEmpty() && columnsToSelect.contains(columnName))
                || (columnsToSelect == null || columnsToSelect.isEmpty());
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.impetus.kundera.client.Client#getIdGenerator()
     */
    @Override
    public Generator getIdGenerator() {
        throw new UnsupportedOperationException(GenerationType.class.getSimpleName()
                + " Strategies not supported by this client : OracleNoSQLClient");
    }

}