info.archinnov.achilles.internal.context.DaoContext Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of achilles-core Show documentation
Show all versions of achilles-core Show documentation
CQL implementation for Achilles using Datastax Java driver
/*
* Copyright (C) 2012-2014 DuyHai DOAN
*
* 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 info.archinnov.achilles.internal.context;
import static info.archinnov.achilles.counter.AchillesCounter.CQLQueryType.DECR;
import static info.archinnov.achilles.counter.AchillesCounter.CQLQueryType.DELETE;
import static info.archinnov.achilles.counter.AchillesCounter.CQLQueryType.INCR;
import static info.archinnov.achilles.counter.AchillesCounter.CQLQueryType.SELECT;
import static info.archinnov.achilles.counter.AchillesCounter.ACHILLES_COUNTER_VALUE;
import static info.archinnov.achilles.counter.AchillesCounter.ClusteredCounterStatement.DELETE_ALL;
import static info.archinnov.achilles.counter.AchillesCounter.ClusteredCounterStatement.SELECT_ALL;
import static info.archinnov.achilles.internal.consistency.ConsistencyConverter.getCQLLevel;
import static info.archinnov.achilles.internal.persistence.operations.CollectionAndMapChangeType.REMOVE_FROM_LIST_AT_INDEX;
import static info.archinnov.achilles.internal.persistence.operations.CollectionAndMapChangeType.SET_TO_LIST_AT_INDEX;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import com.datastax.driver.core.querybuilder.IfExistsClause;
import info.archinnov.achilles.listener.LWTResultListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.datastax.driver.core.BoundStatement;
import com.datastax.driver.core.PreparedStatement;
import com.datastax.driver.core.RegularStatement;
import com.datastax.driver.core.ResultSet;
import com.datastax.driver.core.Row;
import com.datastax.driver.core.Session;
import com.datastax.driver.core.querybuilder.Update;
import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.base.Supplier;
import com.google.common.cache.Cache;
import com.google.common.util.concurrent.ListenableFuture;
import info.archinnov.achilles.counter.AchillesCounter.CQLQueryType;
import info.archinnov.achilles.internal.async.AsyncUtils;
import info.archinnov.achilles.internal.consistency.ConsistencyOverrider;
import info.archinnov.achilles.internal.context.facade.DaoOperations;
import info.archinnov.achilles.internal.metadata.holder.EntityMeta;
import info.archinnov.achilles.internal.metadata.holder.PropertyMeta;
import info.archinnov.achilles.internal.persistence.operations.CollectionAndMapChangeType;
import info.archinnov.achilles.internal.proxy.dirtycheck.DirtyCheckChangeSet;
import info.archinnov.achilles.internal.statement.StatementGenerator;
import info.archinnov.achilles.internal.statement.cache.CacheManager;
import info.archinnov.achilles.internal.statement.cache.StatementCacheKey;
import info.archinnov.achilles.internal.statement.prepared.PreparedStatementBinder;
import info.archinnov.achilles.internal.statement.wrapper.AbstractStatementWrapper;
import info.archinnov.achilles.internal.statement.wrapper.BoundStatementWrapper;
import info.archinnov.achilles.internal.statement.wrapper.RegularStatementWrapper;
import info.archinnov.achilles.query.slice.SliceQueryProperties;
import info.archinnov.achilles.type.ConsistencyLevel;
import info.archinnov.achilles.internal.utils.Pair;
public class DaoContext {
private static final Logger log = LoggerFactory.getLogger(DaoContext.class);
protected Cache dynamicPSCache;
protected Map, PreparedStatement> selectPSs;
protected Map counterQueryMap;
protected Map, Map>> clusteredCounterQueryMap;
protected Session session;
protected CacheManager cacheManager;
protected PreparedStatementBinder binder = PreparedStatementBinder.Singleton.INSTANCE.get();
protected StatementGenerator statementGenerator = StatementGenerator.Singleton.INSTANCE.get();
protected ConsistencyOverrider overrider = ConsistencyOverrider.Singleton.INSTANCE.get();
protected AsyncUtils asyncUtils = AsyncUtils.Singleton.INSTANCE.get();
protected ExecutorService executorService;
protected static final Function RESULTSET_TO_ROW = new Function() {
@Override
public Row apply(ResultSet resultSet) {
return resultSet.one();
}
};
protected ExecutorService getExecutorService() {
return executorService;
}
public void pushInsertStatement(DaoOperations context, List pms) {
log.debug("Push insert statement for PersistenceContext '{}' and properties '{}'", context, pms);
PreparedStatement ps = cacheManager.getCacheForEntityInsert(session, dynamicPSCache, context, pms);
BoundStatementWrapper bsWrapper = binder.bindForInsert(context, ps, pms);
context.pushStatement(bsWrapper);
}
public void pushUpdateStatement(DaoOperations context, List pms) {
log.debug("Push update statement for PersistenceContext '{}' and properties '{}'", context, pms);
PreparedStatement ps = cacheManager.getCacheForFieldsUpdate(session, dynamicPSCache, context, pms);
BoundStatementWrapper bsWrapper = binder.bindForUpdate(context, ps, pms);
context.pushStatement(bsWrapper);
}
public void pushCollectionAndMapUpdateStatement(DaoOperations context, DirtyCheckChangeSet changeSet) {
final CollectionAndMapChangeType changeType = changeSet.getChangeType();
final PropertyMeta propertyMeta = changeSet.getPropertyMeta();
if (log.isDebugEnabled()) {
log.debug("Push update statement for PersistenceContext '{}' and collection/map property '{}' for change type '{}'", context, propertyMeta, changeType);
}
if (changeType == SET_TO_LIST_AT_INDEX || changeType == REMOVE_FROM_LIST_AT_INDEX) {
ConsistencyLevel writeLevel = overrider.getWriteLevel(context);
final Pair pair = statementGenerator.generateCollectionAndMapUpdateOperation(context, changeSet);
if (context.getOptions().isIfExists()) {
pair.left.onlyIf(IfExistsClause.build());
}
context.pushStatement(new RegularStatementWrapper(context.getEntityClass(), pair.left, pair.right, getCQLLevel(writeLevel),
context.getLWTResultListener(), context.getSerialConsistencyLevel()));
} else {
PreparedStatement ps = cacheManager.getCacheForCollectionAndMapOperation(session, dynamicPSCache, context, propertyMeta, changeSet);
BoundStatementWrapper bsWrapper = binder.bindForCollectionAndMapUpdate(context, ps, changeSet);
context.pushStatement(bsWrapper);
}
}
public Row loadProperty(DaoOperations context, PropertyMeta pm) {
log.debug("Load property '{}' for PersistenceContext '{}'", pm, context);
PreparedStatement ps = cacheManager.getCacheForFieldSelect(session, dynamicPSCache, context, pm);
final ListenableFuture resultSetFuture = executeReadWithConsistency(context, ps, pm.structure().isStaticColumn());
final ListenableFuture futureRows = asyncUtils.transformFuture(resultSetFuture, RESULTSET_TO_ROW);
return asyncUtils.buildInterruptible(futureRows).getImmediately();
}
public void bindForDeletion(DaoOperations context, EntityMeta entityMeta) {
log.debug("Push delete statement for PersistenceContext '{}'", context);
final PreparedStatement preparedStatement = cacheManager.getCacheForDeletion(session, dynamicPSCache, context);
ConsistencyLevel consistencyLevel = overrider.getWriteLevel(context);
BoundStatementWrapper bsWrapper = binder.bindForDeletion(context, preparedStatement, entityMeta.structure().hasOnlyStaticColumns(), consistencyLevel);
context.pushStatement(bsWrapper);
}
// Simple counter
public void bindForSimpleCounterIncrement(DaoOperations context, PropertyMeta counterMeta, Long increment) {
log.debug("Push simple counter increment statement for PersistenceContext '{}' and value '{}'", context, increment);
PreparedStatement ps = counterQueryMap.get(INCR);
ConsistencyLevel writeLevel = overrider.getWriteLevel(context, counterMeta);
BoundStatementWrapper bsWrapper = binder.bindForSimpleCounterIncrementDecrement(context, ps, counterMeta, increment, writeLevel);
context.pushCounterStatement(bsWrapper);
}
public ListenableFuture incrementSimpleCounter(DaoOperations context, PropertyMeta counterMeta, Long increment, ConsistencyLevel consistencyLevel) {
log.debug("Increment immediately simple counter for PersistenceContext '{}' and value '{}'", context, increment);
PreparedStatement ps = counterQueryMap.get(INCR);
BoundStatementWrapper bsWrapper = binder.bindForSimpleCounterIncrementDecrement(context, ps, counterMeta, increment, consistencyLevel);
return context.executeImmediate(bsWrapper);
}
public ListenableFuture decrementSimpleCounter(DaoOperations context, PropertyMeta counterMeta, Long decrement, ConsistencyLevel consistencyLevel) {
log.debug("Decrement immediately simple counter for PersistenceContext '{}' and value '{}'", context, decrement);
PreparedStatement ps = counterQueryMap.get(DECR);
BoundStatementWrapper bsWrapper = binder.bindForSimpleCounterIncrementDecrement(context, ps, counterMeta, decrement, consistencyLevel);
return context.executeImmediate(bsWrapper);
}
public Long getSimpleCounter(DaoOperations context, PropertyMeta counterMeta, ConsistencyLevel consistencyLevel) {
if (log.isDebugEnabled()) {
log.debug("Get simple counter value for counterMeta '{}' PersistenceContext '{}' using Consistency level '{}'", counterMeta, context, consistencyLevel);
}
PreparedStatement ps = counterQueryMap.get(SELECT);
BoundStatementWrapper bsWrapper = binder.bindForSimpleCounterSelect(context, ps, counterMeta, consistencyLevel);
final ListenableFuture resultSetFuture = context.executeImmediate(bsWrapper);
final ListenableFuture futureRow = asyncUtils.transformFuture(resultSetFuture, RESULTSET_TO_ROW);
final Row row = asyncUtils.buildInterruptible(futureRow).getImmediately();
return rowToLongFunction(ACHILLES_COUNTER_VALUE).apply(row);
}
public void bindForSimpleCounterDelete(DaoOperations context, PropertyMeta counterMeta) {
log.debug("Push simple counter deletion statement for counterMeta '{}' and PersistenceContext '{}'", counterMeta, context);
PreparedStatement ps = counterQueryMap.get(DELETE);
BoundStatementWrapper bsWrapper = binder.bindForSimpleCounterDelete(context, ps, counterMeta);
context.pushCounterStatement(bsWrapper);
}
// Clustered counter
public void pushClusteredCounterIncrementStatement(DaoOperations context, PropertyMeta counterMeta, Long increment) {
if (log.isDebugEnabled()) {
log.debug("Push clustered counter increment statement for counterMeta '{}' and PersistenceContext '{}' and value '{}'", counterMeta, context, increment);
}
PreparedStatement ps = clusteredCounterQueryMap.get(context.getEntityClass()).get(INCR).get(counterMeta.getPropertyName());
BoundStatementWrapper bsWrapper = binder.bindForClusteredCounterIncrementDecrement(context, ps, counterMeta, increment);
context.pushCounterStatement(bsWrapper);
}
public ListenableFuture getClusteredCounter(DaoOperations context) {
log.debug("Get clustered counter for PersistenceContext '{}'", context);
EntityMeta entityMeta = context.getEntityMeta();
PreparedStatement ps = clusteredCounterQueryMap.get(entityMeta.getEntityClass()).get(SELECT).get(SELECT_ALL.name());
ConsistencyLevel consistencyLevel = overrider.getReadLevel(context);
BoundStatementWrapper bsWrapper = binder.bindForClusteredCounterSelect(context, ps, false, consistencyLevel);
final ListenableFuture resultSetFuture = context.executeImmediate(bsWrapper);
return asyncUtils.transformFuture(resultSetFuture, RESULTSET_TO_ROW);
}
public Long getClusteredCounterColumn(DaoOperations context, PropertyMeta counterMeta) {
log.debug("Get clustered counter for PersistenceContext '{}'", context);
final String propertyName = counterMeta.getPropertyName();
final String cqlColumnName = counterMeta.getCQLColumnName();
PreparedStatement ps = clusteredCounterQueryMap.get(context.getEntityClass()).get(SELECT).get(propertyName);
ConsistencyLevel readLevel = overrider.getReadLevel(context, counterMeta);
BoundStatementWrapper bsWrapper = binder.bindForClusteredCounterSelect(context, ps, counterMeta.structure().isStaticColumn(), readLevel);
final ListenableFuture resultSetFuture = context.executeImmediate(bsWrapper);
final ListenableFuture futureRow = asyncUtils.transformFuture(resultSetFuture, RESULTSET_TO_ROW);
final Row row = asyncUtils.buildInterruptible(futureRow).getImmediately();
return rowToLongFunction(cqlColumnName).apply(row);
}
public void bindForClusteredCounterDelete(DaoOperations context) {
log.debug("Push clustered counter deletion statement for PersistenceContext '{}'", context);
PreparedStatement ps = clusteredCounterQueryMap.get(context.getEntityClass()).get(DELETE).get(DELETE_ALL.name());
BoundStatementWrapper bsWrapper = binder.bindForClusteredCounterDelete(context, ps);
context.pushCounterStatement(bsWrapper);
}
public ListenableFuture loadEntity(DaoOperations context) {
log.debug("Load entity for PersistenceContext '{}'", context);
Class> entityClass = context.getEntityClass();
PreparedStatement ps = selectPSs.get(entityClass);
final EntityMeta entityMeta = context.getEntityMeta();
final ListenableFuture resultSetFuture = executeReadWithConsistency(context, ps, entityMeta.structure().hasOnlyStaticColumns());
return asyncUtils.transformFuture(resultSetFuture, RESULTSET_TO_ROW);
}
public BoundStatementWrapper bindForSliceQuerySelect(SliceQueryProperties> sliceQueryProperties) {
final PreparedStatement ps = cacheManager.getCacheForSliceSelectAndIterator(session, dynamicPSCache, sliceQueryProperties);
return buildBSForSliceQuery(sliceQueryProperties, sliceQueryProperties.getReadConsistencyLevel(), ps);
}
public BoundStatementWrapper bindForSliceQueryDelete(SliceQueryProperties> sliceQueryProperties) {
final PreparedStatement ps = cacheManager.getCacheForSliceDelete(session, dynamicPSCache, sliceQueryProperties);
return buildBSForSliceQuery(sliceQueryProperties, sliceQueryProperties.getWriteConsistencyLevel(), ps);
}
private BoundStatementWrapper buildBSForSliceQuery(final SliceQueryProperties> sliceQueryProperties, ConsistencyLevel consistencyLevel, final PreparedStatement ps) {
final Object[] boundValues = sliceQueryProperties.getBoundValues();
Supplier bs = new Supplier() {
@Override
public BoundStatement get() {
BoundStatement bs = ps.bind(boundValues);
sliceQueryProperties.setFetchSizeToStatement(bs);
return bs;
}
};
return new BoundStatementWrapper(sliceQueryProperties.getEntityClass(), bs, boundValues, getCQLLevel(consistencyLevel),
Optional.absent(), Optional.absent());
}
private ListenableFuture executeReadWithConsistency(DaoOperations context, PreparedStatement ps, boolean onlyStaticColumns) {
ConsistencyLevel readLevel = overrider.getReadLevel(context);
BoundStatementWrapper bsWrapper = binder.bindStatementWithOnlyPKInWhereClause(context, ps, onlyStaticColumns, readLevel);
return context.executeImmediate(bsWrapper);
}
public ListenableFuture execute(AbstractStatementWrapper statementWrapper) {
return statementWrapper.executeAsync(session, executorService);
}
public PreparedStatement prepare(RegularStatement statement) {
return session.prepare(statement.getQueryString());
}
private Function rowToLongFunction(final String counterColumnName) {
return new Function() {
@Override
public Long apply(Row row) {
Long counterValue = null;
if (row != null && !row.isNull(counterColumnName)) {
counterValue = row.getLong(counterColumnName);
}
return counterValue;
}
};
}
public Session getSession() {
return session;
}
void setDynamicPSCache(Cache dynamicPSCache) {
this.dynamicPSCache = dynamicPSCache;
}
void setSelectPSs(Map, PreparedStatement> selectPSs) {
this.selectPSs = selectPSs;
}
void setCounterQueryMap(Map counterQueryMap) {
this.counterQueryMap = counterQueryMap;
}
void setClusteredCounterQueryMap(Map, Map>> clusteredCounterQueryMap) {
this.clusteredCounterQueryMap = clusteredCounterQueryMap;
}
void setSession(Session session) {
this.session = session;
}
void setCacheManager(CacheManager cacheManager) {
this.cacheManager = cacheManager;
}
void setExecutorService(ExecutorService executorService) {
this.executorService = executorService;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy