Java tutorial
/* * 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; } }