com.impetus.kundera.db.accessor.SuperColumnFamilyDataAccessor.java Source code

Java tutorial

Introduction

Here is the source code for com.impetus.kundera.db.accessor.SuperColumnFamilyDataAccessor.java

Source

/*
 * Copyright 2010 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.kundera.db.accessor;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.persistence.PersistenceException;

import org.apache.cassandra.avro.Cassandra;
import org.apache.cassandra.thrift.Column;
import org.apache.cassandra.thrift.SuperColumn;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.impetus.kundera.CassandraClient;
import com.impetus.kundera.ejb.EntityManagerImpl;
import com.impetus.kundera.metadata.EntityMetadata;
import com.impetus.kundera.property.PropertyAccessException;
import com.impetus.kundera.property.PropertyAccessorFactory;
import com.impetus.kundera.property.PropertyAccessorHelper;
import com.impetus.kundera.proxy.EnhancedEntity;

/**
 * DataAccessor implementation for Cassandra's SuperColumnFamily.
 * 
 * @author animesh.kumar
 */
public final class SuperColumnFamilyDataAccessor extends BaseDataAccessor<SuperColumn> {

    /** The Constant log. */
    private static final Log log = LogFactory.getLog(SuperColumnFamilyDataAccessor.class);

    /** The Constant TO_ONE_SUPER_COL_NAME. */
    private static final String TO_ONE_SUPER_COL_NAME = "FKey-TO";

    /**
     * Instantiates a new super column family data accessor.
     * 
     * @param em
     *            the em
     */
    public SuperColumnFamilyDataAccessor(EntityManagerImpl em) {
        super(em);
    }

    /*
     * @see com.impetus.kundera.db.DataAccessor#read(java.lang.Class,
     * com.impetus.kundera.metadata.EntityMetadata, java.lang.String)
     */
    @Override
    public <E> E read(Class<E> clazz, EntityMetadata m, String id) throws Exception {
        log.debug("Cassandra >> Read >> " + clazz.getName() + "_" + id);

        String keyspace = m.getKeyspaceName();
        String family = m.getColumnFamilyName();

        // get super column names for this entity
        List<String> scNames = m.getSuperColumnFieldNames();
        scNames.add(TO_ONE_SUPER_COL_NAME);

        // load column from DB
        List<SuperColumn> columns = ((CassandraClient) getEntityManager().getClient()).loadSuperColumns(keyspace,
                family, id, // row id
                scNames.toArray(new String[0]) // array of names
        );

        E e;
        if (null == columns || columns.size() == 0) {
            e = null;
        } else {
            e = fromThriftRow(clazz, m, this.new ThriftRow(id, family, columns));
        }

        return e;
    }

    /*
     * @see com.impetus.kundera.db.DataAccessor#read(java.lang.Class,
     * com.impetus.kundera.metadata.EntityMetadata, java.lang.String[])
     */
    @Override
    public <E> List<E> read(Class<E> clazz, EntityMetadata m, String... ids) throws Exception {
        log.debug("Cassandra >> Read >> " + clazz.getName() + "_(" + Arrays.asList(ids) + ")");

        String keyspace = m.getKeyspaceName();
        String family = m.getColumnFamilyName();

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

        // load columns from DB
        Map<String, List<SuperColumn>> map = ((CassandraClient) getEntityManager().getClient())
                .loadSuperColumns(keyspace, family, ids);

        // Iterate and populate entities
        for (Map.Entry<String, List<SuperColumn>> entry : map.entrySet()) {

            String id = entry.getKey();
            List<SuperColumn> columns = entry.getValue();

            if (entry.getValue().size() == 0) {
                log.debug("@Entity not found for id: " + id);
                continue;
            }

            E e = fromThriftRow(clazz, m, this.new ThriftRow(id, family, columns));
            entities.add(e);
        }

        return entities;
    }

    /*
     * @seecom.impetus.kundera.db.DataAccessor#write(com.impetus.kundera.proxy.
     * EnhancedEntity, com.impetus.kundera.metadata.EntityMetadata)
     */
    @Override
    public void write(EnhancedEntity e, EntityMetadata m) throws Exception {
        String entityName = e.getEntity().getClass().getName();
        String id = e.getId();

        log.debug("Cassandra >> Write >> " + entityName + "_" + id);

        String keyspace = m.getKeyspaceName();
        String family = m.getColumnFamilyName();

        BaseDataAccessor<SuperColumn>.ThriftRow tf = toThriftRow(e, m);

        ((CassandraClient) getEntityManager().getClient()).writeSuperColumns(keyspace, family, // columnFamily
                tf.getId(), // row id
                tf.getColumns().toArray(new SuperColumn[0]) // list of columns
        );
    }

