This is an automated email from the ASF dual-hosted git repository. ahuber pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/causeway.git
The following commit(s) were added to refs/heads/main by this push: new 8c9669e5981 CAUSEWAY-3896: AsyncProxy API and Javadoc polishing 8c9669e5981 is described below commit 8c9669e5981a90a9588d9e587255de820535e7db Author: Andi Huber <ahu...@apache.org> AuthorDate: Sat Jun 28 07:39:45 2025 +0200 CAUSEWAY-3896: AsyncProxy API and Javadoc polishing --- .../applib/services/wrapper/WrapperFactory.java | 115 ++++++++++++--------- .../causeway/commons/functional/TryFuture.java | 58 +++++++++++ .../wrapper/AsyncProxyInternal.java | 31 ++---- .../wrapper/WrapperFactoryDefault.java | 13 --- .../BackgroundService_IntegTestAbstract.java | 24 ++--- .../jdo/publishing/PublishingTestFactoryJdo.java | 9 +- .../jpa/publishing/PublishingTestFactoryJpa.java | 14 +-- .../integtests/WrapperFactory_async_IntegTest.java | 12 +-- .../testdomain/interact/CommandArgumentTest.java | 6 +- .../WrapperInteraction_Caching_IntegTest.java | 9 +- 10 files changed, 167 insertions(+), 124 deletions(-) diff --git a/api/applib/src/main/java/org/apache/causeway/applib/services/wrapper/WrapperFactory.java b/api/applib/src/main/java/org/apache/causeway/applib/services/wrapper/WrapperFactory.java index 1237f360695..21924f3e541 100644 --- a/api/applib/src/main/java/org/apache/causeway/applib/services/wrapper/WrapperFactory.java +++ b/api/applib/src/main/java/org/apache/causeway/applib/services/wrapper/WrapperFactory.java @@ -20,17 +20,19 @@ import java.util.List; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.TimeUnit; import org.springframework.util.function.ThrowingConsumer; import org.springframework.util.function.ThrowingFunction; import org.apache.causeway.applib.exceptions.recoverable.InteractionException; import org.apache.causeway.applib.services.factory.FactoryService; +import org.apache.causeway.applib.services.iactnlayer.InteractionContext; +import org.apache.causeway.applib.services.repository.RepositoryService; import org.apache.causeway.applib.services.wrapper.control.AsyncControl; import org.apache.causeway.applib.services.wrapper.control.SyncControl; import org.apache.causeway.applib.services.wrapper.events.InteractionEvent; import org.apache.causeway.applib.services.wrapper.listeners.InteractionListener; +import org.apache.causeway.commons.functional.TryFuture; /** * Provides the ability to 'wrap' a domain object such that it can @@ -75,18 +77,30 @@ public interface WrapperFactory { /** + * The result of an async proxy instantiation, + * that allows to submit an async invocation on the wrapped domain object. + * + * <p>The framework takes care, that an async invocation is scoped within both an interaction-context and a transaction. + * Further more, {@link TryFuture}'s success values are unwrapped and detached. + * + * <p>Terminology: + * <ul> + * <li>interaction-context: who/how/when {@link InteractionContext}</li> + * <li>unwrapped: plain object, not proxied {@link WrapperFactory#unwrap}</li> + * <li>detached: object not attached to a persistence session (applicable to entities only) + * {@link RepositoryService#detach(Object)}</li> + * </ul> + * * @since 3.4 {@index} - * @see CompletableFuture + * @see TryFuture */ interface AsyncProxy<T> { - AsyncProxy<Void> thenAcceptAsync(ThrowingConsumer<? super T> action); - <U> AsyncProxy<U> thenApplyAsync(ThrowingFunction<? super T, ? extends U> fn); - AsyncProxy<T> orTimeout(long timeout, TimeUnit unit); - T join(); + TryFuture<Void> acceptAsync(ThrowingConsumer<? super T> action); + <U> TryFuture<U> applyAsync(ThrowingFunction<? super T, ? extends U> fn); } /** - * Provides the "wrapper" of a domain object against which to invoke the action. + * Provides the'wrapper' of a domain object against which to invoke the action. * * <p>The provided {@link SyncControl} determines whether business rules are checked first, and conversely * whether the action is executed. There are therefore three typical cases: @@ -100,48 +114,49 @@ interface AsyncProxy<T> { * * <p>Otherwise, will do all the validations (raise exceptions as required * etc.), but doesn't modify the model. + * + * <p>Any exceptions will be propagated, not swallowed. */ - <T> T wrap(T domainObject, - SyncControl syncControl); + <T> T wrap(T domainObject, SyncControl syncControl); /** - * A convenience overload for {@link #wrap(Object, SyncControl)}, - * returning a wrapper to invoke the action synchronously, enforcing business rules. - * Any exceptions will be propagated, not swallowed. + * A convenience overload for {@link #wrap(Object, SyncControl)} with {@code SyncControl.defaults()}. + * @see #wrap(Object, SyncControl) */ - <T> T wrap(T domainObject); + default <T> T wrap(T domainObject) { + return wrap(domainObject, SyncControl.defaults()); + } /** * Provides the wrapper for a {@link FactoryService#mixin(Class, Object) mixin}, against which to invoke the action. * - * <p> - * The provided {@link SyncControl} determines whether business rules are checked first, and conversely - * whether the action is executed. See {@link #wrap(Object, SyncControl)} for more details on this. - * </p> + * <p>The provided {@link SyncControl} determines whether business rules are checked first, and conversely + * whether the action is executed. + * + * <p>Any exceptions will be propagated, not swallowed. + * @see #wrap(Object, SyncControl) */ - <T> T wrapMixin(Class<T> mixinClass, Object mixee, - SyncControl syncControl); + <T> T wrapMixin(Class<T> mixinClass, Object mixee, SyncControl syncControl); + + /** + * A convenience overload for {@link #wrapMixin(Class, Object, SyncControl)} with {@code SyncControl.defaults()}. + * @see #wrapMixin(Class, Object, SyncControl) + */ + default <T> T wrapMixin(Class<T> mixinClass, Object mixee) { + return wrapMixin(mixinClass, mixee, SyncControl.defaults()); + } /** * Provides the wrapper for a {@link Mixin typesafe} {@link FactoryService#mixin(Class, Object) mixin}, against which to invoke the action. * - * <p> - * The provided {@link SyncControl} determines whether business rules are checked first, and conversely + * <p>The provided {@link SyncControl} determines whether business rules are checked first, and conversely * whether the action is executed. See {@link #wrap(Object, SyncControl)} for more details on this. - * </p> */ default <T extends Mixin<MIXEE>, MIXEE> T wrapMixinT(Class<T> mixinClass, MIXEE mixee, SyncControl syncControl) { return wrapMixin(mixinClass, mixee, syncControl); } - /** - * A convenience overload for {@link #wrapMixin(Class, Object, SyncControl)}, - * returning a wrapper to invoke the action synchronously, enforcing business rules. - * Any exceptions will be propagated, not swallowed. - */ - <T> T wrapMixin(Class<T> mixinClass, Object mixee); - /** * A convenience overload for {@link #wrapMixinT(Class, Object, SyncControl)}, * returning a wrapper to invoke the action synchronously, enforcing business rules. @@ -154,8 +169,7 @@ default <T extends Mixin<MIXEE>, MIXEE> T wrapMixinT(Class<T> mixinClass, MIXEE /** * Obtains the underlying domain object, if wrapped. * - * <p> - * If the object {@link #isWrapper(Object) is not wrapped}, then + * <p>If the object {@link #isWrapper(Object) is not wrapped}, then * should just return the object back unchanged. */ <T> T unwrap(T possibleWrappedDomainObject); @@ -163,47 +177,54 @@ default <T extends Mixin<MIXEE>, MIXEE> T wrapMixinT(Class<T> mixinClass, MIXEE /** * Whether the supplied object is a wrapper around a domain object. * - * @param <T> * @param possibleWrappedDomainObject * - object that might or might not be a wrapper. */ <T> boolean isWrapper(T possibleWrappedDomainObject); - // // -- ASYNC WRAPPING - // /** * Returns a {@link CompletableFuture} holding a proxy object for the provided {@code domainObject}, * through which one can execute the action asynchronously (in another thread). * * @param <T> - the type of the domain object - * @param domainObject - * @param asyncControl * * @since 3.4 */ <T> AsyncProxy<T> asyncWrap(T domainObject, AsyncControl asyncControl); /** - * Returns a {@link CompletableFuture} holding a proxy object for the provided {@code mixinClass}, + * A convenience overload for {@link #asyncWrap(Object, AsyncControl)} with {@code AsyncControl.defaults()}. + * @see #asyncWrap(Object, AsyncControl) + * + * @since 3.4 + */ + default <T> AsyncProxy<T> asyncWrap(T domainObject) { + return asyncWrap(domainObject, AsyncControl.defaults()); + } + + /** + * Returns a {@link AsyncProxy} holding a proxy object for the provided {@code mixinClass}, * through which one can execute the action asynchronously (in another thread). * * @param <T> - the type of the mixin - * @param mixinClass - * @param mixee - * @param asyncControl * * @since 3.4 */ - <T> AsyncProxy<T> asyncWrapMixin( - Class<T> mixinClass, - Object mixee, - AsyncControl asyncControl); + <T> AsyncProxy<T> asyncWrapMixin(Class<T> mixinClass, Object mixee, AsyncControl asyncControl); + + /** + * A convenience overload for {@link #asyncWrapMixin(Class, Object, AsyncControl)} with {@code AsyncControl.defaults()}. + * @see #asyncWrapMixin(Class, Object, AsyncControl) + * + * @since 3.4 + */ + default <T> AsyncProxy<T> asyncWrapMixin(Class<T> mixinClass, Object mixee) { + return asyncWrapMixin(mixinClass, mixee, AsyncControl.defaults()); + } - // // -- INTERACTION EVENT HANDLING - // /** * All {@link InteractionListener}s that have been registered using @@ -239,4 +260,6 @@ boolean removeInteractionListener( InteractionListener listener); void notifyListeners(InteractionEvent ev); + + } diff --git a/commons/src/main/java/org/apache/causeway/commons/functional/TryFuture.java b/commons/src/main/java/org/apache/causeway/commons/functional/TryFuture.java new file mode 100644 index 00000000000..9635d33b2e7 --- /dev/null +++ b/commons/src/main/java/org/apache/causeway/commons/functional/TryFuture.java @@ -0,0 +1,58 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.causeway.commons.functional; + +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Future; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.TimeUnit; + +import lombok.NonNull; + +/** + * Wraps a {@link Future} and catches any exceptions within a {@link Try}, + * such that no exceptions escape the future's {@code get(..)} methods. + * + * @param <T> The result type returned by this TryFuture's {@code tryGet(..)} methods + * @see Future + * @see Try + * @since 3.4 + */ +public record TryFuture<T>(@NonNull Future<T> future) { + + /** + * @throws RejectedExecutionException if the task cannot be + * scheduled for execution + * @throws NullPointerException if the task or executor is null + */ + public TryFuture(@NonNull Callable<T> task, @NonNull ExecutorService executor) { + this(executor.submit(task)); + } + + public Try<T> tryGet() { + return Try.call(future::get); + } + + public Try<T> tryGet(long timeout, TimeUnit unit) { + return Try.call(()->future.get(timeout, unit)); + } + +} + diff --git a/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/wrapper/AsyncProxyInternal.java b/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/wrapper/AsyncProxyInternal.java index e475eb4dccb..84c5439c0fb 100644 --- a/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/wrapper/AsyncProxyInternal.java +++ b/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/wrapper/AsyncProxyInternal.java @@ -18,37 +18,28 @@ */ package org.apache.causeway.core.runtimeservices.wrapper; -import java.util.concurrent.Callable; import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; import org.springframework.util.function.ThrowingConsumer; import org.springframework.util.function.ThrowingFunction; import org.apache.causeway.applib.services.wrapper.WrapperFactory.AsyncProxy; +import org.apache.causeway.commons.functional.TryFuture; -import lombok.SneakyThrows; - -//TODO this is just a proof of concept; chaining makes non sense once future no longer holds a proxy record AsyncProxyInternal<T>( Future<T> future, AsyncExecutor executor) implements AsyncProxy<T> { - @Override public AsyncProxy<Void> thenAcceptAsync(ThrowingConsumer<? super T> action) { - return thenApplyAsync(adapt(action)); - } - - @Override public <U> AsyncProxy<U> thenApplyAsync(ThrowingFunction<? super T, ? extends U> fn) { - return map(()->fn.apply(future.get())); + @Override + public TryFuture<Void> acceptAsync( + ThrowingConsumer<? super T> action) { + return applyAsync(adapt(action)); } - @Override public AsyncProxy<T> orTimeout(long timeout, TimeUnit unit) { - return map(()->future.get(timeout, unit)); - } - - @SneakyThrows - @Override public T join() { - return future.get(); + @Override + public <U> TryFuture<U> applyAsync( + ThrowingFunction<? super T, ? extends U> fn) { + return new TryFuture<>(()->fn.apply(future.get()), executor); } // -- HELPER @@ -58,8 +49,4 @@ private ThrowingFunction<? super T, Void> adapt(ThrowingConsumer<? super T> acti return t->{action.accept(t); return (Void)null; }; } - private <U> AsyncProxy<U> map(Callable<U> callable) { - return new AsyncProxyInternal<>(executor.submit(callable), executor); - } - } \ No newline at end of file diff --git a/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/wrapper/WrapperFactoryDefault.java b/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/wrapper/WrapperFactoryDefault.java index 0fcb27685b0..fa90285387f 100644 --- a/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/wrapper/WrapperFactoryDefault.java +++ b/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/wrapper/WrapperFactoryDefault.java @@ -149,12 +149,6 @@ public void close() { // -- WRAPPING - @Override - public <T> T wrap( - final @NonNull T domainObject) { - return wrap(domainObject, SyncControl.defaults()); - } - @Override public <T> T wrap( final @NonNull T domainObject, @@ -169,13 +163,6 @@ public <T> T wrap( return createProxy(domainObject, syncControl); } - @Override - public <T> T wrapMixin( - final @NonNull Class<T> mixinClass, - final @NonNull Object mixee) { - return wrapMixin(mixinClass, mixee, SyncControl.defaults()); - } - @Override public <T> T wrapMixin( final @NonNull Class<T> mixinClass, diff --git a/extensions/core/commandlog/applib/src/test/java/org/apache/causeway/extensions/commandlog/applib/integtest/BackgroundService_IntegTestAbstract.java b/extensions/core/commandlog/applib/src/test/java/org/apache/causeway/extensions/commandlog/applib/integtest/BackgroundService_IntegTestAbstract.java index 7fbbf988dde..8193b62f7c2 100644 --- a/extensions/core/commandlog/applib/src/test/java/org/apache/causeway/extensions/commandlog/applib/integtest/BackgroundService_IntegTestAbstract.java +++ b/extensions/core/commandlog/applib/src/test/java/org/apache/causeway/extensions/commandlog/applib/integtest/BackgroundService_IntegTestAbstract.java @@ -40,7 +40,6 @@ import org.apache.causeway.applib.services.iactnlayer.InteractionService; import org.apache.causeway.applib.services.wrapper.WrapperFactory; import org.apache.causeway.applib.services.wrapper.WrapperFactory.AsyncProxy; -import org.apache.causeway.applib.services.wrapper.control.AsyncControl; import org.apache.causeway.applib.services.xactn.TransactionService; import org.apache.causeway.core.config.environment.CausewaySystemEnvironment; import org.apache.causeway.extensions.commandlog.applib.dom.BackgroundService; @@ -115,28 +114,24 @@ void async_using_default_executor_service() { transactionService.runTransactional(Propagation.REQUIRES_NEW, () -> { var counter = bookmarkService.lookup(bookmark, Counter.class).orElseThrow(); - var control = AsyncControl.defaults(); - - asyncProxyUnderTest1.set(wrapperFactory.asyncWrap(counter, control)); + asyncProxyUnderTest1.set(wrapperFactory.asyncWrap(counter)); }).ifFailureFail(); // execute async and wait till done { asyncProxyUnderTest1.get() - .thenApplyAsync(Counter::bumpUsingDeclaredAction) - .orTimeout(5, TimeUnit.SECONDS) - .join(); // wait till done + .applyAsync(Counter::bumpUsingDeclaredAction) + .tryGet(5, TimeUnit.SECONDS); // wait till done } // then transactionService.runTransactional(Propagation.REQUIRES_NEW, () -> { var counter = bookmarkService.lookup(bookmark, Counter.class).orElseThrow(); assertThat(counter.getNum()).isEqualTo(1L); - var control = AsyncControl.defaults(); // store the async proxy for later use below - asyncProxyUnderTest2.set(wrapperFactory.asyncWrapMixin(Counter_bumpUsingMixin.class, counter, control)); + asyncProxyUnderTest2.set(wrapperFactory.asyncWrapMixin(Counter_bumpUsingMixin.class, counter)); }).ifFailureFail(); @@ -144,10 +139,10 @@ void async_using_default_executor_service() { { // returns the detached counter entity, so we can immediately check whether the action was executed var counter = asyncProxyUnderTest2.get() - .thenApplyAsync(Counter_bumpUsingMixin::act) + .applyAsync(Counter_bumpUsingMixin::act) // let's wait max 5 sec to allow executor to complete before continuing - .orTimeout(5, TimeUnit.SECONDS) - .join(); // wait till done + .tryGet(5, TimeUnit.SECONDS) + .valueAsNonNullElseFail(); assertThat(counter.getNum()).isEqualTo(2L); } @@ -181,10 +176,9 @@ void using_background_service() { // execute async and wait till done { asyncProxyUnderTest.get() - .thenAcceptAsync(Counter::bumpUsingDeclaredAction) + .acceptAsync(Counter::bumpUsingDeclaredAction) // let's wait max 5 sec to allow executor to complete before continuing - .orTimeout(5, TimeUnit.SECONDS) - .join(); // wait till done + .tryGet(5, TimeUnit.SECONDS); // wait till done } // then no change to the counter diff --git a/regressiontests/base-jdo/src/main/java/org/apache/causeway/testdomain/jdo/publishing/PublishingTestFactoryJdo.java b/regressiontests/base-jdo/src/main/java/org/apache/causeway/testdomain/jdo/publishing/PublishingTestFactoryJdo.java index e48f9aa88ca..ed3d91b307a 100644 --- a/regressiontests/base-jdo/src/main/java/org/apache/causeway/testdomain/jdo/publishing/PublishingTestFactoryJdo.java +++ b/regressiontests/base-jdo/src/main/java/org/apache/causeway/testdomain/jdo/publishing/PublishingTestFactoryJdo.java @@ -365,12 +365,11 @@ protected void wrapperAsyncExecutionNoRules( // when - running asynchronous return wrapper.asyncWrap(book, asyncControl) - .thenAcceptAsync(bk->bk.setName("Book #2")); + .acceptAsync(bk->bk.setName("Book #2")); }); future - .orTimeout(10, TimeUnit.SECONDS) - .join(); // wait till done + .tryGet(10, TimeUnit.SECONDS); // wait till done } @Override @@ -383,13 +382,13 @@ protected void wrapperAsyncExecutionWithRules( context.runGiven(); - // when - running synchronous + // when - running asynchronous var asyncControl = AsyncControl.defaults().withCheckRules(); // enforce rules //assertThrows(DisabledException.class, ()->{ // should fail with DisabledException (synchronous) within the calling Thread wrapper.asyncWrap(book, asyncControl) - .thenAcceptAsync(bk->bk.setName("Book #2")); + .acceptAsync(bk->bk.setName("Book #2")); //}); diff --git a/regressiontests/base-jpa/src/main/java/org/apache/causeway/testdomain/jpa/publishing/PublishingTestFactoryJpa.java b/regressiontests/base-jpa/src/main/java/org/apache/causeway/testdomain/jpa/publishing/PublishingTestFactoryJpa.java index dfd7a5212c4..77805fae6c1 100644 --- a/regressiontests/base-jpa/src/main/java/org/apache/causeway/testdomain/jpa/publishing/PublishingTestFactoryJpa.java +++ b/regressiontests/base-jpa/src/main/java/org/apache/causeway/testdomain/jpa/publishing/PublishingTestFactoryJpa.java @@ -360,12 +360,11 @@ protected void wrapperAsyncExecutionNoRules( // when - running asynchronous return wrapper.asyncWrap(book, asyncControl) - .thenAcceptAsync(bk->bk.setName("Book #2")); + .acceptAsync(bk->bk.setName("Book #2")); }); future - .orTimeout(10, TimeUnit.SECONDS) - .join(); // wait till done + .tryGet(10, TimeUnit.SECONDS); // wait till done } @@ -375,16 +374,13 @@ protected void wrapperAsyncExecutionWithRules( context.bind(commitListener); - // when + // when enforce rules withBookDo(book->{ - // when - running synchronous - var asyncControl = AsyncControl.defaults().withCheckRules(); // enforce rules - //assertThrows(DisabledException.class, ()->{ // should fail with DisabledException (synchronous) within the calling Thread - wrapper.asyncWrap(book, asyncControl) - .thenAcceptAsync(bk->bk.setName("Book #2")); + wrapper.asyncWrap(book) + .acceptAsync(bk->bk.setName("Book #2")); //}); diff --git a/regressiontests/core-wrapperfactory/src/test/java/org/apache/causeway/regressiontests/core/wrapperfactory/integtests/WrapperFactory_async_IntegTest.java b/regressiontests/core-wrapperfactory/src/test/java/org/apache/causeway/regressiontests/core/wrapperfactory/integtests/WrapperFactory_async_IntegTest.java index 76df8059a4a..4284d616169 100644 --- a/regressiontests/core-wrapperfactory/src/test/java/org/apache/causeway/regressiontests/core/wrapperfactory/integtests/WrapperFactory_async_IntegTest.java +++ b/regressiontests/core-wrapperfactory/src/test/java/org/apache/causeway/regressiontests/core/wrapperfactory/integtests/WrapperFactory_async_IntegTest.java @@ -98,9 +98,9 @@ void async_using_default_executor_service(final String displayName, final Execut // execute async and wait till done { asyncProxyUnderTest1.get() - .thenApplyAsync(Counter::increment) - .orTimeout(5_000, TimeUnit.MILLISECONDS) - .join(); // let's wait max 5 sec to allow executor to complete before continuing + .applyAsync(Counter::increment) + // let's wait max 5 sec to allow executor to complete before continuing + .tryGet(5, TimeUnit.SECONDS); } // then @@ -125,10 +125,10 @@ void async_using_default_executor_service(final String displayName, final Execut { // returns the detached counter entity, so we can immediately check whether the action was executed var counter = asyncProxyUnderTest2.get() - .thenApplyAsync(Counter_bumpUsingMixin::act) + .applyAsync(Counter_bumpUsingMixin::act) // let's wait max 5 sec to allow executor to complete before continuing - .orTimeout(5, TimeUnit.SECONDS) - .join(); // wait till done + .tryGet(5, TimeUnit.SECONDS) + .valueAsNonNullElseFail(); assertThat(counter.getNum()).isEqualTo(2L); } diff --git a/regressiontests/interact/src/test/java/org/apache/causeway/testdomain/interact/CommandArgumentTest.java b/regressiontests/interact/src/test/java/org/apache/causeway/testdomain/interact/CommandArgumentTest.java index 516def8849b..ab1f1bfbbb9 100644 --- a/regressiontests/interact/src/test/java/org/apache/causeway/testdomain/interact/CommandArgumentTest.java +++ b/regressiontests/interact/src/test/java/org/apache/causeway/testdomain/interact/CommandArgumentTest.java @@ -125,9 +125,9 @@ void listParam_shouldAllowAsyncInvocation() throws InterruptedException, Executi var control = AsyncControl.defaults(); var stringified = wrapperFactory.asyncWrap(commandArgDemo, control) - .thenApplyAsync(commandResult->commandResult.list(List.of(1L, 2L, 3L))) - .orTimeout(3L, TimeUnit.DAYS) - .join() // wait till done + .applyAsync(commandResult->commandResult.list(List.of(1L, 2L, 3L))) + .tryGet(3L, TimeUnit.DAYS) // wait till done + .valueAsNonNullElseFail() .getResultAsString(); assertEquals("[1, 2, 3]", stringified); diff --git a/regressiontests/interact/src/test/java/org/apache/causeway/testdomain/interact/WrapperInteraction_Caching_IntegTest.java b/regressiontests/interact/src/test/java/org/apache/causeway/testdomain/interact/WrapperInteraction_Caching_IntegTest.java index 53d1141fdc9..96b8e9c53ca 100644 --- a/regressiontests/interact/src/test/java/org/apache/causeway/testdomain/interact/WrapperInteraction_Caching_IntegTest.java +++ b/regressiontests/interact/src/test/java/org/apache/causeway/testdomain/interact/WrapperInteraction_Caching_IntegTest.java @@ -69,7 +69,6 @@ static class StatefulCalculator { @Action @RequiredArgsConstructor public static class StatefulCalculator_add { - @SuppressWarnings("unused") private final StatefulCalculator mixee; public Integer act(final int amount) { return mixee.inc(amount); @@ -119,17 +118,17 @@ void async_wrapped() throws ExecutionException, InterruptedException, TimeoutExc // when var asyncControlForCalculator1 = AsyncControl.defaults(); var asyncCalculator1 = wrapperFactory.asyncWrap(calculator1, asyncControlForCalculator1) - .thenApplyAsync(calc->calc.inc(12)); + .applyAsync(calc->calc.inc(12)); var asyncControlForCalculator2 = AsyncControl.defaults(); var asyncCalculator2 = wrapperFactory.asyncWrap(calculator2, asyncControlForCalculator2) - .thenApplyAsync(calc->calc.inc(24)); + .applyAsync(calc->calc.inc(24)); // then - Assertions.assertThat(asyncCalculator1.orTimeout(10, TimeUnit.SECONDS).join().intValue()).isEqualTo(12); + Assertions.assertThat(asyncCalculator1.tryGet(10, TimeUnit.SECONDS).valueAsNonNullElseFail().intValue()).isEqualTo(12); Assertions.assertThat(calculator1.getTotal()).isEqualTo(12); - Assertions.assertThat(asyncCalculator2.orTimeout(10, TimeUnit.SECONDS).join().intValue()).isEqualTo(24); + Assertions.assertThat(asyncCalculator2.tryGet(10, TimeUnit.SECONDS).valueAsNonNullElseFail().intValue()).isEqualTo(24); Assertions.assertThat(calculator2.getTotal()).isEqualTo(24); }