Java tutorial
/******************************************************************************* * * 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.lang.reflect.Field; import java.sql.Time; import java.sql.Timestamp; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import javax.persistence.ElementCollection; import javax.persistence.metamodel.Attribute; import javax.persistence.metamodel.EmbeddableType; import javax.persistence.metamodel.EntityType; import javax.persistence.metamodel.SingularAttribute; import org.apache.cassandra.db.marshal.BooleanType; import org.apache.cassandra.db.marshal.BytesType; import org.apache.cassandra.db.marshal.CounterColumnType; import org.apache.cassandra.db.marshal.DateType; import org.apache.cassandra.db.marshal.DecimalType; import org.apache.cassandra.db.marshal.DoubleType; import org.apache.cassandra.db.marshal.FloatType; import org.apache.cassandra.db.marshal.Int32Type; import org.apache.cassandra.db.marshal.IntegerType; import org.apache.cassandra.db.marshal.ListType; import org.apache.cassandra.db.marshal.LongType; import org.apache.cassandra.db.marshal.MapType; import org.apache.cassandra.db.marshal.SetType; import org.apache.cassandra.db.marshal.TimestampType; import org.apache.cassandra.db.marshal.UTF8Type; import org.apache.cassandra.db.marshal.UUIDType; import org.apache.cassandra.utils.ByteBufferUtil; import org.apache.commons.codec.binary.Hex; import com.impetus.client.cassandra.common.CassandraConstants; import com.impetus.client.cassandra.common.CassandraUtilities; import com.impetus.kundera.Constants; 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.attributes.AbstractAttribute; import com.impetus.kundera.metadata.model.type.AbstractManagedType; import com.impetus.kundera.persistence.EntityManagerFactoryImpl.KunderaMetadata; import com.impetus.kundera.property.PropertyAccessorFactory; import com.impetus.kundera.property.PropertyAccessorHelper; import com.impetus.kundera.utils.ReflectUtils; /** * CQL translator interface, to translate all CRUD operations into CQL queries. * In case compound primary key is boolean, we need to * $COLUMNS,$COLUMNFAMILY,$COLUMNVALUES : They need to be comma separated. * $COLUMNVALUES : It has to be according to data type(add "'" only for * text/string) * * @author vivek.mishra */ public final class CQLTranslator { /** The Constant CREATE_COLUMNFAMILY_QUERY. */ public static final String CREATE_COLUMNFAMILY_QUERY = "CREATE COLUMNFAMILY $COLUMNFAMILY ($COLUMNS"; /** The Constant ADD_PRIMARYKEY_CLAUSE. */ public static final String ADD_PRIMARYKEY_CLAUSE = " , PRIMARY KEY($COLUMNS))"; /** The Constant SELECTALL_QUERY. */ public static final String SELECTALL_QUERY = "SELECT * FROM $COLUMNFAMILY"; /** The Constant SELECT_COUNT_QUERY. */ public static final String SELECT_COUNT_QUERY = "SELECT COUNT(*) FROM $COLUMNFAMILY"; /** The Constant ADD_WHERE_CLAUSE. */ public static final String ADD_WHERE_CLAUSE = " WHERE "; /** The Constant SELECT_QUERY. */ public static final String SELECT_QUERY = "SELECT $COLUMNS FROM $COLUMNFAMILY"; /** The Constant INSERT_QUERY. */ public static final String INSERT_QUERY = " INSERT INTO $COLUMNFAMILY($COLUMNS) VALUES($COLUMNVALUES) "; /** The Constant DELETE_QUERY. */ public static final String DELETE_QUERY = "DELETE FROM $COLUMNFAMILY"; /** The Constant COLUMN_FAMILY. */ public static final String COLUMN_FAMILY = "$COLUMNFAMILY"; /** The Constant COLUMNS. */ public static final String COLUMNS = "$COLUMNS"; /** The Constant COLUMN_VALUES. */ public static final String COLUMN_VALUES = "$COLUMNVALUES"; /** The Constant AND_CLAUSE. */ public static final String AND_CLAUSE = " AND "; /** The Constant SORT_CLAUSE. */ public static final String SORT_CLAUSE = " ORDER BY "; /** The Constant EQ_CLAUSE. */ public static final String EQ_CLAUSE = "="; /** The Constant WITH_CLAUSE. */ public static final String WITH_CLAUSE = " WITH "; /** The Constant QUOTE_STR. */ public static final String QUOTE_STR = "'"; /** The Constant LIMIT. */ public static final String LIMIT = " LIMIT "; /** The Constant CREATE_INDEX_QUERY. */ public static final String CREATE_INDEX_QUERY = "CREATE INDEX ON $COLUMNFAMILY ($COLUMNS)"; /** The Constant BATCH_QUERY. */ public static final String BATCH_QUERY = "BEGIN BATCH $STATEMENT "; /** The Constant STATEMENT. */ public static final String STATEMENT = "$STATEMENT"; /** The Constant APPLY_BATCH. */ public static final String APPLY_BATCH = " APPLY BATCH"; /** The Constant USING_CONSISTENCY. */ public static final String USING_CONSISTENCY = "$USING CONSISTENCY"; /** The Constant CONSISTENCY_LEVEL. */ public static final String CONSISTENCY_LEVEL = "$CONSISTENCYLEVEL"; /** The Constant DROP_TABLE. */ public static final String DROP_TABLE = "drop columnfamily $COLUMN_FAMILY"; /** The Constant UPDATE_QUERY. */ public static final String UPDATE_QUERY = "UPDATE $COLUMNFAMILY "; /** The Constant ADD_SET_CLAUSE. */ public static final String ADD_SET_CLAUSE = "SET "; /** The Constant COMMA_STR. */ public static final String COMMA_STR = ", "; /** The Constant INCR_COUNTER. */ public static final String INCR_COUNTER = "+"; /** The Constant TOKEN. */ public static final String TOKEN = "token("; /** The Constant CLOSE_BRACKET. */ public static final String CLOSE_BRACKET = ")"; /** The Constant SPACE_STRING. */ public static final String SPACE_STRING = " "; /** The Constant IN_CLAUSE. */ public static final String IN_CLAUSE = "IN"; /** The Constant OPEN_BRACKET. */ public static final String OPEN_BRACKET = "("; /** The Constant CREATE_COLUMNFAMILY_CLUSTER_ORDER. */ public static final String CREATE_COLUMNFAMILY_CLUSTER_ORDER = " WITH CLUSTERING ORDER BY ($COLUMNS"; /** The Constant DEFAULT_KEY_NAME. */ public static final String DEFAULT_KEY_NAME = "key"; /** The Constant CREATE_KEYSPACE. */ public static final String CREATE_KEYSPACE = "CREATE KEYSPACE IF NOT EXISTS $KEYSPACE WITH REPLICATION = { 'class':'$CLASS',$REPLICATION} and durable_writes = '$DURABLE_WRITES'"; /** The Constant SIMPLE_REPLICATION. */ public static final String SIMPLE_REPLICATION = "'replication_factor':$REPLICATION_FACTOR"; /** The Constant DURABLE_WRITES. */ public static final String DURABLE_WRITES = "durable_writes=$DURABLE_WRITES"; /** The Constant CREATE_TYPE. */ public static final String CREATE_TYPE = "CREATE TYPE IF NOT EXISTS $TYPE ($COLUMNS"; /** The Constant TYPE. */ public static final String TYPE = "$TYPE"; /** The Constant FROZEN. */ public static final String FROZEN = "frozen"; /** The Constant BEGIN_COUNTER_BATCH. */ public static final String BEGIN_COUNTER_BATCH = "BEGIN COUNTER BATCH"; /** The Constant BEGIN_BATCH. */ public static final String BEGIN_BATCH = "BEGIN BATCH"; /** * Instantiates a new CQL translator. */ public CQLTranslator() { } /** * The Enum TranslationType. */ public static enum TranslationType { /** The column. */ COLUMN, /** The value. */ VALUE, /** The all. */ ALL; } /** * Prepares column name or column values. * * @param record * entity. * @param entityMetadata * entity meta data * @param type * translation type. * @param externalProperties * the external properties * @param kunderaMetadata * the kundera metadata * @return Map containing translation type as key and string as translated * CQL string. */ public HashMap<TranslationType, Map<String, StringBuilder>> prepareColumnOrColumnValues(final Object record, final EntityMetadata entityMetadata, TranslationType type, Map<String, Object> externalProperties, final KunderaMetadata kunderaMetadata) { HashMap<TranslationType, Map<String, StringBuilder>> parsedColumnOrColumnValue = new HashMap<CQLTranslator.TranslationType, Map<String, StringBuilder>>(); if (type == null) { throw new TranslationException("Please specify TranslationType: either COLUMN or VALUE"); } MetamodelImpl metaModel = (MetamodelImpl) kunderaMetadata.getApplicationMetadata() .getMetamodel(entityMetadata.getPersistenceUnit()); Class entityClazz = entityMetadata.getEntityClazz(); EntityType entityType = metaModel.entity(entityClazz); Map<String, StringBuilder> builders = new HashMap<String, StringBuilder>(); Map<String, StringBuilder> columnBuilders = new HashMap<String, StringBuilder>(); onTranslation(record, entityMetadata, type, metaModel, entityClazz, entityType, builders, columnBuilders, externalProperties, kunderaMetadata); for (String tableName : columnBuilders.keySet()) { StringBuilder builder = builders.get(tableName); StringBuilder columnBuilder = columnBuilders.get(tableName); if (type.equals(TranslationType.ALL) || type.equals(TranslationType.VALUE)) { builder.deleteCharAt(builder.length() - 1); } if (type.equals(TranslationType.ALL) || type.equals(TranslationType.COLUMN)) { columnBuilder.deleteCharAt(columnBuilder.length() - 1); } } parsedColumnOrColumnValue.put(TranslationType.COLUMN, columnBuilders); parsedColumnOrColumnValue.put(TranslationType.VALUE, builders); return parsedColumnOrColumnValue; } /** * Gets the CQL type. * * @param internalClazz * the internal clazz * @return the CQL type */ public static String getCQLType(String internalClazz) { return InternalToCQLMapper.getType(internalClazz); } /** * Gets the keyword. * * @param property * the property * @return the keyword */ public static String getKeyword(String property) { return CQLKeywordMapper.getType(property); } /** * On translation. * * @param record * the record * @param m * the m * @param type * the type * @param metaModel * the meta model * @param entityClazz * the entity clazz * @param entityType * the entity type * @param builders * the builders * @param columnBuilders * the column builders * @param externalProperties * the external properties * @param kunderaMetadata * the kundera metadata */ private void onTranslation(final Object record, final EntityMetadata m, TranslationType type, MetamodelImpl metaModel, Class entityClazz, EntityType entityType, Map<String, StringBuilder> builders, Map<String, StringBuilder> columnBuilders, Map<String, Object> externalProperties, final KunderaMetadata kunderaMetadata) { Set<Attribute> attributes = entityType.getAttributes(); Iterator<Attribute> iterator = attributes.iterator(); while (iterator.hasNext()) { Attribute attribute = iterator.next(); // Populating table name. String tableName = ((AbstractAttribute) attribute).getTableName() != null ? ((AbstractAttribute) attribute).getTableName() : m.getTableName(); StringBuilder columnBuilder = columnBuilders.get(tableName); if (columnBuilder == null) { columnBuilder = new StringBuilder(); columnBuilders.put(tableName, columnBuilder); } StringBuilder builder = builders.get(tableName); if (builder == null) { builder = new StringBuilder(); builders.put(tableName, builder); } Field field = (Field) attribute.getJavaMember(); if (!attribute.equals(m.getIdAttribute()) && !((AbstractAttribute) attribute).getJPAColumnName() .equals(((AbstractAttribute) m.getIdAttribute()).getJPAColumnName())) { if (metaModel.isEmbeddable(((AbstractAttribute) attribute).getBindableJavaType())) { // create embedded entity persisting format if (field.isAnnotationPresent(ElementCollection.class)) { // handle embeddable collection // check list, map, set // build embedded value StringBuilder elementCollectionValue = buildElementCollectionValue(field, record, metaModel, attribute); columnBuilder.append(Constants.ESCAPE_QUOTE); columnBuilder.append(((AbstractAttribute) attribute).getJPAColumnName()); columnBuilder.append(Constants.ESCAPE_QUOTE); columnBuilder.append(Constants.COMMA); builder.append(elementCollectionValue); builder.append(Constants.COMMA); } else { EmbeddableType embeddableKey = metaModel.embeddable(field.getType()); Object embeddableKeyObj = PropertyAccessorHelper.getObject(record, field); if (embeddableKeyObj != null) { StringBuilder embeddedValueBuilder = new StringBuilder(Constants.OPEN_CURLY_BRACKET); for (Field embeddableColumn : field.getType().getDeclaredFields()) { if (!ReflectUtils.isTransientOrStatic(embeddableColumn)) { AbstractAttribute subAttribute = (AbstractAttribute) embeddableKey .getAttribute(embeddableColumn.getName()); if (metaModel.isEmbeddable(subAttribute.getBindableJavaType())) { // construct map; recursive // send attribute if (embeddableColumn.isAnnotationPresent(ElementCollection.class)) { // build element collection value StringBuilder elementCollectionValue = buildElementCollectionValue( embeddableColumn, embeddableKeyObj, metaModel, (Attribute) subAttribute); appendColumnName(embeddedValueBuilder, ((AbstractAttribute) (embeddableKey .getAttribute(embeddableColumn.getName()))) .getJPAColumnName()); embeddedValueBuilder.append(Constants.COLON); embeddedValueBuilder.append(elementCollectionValue); } else { buildEmbeddedValue(embeddableKeyObj, metaModel, embeddedValueBuilder, (SingularAttribute) subAttribute); } } else { // append key value appendColumnName(embeddedValueBuilder, ((AbstractAttribute) (embeddableKey .getAttribute(embeddableColumn.getName()))) .getJPAColumnName()); embeddedValueBuilder.append(Constants.COLON); appendColumnValue(embeddedValueBuilder, embeddableKeyObj, embeddableColumn); } embeddedValueBuilder.append(Constants.COMMA); } } // strip last char and append '}' embeddedValueBuilder.deleteCharAt(embeddedValueBuilder.length() - 1); embeddedValueBuilder.append(Constants.CLOSE_CURLY_BRACKET); // add to columnbuilder and builder columnBuilder.append(Constants.ESCAPE_QUOTE); columnBuilder.append(((AbstractAttribute) attribute).getJPAColumnName()); columnBuilder.append(Constants.ESCAPE_QUOTE); columnBuilder.append(Constants.COMMA); builder.append(embeddedValueBuilder); builder.append(Constants.COMMA); // end if } } } else if (!ReflectUtils.isTransientOrStatic(field) && !attribute.isAssociation()) { onTranslation(type, builder, columnBuilder, ((AbstractAttribute) attribute).getJPAColumnName(), record, field); } } } for (String tableName : columnBuilders.keySet()) { translateCompositeId(record, m, type, metaModel, builders, columnBuilders, externalProperties, kunderaMetadata, tableName, m.getIdAttribute()); } // on inherited columns. onDiscriminatorColumn(builders.get(m.getTableName()), columnBuilders.get(m.getTableName()), entityType); } /** * Builds the element collection value. * * @param field * the field * @param record * the record * @param metaModel * the meta model * @param attribute * the attribute * @return the string builder */ private StringBuilder buildElementCollectionValue(Field field, Object record, MetamodelImpl metaModel, Attribute attribute) { StringBuilder elementCollectionValueBuilder = new StringBuilder(); EmbeddableType embeddableKey = metaModel.embeddable(((AbstractAttribute) attribute).getBindableJavaType()); ((AbstractAttribute) attribute).getJavaMember(); Object value = PropertyAccessorHelper.getObject(record, field); boolean isPresent = false; if (Collection.class.isAssignableFrom(field.getType())) { if (value instanceof Collection) { Collection collection = ((Collection) value); isPresent = true; if (List.class.isAssignableFrom(field.getType())) { elementCollectionValueBuilder.append(Constants.OPEN_SQUARE_BRACKET); } if (Set.class.isAssignableFrom(field.getType())) { elementCollectionValueBuilder.append(Constants.OPEN_CURLY_BRACKET); } for (Object o : collection) { // Allowing null values. // build embedded value if (o != null) { StringBuilder embeddedValueBuilder = new StringBuilder(Constants.OPEN_CURLY_BRACKET); for (Field embeddableColumn : ((AbstractAttribute) attribute).getBindableJavaType() .getDeclaredFields()) { if (!ReflectUtils.isTransientOrStatic(embeddableColumn)) { AbstractAttribute subAttribute = (AbstractAttribute) embeddableKey .getAttribute(embeddableColumn.getName()); if (metaModel.isEmbeddable(subAttribute.getBindableJavaType())) { // construct map; recursive // send attribute if (embeddableColumn.getType().isAnnotationPresent(ElementCollection.class)) { // build element collection value StringBuilder elementCollectionValue = buildElementCollectionValue( embeddableColumn, o, metaModel, (Attribute) subAttribute); appendColumnName(embeddedValueBuilder, ((AbstractAttribute) (embeddableKey .getAttribute(embeddableColumn.getName()))) .getJPAColumnName()); embeddedValueBuilder.append(Constants.COLON); embeddedValueBuilder.append(elementCollectionValue); } else { buildEmbeddedValue(o, metaModel, embeddedValueBuilder, (SingularAttribute) subAttribute); } } else { // append key value appendColumnName(embeddedValueBuilder, ((AbstractAttribute) (embeddableKey .getAttribute(embeddableColumn.getName()))).getJPAColumnName()); embeddedValueBuilder.append(Constants.COLON); appendColumnValue(embeddedValueBuilder, o, embeddableColumn); } embeddedValueBuilder.append(Constants.COMMA); } } // strip last char and append '}' embeddedValueBuilder.deleteCharAt(embeddedValueBuilder.length() - 1); embeddedValueBuilder.append(Constants.CLOSE_CURLY_BRACKET); // add to columnbuilder and builder elementCollectionValueBuilder.append(embeddedValueBuilder); // end if } elementCollectionValueBuilder.append(Constants.COMMA); } if (!collection.isEmpty()) { elementCollectionValueBuilder.deleteCharAt(elementCollectionValueBuilder.length() - 1); } if (List.class.isAssignableFrom(field.getType())) { elementCollectionValueBuilder.append(Constants.CLOSE_SQUARE_BRACKET); } if (Set.class.isAssignableFrom(field.getType())) { elementCollectionValueBuilder.append(Constants.CLOSE_CURLY_BRACKET); } return elementCollectionValueBuilder; } return null; } else if (Map.class.isAssignableFrom(field.getType())) { if (value instanceof Map) { Map map = ((Map) value); isPresent = true; elementCollectionValueBuilder.append(Constants.OPEN_CURLY_BRACKET); for (Object mapKey : map.keySet()) { Object mapValue = map.get(mapKey); // Allowing null keys. // key is basic type.. no support for embeddable keys appendValue(elementCollectionValueBuilder, mapKey != null ? mapKey.getClass() : null, mapKey, false); elementCollectionValueBuilder.append(Constants.COLON); // Allowing null values. if (mapValue != null) { StringBuilder embeddedValueBuilder = new StringBuilder(Constants.OPEN_CURLY_BRACKET); for (Field embeddableColumn : ((AbstractAttribute) attribute).getBindableJavaType() .getDeclaredFields()) { if (!ReflectUtils.isTransientOrStatic(embeddableColumn)) { AbstractAttribute subAttribute = (AbstractAttribute) embeddableKey .getAttribute(embeddableColumn.getName()); if (metaModel.isEmbeddable(subAttribute.getBindableJavaType())) { // construct map; recursive // send attribute if (embeddableColumn.getType().isAnnotationPresent(ElementCollection.class)) { // build element collection value StringBuilder elementCollectionValue = buildElementCollectionValue( embeddableColumn, mapValue, metaModel, (Attribute) subAttribute); appendColumnName(embeddedValueBuilder, ((AbstractAttribute) (embeddableKey .getAttribute(embeddableColumn.getName()))) .getJPAColumnName()); embeddedValueBuilder.append(Constants.COLON); embeddedValueBuilder.append(elementCollectionValue); } else { buildEmbeddedValue(mapValue, metaModel, embeddedValueBuilder, (SingularAttribute) subAttribute); } } else { // append key value appendColumnName(embeddedValueBuilder, ((AbstractAttribute) (embeddableKey .getAttribute(embeddableColumn.getName()))).getJPAColumnName()); embeddedValueBuilder.append(Constants.COLON); appendColumnValue(embeddedValueBuilder, mapValue, embeddableColumn); } embeddedValueBuilder.append(Constants.COMMA); } } // strip last char and append '}' embeddedValueBuilder.deleteCharAt(embeddedValueBuilder.length() - 1); embeddedValueBuilder.append(Constants.CLOSE_CURLY_BRACKET); // add to columnbuilder and builder elementCollectionValueBuilder.append(embeddedValueBuilder); // end if } elementCollectionValueBuilder.append(Constants.COMMA); } if (!map.isEmpty()) { elementCollectionValueBuilder.deleteCharAt(elementCollectionValueBuilder.length() - 1); } elementCollectionValueBuilder.append(Constants.CLOSE_CURLY_BRACKET); return elementCollectionValueBuilder; } return null; } return null; } /** * Builds the embedded value. * * @param record * the record * @param metaModel * the meta model * @param embeddedValueBuilder * the embedded value builder * @param attribute * the attribute */ private void buildEmbeddedValue(final Object record, MetamodelImpl metaModel, StringBuilder embeddedValueBuilder, SingularAttribute attribute) { // TODO Auto-generated method stub Field field = (Field) attribute.getJavaMember(); EmbeddableType embeddableKey = metaModel.embeddable(field.getType()); Object embeddableKeyObj = PropertyAccessorHelper.getObject(record, field); if (embeddableKeyObj != null) { StringBuilder tempBuilder = new StringBuilder(); tempBuilder.append(Constants.OPEN_CURLY_BRACKET); for (Field embeddableColumn : field.getType().getDeclaredFields()) { if (!ReflectUtils.isTransientOrStatic(embeddableColumn)) { Attribute subAttribute = (SingularAttribute) embeddableKey .getAttribute(embeddableColumn.getName()); if (metaModel.isEmbeddable(((AbstractAttribute) subAttribute).getBindableJavaType())) { // construct map; recursive // send attribute buildEmbeddedValue(embeddableKeyObj, metaModel, tempBuilder, (SingularAttribute) subAttribute); } else { // append key value appendColumnName(tempBuilder, ((AbstractAttribute) (embeddableKey.getAttribute(embeddableColumn.getName()))) .getJPAColumnName()); tempBuilder.append(Constants.COLON); appendColumnValue(tempBuilder, embeddableKeyObj, embeddableColumn); } tempBuilder.append(Constants.COMMA); } } // strip last char and append '}' tempBuilder.deleteCharAt(tempBuilder.length() - 1); tempBuilder.append(Constants.CLOSE_CURLY_BRACKET); appendColumnName(embeddedValueBuilder, ((AbstractAttribute) attribute).getJPAColumnName()); embeddedValueBuilder.append(Constants.COLON); embeddedValueBuilder.append(tempBuilder); } else { embeddedValueBuilder.deleteCharAt(embeddedValueBuilder.length() - 1); } } /** * Translate composite id. * * @param record * the record * @param m * the m * @param type * the type * @param metaModel * the meta model * @param builders * the builders * @param columnBuilders * the column builders * @param externalProperties * the external properties * @param kunderaMetadata * the kundera metadata * @param tableName * the table name * @param attribute * the attribute */ private void translateCompositeId(final Object record, final EntityMetadata m, TranslationType type, MetamodelImpl metaModel, Map<String, StringBuilder> builders, Map<String, StringBuilder> columnBuilders, Map<String, Object> externalProperties, final KunderaMetadata kunderaMetadata, String tableName, SingularAttribute attribute) { StringBuilder builder = builders.get(tableName); StringBuilder columnBuilder = columnBuilders.get(tableName); Field field = (Field) attribute.getJavaMember(); if (metaModel.isEmbeddable(((AbstractAttribute) attribute).getBindableJavaType())) { // builder. // Means it is a compound key! As other // iterate for it's fields to populate it's values in // order! EmbeddableType compoundKey = metaModel.embeddable(field.getType()); Object compoundKeyObj = PropertyAccessorHelper.getObject(record, field); for (Field compositeColumn : field.getType().getDeclaredFields()) { if (!ReflectUtils.isTransientOrStatic(compositeColumn)) { attribute = (SingularAttribute) compoundKey.getAttribute(compositeColumn.getName()); if (metaModel.isEmbeddable(((AbstractAttribute) attribute).getBindableJavaType())) { translateCompositeId(compoundKeyObj, m, type, metaModel, builders, columnBuilders, externalProperties, kunderaMetadata, tableName, attribute); } else { onTranslation(type, builder, columnBuilder, ((AbstractAttribute) (compoundKey.getAttribute(compositeColumn.getName()))) .getJPAColumnName(), compoundKeyObj, compositeColumn); } } } } else if (!ReflectUtils.isTransientOrStatic(field)) { onTranslation(type, builder, columnBuilder, CassandraUtilities.getIdColumnName(kunderaMetadata, m, externalProperties, true), record, field); } } /** * On discriminator column. * * @param builder * the builder * @param columnBuilder * the column builder * @param entityType * the entity type */ private void onDiscriminatorColumn(StringBuilder builder, StringBuilder columnBuilder, EntityType entityType) { 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) { appendValue(builder, String.class, discrValue, false); builder.append(Constants.COMMA); appendColumnName(columnBuilder, discrColumn); columnBuilder.append(Constants.COMMA); // because only key columns } } /** * Build where clause with @ EQ_CLAUSE} clause. * * @param builder * the builder * @param field * the field * @param member * the member * @param entity * the entity */ public void buildWhereClause(StringBuilder builder, String field, Field member, Object entity) { // builder = ensureCase(builder, field, false); // builder.append(EQ_CLAUSE); // appendColumnValue(builder, entity, member); // builder.append(AND_CLAUSE); Object value = PropertyAccessorHelper.getObject(entity, member); buildWhereClause(builder, member.getType(), field, value, EQ_CLAUSE, false); } /** * Build where clause with given clause. * * @param builder * the builder * @param fieldClazz * the field clazz * @param field * the field * @param value * the value * @param clause * the clause * @param useToken * the use token */ public void buildWhereClause(StringBuilder builder, Class fieldClazz, String field, Object value, String clause, boolean useToken) { builder = onWhereClause(builder, fieldClazz, field, value, clause, useToken); builder.append(AND_CLAUSE); } /** * Build where clause with given clause. * * @param builder * the builder * @param fieldClazz * the field clazz * @param field * the field * @param value * the value * @param clause * the clause * @param useToken * the use token * @return the string builder */ public StringBuilder onWhereClause(StringBuilder builder, Class fieldClazz, String field, Object value, String clause, boolean useToken) { if (clause.trim().equals(IN_CLAUSE)) { useToken = false; } builder = ensureCase(builder, field, useToken); builder.append(SPACE_STRING); if (fieldClazz.isAssignableFrom(List.class) || fieldClazz.isAssignableFrom(Map.class) || fieldClazz.isAssignableFrom(Set.class)) { builder.append("CONTAINS"); } else { builder.append(clause); } builder.append(SPACE_STRING); if (clause.trim().equals(IN_CLAUSE)) { builder.append(OPEN_BRACKET); String itemValues = String.valueOf(value); itemValues = itemValues.startsWith(OPEN_BRACKET) && itemValues.endsWith(CLOSE_BRACKET) ? itemValues.substring(1, itemValues.length() - 1) : itemValues; List<String> items = Arrays.asList(((String) itemValues).split("\\s*,\\s*")); int counter = 0; for (String str : items) { str = str.trim(); str = (str.startsWith(Constants.ESCAPE_QUOTE) && str.endsWith(Constants.ESCAPE_QUOTE)) || (str.startsWith("'") && str.endsWith("'")) ? str.substring(1, str.length() - 1) : str; appendValue(builder, fieldClazz, str, false, false); counter++; if (counter < items.size()) { builder.append(COMMA_STR); } } builder.append(CLOSE_BRACKET); } else { appendValue(builder, fieldClazz, value, false, useToken); } return builder; } /** * Builds set clause for a given counter field. * * @param builder * the builder * @param field * the field * @param value * the value */ public void buildSetClauseForCounters(StringBuilder builder, String field, Object value) { builder = ensureCase(builder, field, false); builder.append(EQ_CLAUSE); builder = ensureCase(builder, field, false); builder.append(INCR_COUNTER); appendValue(builder, value.getClass(), value, false, false); builder.append(COMMA_STR); } /** * Builds set clause for a given field. * * @param m * the m * @param builder * the builder * @param property * the property * @param value * the value */ public void buildSetClause(EntityMetadata m, StringBuilder builder, String property, Object value) { builder = ensureCase(builder, property, false); builder.append(EQ_CLAUSE); if (m.isCounterColumnType()) { builder = ensureCase(builder, property, false); builder.append(INCR_COUNTER); builder.append(value); } else { appendValue(builder, value.getClass(), value, false, false); } builder.append(COMMA_STR); } /** * Ensures case for corresponding column name. * * @param builder * column name builder. * @param fieldName * column name. * @param useToken * the use token * @return builder object with appended column name. */ public StringBuilder ensureCase(StringBuilder builder, String fieldName, boolean useToken) { if (useToken) { builder.append(TOKEN); } builder.append(Constants.ESCAPE_QUOTE); builder.append(fieldName); builder.append(Constants.ESCAPE_QUOTE); if (useToken) { builder.append(CLOSE_BRACKET); } return builder; } /** * Translates input object and corresponding field based on: a) ALL : * translate both column name and column value. b) COlUMN: translates column * name only. c) VALUE: translates column value only. * * @param type * translation type. * @param builder * column value builder object. * @param columnBuilder * column name builder object. * @param columnName * column name. * @param record * value object. * @param column * value column name. */ private void onTranslation(TranslationType type, StringBuilder builder, StringBuilder columnBuilder, String columnName, Object record, Field column) { switch (type) { case ALL: if (appendColumnValue(builder, record, column)) { builder.append(Constants.COMMA); appendColumnName(columnBuilder, columnName); columnBuilder.append(Constants.COMMA); // because only key columns } break; case COLUMN: appendColumnName(columnBuilder, columnName); columnBuilder.append(Constants.COMMA); // because only key columns break; case VALUE: if (appendColumnValue(builder, record, column)) { builder.append(Constants.COMMA); // because only key columns } break; } } /** * Appends column value with parametrised builder object. Returns true if * value is present. * * @param builder * the builder * @param valueObj * the value obj * @param column * the column * @return true if value is not null,else false. */ private boolean appendColumnValue(StringBuilder builder, Object valueObj, Field column) { Object value = PropertyAccessorHelper.getObject(valueObj, column); boolean isPresent = false; isPresent = appendValue(builder, column.getType(), value, isPresent, false); return isPresent; } /** * Appends value to builder object for given class type. * * @param builder * string builder. * @param fieldClazz * field class. * @param value * value to be appended. * @param isPresent * if field is present. * @param useToken * the use token * @return true, if value is not null else false. */ public boolean appendValue(StringBuilder builder, Class fieldClazz, Object value, boolean isPresent, boolean useToken) { if (List.class.isAssignableFrom(fieldClazz)) { isPresent = appendList(builder, value != null ? value : new ArrayList()); } else if (Set.class.isAssignableFrom(fieldClazz)) { isPresent = appendSet(builder, value != null ? value : new HashSet()); } else if (Map.class.isAssignableFrom(fieldClazz)) { isPresent = appendMap(builder, value != null ? value : new HashMap()); } else { isPresent = true; appendValue(builder, fieldClazz, value, useToken); } return isPresent; } /** * Appends a object of type {@link java.util.List} * * @param builder * the builder * @param value * the value * @return true, if successful */ private boolean appendList(StringBuilder builder, Object value) { boolean isPresent = false; if (value instanceof Collection) { Collection collection = ((Collection) value); isPresent = true; builder.append(Constants.OPEN_SQUARE_BRACKET); for (Object o : collection) { // Allowing null values. appendValue(builder, o != null ? o.getClass() : null, o, false); builder.append(Constants.COMMA); } if (!collection.isEmpty()) { builder.deleteCharAt(builder.length() - 1); } builder.append(Constants.CLOSE_SQUARE_BRACKET); } else { appendValue(builder, value.getClass(), value, false); } return isPresent; } /** * Appends a object of type {@link java.util.Map} * * @param builder * the builder * @param value * the value * @return true, if successful */ private boolean appendSet(StringBuilder builder, Object value) { boolean isPresent = false; if (value instanceof Collection) { Collection collection = ((Collection) value); isPresent = true; builder.append(Constants.OPEN_CURLY_BRACKET); for (Object o : collection) { // Allowing null values. appendValue(builder, o != null ? o.getClass() : null, o, false); builder.append(Constants.COMMA); } if (!collection.isEmpty()) { builder.deleteCharAt(builder.length() - 1); } builder.append(Constants.CLOSE_CURLY_BRACKET); } else { appendValue(builder, value.getClass(), value, false); } return isPresent; } /** * Appends a object of type {@link java.util.List} * * @param builder * the builder * @param value * the value * @return true, if successful */ private boolean appendMap(StringBuilder builder, Object value) { boolean isPresent = false; if (value instanceof Map) { Map map = ((Map) value); isPresent = true; builder.append(Constants.OPEN_CURLY_BRACKET); for (Object mapKey : map.keySet()) { Object mapValue = map.get(mapKey); // Allowing null keys. appendValue(builder, mapKey != null ? mapKey.getClass() : null, mapKey, false); builder.append(Constants.COLON); // Allowing null values. appendValue(builder, mapValue != null ? mapValue.getClass() : null, mapValue, false); builder.append(Constants.COMMA); } if (!map.isEmpty()) { builder.deleteCharAt(builder.length() - 1); } builder.append(Constants.CLOSE_CURLY_BRACKET); } else { appendValue(builder, value.getClass(), value, false); } return isPresent; } /** * Append value. * * @param builder * the builder * @param fieldClazz * the field clazz * @param value * the value * @param useToken * the use token */ private void appendValue(StringBuilder builder, Class fieldClazz, Object value, boolean useToken) { // To allow handle byte array class object by converting it to string if (fieldClazz != null && fieldClazz.isAssignableFrom(byte[].class)) { value = value != null ? value : ByteBufferUtil.EMPTY_BYTE_BUFFER.array(); StringBuilder hexstr = new StringBuilder("0x"); builder.append(hexstr.append((Hex.encodeHex((byte[]) value)))); } else { if (useToken) { builder.append(TOKEN); } if (fieldClazz != null && value != null && (fieldClazz.isAssignableFrom(String.class) || isDate(fieldClazz) || fieldClazz.isAssignableFrom(char.class) || fieldClazz.isAssignableFrom(Character.class) || value instanceof Enum)) { if (fieldClazz.isAssignableFrom(String.class)) { // To allow escape character value = ((String) value).replaceAll("'", "''"); } builder.append("'"); if (isDate(fieldClazz)) // For CQL, date has to // be in date.getTime() { builder.append(PropertyAccessorFactory.getPropertyAccessor(fieldClazz).toString(value)); } else if (value instanceof Enum) { builder.append(((Enum) value).name()); } else { builder.append(value); } builder.append("'"); } else { builder.append(value); } } if (useToken) { builder.append(CLOSE_BRACKET); } } /** * Appends column name and ensure case sensitivity. * * @param builder * string builder. * @param columnName * column name. */ public void appendColumnName(StringBuilder builder, String columnName) { ensureCase(builder, columnName, false); } /** * Appends column name and data type also ensures case sensitivity. * * @param builder * string builder * @param columnName * column name * @param dataType * data type. */ public void appendColumnName(StringBuilder builder, String columnName, String dataType) { ensureCase(builder, columnName, false); builder.append(" "); // because only key columns builder.append(dataType); } /** * Validates if input class is of type input. * * @param clazz * class * * @return true, if it is a date field class. */ private boolean isDate(Class clazz) { return clazz.isAssignableFrom(Date.class) || clazz.isAssignableFrom(java.sql.Date.class) || clazz.isAssignableFrom(Timestamp.class) || clazz.isAssignableFrom(Time.class) || clazz.isAssignableFrom(Calendar.class); } /** * Maps internal data type of cassandra to CQL type representation. * * @author vivek.mishra */ private static class InternalToCQLMapper { /** The Mapper. */ private final static Map<String, String> mapper; static { Map<String, String> validationClassMapper = new HashMap<String, String>(); // TODO: support for ascii is missing! // putting possible combination into map. validationClassMapper.put(UTF8Type.class.getSimpleName(), "text"); validationClassMapper.put(IntegerType.class.getSimpleName(), "varint"); validationClassMapper.put(Int32Type.class.getSimpleName(), "int"); validationClassMapper.put(DoubleType.class.getSimpleName(), "double"); validationClassMapper.put(BooleanType.class.getSimpleName(), "boolean"); validationClassMapper.put(LongType.class.getSimpleName(), "bigint"); validationClassMapper.put(BytesType.class.getSimpleName(), "blob"); validationClassMapper.put(FloatType.class.getSimpleName(), "float"); // missing validationClassMapper.put(CounterColumnType.class.getSimpleName(), "counter"); validationClassMapper.put(DecimalType.class.getSimpleName(), "decimal"); validationClassMapper.put(UUIDType.class.getSimpleName(), "uuid"); validationClassMapper.put(DateType.class.getSimpleName(), "timestamp"); validationClassMapper.put(TimestampType.class.getSimpleName(), "timestamp"); // collection types validationClassMapper.put(ListType.class.getSimpleName(), "list"); validationClassMapper.put(SetType.class.getSimpleName(), "set"); validationClassMapper.put(MapType.class.getSimpleName(), "map"); mapper = Collections.synchronizedMap(validationClassMapper); } /** * Gets the type. * * @param internalClassName * the internal class name * @return the type */ private static final String getType(final String internalClassName) { return mapper.get(internalClassName); } } /** * The Class CQLKeywordMapper. */ private static class CQLKeywordMapper { /** The Mapper. */ private final static Map<String, String> mapper = new HashMap<String, String>(); // missing: compaction_strategy_options, // compression_parameters,sstable_size_in_mb static { mapper.put(CassandraConstants.READ_REPAIR_CHANCE, "read_repair_chance"); mapper.put(CassandraConstants.DCLOCAL_READ_REPAIR_CHANCE, "dclocal_read_repair_chance"); mapper.put(CassandraConstants.BLOOM_FILTER_FP_CHANCE, "bloom_filter_fp_chance"); mapper.put(CassandraConstants.COMPACTION_STRATEGY, "compaction_strategy_class"); mapper.put(CassandraConstants.BLOOM_FILTER_FP_CHANCE, "bloom_filter_fp_chance"); // mapper.put(CassandraConstants.COMPARATOR_TYPE, "comparator"); mapper.put(CassandraConstants.REPLICATE_ON_WRITE, "replicate_on_write"); mapper.put(CassandraConstants.CACHING, "caching"); // TODO: these are not supported. // mapper.put(CassandraConstants.MAX_COMPACTION_THRESHOLD, // "max_compaction_threshold"); // mapper.put(CassandraConstants.MIN_COMPACTION_THRESHOLD, // "min_compaction_threshold"); mapper.put(CassandraConstants.COMMENT, "comment"); mapper.put(CassandraConstants.GC_GRACE_SECONDS, "gc_grace_seconds"); } /** * Gets the type. * * @param propertyName * the property name * @return the type */ private static final String getType(final String propertyName) { return mapper.get(propertyName); } } /** * Builds the filtering clause. * * @param builder * the builder */ public void buildFilteringClause(StringBuilder builder) { builder.append(" ALLOW FILTERING"); } /** * Builds the order by clause. * * @param builder * the builder * @param field * the field * @param orderType * the order type * @param useToken * the use token */ public void buildOrderByClause(StringBuilder builder, String field, Object orderType, boolean useToken) { builder.append(SPACE_STRING); builder.append(SORT_CLAUSE); builder = ensureCase(builder, field, useToken); builder.append(SPACE_STRING); builder.append(orderType); } /** * Builds the select query. * * @param descriptor * the descriptor * @return the string builder */ public StringBuilder buildSelectQuery(TableGeneratorDiscriptor descriptor) { StringBuilder builder = new StringBuilder("Select "); ensureCase(builder, descriptor.getValueColumnName(), false).append(" from "); ensureCase(builder, descriptor.getTable(), false).append(" where "); ensureCase(builder, descriptor.getPkColumnName(), false).append(" = '") .append(descriptor.getPkColumnValue() + "'"); return builder; } /** * Builds the update query. * * @param descriptor * the descriptor * @return the string builder */ public StringBuilder buildUpdateQuery(TableGeneratorDiscriptor descriptor) { StringBuilder builder = new StringBuilder("Update "); ensureCase(builder, descriptor.getTable(), false).append(" set "); ensureCase(builder, descriptor.getValueColumnName(), false).append(" = "); ensureCase(builder, descriptor.getValueColumnName(), false).append(" + ").append(1).append(" where "); ensureCase(builder, descriptor.getPkColumnName(), false).append(" = '") .append(descriptor.getPkColumnValue() + "'"); return builder; } }