    // Helper method to convert ThriftRow to @Entity
    /**
     * From thrift row.
     * 
     * @param <E>
     *            the element type
     * @param clazz
     *            the clazz
     * @param m
     *            the m
     * @param cr
     *            the cr
     * @return the e
     * @throws Exception
     *             the exception
     */
    private <E> E fromThriftRow(Class<E> clazz, EntityMetadata m, BaseDataAccessor<SuperColumn>.ThriftRow cr)
            throws Exception {

        // Instantiate a new instance
        E e = clazz.newInstance();

        // Set row-key. Note: @Id is always String.
        PropertyAccessorHelper.set(e, m.getIdProperty(), cr.getId());

        // Get a name->field map for super-columns
        Map<String, Field> columnNameToFieldMap = new HashMap<String, Field>();
        for (Map.Entry<String, EntityMetadata.SuperColumn> entry : m.getSuperColumnsMap().entrySet()) {
            for (EntityMetadata.Column cMetadata : entry.getValue().getColumns()) {
                columnNameToFieldMap.put(cMetadata.getName(), cMetadata.getField());
            }
        }

        for (SuperColumn sc : cr.getColumns()) {

            String scName = PropertyAccessorFactory.STRING.fromBytes(sc.getName());
            boolean intoRelations = false;
            if (scName.equals(TO_ONE_SUPER_COL_NAME)) {
                intoRelations = true;
            }

            for (Column column : sc.getColumns()) {
                String name = PropertyAccessorFactory.STRING.fromBytes(column.getName());
                byte[] value = column.getValue();

                if (value == null) {
                    continue;
                }

                if (intoRelations) {
                    EntityMetadata.Relation relation = m.getRelation(name);

                    String foreignKeys = PropertyAccessorFactory.STRING.fromBytes(value);
                    Set<String> keys = deserializeKeys(foreignKeys);
                    getEntityManager().getEntityResolver().populateForeignEntities(e, cr.getId(), relation,
                            keys.toArray(new String[0]));

                } else {
                    // set value of the field in the bean
                    Field field = columnNameToFieldMap.get(name);
                    PropertyAccessorHelper.set(e, field, value);
                }
            }
        }
        return e;
    }

    // Helper method to convert @Entity to ThriftRow
    /**
     * To thrift row.
     * 
     * @param e
     *            the e
     * @param m
     *            the m
     * @return the base data accessor. thrift row
     * @throws Exception
     *             the exception
     */
    private BaseDataAccessor<SuperColumn>.ThriftRow toThriftRow(EnhancedEntity e, EntityMetadata m)
            throws Exception {

        // timestamp to use in thrift column objects
        long timestamp = System.currentTimeMillis();

        BaseDataAccessor<SuperColumn>.ThriftRow cr = this.new ThriftRow();

        // column-family name
        cr.setColumnFamilyName(m.getColumnFamilyName());

        // Set row key
        cr.setId(e.getId());

        for (EntityMetadata.SuperColumn superColumn : m.getSuperColumnsAsList()) {
            String superColumnName = superColumn.getName();

            List<Column> columns = new ArrayList<Column>();

            for (EntityMetadata.Column column : superColumn.getColumns()) {
                Field field = column.getField();
                String name = column.getName();

                try {
                    byte[] value = PropertyAccessorHelper.get(e.getEntity(), field);
                    if (null != value) {
                        columns.add(new Column(PropertyAccessorFactory.STRING.toBytes(name), value, timestamp));
                    }
                } catch (PropertyAccessException exp) {
                    log.warn(exp.getMessage());
                }
            }
            cr.addColumn(new SuperColumn(PropertyAccessorFactory.STRING.toBytes(superColumnName), columns));
        }

        // add toOne relations
        List<Column> columns = new ArrayList<Column>();
        for (Map.Entry<String, Set<String>> entry : e.getForeignKeysMap().entrySet()) {
            String property = entry.getKey();
            Set<String> foreignKeys = entry.getValue();

            String keys = serializeKeys(foreignKeys);
            if (null != keys) {
                columns.add(new Column(PropertyAccessorFactory.STRING.toBytes(property),
                        PropertyAccessorFactory.STRING.toBytes(keys), timestamp));
            }
        }
        if (!columns.isEmpty()) {
            cr.addColumn(new SuperColumn(PropertyAccessorFactory.STRING.toBytes(TO_ONE_SUPER_COL_NAME), columns));
        }
        return cr;
    }

}