Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.impetus.client.cassandra.query.CassQuery Maven / Gradle / Ivy
/*******************************************************************************
* * 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.query;
import java.lang.reflect.Field;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javassist.Modifier;
import javax.persistence.Transient;
import javax.persistence.metamodel.Attribute;
import javax.persistence.metamodel.EmbeddableType;
import javax.persistence.metamodel.EntityType;
import javax.persistence.metamodel.Metamodel;
import org.apache.cassandra.thrift.IndexClause;
import org.apache.cassandra.thrift.IndexExpression;
import org.apache.cassandra.thrift.IndexOperator;
import org.apache.cassandra.utils.ByteBufferUtil;
import org.apache.commons.lang.StringUtils;
import org.eclipse.persistence.jpa.jpql.parser.CountFunction;
import org.eclipse.persistence.jpa.jpql.parser.Expression;
import org.eclipse.persistence.jpa.jpql.parser.SelectClause;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.impetus.client.cassandra.CassandraClientBase;
import com.impetus.client.cassandra.common.CassandraUtilities;
import com.impetus.client.cassandra.index.CassandraIndexHelper;
import com.impetus.client.cassandra.thrift.CQLTranslator;
import com.impetus.kundera.Constants;
import com.impetus.kundera.client.Client;
import com.impetus.kundera.client.ClientBase;
import com.impetus.kundera.client.EnhanceEntity;
import com.impetus.kundera.metadata.KunderaMetadataManager;
import com.impetus.kundera.metadata.MetadataUtils;
import com.impetus.kundera.metadata.model.ApplicationMetadata;
import com.impetus.kundera.metadata.model.EntityMetadata;
import com.impetus.kundera.metadata.model.MetamodelImpl;
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.PersistenceDelegator;
import com.impetus.kundera.property.PropertyAccessorHelper;
import com.impetus.kundera.query.KunderaQuery;
import com.impetus.kundera.query.KunderaQuery.FilterClause;
import com.impetus.kundera.query.KunderaQuery.SortOrdering;
import com.impetus.kundera.query.KunderaQuery.UpdateClause;
import com.impetus.kundera.query.QueryHandlerException;
import com.impetus.kundera.query.QueryImpl;
import com.impetus.kundera.utils.ReflectUtils;
/**
* The Class CassQuery.
*
* @author vivek.mishra
*
* Query implementation for Cassandra.
*/
@SuppressWarnings("unchecked")
public class CassQuery extends QueryImpl
{
/** the log used by this class. */
private static Logger log = LoggerFactory.getLogger(CassQuery.class);
/** The reader. */
private EntityReader reader;
/** The external properties. */
private Map externalProperties;
/**
* Instantiates a new cass query.
*
* @param kunderaQuery
* the kundera query
* @param persistenceDelegator
* the persistence delegator
* @param kunderaMetadata
* the kundera metadata
*/
public CassQuery(KunderaQuery kunderaQuery, PersistenceDelegator persistenceDelegator,
final KunderaMetadata kunderaMetadata)
{
super(kunderaQuery, persistenceDelegator, kunderaMetadata);
}
/*
* (non-Javadoc)
*
* @see
* com.impetus.kundera.query.QueryImpl#populateEntities(com.impetus.kundera
* .metadata.model.EntityMetadata, com.impetus.kundera.client.Client)
*/
@Override
protected List populateEntities(EntityMetadata m, Client client)
{
if (log.isDebugEnabled())
{
log.debug("Populating entities for Cassandra query {}.", getJPAQuery());
}
List result = new ArrayList();
ApplicationMetadata appMetadata = kunderaMetadata.getApplicationMetadata();
externalProperties = ((CassandraClientBase) client).getExternalProperties();
// if id attribute is embeddable, it is meant for CQL translation.
// make it independent of embedded stuff and allow even to add non
// composite into where clause and let cassandra complain for it.
MetamodelImpl metaModel = (MetamodelImpl) kunderaMetadata.getApplicationMetadata().getMetamodel(
m != null ? m.getPersistenceUnit() : client.getPersistenceUnit());
String query = appMetadata.getQuery(getJPAQuery());
boolean isNative = kunderaQuery.isNative();
if (!isNative && !MetadataUtils.useSecondryIndex(((ClientBase) client).getClientMetadata()))
{
result = populateUsingLucene(m, client, result, getKunderaQuery().getResult());
}
// change for embeddable
else if (!isNative && ((CassandraClientBase) client).isCql3Enabled(m)
&& MetadataUtils.useSecondryIndex(((ClientBase) client).getClientMetadata()))
{
result = ((CassandraClientBase) client).executeQuery(m.getEntityClazz(), null, isNative,
onQueryOverCQL3(m, client, metaModel, null));
}
else
{
if (isNative)
{
result = ((CassandraClientBase) client).executeQuery(m != null ? m.getEntityClazz() : null, null,
isNative, query != null ? query : getJPAQuery());
}
else
{
if (MetadataUtils.useSecondryIndex(((ClientBase) client).getClientMetadata()))
{
// Index in Inverted Index table if applicable
boolean useInvertedIndex = CassandraIndexHelper.isInvertedIndexingApplicable(m,
MetadataUtils.useSecondryIndex(((ClientBase) client).getClientMetadata()));
Map> ixClause = prepareIndexClause(m, useInvertedIndex);
if (useInvertedIndex && !getKunderaQuery().getFilterClauseQueue().isEmpty())
{
result = (List) ((CassandraEntityReader) getReader()).readFromIndexTable(m, client, ixClause);
}
else
{
boolean isRowKeyQuery = ixClause.keySet().iterator().next();
if (!isRowKeyQuery)
{
result = ((CassandraClientBase) client).find(ixClause.get(isRowKeyQuery), m, false, null,
isSingleResult ? 1 : this.maxResult,
getColumnList(m, metaModel, getKunderaQuery().getResult(), null));
}
else
{
result = ((CassandraEntityReader) getReader()).handleFindByRange(m, client, result,
ixClause, isRowKeyQuery,
getColumnList(m, metaModel, getKunderaQuery().getResult(), null),
isSingleResult ? 1 : this.maxResult);
}
}
}
}
}
return result;
}
/*
* (non-Javadoc)
*
* @see
* com.impetus.kundera.query.QueryImpl#findUsingLucene(com.impetus.kundera
* .metadata.model.EntityMetadata, com.impetus.kundera.client.Client)
*/
protected List findUsingLucene(EntityMetadata m, Client client)
{
MetamodelImpl metaModel = (MetamodelImpl) kunderaMetadata.getApplicationMetadata().getMetamodel(
m.getPersistenceUnit());
boolean useInvertedIndex = CassandraIndexHelper.isInvertedIndexingApplicable(m,
MetadataUtils.useSecondryIndex(((ClientBase) client).getClientMetadata()));
Map> ixClause = prepareIndexClause(m, useInvertedIndex);
List result = new ArrayList();
if (((CassandraClientBase) client).isCql3Enabled(m))
{
result = ((CassandraClientBase) client).executeQuery(m.getEntityClazz(), m.getRelationNames(), false,
onQueryOverCQL3(m, client, metaModel, m.getRelationNames()));
}
else
{
result = ((CassandraEntityReader) getReader()).handleFindByRange(m, client, result, ixClause, true,
getColumnList(m, metaModel, getKunderaQuery().getResult(), null), isSingleResult ? 1
: this.maxResult);
}
return result;
}
/**
* (non-Javadoc).
*
* @param m
* the m
* @param client
* the client
* @return the list
* @see com.impetus.kundera.query.QueryImpl#recursivelyPopulateEntities(com.impetus
* .kundera.metadata.model.EntityMetadata,
* com.impetus.kundera.client.Client)
*/
@SuppressWarnings("unchecked")
@Override
protected List recursivelyPopulateEntities(EntityMetadata m, Client client)
{
List ls = null;
ApplicationMetadata appMetadata = kunderaMetadata.getApplicationMetadata();
externalProperties = ((CassandraClientBase) client).getExternalProperties();
MetamodelImpl metaModel = (MetamodelImpl) kunderaMetadata.getApplicationMetadata().getMetamodel(
m.getPersistenceUnit());
String query = appMetadata.getQuery(getJPAQuery());
boolean isNative = kunderaQuery.isNative();
if (isNative)
{
ls = (List) ((CassandraClientBase) client).executeQuery(m.getEntityClazz(),
m.getRelationNames(), isNative, query != null ? query : getJPAQuery());
}
else if (!isNative && ((CassandraClientBase) client).isCql3Enabled(m))
{
// edited
// check if lucene or indexer are enabled then populate
if (MetadataUtils.useSecondryIndex(((ClientBase) client).getClientMetadata()))
{
ls = ((CassandraClientBase) client).executeQuery(m.getEntityClazz(), m.getRelationNames(), isNative,
onQueryOverCQL3(m, client, metaModel, m.getRelationNames()));
}
else
{
ls = populateUsingLucene(m, client, null, getKunderaQuery().getResult());
}
}
else
{
// Index in Inverted Index table if applicable
boolean useInvertedIndex = CassandraIndexHelper.isInvertedIndexingApplicable(m,
MetadataUtils.useSecondryIndex(((ClientBase) client).getClientMetadata()));
Map> ixClause = MetadataUtils.useSecondryIndex(((ClientBase) client)
.getClientMetadata()) ? prepareIndexClause(m, useInvertedIndex) : null;
if (useInvertedIndex && !getKunderaQuery().getFilterClauseQueue().isEmpty())
{
ls = ((CassandraEntityReader) getReader()).readFromIndexTable(m, client, ixClause);
}
else
{
((CassandraEntityReader) getReader()).setConditions(ixClause);
ls = reader.populateRelation(m, client, isSingleResult ? 1 : this.maxResult);
}
}
return setRelationEntities(ls, client, m);
}
/**
* On executeUpdate.
*
* @return zero
*/
@Override
protected int onExecuteUpdate()
{
EntityMetadata m = getEntityMetadata();
Client client = m != null ? persistenceDelegeator.getClient(m) : persistenceDelegeator.getClient(kunderaQuery
.getPersistenceUnit());
externalProperties = ((CassandraClientBase) client).getExternalProperties();
ApplicationMetadata appMetadata = kunderaMetadata.getApplicationMetadata();
String query = appMetadata.getQuery(getJPAQuery());
boolean isNative = kunderaQuery.isNative();
if (isNative)
{
((CassandraClientBase) client).executeQuery(m == null ? null : m.getEntityClazz(), null, isNative,
query != null ? query : getJPAQuery());
}
else if (kunderaQuery.isDeleteUpdate())
{
// If query is not convertible to CQL, fetch and merge records usual
// way, otherwise
// convert to CQL and execute
if (!isQueryConvertibleToCQL(kunderaQuery))
{
return onUpdateDeleteEvent();
}
else
{
query = null;
if (kunderaQuery.isUpdateClause())
{
query = createUpdateQuery(kunderaQuery);
}
else
{
query = createDeleteQuery(kunderaQuery);
}
return ((CassandraClientBase) client).executeUpdateDeleteQuery(query);
}
}
return 0;
}
/**
* Checks whether a given JPA DML query is convertible to CQL.
*
* @param kunderaQuery
* the kundera query
* @return true, if is query convertible to cql
*/
private boolean isQueryConvertibleToCQL(KunderaQuery kunderaQuery)
{
EntityMetadata m = kunderaQuery.getEntityMetadata();
if (kunderaQuery.isUpdateClause() && m.isCounterColumnType())
return false;
List opsNotAllowed = Arrays.asList(new String[] { ">", "<", ">=", "<=" });
boolean result = false;
if (!kunderaQuery.getFilterClauseQueue().isEmpty())
{
String idColumn = ((AbstractAttribute) m.getIdAttribute()).getJPAColumnName();
for (Object o : kunderaQuery.getFilterClauseQueue())
{
if (o instanceof FilterClause)
{
FilterClause filterClause = (FilterClause) o;
if (!idColumn.equals(filterClause.getProperty())
|| opsNotAllowed.contains(filterClause.getCondition()))
{
result = false;
break;
}
result = true;
}
}
}
return result;
}
/**
* Gets the column list.
*
* @param m
* the m
* @param metamodel
* the metamodel
* @param results
* the results
* @param compoundKey
* the compound key
* @return the column list
*/
List getColumnList(EntityMetadata m, MetamodelImpl metamodel, String[] results, EmbeddableType compoundKey)
{
List columns = new ArrayList();
if (results != null && results.length > 0)
{
MetamodelImpl metaModel = (MetamodelImpl) kunderaMetadata.getApplicationMetadata().getMetamodel(
m.getPersistenceUnit());
EntityType entity = metaModel.entity(m.getEntityClazz());
String keyFieldName = CassandraUtilities.getIdColumnName(kunderaMetadata, m, externalProperties,
((CassandraClientBase) persistenceDelegeator.getClient(m)).isCql3Enabled(m));
for (int i = 1; i < results.length; i++)
{
if (results[i] != null)
{
if (results[i].indexOf(".") > 0)
{
String fieldName = results[i].substring(0, results[i].indexOf("."));
String embeddedFieldName = results[i].substring(results[i].indexOf(".") + 1,
results[i].length());
AbstractAttribute attribute = (AbstractAttribute) entity.getAttribute(fieldName);
EmbeddableType embeddable = metamodel.embeddable(attribute.getBindableJavaType());
Attribute embeddableAttribute = embeddable.getAttribute(embeddedFieldName);
columns.add(((AbstractAttribute) embeddableAttribute).getJPAColumnName());
}
else
{
Attribute attribute = entity.getAttribute(results[i]);
if (attribute == null)
{
throw new QueryHandlerException("Column type is null for : " + results);
}
else if (m.getIdAttribute().equals(attribute) && compoundKey != null)
{
Field[] fields = m.getIdAttribute().getBindableJavaType().getDeclaredFields();
for (Field field : fields)
{
if (!ReflectUtils.isTransientOrStatic(field))
{
Attribute compositeColumn = compoundKey.getAttribute(field.getName());
columns.add(((AbstractAttribute) compositeColumn).getJPAColumnName());
}
}
}
else if (m.getIdAttribute().equals(attribute) && compoundKey == null)
{
columns.add(keyFieldName);
}
else
{
columns.add(((AbstractAttribute) attribute).getJPAColumnName());
}
}
}
}
return columns;
}
if (log.isInfoEnabled())
{
log.info("No record found, returning null.");
}
return null;
}
/**
* Prepare index clause.
*
* @param m
* the m
* @param isQueryForInvertedIndex
* the is query for inverted index
* @return the map
*/
Map> prepareIndexClause(EntityMetadata m, boolean isQueryForInvertedIndex)
{
IndexClause indexClause = new IndexClause(new ArrayList(), ByteBufferUtil.EMPTY_BYTE_BUFFER,
maxResult);
List clauses = new ArrayList();
List expr = new ArrayList();
Map> idxClauses = new HashMap>(1);
// check if id column are mixed with other columns or not?
String idColumn = ((AbstractAttribute) m.getIdAttribute()).getJPAColumnName();
boolean idPresent = false;
if (log.isInfoEnabled())
{
log.info("Preparing index clause for query {}", getJPAQuery());
}
for (Object o : getKunderaQuery().getFilterClauseQueue())
{
if (o instanceof FilterClause)
{
FilterClause clause = ((FilterClause) o);
String fieldName = clause.getProperty();
// in case id column matches with field name, set it for first
// time.
if (!idPresent && idColumn.equalsIgnoreCase(fieldName))
{
idPresent = true;
}
String condition = clause.getCondition();
List value = clause.getValue();
if (value != null && value.size() > 1)
{
log.error("IN clause is not enabled for thrift, use cql3.");
throw new QueryHandlerException("IN clause is not enabled for thrift, use cql3.");
}
IndexOperator operator = getOperator(condition, idPresent);
IndexExpression expression = new IndexExpression(ByteBufferUtil.bytes(fieldName), operator,
getBytesValue(fieldName, m, value.get(0)));
expr.add(expression);
}
else
{
// Case of AND and OR clause.
String opr = o.toString();
if (opr.equalsIgnoreCase("or"))
{
log.error("Support for OR clause is not enabled within cassandra.");
throw new QueryHandlerException("Unsupported clause " + opr + " for cassandra.");
}
}
}
if (!StringUtils.isBlank(getKunderaQuery().getFilter()))
{
indexClause.setExpressions(expr);
clauses.add(indexClause);
}
idxClauses.put(idPresent, clauses);
return idxClauses;
}
/**
* Gets the operator.
*
* @param condition
* the condition
* @param idPresent
* the id present
* @return the operator
*/
private IndexOperator getOperator(String condition, boolean idPresent)
{
if (/* !idPresent && */condition.equals("="))
{
return IndexOperator.EQ;
}
else if (/* !idPresent && */condition.equals(">"))
{
return IndexOperator.GT;
}
else if (/* !idPresent && */condition.equals("<"))
{
return IndexOperator.LT;
}
else if (condition.equals(">="))
{
return IndexOperator.GTE;
}
else if (condition.equals("<="))
{
return IndexOperator.LTE;
}
else
{
if (!idPresent)
{
throw new UnsupportedOperationException("Condition " + condition + " is not suported in cassandra.");
}
else
{
throw new UnsupportedOperationException("Condition " + condition
+ " is not suported for query on row key.");
}
}
}
/*
* (non-Javadoc)
*
* @see com.impetus.kundera.query.QueryImpl#getReader()
*/
@Override
protected EntityReader getReader()
{
if (reader == null)
{
reader = new CassandraEntityReader(kunderaQuery, kunderaMetadata);
}
return reader;
}
/**
* Returns bytes value for given value.
*
* @param jpaFieldName
* field name.
* @param m
* entity metadata
* @param value
* value.
* @return bytes value.
*/
ByteBuffer getBytesValue(String jpaFieldName, EntityMetadata m, Object value)
{
Attribute idCol = m.getIdAttribute();
MetamodelImpl metaModel = (MetamodelImpl) kunderaMetadata.getApplicationMetadata().getMetamodel(
m.getPersistenceUnit());
EntityType entity = metaModel.entity(m.getEntityClazz());
Field f = null;
boolean isId = false;
if (((AbstractAttribute) idCol).getJPAColumnName().equals(jpaFieldName))
{
f = (Field) idCol.getJavaMember();
isId = true;
}
else
{
if (jpaFieldName != null && jpaFieldName.indexOf(Constants.INDEX_TABLE_ROW_KEY_DELIMITER) > 0)
{
String embeddedFieldName = jpaFieldName.substring(0,
jpaFieldName.indexOf(Constants.INDEX_TABLE_ROW_KEY_DELIMITER));
String columnFieldName = jpaFieldName.substring(
jpaFieldName.indexOf(Constants.INDEX_TABLE_ROW_KEY_DELIMITER) + 1, jpaFieldName.length());
Attribute embeddedAttr = entity.getAttribute(embeddedFieldName);
try
{
Class> embeddedClass = embeddedAttr.getJavaType();
if (Collection.class.isAssignableFrom(embeddedClass))
{
Class> genericClass = PropertyAccessorHelper.getGenericClass((Field) embeddedAttr
.getJavaMember());
f = genericClass.getDeclaredField(columnFieldName);
}
else
{
f = embeddedClass.getDeclaredField(columnFieldName);
}
}
catch (SecurityException e)
{
log.error("Error while extrating " + jpaFieldName + ", Caused by: ", e);
throw new QueryHandlerException("Error while extrating " + jpaFieldName + ".");
}
catch (NoSuchFieldException e)
{
log.error("Error while extrating " + jpaFieldName + ", Caused by: ", e);
throw new QueryHandlerException("Error while extrating " + jpaFieldName + ".");
}
}
else
{
String discriminatorColumn = ((AbstractManagedType) entity).getDiscriminatorColumn();
if (!jpaFieldName.equals(discriminatorColumn))
{
String fieldName = m.getFieldName(jpaFieldName);
Attribute col = entity.getAttribute(fieldName);
if (col == null)
{
throw new QueryHandlerException("column type is null for: " + jpaFieldName);
}
f = (Field) col.getJavaMember();
}
}
}
// need to do integer.parseInt..as value will be string in case of
// create query.
if (f != null && f.getType() != null)
{
return CassandraUtilities.toBytes(value, f);
}
else
{
// default is String type
return CassandraUtilities.toBytes(value, String.class);
}
}
/**
* On query over composite columns.
*
* @param m
* the m
* @param client
* the client
* @param metaModel
* the meta model
* @param relations
* the relations
* @return the list
*/
String onQueryOverCQL3(EntityMetadata m, Client client, MetamodelImpl metaModel, List relations)
{
// select column will always be of entity field only!
// where clause ordering
Class compoundKeyClass = m.getIdAttribute().getBindableJavaType();
EmbeddableType compoundKey = null;
String idColumn;
if (metaModel.isEmbeddable(compoundKeyClass))
{
compoundKey = metaModel.embeddable(compoundKeyClass);
idColumn = ((AbstractAttribute) m.getIdAttribute()).getJPAColumnName();
}
else
{
idColumn = ((AbstractAttribute) m.getIdAttribute()).getJPAColumnName();
}
StringBuilder builder = new StringBuilder();
boolean isPresent = false;
List columns = getColumnList(m, metaModel, getKunderaQuery().getResult(), compoundKey);
String selectQuery = setSelectQuery(columns);
CQLTranslator translator = new CQLTranslator();
selectQuery = StringUtils.replace(selectQuery, CQLTranslator.COLUMN_FAMILY,
translator.ensureCase(new StringBuilder(), m.getTableName(), false).toString());
builder = CassandraUtilities.appendColumns(builder, columns, selectQuery, translator);
addWhereClause(builder);
onCondition(m, metaModel, compoundKey, idColumn, builder, isPresent, translator, true);
return builder.toString();
}
/**
* Sets the select query.
*
* @param columns
* the columns
* @return the string
*/
private String setSelectQuery(List columns)
{
if (columns != null && !columns.isEmpty())
{
return CQLTranslator.SELECT_QUERY;
}
if (kunderaQuery.isAggregated())
{
Expression selectExpression = ((SelectClause) kunderaQuery.getSelectStatement().getSelectClause())
.getSelectExpression();
// create query depending on function
if (selectExpression instanceof CountFunction)
{
return CQLTranslator.SELECT_COUNT_QUERY;
}
}
return CQLTranslator.SELECTALL_QUERY;
}
/**
* Add provided max result limit.
*
* @param builder
* string builder.
*/
private void onLimit(StringBuilder builder)
{
if (Integer.MAX_VALUE != maxResult)
{
builder.append(CQLTranslator.LIMIT);
builder.append(isSingleResult ? 1 : this.maxResult);
}
}
/**
* On condition.
*
* @param m
* the m
* @param metaModel
* the meta model
* @param keyObj
* the compound key
* @param idColumn
* the id column
* @param builder
* the builder
* @param isPresent
* the is present
* @param translator
* the translator
* @param use
* the use
* @return true, if successful
*/
private boolean onCondition(EntityMetadata m, MetamodelImpl metaModel, EmbeddableType keyObj, String idColumn,
StringBuilder builder, boolean isPresent, CQLTranslator translator, boolean use)
{
String partitionKey = null;
boolean allowFiltering = false;
for (Object o : getKunderaQuery().getFilterClauseQueue())
{
if (o instanceof FilterClause)
{
FilterClause clause = ((FilterClause) o);
String fieldName = clause.getProperty();
String condition = clause.getCondition();
List value = clause.getValue();
boolean useInClause = condition.trim().equalsIgnoreCase("IN");
// if compound key field is given in where clause.
isPresent = true;
if (keyObj != null && idColumn.equals(fieldName))
{
Field[] fields = m.getIdAttribute().getBindableJavaType().getDeclaredFields();
Map> columnValues = new HashMap>();
for (Field field : fields)
{
if (!ReflectUtils.isTransientOrStatic(field))
{
extractCompositeKey(metaModel, keyObj, builder, translator, value, useInClause,
columnValues, field);
}
}
// Composite key always contains clusterKey.
allowFiltering = true;
if (useInClause)
{
for (Attribute columnAttribute : columnValues.keySet())
{
isPresent = appendInClause(builder, translator, columnValues.get(columnAttribute),
((AbstractAttribute) columnAttribute).getBindableJavaType(),
((AbstractAttribute) columnAttribute).getJPAColumnName(), isPresent);
}
}
}
else if (keyObj != null && metaModel.isEmbeddable(m.getIdAttribute().getBindableJavaType())
&& StringUtils.contains(fieldName, '.'))
{
// Means it is a case of composite column.
isPresent = getCompoundKeyColumn(metaModel, keyObj, builder, isPresent, translator, fieldName,
condition, value, useInClause);
allowFiltering = true;
}
else if (idColumn.equals(fieldName))
{
// dont use token for equals query on id column (#856)
boolean useToken = use;
if (condition.equals("="))
{
useToken = false;
}
isPresent = buildWhereClause(builder, isPresent, translator, condition, value, useInClause,
((AbstractAttribute) m.getIdAttribute()), CassandraUtilities.getIdColumnName(
kunderaMetadata, m, externalProperties,
((CassandraClientBase) persistenceDelegeator.getClient(m)).isCql3Enabled(m)), useToken);
}
else
{
EntityType entity = metaModel.entity(m.getEntityClazz());
// Metamodel metamodel =
// KunderaMetadataManager.getMetamodel(kunderaMetadata,
// m.getPersistenceUnit());
String discriminatorColumn = ((AbstractManagedType) entity).getDiscriminatorColumn();
if (fieldName.equals(discriminatorColumn))
{
translator.buildWhereClause(builder, String.class, fieldName,
value.isEmpty() ? null : value.get(0), condition, false);
isPresent = true;
}
else
{
Metamodel metamodel = KunderaMetadataManager.getMetamodel(kunderaMetadata,
m.getPersistenceUnit());
Attribute attribute = ((MetamodelImpl) metamodel).getEntityAttribute(m.getEntityClazz(),
m.getFieldName(fieldName));
isPresent = buildWhereClause(builder, isPresent, translator, condition, value, useInClause,
((AbstractAttribute) attribute), fieldName, false);
}
allowFiltering = true;
}
}
}
// Strip last AND clause.
if (isPresent)
{
builder.delete(builder.lastIndexOf(CQLTranslator.AND_CLAUSE), builder.length());
}
// Append order by clause into query
builder = appendOrderByClause(metaModel, m, keyObj, builder, translator);
if (allowFiltering && use)
{
onLimit(builder);
builder.append(" ");
translator.buildFilteringClause(builder);
}
else if (use)
{
onLimit(builder);
}
return isPresent;
}
/**
* Gets the compound key column.
*
* @param metamodel
* the metamodel
* @param keyObj
* the key obj
* @param builder
* the builder
* @param isPresent
* the is present
* @param translator
* the translator
* @param fieldName
* the field name
* @param condition
* the condition
* @param value
* the value
* @param useInClause
* the use in clause
* @return the compound key column
*/
private boolean getCompoundKeyColumn(MetamodelImpl metamodel, EmbeddableType keyObj, StringBuilder builder,
boolean isPresent, CQLTranslator translator, String fieldName, String condition, List value,
boolean useInClause)
{
fieldName = fieldName.substring(fieldName.indexOf(".") + 1);
// If partition key part age given in query, i.e. restriction on
// id.compositekey.compositePartitionkey.partitionkeyColumn.
if (fieldName.indexOf(".") > 0)
{
String compositePartitionkeyName = fieldName.substring(0, fieldName.indexOf("."));
AbstractAttribute attribute = (AbstractAttribute) keyObj.getAttribute(compositePartitionkeyName);
fieldName = fieldName.substring(fieldName.indexOf(".") + 1);
EmbeddableType compositePartitionkey = metamodel.embeddable(attribute.getBindableJavaType());
attribute = (AbstractAttribute) compositePartitionkey.getAttribute(fieldName);
String columnName = attribute.getJPAColumnName();
isPresent = buildWhereClause(builder, isPresent, translator, condition, value, useInClause, attribute,
columnName, false);
}
// if composite partition key object is given in query, i.e. restriction
// on id.compositekey.compositePartitionkey
else if (metamodel.isEmbeddable(((AbstractAttribute) keyObj.getAttribute(fieldName)).getBindableJavaType()))
{
AbstractAttribute attribute = (AbstractAttribute) keyObj.getAttribute(fieldName);
Set attributes = metamodel.embeddable(attribute.getBindableJavaType()).getAttributes();
if (!useInClause)
{
// Iterating and appending each column of composite partition
// key in query builder.
for (Attribute nestedAttribute : attributes)
{
String columnName = ((AbstractAttribute) nestedAttribute).getJPAColumnName();
Object valueObject = PropertyAccessorHelper.getObject(value.isEmpty() ? null : value.get(0),
(Field) nestedAttribute.getJavaMember());
translator.buildWhereClause(builder, nestedAttribute.getJavaType(), columnName, valueObject,
condition, false);
}
}
else
{
throw new IllegalArgumentException("In clause is not supported on first part of partition key.");
}
isPresent = true;
}
// if Not a composite partition key,
// id.compositekey.partitionkey/clusterKey.
else
{
AbstractAttribute attribute = (AbstractAttribute) keyObj.getAttribute(fieldName);
String columnName = attribute.getJPAColumnName();
isPresent = buildWhereClause(builder, isPresent, translator, condition, value, useInClause, attribute,
columnName, false);
}
return isPresent;
}
/**
* Append order by clause.
*
* @param metaModel
* the meta model
* @param m
* the m
* @param keyObj
* the key obj
* @param builder
* the builder
* @param translator
* the translator
* @return the string builder
*/
private StringBuilder appendOrderByClause(MetamodelImpl metaModel, EntityMetadata m, EmbeddableType keyObj,
StringBuilder builder, CQLTranslator translator)
{
List orders = getKunderaQuery().getOrdering();
if (orders != null)
{
builder.append(CQLTranslator.SPACE_STRING);
builder.append(CQLTranslator.SORT_CLAUSE);
for (SortOrdering order : orders)
{
String orderColumnName = order.getColumnName();
orderColumnName = orderColumnName.substring(orderColumnName.indexOf(".") + 1, orderColumnName.length());
String orderByColumnName;
if (StringUtils.contains(orderColumnName, '.'))
{
String propertyName = orderColumnName.substring(0, orderColumnName.indexOf("."));
Attribute embeddableAttribute = metaModel.getEntityAttribute(m.getEntityClazz(), propertyName);
EmbeddableType embeddableType = metaModel.embeddable(((AbstractAttribute) embeddableAttribute)
.getBindableJavaType());
orderColumnName = orderColumnName.substring(orderColumnName.indexOf(".") + 1);
AbstractAttribute attribute = (AbstractAttribute) embeddableType.getAttribute(orderColumnName);
orderByColumnName = attribute.getJPAColumnName();
}
else
{
Attribute attribute = metaModel.getEntityAttribute(m.getEntityClazz(), orderColumnName);
orderByColumnName = ((AbstractAttribute) attribute).getJPAColumnName();
}
builder = translator.ensureCase(builder, orderByColumnName, false);
builder.append(CQLTranslator.SPACE_STRING);
builder.append(order.getOrder());
builder.append(CQLTranslator.COMMA_STR);
}
if (!orders.isEmpty())
{
builder.deleteCharAt(builder.lastIndexOf(CQLTranslator.COMMA_STR));
}
}
return builder;
}
/**
* Extract composite key.
*
* @param metaModel
* the meta model
* @param keyObj
* the key obj
* @param builder
* the builder
* @param translator
* the translator
* @param value
* the value
* @param useInClause
* the use in clause
* @param columnValues
* the column values
* @param field
* the field
* @return true, if successful
*/
private boolean extractCompositeKey(MetamodelImpl metaModel, EmbeddableType keyObj, StringBuilder builder,
CQLTranslator translator, List value, boolean useInClause,
Map> columnValues, Field field)
{
Attribute compositeColumn = keyObj.getAttribute(field.getName());
String jpaColumnName = ((AbstractAttribute) compositeColumn).getJPAColumnName();
if (useInClause)
{
for (Object embeddedObject : value)
{
Object valueObject = PropertyAccessorHelper.getObject(embeddedObject, field);
// Checking for composite partition key.
if (metaModel.isEmbeddable(((AbstractAttribute) compositeColumn).getBindableJavaType()))
{
Set attributes = metaModel.embeddable(
((AbstractAttribute) compositeColumn).getBindableJavaType()).getAttributes();
// Iterating over composite partition key columns.
for (Attribute nestedAttribute : attributes)
{
List valueList = columnValues.get(compositeColumn);
if (valueList == null)
{
valueList = new ArrayList();
}
Object obj = PropertyAccessorHelper.getObject(valueObject,
(Field) nestedAttribute.getJavaMember());
valueList.add(obj);
columnValues.put(nestedAttribute, valueList);
}
}
else
{
List valueList = columnValues.get(compositeColumn);
if (valueList == null)
{
valueList = new ArrayList();
}
valueList.add(valueObject);
columnValues.put(compositeColumn, valueList);
}
}
}
else
{
Object valueObject = PropertyAccessorHelper.getObject(value.isEmpty() ? null : value.get(0), field);
// Checking for composite partition key.
if (metaModel.isEmbeddable(((AbstractAttribute) compositeColumn).getBindableJavaType()))
{
Set attributes = metaModel.embeddable(
((AbstractAttribute) compositeColumn).getBindableJavaType()).getAttributes();
// Iterating over composite partition key columns.
for (Attribute nestedAttribute : attributes)
{
String columnName = ((AbstractAttribute) nestedAttribute).getJPAColumnName();
Object obj = PropertyAccessorHelper.getObject(valueObject, (Field) nestedAttribute.getJavaMember());
translator.buildWhereClause(builder, nestedAttribute.getJavaType(), columnName, obj,
CQLTranslator.EQ_CLAUSE, false);
}
// returning true because builder has AND clause at end.
return true;
}
else
{
translator.buildWhereClause(builder, field.getType(), jpaColumnName, valueObject,
CQLTranslator.EQ_CLAUSE, false);
// returning true because builder has AND clause at end.
return true;
}
}
// returning false because builder does not have AND clause at end.
return false;
}
/**
* Builds the where clause.
*
* @param builder
* the builder
* @param isPresent
* the is present
* @param translator
* the translator
* @param condition
* the condition
* @param value
* the value
* @param useInClause
* the use in clause
* @param idAttributeColumn
* the id attribute column
* @param columnName
* the column name
* @param useToken
* the use token
* @return true, if successful
*/
private boolean buildWhereClause(StringBuilder builder, boolean isPresent, CQLTranslator translator,
String condition, List value, boolean useInClause, AbstractAttribute idAttributeColumn,
String columnName, boolean useToken)
{
if (value.isEmpty())
{
isPresent = appendIn(builder, translator, columnName);
builder.append("( )");
builder.append(" AND ");
}
// handle relations in Id
else if (useInClause && value.size() > 1)
{
isPresent = appendInClause(builder, translator, value, idAttributeColumn.getBindableJavaType(), columnName,
isPresent);
}
else
{
// TODO for partition key in case of embedded key.
// idAttributeColumn.getBindableJavaType() was sending this class,
// changed to getJavaType()
translator.buildWhereClause(builder, ((Attribute) idAttributeColumn).getJavaType(), columnName,
value.isEmpty() ? null : value.get(0), condition, useToken);
}
return isPresent;
}
/**
* Append in.
*
* @param builder
* the builder
* @param translator
* the translator
* @param columnName
* the column name
* @return true, if successful
*/
private boolean appendIn(StringBuilder builder, CQLTranslator translator, String columnName)
{
boolean isPresent;
isPresent = true;
translator.ensureCase(builder, columnName, false);
builder.append(" IN ");
return isPresent;
}
/**
* Append in clause.
*
* @param queryBuilder
* the query builder
* @param translator
* the translator
* @param value
* the value
* @param fieldClazz
* the field clazz
* @param columnName
* the column name
* @param isPresent
* the is present
* @return true, if successful
*/
private boolean appendInClause(StringBuilder queryBuilder, CQLTranslator translator, List value,
Class fieldClazz, String columnName, boolean isPresent)
{
isPresent = appendIn(queryBuilder, translator, columnName);
queryBuilder.append("(");
for (Object objectvalue : value)
{
translator.appendValue(queryBuilder, fieldClazz, objectvalue, isPresent, false);
queryBuilder.append(", ");
}
queryBuilder.deleteCharAt(queryBuilder.lastIndexOf(", "));
queryBuilder.append(") ");
queryBuilder.append(" AND ");
return isPresent;
}
/**
* Adds the where clause.
*
* @param builder
* the builder
*/
void addWhereClause(StringBuilder builder)
{
if (!getKunderaQuery().getFilterClauseQueue().isEmpty())
{
builder.append(CQLTranslator.ADD_WHERE_CLAUSE);
}
}
/*
* (non-Javadoc)
*
* @see com.impetus.kundera.query.QueryImpl#close()
*/
@Override
public void close()
{
// Nothing to close.
}
/*
* (non-Javadoc)
*
* @see com.impetus.kundera.query.QueryImpl#iterate()
*/
@Override
public Iterator iterate()
{
if (kunderaQuery.isNative())
{
throw new UnsupportedOperationException("Iteration not supported over native queries");
}
EntityMetadata m = getEntityMetadata();
Client client = persistenceDelegeator.getClient(m);
externalProperties = ((CassandraClientBase) client).getExternalProperties();
if (!MetadataUtils.useSecondryIndex(((ClientBase) client).getClientMetadata()))
{
throw new UnsupportedOperationException("Scrolling over cassandra is unsupported for lucene queries");
}
return new ResultIterator(this, m, persistenceDelegeator.getClient(m), this.getReader(),
getFetchSize() != null ? getFetchSize() : this.maxResult, kunderaMetadata);
}
/**
* Sets the relational entities.
*
* @param enhanceEntities
* the enhance entities
* @param client
* the client
* @param m
* the m
*/
void setRelationalEntities(List enhanceEntities, Client client, EntityMetadata m)
{
super.setRelationEntities(enhanceEntities, client, m);
}
/**
* Create Update CQL query from a given JPA query.
*
* @param kunderaQuery
* the kundera query
* @return the string
*/
public String createUpdateQuery(KunderaQuery kunderaQuery)
{
EntityMetadata metadata = kunderaQuery.getEntityMetadata();
MetamodelImpl metaModel = (MetamodelImpl) kunderaMetadata.getApplicationMetadata().getMetamodel(
metadata.getPersistenceUnit());
CQLTranslator translator = new CQLTranslator();
String update_Query = translator.UPDATE_QUERY;
String tableName = metadata.getTableName();
update_Query = StringUtils.replace(update_Query, CQLTranslator.COLUMN_FAMILY,
translator.ensureCase(new StringBuilder(), tableName, false).toString());
StringBuilder builder = new StringBuilder(update_Query);
Object ttlColumns = ((CassandraClientBase) persistenceDelegeator.getClient(metadata)).getTtlValues().get(
metadata.getTableName());
if ((ttlColumns != null && ttlColumns instanceof Integer) || this.ttl != null)
{
int ttl = this.ttl != null ? this.ttl : ((Integer) ttlColumns).intValue();
if (ttl != 0)
{
builder.append(" USING TTL ");
builder.append(ttl);
builder.append(" ");
}
}
builder.append(CQLTranslator.ADD_SET_CLAUSE);
for (UpdateClause updateClause : kunderaQuery.getUpdateClauseQueue())
{
String property = updateClause.getProperty();
String jpaColumnName = getColumnName(metadata, property);
Object value = updateClause.getValue();
translator.buildSetClause(metadata, builder, jpaColumnName, value);
}
builder.delete(builder.lastIndexOf(CQLTranslator.COMMA_STR), builder.length());
builder.append(CQLTranslator.ADD_WHERE_CLAUSE);
Class compoundKeyClass = metadata.getIdAttribute().getBindableJavaType();
EmbeddableType compoundKey = null;
String idColumn;
if (metaModel.isEmbeddable(compoundKeyClass))
{
compoundKey = metaModel.embeddable(compoundKeyClass);
idColumn = ((AbstractAttribute) metadata.getIdAttribute()).getJPAColumnName();
}
else
{
idColumn = ((AbstractAttribute) metadata.getIdAttribute()).getJPAColumnName();
}
onCondition(metadata, metaModel, compoundKey, idColumn, builder, false, translator, false);
return builder.toString();
}
/**
* Create Delete query from a given JPA query.
*
* @param kunderaQuery
* the kundera query
* @return the string
*/
public String createDeleteQuery(KunderaQuery kunderaQuery)
{
EntityMetadata metadata = kunderaQuery.getEntityMetadata();
MetamodelImpl metaModel = (MetamodelImpl) kunderaMetadata.getApplicationMetadata().getMetamodel(
metadata.getPersistenceUnit());
CQLTranslator translator = new CQLTranslator();
String delete_query = translator.DELETE_QUERY;
String tableName = kunderaQuery.getEntityMetadata().getTableName();
delete_query = StringUtils.replace(delete_query, CQLTranslator.COLUMN_FAMILY,
translator.ensureCase(new StringBuilder(), tableName, false).toString());
StringBuilder builder = new StringBuilder(delete_query);
builder.append(CQLTranslator.ADD_WHERE_CLAUSE);
Class compoundKeyClass = metadata.getIdAttribute().getBindableJavaType();
EmbeddableType compoundKey = null;
String idColumn;
if (metaModel.isEmbeddable(compoundKeyClass))
{
compoundKey = metaModel.embeddable(compoundKeyClass);
idColumn = ((AbstractAttribute) metadata.getIdAttribute()).getJPAColumnName();
}
else
{
idColumn = ((AbstractAttribute) metadata.getIdAttribute()).getJPAColumnName();
}
onCondition(metadata, metaModel, compoundKey, idColumn, builder, false, translator, false);
return builder.toString();
}
/**
* Builds where Clause.
*
* @param kunderaQuery
* the kundera query
* @param metadata
* the metadata
* @param metaModel
* the meta model
* @param translator
* the translator
* @param builder
* the builder
*/
private void buildWhereClause(KunderaQuery kunderaQuery, EntityMetadata metadata, MetamodelImpl metaModel,
CQLTranslator translator, StringBuilder builder)
{
for (Object clause : kunderaQuery.getFilterClauseQueue())
{
FilterClause filterClause = (FilterClause) clause;
Field f = (Field) metaModel.entity(metadata.getEntityClazz())
.getAttribute(metadata.getFieldName(filterClause.getProperty())).getJavaMember();
String jpaColumnName = getColumnName(metadata, filterClause.getProperty());
if (metaModel.isEmbeddable(metadata.getIdAttribute().getBindableJavaType()))
{
Field[] fields = metadata.getIdAttribute().getBindableJavaType().getDeclaredFields();
EmbeddableType compoundKey = metaModel.embeddable(metadata.getIdAttribute().getBindableJavaType());
for (Field field : fields)
{
if (field != null && !Modifier.isStatic(field.getModifiers())
&& !Modifier.isTransient(field.getModifiers())
&& !field.isAnnotationPresent(Transient.class))
{
Attribute attribute = compoundKey.getAttribute(field.getName());
String columnName = ((AbstractAttribute) attribute).getJPAColumnName();
Object value = PropertyAccessorHelper.getObject(filterClause.getValue().get(0), field);
// TODO
translator.buildWhereClause(builder, field.getType(), columnName, value,
filterClause.getCondition(), false);
}
}
}
else
{
translator.buildWhereClause(builder, f.getType(), jpaColumnName, filterClause.getValue().get(0),
filterClause.getCondition(), false);
}
}
builder.delete(builder.lastIndexOf(CQLTranslator.AND_CLAUSE), builder.length());
}
/**
* Gets column name for a given field name.
*
* @param metadata
* the metadata
* @param property
* the property
* @return the column name
*/
private String getColumnName(EntityMetadata metadata, String property)
{
MetamodelImpl metaModel = (MetamodelImpl) kunderaMetadata.getApplicationMetadata().getMetamodel(
metadata.getPersistenceUnit());
String jpaColumnName = null;
if (property.equals(((AbstractAttribute) metadata.getIdAttribute()).getJPAColumnName()))
{
jpaColumnName = CassandraUtilities.getIdColumnName(kunderaMetadata, metadata,
((CassandraClientBase) persistenceDelegeator.getClient(metadata)).getExternalProperties(),
((CassandraClientBase) persistenceDelegeator.getClient(metadata)).isCql3Enabled(metadata));
}
else
{
jpaColumnName = ((AbstractAttribute) metaModel.getEntityAttribute(metadata.getEntityClazz(), property))
.getJPAColumnName();
}
return jpaColumnName;
}
/**
* Checks if is native.
*
* @return true, if is native
*/
boolean isNative()
{
return kunderaQuery.isNative();
}
}