use of org.hibernate.reactive.engine.impl.Cascade in project hibernate-reactive by hibernate.
the class DefaultReactiveLockEventListener method cascadeOnLock.
private void cascadeOnLock(LockEvent event, EntityPersister persister, Object entity) {
EventSource source = event.getSession();
final PersistenceContext persistenceContext = source.getPersistenceContextInternal();
persistenceContext.incrementCascadeLevel();
try {
new Cascade(CascadingActions.LOCK, CascadePoint.AFTER_LOCK, persister, entity, event.getLockOptions(), source).cascade();
} finally {
persistenceContext.decrementCascadeLevel();
}
}
use of org.hibernate.reactive.engine.impl.Cascade in project hibernate-reactive by hibernate.
the class DefaultReactiveMergeEventListener method entityIsTransient.
protected CompletionStage<Void> entityIsTransient(MergeEvent event, MergeContext copyCache) {
LOG.trace("Merging transient instance");
final Object entity = event.getEntity();
final EventSource session = event.getSession();
final String entityName = event.getEntityName();
final EntityPersister persister = session.getEntityPersister(entityName, entity);
final Serializable id = persister.hasIdentifierProperty() ? persister.getIdentifier(entity, session) : null;
final Object copy;
final Object existingCopy = copyCache.get(entity);
if (existingCopy != null) {
persister.setIdentifier(copyCache.get(entity), id, session);
copy = existingCopy;
} else {
copy = session.instantiate(persister, id);
// before cascade!
copyCache.put(entity, copy, true);
}
// cascadeOnMerge(event, persister, entity, copyCache, Cascades.CASCADE_BEFORE_MERGE);
return super.cascadeBeforeSave(session, persister, entity, copyCache).thenCompose(v -> copyValues(persister, entity, copy, session, copyCache, FROM_PARENT)).thenCompose(v -> saveTransientEntity(copy, entityName, event.getRequestedId(), session, copyCache)).thenCompose(v -> super.cascadeAfterSave(session, persister, entity, copyCache)).thenCompose(v -> copyValues(persister, entity, copy, session, copyCache, TO_PARENT)).thenAccept(v -> {
event.setResult(copy);
if (copy instanceof PersistentAttributeInterceptable) {
final PersistentAttributeInterceptable interceptable = (PersistentAttributeInterceptable) copy;
final PersistentAttributeInterceptor interceptor = interceptable.$$_hibernate_getInterceptor();
if (interceptor == null) {
persister.getBytecodeEnhancementMetadata().injectInterceptor(copy, id, session);
}
}
});
}
use of org.hibernate.reactive.engine.impl.Cascade in project hibernate-reactive by hibernate.
the class DefaultReactiveMergeEventListener method entityIsDetached.
protected CompletionStage<Void> entityIsDetached(MergeEvent event, MergeContext copyCache) {
LOG.trace("Merging detached instance");
final Object entity = event.getEntity();
final EventSource source = event.getSession();
final EntityPersister persister = source.getEntityPersister(event.getEntityName(), entity);
final String entityName = persister.getEntityName();
Serializable requestedId = event.getRequestedId();
Serializable id;
if (requestedId == null) {
id = persister.getIdentifier(entity, source);
} else {
id = requestedId;
// check that entity id = requestedId
Serializable entityId = persister.getIdentifier(entity, source);
if (!persister.getIdentifierType().isEqual(id, entityId, source.getFactory())) {
throw LOG.mergeRequestedIdNotMatchingIdOfPassedEntity();
}
}
String previousFetchProfile = source.getLoadQueryInfluencers().getInternalFetchProfile();
source.getLoadQueryInfluencers().setInternalFetchProfile("merge");
// we must clone embedded composite identifiers, or
// we will get back the same instance that we pass in
final Serializable clonedIdentifier = (Serializable) persister.getIdentifierType().deepCopy(id, source.getFactory());
return source.unwrap(ReactiveSession.class).reactiveGet((Class<?>) persister.getMappedClass(), clonedIdentifier).thenCompose(result -> {
if (result != null) {
// before cascade!
copyCache.put(entity, result, true);
Object target = unproxyManagedForDetachedMerging(entity, result, persister, source);
if (target == entity) {
throw new AssertionFailure("entity was not detached");
} else if (!source.getEntityName(target).equals(entityName)) {
throw new WrongClassException("class of the given object did not match class of persistent copy", event.getRequestedId(), entityName);
} else if (isVersionChanged(entity, source, persister, target)) {
final StatisticsImplementor statistics = source.getFactory().getStatistics();
if (statistics.isStatisticsEnabled()) {
statistics.optimisticFailure(entityName);
}
throw new StaleObjectStateException(entityName, id);
}
// copy created before we actually copy
return cascadeOnMerge(source, persister, entity, copyCache).thenCompose(v -> fetchAndCopyValues(persister, entity, target, source, copyCache)).thenAccept(v -> {
// copyValues() (called by fetchAndCopyValues) works by reflection,
// so explicitly mark the entity instance dirty
markInterceptorDirty(entity, target, persister);
event.setResult(result);
});
} else {
// really persistent
return entityIsTransient(event, copyCache);
}
}).whenComplete((v, e) -> source.getLoadQueryInfluencers().setInternalFetchProfile(previousFetchProfile));
}
use of org.hibernate.reactive.engine.impl.Cascade in project hibernate-reactive by hibernate.
the class DefaultReactiveRefreshEventListener method reactiveOnRefresh.
private CompletionStage<Void> reactiveOnRefresh(RefreshEvent event, IdentitySet refreshedAlready, Object entity) {
EventSource source = event.getSession();
PersistenceContext persistenceContext = source.getPersistenceContextInternal();
if (refreshedAlready.contains(entity)) {
LOG.trace("Already refreshed");
return voidFuture();
}
final EntityEntry e = persistenceContext.getEntry(entity);
final EntityPersister persister;
final Serializable id;
if (e == null) {
persister = source.getEntityPersister(event.getEntityName(), entity);
// refresh() does not pass an entityName
id = persister.getIdentifier(entity, event.getSession());
if (LOG.isTraceEnabled()) {
LOG.tracev("Refreshing transient {0}", infoString(persister, id, source.getFactory()));
}
if (persistenceContext.getEntry(source.generateEntityKey(id, persister)) != null) {
throw new PersistentObjectException("attempted to refresh transient instance when persistent instance was already associated with the session: " + infoString(persister, id, source.getFactory()));
}
} else {
if (LOG.isTraceEnabled()) {
LOG.tracev("Refreshing ", infoString(e.getPersister(), e.getId(), source.getFactory()));
}
if (!e.isExistsInDatabase()) {
throw new UnresolvableObjectException(e.getId(), "this instance does not yet exist as a row in the database");
}
persister = e.getPersister();
id = e.getId();
}
// cascade the refresh prior to refreshing this entity
refreshedAlready.add(entity);
return cascadeRefresh(source, persister, entity, refreshedAlready).thenCompose(v -> {
if (e != null) {
final EntityKey key = source.generateEntityKey(id, persister);
persistenceContext.removeEntity(key);
if (persister.hasCollections()) {
new EvictVisitor(source, entity).process(entity, persister);
}
}
if (persister.canWriteToCache()) {
Object previousVersion = null;
if (persister.isVersionPropertyGenerated()) {
// we need to grab the version value from the entity, otherwise
// we have issues with generated-version entities that may have
// multiple actions queued during the same flush
previousVersion = persister.getVersion(entity);
}
final EntityDataAccess cache = persister.getCacheAccessStrategy();
final Object ck = cache.generateCacheKey(id, persister, source.getFactory(), source.getTenantIdentifier());
final SoftLock lock = cache.lockItem(source, ck, previousVersion);
cache.remove(source, ck);
source.getActionQueue().registerProcess((success, session) -> cache.unlockItem(session, ck, lock));
}
evictCachedCollections(persister, id, source);
String previousFetchProfile = source.getLoadQueryInfluencers().getInternalFetchProfile();
source.getLoadQueryInfluencers().setInternalFetchProfile("refresh");
// Handle the requested lock-mode (if one) in relation to the entry's (if one) current lock-mode
LockOptions lockOptionsToUse = event.getLockOptions();
final LockMode requestedLockMode = lockOptionsToUse.getLockMode();
final LockMode postRefreshLockMode;
if (e != null) {
final LockMode currentLockMode = e.getLockMode();
if (currentLockMode.greaterThan(requestedLockMode)) {
// the requested lock-mode is less restrictive than the current one
// - pass along the current lock-mode (after accounting for WRITE)
lockOptionsToUse = LockOptions.copy(event.getLockOptions(), new LockOptions());
if (currentLockMode == LockMode.WRITE || currentLockMode == LockMode.PESSIMISTIC_WRITE || currentLockMode == LockMode.PESSIMISTIC_READ) {
// our transaction should already hold the exclusive lock on
// the underlying row - so READ should be sufficient.
//
// in fact, this really holds true for any current lock-mode that indicates we
// hold an exclusive lock on the underlying row - but we *need* to handle
// WRITE specially because the Loader/Locker mechanism does not allow for WRITE
// locks
lockOptionsToUse.setLockMode(LockMode.READ);
// and prepare to reset the entry lock-mode to the previous lock mode after
// the refresh completes
postRefreshLockMode = currentLockMode;
} else {
lockOptionsToUse.setLockMode(currentLockMode);
postRefreshLockMode = null;
}
} else {
postRefreshLockMode = null;
}
} else {
postRefreshLockMode = null;
}
return ((ReactiveAbstractEntityPersister) persister).reactiveLoad(id, entity, lockOptionsToUse, source).thenAccept(result -> {
if (result != null) {
// apply `postRefreshLockMode`, if needed
if (postRefreshLockMode != null) {
// if we get here, there was a previous entry and we need to re-set its lock-mode
// - however, the refresh operation actually creates a new entry, so get it
persistenceContext.getEntry(result).setLockMode(postRefreshLockMode);
}
// If it was transient, then set it to the default for the source.
if (!persister.isMutable()) {
// this is probably redundant; it should already be read-only
source.setReadOnly(result, true);
} else {
source.setReadOnly(result, e == null ? source.isDefaultReadOnly() : e.isReadOnly());
}
}
UnresolvableObjectException.throwIfNull(result, id, persister.getEntityName());
}).whenComplete((vv, t) -> source.getLoadQueryInfluencers().setInternalFetchProfile(previousFetchProfile));
});
}
use of org.hibernate.reactive.engine.impl.Cascade in project hibernate-reactive by hibernate.
the class DefaultReactiveMergeEventListener method entityIsPersistent.
protected CompletionStage<Void> entityIsPersistent(MergeEvent event, MergeContext copyCache) {
LOG.trace("Ignoring persistent instance");
// TODO: check that entry.getIdentifier().equals(requestedId)
final Object entity = event.getEntity();
final EventSource source = event.getSession();
final EntityPersister persister = source.getEntityPersister(event.getEntityName(), entity);
// before cascade!
copyCache.put(entity, entity, true);
return cascadeOnMerge(source, persister, entity, copyCache).thenCompose(v -> fetchAndCopyValues(persister, entity, entity, source, copyCache)).thenAccept(v -> event.setResult(entity));
}
Aggregations