diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/Cascade.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/Cascade.java index 34a1026889..60f5971dc7 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/Cascade.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/Cascade.java @@ -98,18 +98,17 @@ public static CompletionStage cascade( final EntityPersister persister, final Object parent, final T anything) throws HibernateException { - return voidFuture().thenCompose( v -> { - CacheMode cacheMode = eventSource.getCacheMode(); - if ( action == CascadingActions.REMOVE ) { - eventSource.setCacheMode( CacheMode.GET ); - } - eventSource.getPersistenceContextInternal().incrementCascadeLevel(); - return cascadeInternal( action, cascadePoint, eventSource, persister, parent, anything ) - .whenComplete( (unused, throwable) -> { - eventSource.getPersistenceContextInternal().decrementCascadeLevel(); - eventSource.setCacheMode( cacheMode ); - } ); - } ); + CacheMode cacheMode = eventSource.getCacheMode(); + if ( action == CascadingActions.REMOVE ) { + eventSource.setCacheMode( CacheMode.GET ); + } + eventSource.getPersistenceContextInternal().incrementCascadeLevel(); + return voidFuture() + .thenCompose( v -> cascadeInternal( action, cascadePoint, eventSource, persister, parent, anything ) ) + .whenComplete( (unused, throwable) -> { + eventSource.getPersistenceContextInternal().decrementCascadeLevel(); + eventSource.setCacheMode( cacheMode ); + } ); } private static CompletionStage cascadeInternal( @@ -270,7 +269,6 @@ private static CompletionStage cascadeProperty( final T anything, final boolean isCascadeDeleteEnabled) throws HibernateException { - CompletionStage stage = voidFuture(); if ( child != null ) { if ( type.isAssociationType() ) { final AssociationType associationType = (AssociationType) type; @@ -279,18 +277,8 @@ private static CompletionStage cascadeProperty( .isUnownedAssociationTransientCheck(); if ( cascadeAssociationNow( action, cascadePoint, associationType, eventSource.getFactory(), unownedTransient ) ) { final List path = componentPath; - stage = stage.thenCompose( v -> cascadeAssociation( - action, - cascadePoint, - eventSource, - path, - parent, - child, - type, - style, - anything, - isCascadeDeleteEnabled - ) ); + return cascadeAssociation( action, cascadePoint, eventSource, path, parent, child, type, style, anything, isCascadeDeleteEnabled ) + .thenCompose( v -> cascadeLogicalOneToOne( action, eventSource, path, parent, child, type, style, propertyName, isCascadeDeleteEnabled ) ); } } else if ( type.isComponentType() ) { @@ -301,40 +289,40 @@ else if ( type.isComponentType() ) { componentPath.add( propertyName ); } final List path = componentPath; - stage = stage - .thenCompose( v -> cascadeComponent( - action, - cascadePoint, - eventSource, - path, - parent, - child, - (CompositeType) type, - anything - ) - .thenRun( () -> { - if ( path != null ) { - path.remove( path.size() - 1 ); - } - } ) - ); + return cascadeComponent( action, cascadePoint, eventSource, path, parent, child, (CompositeType) type, anything ) + .thenRun( () -> { + if ( path != null ) { + path.remove( path.size() - 1 ); + } + } ) + .thenCompose( v -> cascadeLogicalOneToOne( action, eventSource, path, parent, child, type, style, propertyName, isCascadeDeleteEnabled ) ); } } - if ( isLogicalOneToOne( type ) ) { - final List path = componentPath; - stage = stage.thenCompose( v -> cascadeLogicalOneToOneOrphanRemoval( - action, - eventSource, - path, - parent, - child, - type, - style, - propertyName, - isCascadeDeleteEnabled - ) ); - } - return stage; + return cascadeLogicalOneToOne( + action, + eventSource, + componentPath, + parent, + child, + type, + style, + propertyName, + isCascadeDeleteEnabled ); + } + + private static CompletionStage cascadeLogicalOneToOne( + CascadingAction action, + EventSource eventSource, + List componentPath, + Object parent, + Object child, + Type type, + CascadeStyle style, + String propertyName, + boolean isCascadeDeleteEnabled) { + return isLogicalOneToOne( type ) + ? cascadeLogicalOneToOneOrphanRemoval( action, eventSource, componentPath, parent, child, type, style, propertyName, isCascadeDeleteEnabled ) + : voidFuture(); } private static CompletionStage cascadeLogicalOneToOneOrphanRemoval( @@ -611,8 +599,8 @@ private static CompletionStage cascadeToOne( if ( style.reallyDoCascade( action.delegate() ) ) { //not really necessary, but good for consistency... final PersistenceContext persistenceContext = eventSource.getPersistenceContextInternal(); + persistenceContext.addChildParent( child, parent ); return voidFuture() - .thenRun( () -> persistenceContext.addChildParent( child, parent ) ) .thenCompose( v -> action.cascade( eventSource, child, entityName, anything, isCascadeDeleteEnabled ) ) .whenComplete( (v, e) -> persistenceContext.removeChildParent( child ) ); } @@ -638,9 +626,11 @@ private static CompletionStage cascadeCollectionElements( CompletionStage stage = voidFuture(); if ( reallyDoCascade ) { final boolean traceEnabled = LOG.isTraceEnabled(); - if ( traceEnabled ) { - LOG.tracev( "Cascade {0} for collection: {1}", action, collectionType.getRole() ); - } + stage = stage.thenRun( () -> { + if ( traceEnabled ) { + LOG.tracev( "Done cascade {0} for collection: {1}", action, collectionType.getRole() ); + } + } ); final Iterator itr = action.getCascadableChildrenIterator( eventSource, collectionType, child ); while ( itr.hasNext() ) { @@ -665,6 +655,17 @@ private static CompletionStage cascadeCollectionElements( } ); } + return stage + .thenCompose( v -> doDeleteOrphans( action, eventSource, child, collectionType, style, elemType ) ); + } + + private static CompletionStage doDeleteOrphans( + CascadingAction action, + EventSource eventSource, + Object child, + CollectionType collectionType, + CascadeStyle style, + Type elemType) { final boolean deleteOrphans = style.hasOrphanDelete() && action.deleteOrphans() && elemType.isEntityType() @@ -673,30 +674,28 @@ private static CompletionStage cascadeCollectionElements( && ! ( (PersistentCollection) child ).isNewlyInstantiated(); if ( deleteOrphans ) { - stage = stage.thenCompose( v -> { - final boolean traceEnabled = LOG.isTraceEnabled(); - if ( traceEnabled ) { - LOG.tracev( "Deleting orphans for collection: {0}", collectionType.getRole() ); - } - // we can do the cast since orphan-delete does not apply to: - // 1. newly instantiated collections - // 2. arrays (we can't track orphans for detached arrays) - final String entityName = collectionType.getAssociatedEntityName( eventSource.getFactory() ); - return deleteOrphans( eventSource, entityName, (PersistentCollection) child ) - .thenRun( () -> { - if ( traceEnabled ) { - LOG.tracev( "Done deleting orphans for collection: {0}", collectionType.getRole() ); - } - } ); - } ); + final boolean traceEnabled = LOG.isTraceEnabled(); + if ( traceEnabled ) { + LOG.tracev( "Deleting orphans for collection: {0}", collectionType.getRole() ); + } + // we can do the cast since orphan-delete does not apply to: + // 1. newly instantiated collections + // 2. arrays (we can't track orphans for detached arrays) + final String entityName = collectionType.getAssociatedEntityName( eventSource.getFactory() ); + return doDeleteOrphans( eventSource, entityName, (PersistentCollection) child ) + .thenRun( () -> { + if ( traceEnabled ) { + LOG.tracev( "Done deleting orphans for collection: {0}", collectionType.getRole() ); + } + } ); } - return stage; + return voidFuture(); } /** * Delete any entities that were removed from the collection */ - private static CompletionStage deleteOrphans(EventSource eventSource, String entityName, PersistentCollection pc) { + private static CompletionStage doDeleteOrphans(EventSource eventSource, String entityName, PersistentCollection pc) { final Collection orphans = getOrphans( eventSource, entityName, pc ); final ReactiveSession session = (ReactiveSession) eventSource; return loop( orphans, Objects::nonNull, orphan -> { diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/id/impl/BlockingIdentifierGenerator.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/id/impl/BlockingIdentifierGenerator.java index d15de1779a..224410853f 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/id/impl/BlockingIdentifierGenerator.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/id/impl/BlockingIdentifierGenerator.java @@ -10,9 +10,9 @@ import io.vertx.core.net.impl.pool.CombinerExecutor; import io.vertx.core.net.impl.pool.Executor; import io.vertx.core.net.impl.pool.Task; + import org.hibernate.reactive.id.ReactiveIdentifierGenerator; import org.hibernate.reactive.session.ReactiveConnectionSupplier; -import org.hibernate.reactive.util.impl.CompletionStages; import java.util.Objects; import java.util.concurrent.CompletableFuture; @@ -29,7 +29,6 @@ * @author Gavin King * @author Davide D'Alto * @author Sanne Grinovero - * */ public abstract class BlockingIdentifierGenerator implements ReactiveIdentifierGenerator { @@ -83,40 +82,41 @@ public CompletionStage generate(ReactiveConnectionSupplier connectionSuppl //(this does actually hit a synchronization, but it's extremely short) final long next = next(); if ( next != -1 ) { - return CompletionStages.completedFuture( next ); + return completedFuture( next ); } //Another special case we need to deal with; this is an unlikely configuration, but //if it were to happen we should be better off with direct execution rather than using //the co-operative executor: if ( getBlockSize() <= 1 ) { - return nextHiValue( connectionSupplier ) - .thenApply( i -> next( i ) ); + return nextHiValue( connectionSupplier ).thenApply( this::next ); } final CompletableFuture resultForThisEventLoop = new CompletableFuture<>(); final CompletableFuture result = new CompletableFuture<>(); - executor.submit( new GenerateIdAction( connectionSupplier, result ) ); final Context context = Vertx.currentContext(); - result.whenComplete( (id,t) -> { + executor.submit( new GenerateIdAction( connectionSupplier, result ) ); + result.whenComplete( (id, t) -> { final Context newContext = Vertx.currentContext(); //Need to be careful in resuming processing on the same context as the original //request, potentially having to switch back if we're no longer executing on the same: if ( newContext != context ) { if ( t != null ) { - context.runOnContext( ( v ) -> resultForThisEventLoop.completeExceptionally( t ) ); - } else { - context.runOnContext( ( v ) -> resultForThisEventLoop.complete( id ) ); + context.runOnContext( v -> resultForThisEventLoop.completeExceptionally( t ) ); + } + else { + context.runOnContext( v -> resultForThisEventLoop.complete( id ) ); } } else { if ( t != null ) { resultForThisEventLoop.completeExceptionally( t ); - } else { + } + else { resultForThisEventLoop.complete( id ); } } - }); + } ); return resultForThisEventLoop; } @@ -126,8 +126,8 @@ private final class GenerateIdAction implements Executor.Action private final CompletableFuture result; public GenerateIdAction(ReactiveConnectionSupplier connectionSupplier, CompletableFuture result) { - this.connectionSupplier = Objects.requireNonNull(connectionSupplier); - this.result = Objects.requireNonNull(result); + this.connectionSupplier = Objects.requireNonNull( connectionSupplier ); + this.result = Objects.requireNonNull( result ); } @Override @@ -137,21 +137,22 @@ public Task execute(GeneratorState state) { // We don't need to update or initialize the hi // value in the table, so just increment the lo // value and return the next id in the block - completedFuture( local ) - .whenComplete( this::acceptAsReturnValue ); + completedFuture( local ).whenComplete( this::acceptAsReturnValue ); return null; - } else { + } + else { nextHiValue( connectionSupplier ) .whenComplete( (newlyGeneratedHi, throwable) -> { if ( throwable != null ) { result.completeExceptionally( throwable ); - } else { + } + else { //We ignore the state argument as we actually use the field directly //for convenience, but they are the same object. executor.submit( stateIgnored -> { result.complete( next( newlyGeneratedHi ) ); return null; - }); + } ); } } ); return null; diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/id/impl/ReactiveGeneratorWrapper.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/id/impl/ReactiveGeneratorWrapper.java index fd7cda2c59..6edfed3dfb 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/id/impl/ReactiveGeneratorWrapper.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/id/impl/ReactiveGeneratorWrapper.java @@ -16,6 +16,8 @@ import java.util.Objects; import java.util.concurrent.CompletionStage; +import static java.util.function.Function.identity; + /** * @author Gavin King */ @@ -46,7 +48,7 @@ public void initialize(SqlStringGenerationContext context) { @Override public CompletionStage generate(ReactiveConnectionSupplier session, Object entity) { - return reactiveGenerator.generate( session, entity ).thenApply( id -> id ); + return reactiveGenerator.generate( session, entity ).thenApply( identity() ); } @Override diff --git a/hibernate-reactive-core/src/test/resources/log4j2.properties b/hibernate-reactive-core/src/test/resources/log4j2.properties index 3fbc4ab846..57ba774b98 100644 --- a/hibernate-reactive-core/src/test/resources/log4j2.properties +++ b/hibernate-reactive-core/src/test/resources/log4j2.properties @@ -17,9 +17,6 @@ logger.sql-connection.level = info logger.reactive-engine.name = org.hibernate.reactive.engine.impl logger.reactive-engine.level = trace -logger.orm-engine.name = org.hibernate.engine -logger.orm-engine.level = trace - # Setting level to TRACE will show parameters values logger.sql-parameters-values.name = org.hibernate.type logger.sql-parameters-values.level = info