info.archinnov.achilles.internal.context.PersistenceContext 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 com.google.common.collect.FluentIterable.from;
import static info.archinnov.achilles.interceptor.Event.POST_LOAD;
import static info.archinnov.achilles.interceptor.Event.POST_INSERT;
import static info.archinnov.achilles.interceptor.Event.POST_DELETE;
import static info.archinnov.achilles.interceptor.Event.POST_UPDATE;
import static info.archinnov.achilles.interceptor.Event.PRE_INSERT;
import static info.archinnov.achilles.interceptor.Event.PRE_DELETE;
import static info.archinnov.achilles.interceptor.Event.PRE_UPDATE;
import static info.archinnov.achilles.options.Options.LWTCondition;
import java.lang.reflect.Method;
import java.util.*;
import java.util.concurrent.ExecutorService;
import info.archinnov.achilles.listener.LWTResultListener;
import info.archinnov.achilles.type.Empty;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.datastax.driver.core.ResultSet;
import com.datastax.driver.core.Row;
import com.google.common.base.Function;
import com.google.common.base.Objects;
import com.google.common.base.Optional;
import com.google.common.util.concurrent.ListenableFuture;
import info.archinnov.achilles.async.AchillesFuture;
import info.archinnov.achilles.internal.async.AsyncUtils;
import info.archinnov.achilles.internal.async.ImmediateValue;
import info.archinnov.achilles.internal.consistency.ConsistencyOverrider;
import info.archinnov.achilles.internal.context.facade.DaoOperations;
import info.archinnov.achilles.internal.context.facade.EntityOperations;
import info.archinnov.achilles.internal.context.facade.PersistenceManagerOperations;
import info.archinnov.achilles.internal.context.facade.PersistentStateHolder;
import info.archinnov.achilles.internal.metadata.holder.EntityMeta;
import info.archinnov.achilles.internal.metadata.holder.PropertyMeta;
import info.archinnov.achilles.internal.persistence.operations.EntityInitializer;
import info.archinnov.achilles.internal.persistence.operations.EntityLoader;
import info.archinnov.achilles.internal.persistence.operations.EntityPersister;
import info.archinnov.achilles.internal.persistence.operations.EntityProxifier;
import info.archinnov.achilles.internal.persistence.operations.EntityUpdater;
import info.archinnov.achilles.internal.proxy.dirtycheck.DirtyCheckChangeSet;
import info.archinnov.achilles.internal.statement.wrapper.AbstractStatementWrapper;
import info.archinnov.achilles.internal.validation.Validator;
import info.archinnov.achilles.type.ConsistencyLevel;
import info.archinnov.achilles.options.Options;
import info.archinnov.achilles.options.OptionsBuilder;
public class PersistenceContext {
private static final Logger log = LoggerFactory.getLogger(PersistenceContext.class);
protected AbstractFlushContext flushContext;
protected EntityInitializer initializer = EntityInitializer.Singleton.INSTANCE.get();
protected EntityPersister persister = EntityPersister.Singleton.INSTANCE.get();
protected EntityProxifier proxifier = EntityProxifier.Singleton.INSTANCE.get();
protected EntityLoader loader = EntityLoader.Singleton.INSTANCE.get();
protected EntityUpdater updater = EntityUpdater.Singleton.INSTANCE.get();
protected ConfigurationContext configContext;
protected Class> entityClass;
protected EntityMeta entityMeta;
protected Object entity;
protected Object primaryKey;
protected Object partitionKey;
protected Options options = OptionsBuilder.noOptions();
protected DaoContext daoContext;
private ConsistencyOverrider overrider = ConsistencyOverrider.Singleton.INSTANCE.get();
protected AsyncUtils asyncUtils = AsyncUtils.Singleton.INSTANCE.get();
protected PersistenceManagerFacade persistenceManagerFacade = new PersistenceManagerFacade();
protected EntityFacade entityFacade = new EntityFacade();
protected DaoFacade daoFacade = new DaoFacade();
protected StateHolderFacade stateHolderFacade = new StateHolderFacade();
private Function metaToGetter = new Function() {
@Override
public Method apply(PropertyMeta meta) {
return meta.getGetter();
}
};
public PersistenceContext(EntityMeta entityMeta, ConfigurationContext configContext, DaoContext daoContext, AbstractFlushContext flushContext) {
this.entityClass = entityMeta.getEntityClass();
this.entityMeta = entityMeta;
this.configContext = configContext;
this.daoContext = daoContext;
this.flushContext = flushContext;
}
public PersistenceContext(EntityMeta entityMeta, ConfigurationContext configContext, DaoContext daoContext,
AbstractFlushContext flushContext, Object entity, Options options) {
Validator.validateNotNull(entity,
"The entity of type '{}' should not be null for persistence context creation",
entityMeta.getClassName());
this.primaryKey = entityMeta.forOperations().getPrimaryKey(entity);
Validator.validateNotNull(primaryKey,
"The primary key for the entity class '{}' should not be null for persistence context creation",
entityMeta.getClassName());
this.entityClass = entityMeta.getEntityClass();
this.entityMeta = entityMeta;
this.configContext = configContext;
this.daoContext = daoContext;
this.flushContext = flushContext;
this.entity = entity;
this.options = overrider.overrideRuntimeValueByBatchSetting(options, flushContext);
}
public PersistenceContext(EntityMeta entityMeta, ConfigurationContext configContext, DaoContext daoContext,
AbstractFlushContext flushContext, Class> entityClass, Object primaryKey, Options options) {
Validator.validateNotNull(entityClass, "The entity class should not be null for persistence context creation");
Validator.validateNotNull(primaryKey,
"The primary key for the entity class '{}' should not be null for persistence context creation",
entityClass.getCanonicalName());
this.entityMeta = entityMeta;
this.configContext = configContext;
this.daoContext = daoContext;
this.flushContext = flushContext;
this.entityClass = entityClass;
this.primaryKey = primaryKey;
this.options = overrider.overrideRuntimeValueByBatchSetting(options, flushContext);
}
public PersistenceContext duplicate(Object entity) {
log.trace("Duplicate PersistenceContext for entity '{}'", entity);
return new PersistenceContext(entityMeta, configContext, daoContext, flushContext.duplicate(), entity,
options.duplicateWithoutTtlAndTimestamp());
}
public StateHolderFacade getStateHolderFacade() {
return stateHolderFacade;
}
public EntityFacade getEntityFacade() {
return entityFacade;
}
public PersistenceManagerFacade getPersistenceManagerFacade() {
return persistenceManagerFacade;
}
@Override
public String toString() {
return Objects.toStringHelper(PersistenceContext.class).add("entity class", this.entityClass)
.add("primary key", this.primaryKey).add("partition key", this.partitionKey).toString();
}
public class StateHolderFacade implements PersistentStateHolder {
private StateHolderFacade() {
}
public PropertyMeta getIdMeta() {
return entityMeta.getIdMeta();
}
public boolean isClusteredCounter() {
return entityMeta.structure().isClusteredCounter();
}
public EntityMeta getEntityMeta() {
return entityMeta;
}
public Object getEntity() {
return entity;
}
public void setEntity(Object entity) {
PersistenceContext.this.entity = entity;
}
@SuppressWarnings("unchecked")
public Class getEntityClass() {
return (Class) entityClass;
}
public Object getPrimaryKey() {
return primaryKey;
}
public Options getOptions() {
return options;
}
@Override
public boolean hasTTL() {
return options.hasTTL();
}
@Override
public boolean hasTimestamp() {
return options.hasTimestamp();
}
public Optional getTtl() {
return options.getTtl();
}
public Optional getTimestamp() {
return options.getTimestamp();
}
public Optional getConsistencyLevel() {
return options.getConsistencyLevel();
}
@Override
public Optional getSerialConsistencyLevel() {
return options.getSerialConsistency();
}
public List getLWTConditions() {
return Optional.fromNullable(options.getLwtConditions()).or(new ArrayList());
}
public boolean hasLWTConditions() {
return options.hasLWTConditions();
}
public Optional getLWTResultListener() {
return options.getLWTResultListener();
}
public Set getAllGettersExceptCounters() {
return new HashSet<>(from(entityMeta.getAllMetasExceptCounters()).transform(metaToGetter).toList());
}
public Set getAllGetters() {
return new HashSet<>(from(entityMeta.getAllMetas()).transform(metaToGetter).toList());
}
public List getAllCountersMeta() {
return entityMeta.getAllCounterMetas();
}
public ConfigurationContext getConfigContext() {
return configContext;
}
public ExecutorService getExecutorService() {
return configContext.getExecutorService();
}
}
public class PersistenceManagerFacade extends StateHolderFacade implements PersistenceManagerOperations {
private PersistenceManagerFacade() {
}
public AchillesFuture insert(final T rawEntity) {
flushContext.triggerInterceptor(entityMeta, rawEntity, PRE_INSERT);
persister.persist(entityFacade);
final ListenableFuture> resultSetFutures = flush();
Function, T> applyTriggers = new Function, T>() {
@Override
public T apply(List input) {
flushContext.triggerInterceptor(entityMeta, rawEntity, POST_INSERT);
return rawEntity;
}
};
Function returnRaw = new Function() {
@Override
public T apply(T input) {
return rawEntity;
}
};
final ListenableFuture triggersApplied = asyncUtils.transformFuture(resultSetFutures, applyTriggers, getExecutorService());
asyncUtils.maybeAddAsyncListeners(triggersApplied, options);
final ListenableFuture proxyCreated = asyncUtils.transformFuture(triggersApplied, returnRaw);
return asyncUtils.buildInterruptible(proxyCreated);
}
public AchillesFuture batchInsert(final T rawEntity) {
flushContext.triggerInterceptor(entityMeta, rawEntity, PRE_INSERT);
persister.persist(entityFacade);
flush();
flushContext.triggerInterceptor(entityMeta, rawEntity, POST_INSERT);
final T proxy = proxifier.buildProxyWithAllFieldsLoadedExceptCounters(rawEntity, entityFacade);
return asyncUtils.buildInterruptible(new ImmediateValue<>(proxy));
}
public AchillesFuture update(final T proxy) {
flushContext.triggerInterceptor(entityMeta, proxy, PRE_UPDATE);
updater.update(entityFacade, proxy);
final ListenableFuture> resultSetFutures = flush();
Function, T> applyTriggers = new Function, T>() {
@Override
public T apply(List input) {
flushContext.triggerInterceptor(entityMeta, proxy, POST_UPDATE);
proxifier.getInterceptor(proxy).getDirtyMap().clear();
return proxy;
}
};
final ListenableFuture triggersApplied = asyncUtils.transformFuture(resultSetFutures, applyTriggers, getExecutorService());
asyncUtils.maybeAddAsyncListeners(triggersApplied, options);
return asyncUtils.buildInterruptible(triggersApplied);
}
public AchillesFuture delete() {
flushContext.triggerInterceptor(entityMeta, entity, PRE_DELETE);
persister.delete(entityFacade);
final ListenableFuture> resultSetFutures = flush();
Function, T> applyTriggers = new Function, T>() {
@Override
public T apply(List input) {
flushContext.triggerInterceptor(entityMeta, entity, POST_DELETE);
return (T) entity;
}
};
final ListenableFuture triggersApplied = asyncUtils.transformFuture(resultSetFutures, applyTriggers, getExecutorService());
asyncUtils.maybeAddAsyncListeners(triggersApplied, options);
return asyncUtils.buildInterruptible(triggersApplied);
}
public AchillesFuture deleteById() {
persister.delete(entityFacade);
final ListenableFuture> resultSetFutures = flush();
Function, Empty> toEmpty = new Function, Empty>() {
@Override
public Empty apply(List input) {
return Empty.INSTANCE;
}
};
final ListenableFuture triggersApplied = asyncUtils.transformFuture(resultSetFutures, toEmpty, getExecutorService());
asyncUtils.maybeAddAsyncListeners(triggersApplied, options);
return asyncUtils.buildInterruptible(triggersApplied);
}
public AchillesFuture find(Class entityClass) {
final AchillesFuture achillesFuture = loader.load(entityFacade, entityClass);
Function applyTrigger = new Function() {
@Override
public T apply(T rawEntity) {
if (rawEntity != null) {
flushContext.triggerInterceptor(entityMeta, rawEntity, POST_LOAD);
}
return rawEntity;
}
};
final ListenableFuture triggersApplied = asyncUtils.transformFuture(achillesFuture, applyTrigger);
asyncUtils.maybeAddAsyncListeners(triggersApplied, options);
Function createProxy = new Function() {
@Override
public T apply(T rawEntity) {
if (options.shouldCreateProxy()) {
if (entityMeta.structure().isClusteredCounter()) {
return proxifier.buildProxyWithAllFieldsLoaded(rawEntity, entityFacade);
} else {
return proxifier.buildProxyWithAllFieldsLoadedExceptCounters(rawEntity, entityFacade);
}
} else {
return rawEntity;
}
}
};
final ListenableFuture proxyCreated = asyncUtils.transformFuture(triggersApplied, createProxy);
return asyncUtils.buildInterruptible(proxyCreated);
}
public T getProxy(Class entityClass) {
T entity = loader.createEmptyEntity(entityFacade, entityClass);
return proxifier.buildProxyWithNoFieldLoaded(entity, entityFacade);
}
public T getProxyForUpdate(Class entityClass) {
T entity = loader.createEmptyEntity(entityFacade, entityClass);
return proxifier.buildProxyForUpdate(entity, entityFacade);
}
public T initialize(T proxy) {
initializer.initializeEntity(proxy, entityMeta);
return proxy;
}
public List initialize(List entities) {
for (T entity : entities) {
initialize(entity);
}
return entities;
}
public Set initialize(Set entities) {
for (T entity : entities) {
initialize(entity);
}
return entities;
}
protected ListenableFuture> flush() {
return flushContext.flush();
}
}
public class EntityFacade extends StateHolderFacade implements EntityOperations {
private EntityFacade() {
}
public ListenableFuture loadEntity() {
return daoContext.loadEntity(daoFacade);
}
public Row loadProperty(PropertyMeta pm) {
return daoContext.loadProperty(daoFacade, pm);
}
public void pushInsertStatement() {
final List pms = entityMeta.forOperations().retrievePropertyMetasForInsert(entity);
daoContext.pushInsertStatement(daoFacade, pms);
}
public void pushUpdateStatement(List pms) {
daoContext.pushUpdateStatement(daoFacade, pms);
}
public void pushCollectionAndMapUpdateStatements(DirtyCheckChangeSet changeSet) {
daoContext.pushCollectionAndMapUpdateStatement(daoFacade, changeSet);
}
public void bindForDeletion() {
daoContext.bindForDeletion(daoFacade, entityMeta);
}
// Simple counter
public void bindForSimpleCounterIncrement(PropertyMeta counterMeta, Long increment) {
daoContext.bindForSimpleCounterIncrement(daoFacade, counterMeta, increment);
}
public Long getSimpleCounter(PropertyMeta counterMeta, ConsistencyLevel consistency) {
log.trace("Get counter value for counterMeta '{}' with consistency level '{}'", counterMeta, consistency);
return daoContext.getSimpleCounter(daoFacade, counterMeta, consistency);
}
public void bindForSimpleCounterDeletion(PropertyMeta counterMeta) {
daoContext.bindForSimpleCounterDelete(daoFacade, counterMeta);
}
// Clustered counter
public void pushClusteredCounterIncrementStatement(PropertyMeta counterMeta, Long increment) {
daoContext.pushClusteredCounterIncrementStatement(daoFacade, counterMeta, increment);
}
public ListenableFuture getClusteredCounter() {
log.trace("Get clustered counter value for entityMeta '{}'", entityMeta);
return daoContext.getClusteredCounter(daoFacade);
}
public Long getClusteredCounterColumn(PropertyMeta counterMeta) {
log.trace("Get clustered counter value for counterMeta '{}'", counterMeta);
return daoContext.getClusteredCounterColumn(daoFacade, counterMeta);
}
public void bindForClusteredCounterDeletion() {
daoContext.bindForClusteredCounterDelete(daoFacade);
}
}
public class DaoFacade extends StateHolderFacade implements DaoOperations {
private DaoFacade() {
}
public void pushStatement(AbstractStatementWrapper statementWrapper) {
flushContext.pushStatement(statementWrapper);
}
public void pushCounterStatement(AbstractStatementWrapper statementWrapper) {
flushContext.pushCounterStatement(statementWrapper);
}
public ListenableFuture executeImmediate(AbstractStatementWrapper bsWrapper) {
return flushContext.execute(bsWrapper);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy