You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by da...@apache.org on 2020/03/15 17:28:24 UTC
[isis] 31/31: ISIS-2278: adds some more AsyncControl flesh
This is an automated email from the ASF dual-hosted git repository.
danhaywood pushed a commit to branch ISIS-2278
in repository https://gitbox.apache.org/repos/asf/isis.git
commit ed4a39d4b85853caf94ffe831f705055490c8fb0
Author: danhaywood <da...@haywood-associates.co.uk>
AuthorDate: Sun Mar 15 17:26:11 2020 +0000
ISIS-2278: adds some more AsyncControl flesh
---
.../applib/services/wrapper/WrapperFactory.java | 145 ++++++----------
.../applib/services/wrapper/WrappingObject.java | 8 +-
.../services/wrapper/control/AsyncControl.java | 105 +++++++-----
.../wrapper/control/AsyncControlService.java | 7 +-
.../services/wrapper/control/ControlAbstract.java | 102 +++++++++++
.../services/wrapper/control/ExecutionMode.java | 15 +-
.../services/wrapper/control/ExecutionModes.java | 53 ------
.../wrapper/control/RuleCheckingPolicy.java | 8 -
.../{AsyncControlService.java => SyncControl.java} | 29 ++--
.../command/CommandExecutorServiceDefault.java | 3 +
.../wrapper/WrapperFactoryDefault.java | 187 +++++++++------------
.../AbstractCollectionInvocationHandler.java | 2 +-
.../DelegatingInvocationHandlerDefault.java | 9 +-
.../handlers/DomainObjectInvocationHandler.java | 90 ++++------
.../wrapper/handlers/ProxyContextHandler.java | 7 +-
.../wrapper/WrapperFactoryDefaultTest.java | 30 ++--
.../testdomain/auditing/AuditerServiceTest.java | 1 -
.../commandexecution/WrapperAsyncTest.java | 6 +-
.../publishing/PublisherServiceTest.java | 1 -
.../applib/fixturescripts/FixtureScript.java | 7 +-
20 files changed, 387 insertions(+), 428 deletions(-)
diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/wrapper/WrapperFactory.java b/api/applib/src/main/java/org/apache/isis/applib/services/wrapper/WrapperFactory.java
index 15a1179..db42c48 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/services/wrapper/WrapperFactory.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/services/wrapper/WrapperFactory.java
@@ -20,14 +20,10 @@
package org.apache.isis.applib.services.wrapper;
import java.util.List;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.ForkJoinPool;
import org.apache.isis.applib.services.factory.FactoryService;
import org.apache.isis.applib.services.wrapper.control.AsyncControl;
-import org.apache.isis.applib.services.wrapper.control.ExecutionMode;
-import org.apache.isis.applib.services.wrapper.control.ExecutionModes;
-import org.apache.isis.applib.services.wrapper.control.RuleCheckingPolicy;
+import org.apache.isis.applib.services.wrapper.control.SyncControl;
import org.apache.isis.applib.services.wrapper.events.InteractionEvent;
import org.apache.isis.applib.services.wrapper.listeners.InteractionListener;
import org.apache.isis.core.commons.collections.ImmutableEnumSet;
@@ -35,7 +31,14 @@ import org.apache.isis.core.commons.collections.ImmutableEnumSet;
/**
* Provides the ability to "wrap" of a domain object such that it can
* be interacted with while enforcing the hide/disable/validate rules implied by
- * the Isis programming model.
+ * the Apache Isis programming model.
+ *
+ * <p>
+ * The wrapper can alternatively also be used to execute the action
+ * asynchronously, through an {@link java.util.concurrent.ExecutorService}.
+ * Any business rules will be invoked synchronously beforehand, however.
+ * hand
+ * </p>
*
* <p>
* The 'wrap' is a runtime-code-generated proxy that wraps the underlying domain
@@ -43,14 +46,13 @@ import org.apache.isis.core.commons.collections.ImmutableEnumSet;
* <ul>
* <li>a <tt>get</tt> method for properties or collections</li>
* <li>a <tt>set</tt> method for properties</li>
- * <li>an <tt>addTo</tt> or <tt>removeFrom</tt> method for collections</li>
* <li>any action</li>
* </ul>
*
* <p>
* Calling any of the above methods may result in a (subclass of)
* {@link InteractionException} if the object disallows it. For example, if a
- * property is annotated with {@link Hidden} then a {@link HiddenException} will
+ * property is annotated as hidden then a {@link HiddenException} will
* be thrown. Similarly if an action has a <tt>validate</tt> method and the
* supplied arguments are invalid then a {@link InvalidException} will be
* thrown.
@@ -63,12 +65,8 @@ import org.apache.isis.core.commons.collections.ImmutableEnumSet;
* </ul>
*
* <p>
- * An exception will be thrown if any other methods are thrown.
- *
- * <p>
- * An implementation of this service (<tt>WrapperFactoryDefault</tt>) can be registered by including
- * <tt>o.a.i.core:isis-core-wrapper</tt> on the classpath; no further configuration is required.
- * </p>
+ * If the object has (see {@link #isWrapper(Object)} already been wrapped),
+ * then should just return the object back unchanged.
*/
// tag::refguide[]
// tag::refguide-async[]
@@ -80,8 +78,20 @@ public interface WrapperFactory {
// end::refguide[]
/**
- * Same as {@link #wrap(Object)}, except the actual execution occurs only if
- * the <tt>execute</tt> parameter indicates.
+ * 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:
+ * <ul>
+ * <li>check rules, execute action</li>
+ * <li>skip rules, execute action</li>
+ * <li>check rules, skip action</li>
+ * </ul>
+ * <p>
+ * The last logical option (skip rules, skip action) is valid but doesn't make sense, as it's basically a no-op.
+ * </p>
+ * </p>
*
* <p>
* Otherwise, will do all the validations (raise exceptions as required
@@ -89,46 +99,35 @@ public interface WrapperFactory {
*/
// tag::refguide[]
<T> T wrap(T domainObject, // <.>
- ImmutableEnumSet<ExecutionMode> modes);
+ SyncControl syncControl);
// end::refguide[]
/**
- * Provides the "wrapper" of the underlying domain object.
- *
- * <p>
- * If the object has (see {@link #isWrapper(Object)} already been wrapped),
- * then should just return the object back unchanged.
+ * 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.
*/
// tag::refguide[]
<T> T wrap(T domainObject); // <.>
// end::refguide[]
/**
- * Convenience method for {@link #wrap(Object, ImmutableEnumSet)} with {@link ExecutionModes#TRY},
- * to make this feature more discoverable.
- */
- // tag::refguide[]
- <T> T wrapTry(T domainObject); // <.>
-
- // end::refguide[]
- /**
- * Convenience method for {@link #wrap(Object, ImmutableEnumSet)} with {@link ExecutionModes#NO_EXECUTE},
- * to make this feature more discoverable.
- */
- // tag::refguide[]
- <T> T wrapNoExecute(T domainObject); // <.>
-
- // end::refguide[]
- /**
- * Convenience method for {@link #wrap(Object, ImmutableEnumSet)} with {@link ExecutionModes#SKIP_RULES},
- * to make this feature more discoverable.
+ * 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>
*/
// tag::refguide[]
- <T> T wrapSkipRules(T domainObject); // <.>
+ <T> T wrapMixin(Class<T> mixinClass, Object mixedIn, // <.>
+ SyncControl syncControl);
// end::refguide[]
/**
- * {@link #wrap(Object) wraps} a {@link FactoryService#mixin(Class, Object) mixin}.
+ * 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.
*/
// tag::refguide[]
<T> T wrapMixin(Class<T> mixinClass, Object mixedIn); // <.>
@@ -168,11 +167,11 @@ public interface WrapperFactory {
* Returns a proxy object for the provided {@code domainObject},
* through which can execute the action asynchronously.
*
- * @param <T>
+ * @param <T> - the type of the domain object
+ * @param <R> - the type of the return of the action
* @param domainObject
- * @param mode
+ * @param asyncControl
*
- * @param executorService
* @since 2.0
*/
// tag::refguide-async[]
@@ -187,63 +186,15 @@ public interface WrapperFactory {
* @param <T>
* @param mixinClass
* @param mixedIn
- * @param modes
+ * @param asyncControl
*
* @since 2.0
*/
// tag::refguide-async[]
- <T> T asyncMixin( // <.>
- Class<T> mixinClass, Object mixedIn,
- ImmutableEnumSet<ExecutionMode> modes,
- RuleCheckingPolicy ruleCheckingPolicy,
- ExecutorService executorService);
-
- // end::refguide-async[]
- /**
- * Returns a {@link AsyncControl} bound to the provided {@code mixinClass},
- * to prepare for type-safe asynchronous action execution.
- *
- * @param <T>
- * @param mixinClass
- * @param mixedIn
- * @param modes
- *
- * @since 2.0
- */
- // tag::refguide-async[]
- default <T> T asyncMixin( // <.>
- Class<T> mixinClass, Object mixedIn,
- ImmutableEnumSet<ExecutionMode> modes) {
- // end::refguide-async[]
-
- return asyncMixin(
- mixinClass, mixedIn, modes,
- RuleCheckingPolicy.ASYNC, ForkJoinPool.commonPool());
-
- // tag::refguide-async[]
- // ...
- }
-
- // end::refguide-async[]
- /**
- * Shortcut for {@link #asyncMixin(Class, Object, ImmutableEnumSet)} using execution mode
- * {@link ExecutionModes#EXECUTE}.
- * @param <T>
- * @param mixinClass
- * @param mixedIn
- *
- * @since 2.0
- */
- // tag::refguide-async[]
- default <T> T asyncMixin( // <.>
- Class<T> mixinClass, Object mixedIn) {
- // end::refguide-async[]
-
- return asyncMixin(mixinClass, mixedIn, ExecutionModes.EXECUTE);
+ <T,R> T asyncMixin( // <.>
+ Class<T> mixinClass, Object mixedIn,
+ AsyncControl<R> asyncControl);
- // tag::refguide-async[]
- // ...
- }
// end::refguide-async[]
diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/wrapper/WrappingObject.java b/api/applib/src/main/java/org/apache/isis/applib/services/wrapper/WrappingObject.java
index efcec9b..62369ab 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/services/wrapper/WrappingObject.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/services/wrapper/WrappingObject.java
@@ -66,9 +66,9 @@ public interface WrappingObject {
// end::refguide[]
/**
- * The {@link EnumSet< ExecutionMode > execution mode}
- * with which this wrapper was
- * {@link WrapperFactory#wrap(Object, ImmutableEnumSet) created}.
+ * The {@link EnumSet<ExecutionMode > execution modes} inferred from the
+ * {@link org.apache.isis.applib.services.wrapper.control.SyncControl} with which this wrapper was
+ * {@link WrapperFactory#wrap(Object, org.apache.isis.applib.services.wrapper.control.SyncControl) created}.
*
* <p>
* NOTE: domain classes may not have a method with this name. The <tt>__isis_</tt> prefix is
@@ -76,7 +76,7 @@ public interface WrappingObject {
* </p>
*/
// tag::refguide[]
- ImmutableEnumSet<ExecutionMode> __isis_executionMode();
+ ImmutableEnumSet<ExecutionMode> __isis_executionModes();
}
// end::refguide[]
diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/wrapper/control/AsyncControl.java b/api/applib/src/main/java/org/apache/isis/applib/services/wrapper/control/AsyncControl.java
index 4f5d893..8059930 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/services/wrapper/control/AsyncControl.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/services/wrapper/control/AsyncControl.java
@@ -19,11 +19,21 @@
package org.apache.isis.applib.services.wrapper.control;
import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.Future;
import java.util.function.Consumer;
+import javax.annotation.PostConstruct;
+import javax.inject.Inject;
+
+import org.apache.isis.applib.services.bookmark.Bookmark;
+import org.apache.isis.applib.services.user.RoleMemento;
+import org.apache.isis.applib.services.user.UserMemento;
+import org.apache.isis.applib.services.user.UserService;
import org.apache.isis.core.commons.collections.ImmutableEnumSet;
import org.apache.isis.schema.common.v2.OidDto;
@@ -38,43 +48,44 @@ import lombok.extern.log4j.Log4j2;
* @param <R> - return value.
*/
@Log4j2
-public class AsyncControl<R> {
-
- public static <X> AsyncControl<X> toReturn(final Class<X> clazz) {
- return new AsyncControl<>();
- }
+public class AsyncControl<R> extends ControlAbstract<AsyncControl<R>> {
- public static AsyncControl<Void> ignoreReturn() {
+ public static AsyncControl<Void> create() {
return new AsyncControl<>();
}
- public static AsyncControl<Void> voidReturn() {
+ public static <X> AsyncControl<X> create(final Class<X> clazz) {
return new AsyncControl<>();
}
- private AsyncControl() {
+ /**
+ * Alias for {@link #create(Class)}
+ */
+ public static <X> AsyncControl<X> toReturn(final Class<X> clazz) {
+ return create(clazz);
}
/**
- * Set by framework.
+ * Alias for {@link #create()}
*/
- @Setter(AccessLevel.PACKAGE)
- private Method method;
+ public static AsyncControl<Void> ignoreReturn() {
+ return create();
+ }
/**
- * Set by framework.
+ * Alias for {@link #create()}
*/
- @Setter(AccessLevel.PACKAGE)
- private OidDto oidDto;
-
+ public static AsyncControl<Void> voidReturn() {
+ return create();
+ }
- @Getter @NonNull
- private ImmutableEnumSet<ExecutionMode> executionModes = ExecutionModes.EXECUTE;
- public AsyncControl<R> with(ImmutableEnumSet<ExecutionMode> executionModes) {
- this.executionModes = executionModes;
- return this;
+ private AsyncControl() {
+ with((exception) -> {
+ log.error(logMessage(), exception);
+ });
}
+
@Getter @NonNull
private ExecutorService executorService = ForkJoinPool.commonPool();
public AsyncControl<R> with(ExecutorService executorService) {
@@ -82,41 +93,49 @@ public class AsyncControl<R> {
return this;
}
- @Getter @NonNull
- private RuleCheckingPolicy ruleCheckingPolicy = RuleCheckingPolicy.ASYNC;
- public AsyncControl<R> with(RuleCheckingPolicy ruleCheckingPolicy) {
- this.ruleCheckingPolicy = ruleCheckingPolicy;
+
+ /**
+ * Defaults to user initiating the action, if not overridden
+ */
+ @Getter
+ private String user;
+ public AsyncControl<R> withUser(final String user) {
+ this.user = user;
return this;
}
- @Getter @NonNull
- private Consumer<Exception> exceptionHandler = (exception) -> {
- log.error(logMessage(), exception);
- };
- public AsyncControl<R> with(Consumer<Exception> exceptionHandler) {
- this.exceptionHandler = exceptionHandler;
+ /**
+ * Defaults to roles of user initiating the action, if not overridden
+ */
+ @Getter
+ private List<String> roles;
+ public AsyncControl<R> withRoles(final List<String> roles) {
+ this.roles = Collections.unmodifiableList(roles);
return this;
}
+ public AsyncControl<R> withRoles(String... roles) {
+ return withRoles(Arrays.asList(roles));
+ }
+
+ /**
+ * Set by framework
+ */
+ @Getter @Setter(AccessLevel.PACKAGE)
+ private Future<R> future;
private String logMessage() {
StringBuilder buf = new StringBuilder("Failed to execute ");
- if(method != null) {
- buf.append(" ").append(method.getName()).append(" ");
- if(oidDto != null) {
+ if(getMethod() != null) {
+ buf.append(" ").append(getMethod().getName()).append(" ");
+ if(getBookmark() != null) {
buf.append(" on '")
- .append(oidDto.getType())
- .append(":")
- .append(oidDto.getId())
- .append("'");
+ .append(getBookmark().getObjectType())
+ .append(":")
+ .append(getBookmark().getIdentifier())
+ .append("'");
}
}
return buf.toString();
}
- /**
- * Set by framework
- */
- @Getter @Setter(AccessLevel.PACKAGE)
- private Future<R> future;
-
}
diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/wrapper/control/AsyncControlService.java b/api/applib/src/main/java/org/apache/isis/applib/services/wrapper/control/AsyncControlService.java
index 44621c5..853c94c 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/services/wrapper/control/AsyncControlService.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/services/wrapper/control/AsyncControlService.java
@@ -26,6 +26,7 @@ import java.util.function.Consumer;
import org.springframework.stereotype.Component;
+import org.apache.isis.applib.services.bookmark.Bookmark;
import org.apache.isis.core.commons.collections.ImmutableEnumSet;
import org.apache.isis.schema.common.v2.OidDto;
@@ -39,11 +40,11 @@ import lombok.extern.log4j.Log4j2;
* For framework internal use.
*/
@Component
-public class AsyncControlService<R> {
+public class AsyncControlService {
- public <R> AsyncControl<R> init(AsyncControl<R> asyncControl, Method method, OidDto oidDto) {
+ public <R> AsyncControl<R> init(AsyncControl<R> asyncControl, Method method, Bookmark bookmark) {
asyncControl.setMethod(method);
- asyncControl.setOidDto(oidDto);
+ asyncControl.setBookmark(bookmark);
return asyncControl;
}
diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/wrapper/control/ControlAbstract.java b/api/applib/src/main/java/org/apache/isis/applib/services/wrapper/control/ControlAbstract.java
new file mode 100644
index 0000000..0ed6a1e
--- /dev/null
+++ b/api/applib/src/main/java/org/apache/isis/applib/services/wrapper/control/ControlAbstract.java
@@ -0,0 +1,102 @@
+/*
+ * 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.isis.applib.services.wrapper.control;
+
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.concurrent.Future;
+import java.util.function.Consumer;
+
+import org.apache.isis.applib.services.bookmark.Bookmark;
+import org.apache.isis.applib.services.iactn.Interaction;
+import org.apache.isis.core.commons.collections.ImmutableEnumSet;
+
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.NonNull;
+import lombok.Setter;
+import lombok.extern.log4j.Log4j2;
+
+@Log4j2
+public class ControlAbstract<T extends ControlAbstract<T>> {
+
+ protected ControlAbstract() {
+ }
+
+ /**
+ * Set by framework.
+ */
+ @Getter(AccessLevel.PACKAGE)
+ @Setter(AccessLevel.PACKAGE)
+ private Method method;
+
+ /**
+ * Set by framework.
+ */
+ @Getter(AccessLevel.PACKAGE)
+ @Setter(AccessLevel.PACKAGE)
+ private Bookmark bookmark;
+
+ private boolean checkRules = true;
+ public T withCheckRules() {
+ checkRules = true;
+ return (T)this;
+ }
+ public T withSkipRules() {
+ checkRules = false;
+ return (T)this;
+ }
+
+ private boolean execute = true;
+ public T withExecute() {
+ execute = true;
+ return (T)this;
+ }
+ public T withNoExecute() {
+ execute = false;
+ return (T)this;
+ }
+
+ public ImmutableEnumSet<ExecutionMode> getExecutionModes() {
+ EnumSet<ExecutionMode> modes = EnumSet.noneOf(ExecutionMode.class);
+ if(!checkRules) {
+ modes.add(ExecutionMode.SKIP_RULE_VALIDATION);
+ }
+ if(!execute) {
+ modes.add(ExecutionMode.SKIP_EXECUTION);
+ }
+ return ImmutableEnumSet.from(modes);
+ }
+
+ /**
+ * Initialized in constructor.
+ */
+ @Getter @NonNull
+ private Consumer<Exception> exceptionHandler;
+ public T with(Consumer<Exception> exceptionHandler) {
+ this.exceptionHandler = exceptionHandler;
+ return (T)this;
+ }
+
+
+
+}
diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/wrapper/control/ExecutionMode.java b/api/applib/src/main/java/org/apache/isis/applib/services/wrapper/control/ExecutionMode.java
index 3226e41..694a1c3 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/services/wrapper/control/ExecutionMode.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/services/wrapper/control/ExecutionMode.java
@@ -1,6 +1,9 @@
package org.apache.isis.applib.services.wrapper.control;
+import java.util.function.Consumer;
+
import org.apache.isis.applib.services.wrapper.WrapperFactory;
+import org.apache.isis.applib.services.wrapper.control.AsyncControl;
import org.apache.isis.core.commons.collections.ImmutableEnumSet;
import lombok.AccessLevel;
@@ -10,7 +13,7 @@ import lombok.RequiredArgsConstructor;
* Whether interactions with the wrapper are actually passed onto the
* underlying domain object.
*
- * @see WrapperFactory#wrap(Object, ImmutableEnumSet)
+ * @see WrapperFactory#wrap(Object, org.apache.isis.applib.services.wrapper.control.SyncControl)
*/
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
// tag::refguide[]
@@ -23,15 +26,13 @@ public enum ExecutionMode {
SKIP_RULE_VALIDATION,
// end::refguide[]
/**
- * Skip execution.
+ * Skip actual execution.
+ *
+ * <p>
+ * This is not supported for {@link WrapperFactory#async(Object, AsyncControl)}; instead just invoke {@link WrapperFactory#wrap(Object, ImmutableEnumSet)}.
*/
// tag::refguide[]
SKIP_EXECUTION,
// end::refguide[]
- /**
- * Don't fail fast, swallow any exception during validation or execution.
- */
- // tag::refguide[]
- SWALLOW_EXCEPTIONS,
}
// end::refguide[]
diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/wrapper/control/ExecutionModes.java b/api/applib/src/main/java/org/apache/isis/applib/services/wrapper/control/ExecutionModes.java
deleted file mode 100644
index d910eed..0000000
--- a/api/applib/src/main/java/org/apache/isis/applib/services/wrapper/control/ExecutionModes.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package org.apache.isis.applib.services.wrapper.control;
-
-import org.apache.isis.core.commons.collections.ImmutableEnumSet;
-
-import static org.apache.isis.core.commons.collections.ImmutableEnumSet.noneOf;
-import static org.apache.isis.core.commons.collections.ImmutableEnumSet.of;
-
-import lombok.experimental.UtilityClass;
-
-// tag::refguide[]
-@UtilityClass
-public class ExecutionModes {
- // end::refguide[]
- /**
- * Validate all business rules and then execute. May throw exceptions in order to fail fast.
- */
- // tag::refguide[]
- public static final ImmutableEnumSet<ExecutionMode> EXECUTE =
- noneOf(ExecutionMode.class);
- // end::refguide[]
- /**
- * Skip all business rules and then execute, does throw an exception if execution fails.
- */
- // tag::refguide[]
- public static final ImmutableEnumSet<ExecutionMode> SKIP_RULES =
- of(ExecutionMode.SKIP_RULE_VALIDATION);
- // end::refguide[]
- /**
- * Validate all business rules but do not execute, throw an exception if validation
- * fails.
- */
- // tag::refguide[]
- public static final ImmutableEnumSet<ExecutionMode> NO_EXECUTE =
- of(ExecutionMode.SKIP_EXECUTION);
- // end::refguide[]
- /**
- * Validate all business rules and then execute, but don't throw an exception if validation
- * or execution fails.
- */
- // tag::refguide[]
- public static final ImmutableEnumSet<ExecutionMode> TRY =
- of(ExecutionMode.SWALLOW_EXCEPTIONS);
- // end::refguide[]
- /**
- * Skips all steps.
- * @since 2.0
- */
- // tag::refguide[]
- public static final ImmutableEnumSet<ExecutionMode> NOOP =
- of(ExecutionMode.SKIP_RULE_VALIDATION,
- ExecutionMode.SKIP_EXECUTION);
-}
-// end::refguide[]
diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/wrapper/control/RuleCheckingPolicy.java b/api/applib/src/main/java/org/apache/isis/applib/services/wrapper/control/RuleCheckingPolicy.java
deleted file mode 100644
index bc3dc06..0000000
--- a/api/applib/src/main/java/org/apache/isis/applib/services/wrapper/control/RuleCheckingPolicy.java
+++ /dev/null
@@ -1,8 +0,0 @@
-package org.apache.isis.applib.services.wrapper.control;
-
-// tag::refguide[]
-public enum RuleCheckingPolicy {
- IMMEDIATE, // <.>
- ASYNC // <.>
-}
-// end::refguide[]
diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/wrapper/control/AsyncControlService.java b/api/applib/src/main/java/org/apache/isis/applib/services/wrapper/control/SyncControl.java
similarity index 73%
copy from api/applib/src/main/java/org/apache/isis/applib/services/wrapper/control/AsyncControlService.java
copy to api/applib/src/main/java/org/apache/isis/applib/services/wrapper/control/SyncControl.java
index 44621c5..3bc403b 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/services/wrapper/control/AsyncControlService.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/services/wrapper/control/SyncControl.java
@@ -19,13 +19,14 @@
package org.apache.isis.applib.services.wrapper.control;
import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.Future;
import java.util.function.Consumer;
-import org.springframework.stereotype.Component;
-
import org.apache.isis.core.commons.collections.ImmutableEnumSet;
import org.apache.isis.schema.common.v2.OidDto;
@@ -33,23 +34,27 @@ import lombok.AccessLevel;
import lombok.Getter;
import lombok.NonNull;
import lombok.Setter;
+import lombok.SneakyThrows;
import lombok.extern.log4j.Log4j2;
/**
- * For framework internal use.
*/
-@Component
-public class AsyncControlService<R> {
+@Log4j2
+public class SyncControl extends ControlAbstract<SyncControl> {
- public <R> AsyncControl<R> init(AsyncControl<R> asyncControl, Method method, OidDto oidDto) {
- asyncControl.setMethod(method);
- asyncControl.setOidDto(oidDto);
- return asyncControl;
+ public static SyncControl create() {
+ return new SyncControl();
}
- public <R> AsyncControl<R> update(AsyncControl<R> asyncControl, Future<R> future) {
- asyncControl.setFuture(future);
- return asyncControl;
+ private SyncControl() {
+
+ with(new Consumer<Exception>() {
+ @SneakyThrows
+ @Override
+ public void accept(Exception e) {
+ throw e;
+ }
+ });
}
}
diff --git a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/command/CommandExecutorServiceDefault.java b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/command/CommandExecutorServiceDefault.java
index d729583..7103ccb 100644
--- a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/command/CommandExecutorServiceDefault.java
+++ b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/command/CommandExecutorServiceDefault.java
@@ -53,6 +53,8 @@ import org.apache.isis.core.metamodel.adapter.oid.Oid;
import org.apache.isis.core.metamodel.adapter.oid.RootOid;
import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy;
import org.apache.isis.core.metamodel.facets.actions.action.invocation.CommandUtil;
+import org.apache.isis.core.metamodel.interactions.InteractionUtils;
+import org.apache.isis.core.metamodel.interactions.VisibilityContext;
import org.apache.isis.core.metamodel.objectmanager.load.ObjectLoader;
import org.apache.isis.core.metamodel.spec.ManagedObject;
import org.apache.isis.core.metamodel.spec.ObjectSpecId;
@@ -175,6 +177,7 @@ public class CommandExecutorServiceDefault implements CommandExecutorService {
// we pass 'null' for the mixedInAdapter; if this action _is_ a mixin then
// it will switch the targetAdapter to be the mixedInAdapter transparently
val argAdapters = argAdaptersFor(actionDto);
+
val resultAdapter = objectAction.execute(
targetAdapter, null, argAdapters, InteractionInitiatedBy.FRAMEWORK);
diff --git a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/wrapper/WrapperFactoryDefault.java b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/wrapper/WrapperFactoryDefault.java
index 074686e..1d45c36 100644
--- a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/wrapper/WrapperFactoryDefault.java
+++ b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/wrapper/WrapperFactoryDefault.java
@@ -18,6 +18,7 @@
*/
package org.apache.isis.core.runtimeservices.wrapper;
+import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
@@ -40,18 +41,17 @@ import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Service;
import org.apache.isis.applib.annotation.OrderPrecedence;
+import org.apache.isis.applib.services.bookmark.Bookmark;
import org.apache.isis.applib.services.bookmark.BookmarkService;
-import org.apache.isis.applib.services.command.Command;
import org.apache.isis.applib.services.command.CommandContext;
import org.apache.isis.applib.services.command.CommandExecutorService;
import org.apache.isis.applib.services.factory.FactoryService;
import org.apache.isis.applib.services.wrapper.control.AsyncControl;
import org.apache.isis.applib.services.wrapper.control.AsyncControlService;
-import org.apache.isis.applib.services.wrapper.control.RuleCheckingPolicy;
import org.apache.isis.applib.services.wrapper.control.ExecutionMode;
import org.apache.isis.applib.services.wrapper.WrapperFactory;
import org.apache.isis.applib.services.wrapper.WrappingObject;
-import org.apache.isis.applib.services.wrapper.control.ExecutionModes;
+import org.apache.isis.applib.services.wrapper.control.SyncControl;
import org.apache.isis.applib.services.wrapper.events.ActionArgumentEvent;
import org.apache.isis.applib.services.wrapper.events.ActionInvocationEvent;
import org.apache.isis.applib.services.wrapper.events.ActionUsabilityEvent;
@@ -92,6 +92,7 @@ import org.apache.isis.core.runtimeservices.wrapper.dispatchers.InteractionEvent
import org.apache.isis.core.runtimeservices.wrapper.handlers.ProxyContextHandler;
import org.apache.isis.core.runtimeservices.wrapper.proxy.ProxyCreator;
import org.apache.isis.schema.cmd.v2.CommandDto;
+import org.apache.isis.schema.common.v2.OidDto;
import lombok.val;
import lombok.extern.log4j.Log4j2;
@@ -154,48 +155,40 @@ public class WrapperFactoryDefault implements WrapperFactory {
// -- WRAPPING
@Override
- public <T> T wrapMixin(Class<T> mixinClass, Object mixedIn) {
- return wrap(factoryService.mixin(mixinClass, mixedIn));
- }
-
- @Override
public <T> T wrap(T domainObject) {
- return wrap(domainObject, ExecutionModes.EXECUTE);
- }
-
- @Override
- public <T> T wrapTry(T domainObject) {
- return wrap(domainObject, ExecutionModes.TRY);
- }
-
- @Override
- public <T> T wrapNoExecute(T domainObject) {
- return wrap(domainObject, ExecutionModes.NO_EXECUTE);
- }
-
- @Override
- public <T> T wrapSkipRules(T domainObject) {
- return wrap(domainObject, ExecutionModes.SKIP_RULES);
+ return wrap(domainObject, SyncControl.create());
}
@Override
public <T> T wrap(
final T domainObject,
- final ImmutableEnumSet<ExecutionMode> modes) {
+ final SyncControl syncControl) {
+ final ImmutableEnumSet<ExecutionMode> modes = syncControl.getExecutionModes();
if (domainObject instanceof WrappingObject) {
val wrapperObject = (WrappingObject) domainObject;
- val executionMode = wrapperObject.__isis_executionMode();
+ val executionMode = wrapperObject.__isis_executionModes();
if(executionMode != modes) {
val underlyingDomainObject = wrapperObject.__isis_wrapped();
- return _Casts.uncheckedCast(createProxy(underlyingDomainObject, modes));
+ return _Casts.uncheckedCast(createProxy(underlyingDomainObject, syncControl));
}
return domainObject;
}
- return createProxy(domainObject, modes);
+ return createProxy(domainObject, syncControl);
}
- protected <T> T createProxy(T domainObject, ImmutableEnumSet<ExecutionMode> modes) {
- return proxyContextHandler.proxy(metaModelContext, domainObject, modes);
+ @Override
+ public <T> T wrapMixin(Class<T> mixinClass, Object mixedIn) {
+ return wrapMixin(mixinClass, mixedIn, SyncControl.create());
+ }
+
+ @Override
+ public <T> T wrapMixin(Class<T> mixinClass, Object mixedIn, SyncControl syncControl) {
+ T mixin = factoryService.mixin(mixinClass, mixedIn);
+ return wrap(mixin, syncControl);
+ }
+
+ protected <T> T createProxy(T domainObject, SyncControl syncControl) {
+ return proxyContextHandler.proxy(metaModelContext, domainObject, syncControl);
}
@Override
@@ -216,7 +209,7 @@ public class WrapperFactoryDefault implements WrapperFactory {
// -- ASYNC WRAPPING
@Inject
- AsyncControlService asyncControlService;
+ private AsyncControlService asyncControlService;
@Override
public <T,R> T async(
@@ -224,92 +217,82 @@ public class WrapperFactoryDefault implements WrapperFactory {
final AsyncControl<R> asyncControl) {
final ImmutableEnumSet<ExecutionMode> executionModes = asyncControl.getExecutionModes();
- final RuleCheckingPolicy ruleCheckingPolicy = asyncControl.getRuleCheckingPolicy();
final ExecutorService executorService = asyncControl.getExecutorService();
Class<T> domainClass = (Class<T>) domainObject.getClass();
ProxyFactory<T> factory = proxyFactoryService.factory(domainClass, WrappingObject.class);
- return factory.createInstance((Object proxy, Method method, Object[] args) -> {
-
- val executionModesAsync = determineExecutionModesAsync(executionModes, ruleCheckingPolicy);
- if (!shouldValidateAsync(executionModesAsync) && !shouldExecuteAsync(executionModesAsync)) {
- // nothing to be done.
- return null;
- }
+ return factory.createInstance(new InvocationHandler() {
+ @Override
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+
+ //
+ // executed in the same thread as caller..
+ //
+ final boolean inheritedFromObject = method.getDeclaringClass().equals(Object.class);
+ if (inheritedFromObject) {
+ return method.invoke(domainObject, args);
+ }
- //
- // executed in the same thread as caller..
- //
- final boolean inheritedFromObject = method.getDeclaringClass().equals(Object.class);
- if(inheritedFromObject) {
- return method.invoke(domainObject, args);
- }
+ val skipRules = executionModes.contains(ExecutionMode.SKIP_RULE_VALIDATION);
+ if(!skipRules) {
+ // normal wrapped object...
+ SyncControl syncControl = SyncControl.create().withNoExecute();
+ T syncProxy = WrapperFactoryDefault.this.createProxy(domainObject, syncControl);
+ method.invoke(syncProxy, args);
+ }
- val executionModesSync = determineExecutionModesSync(executionModes, ruleCheckingPolicy);
- if(shouldValidateSync(executionModesSync)) {
- // normal wrapped object...
- T syncProxy = createProxy(domainObject, executionModesSync);
- method.invoke(syncProxy, args);
- }
- //
- // submit async stuff
- //
- final ObjectSpecificationDefault targetObjSpec = (ObjectSpecificationDefault) specificationLoader.loadSpecification(method.getDeclaringClass());
- final ObjectMember member = targetObjSpec.getMember(method);
+ //
+ // submit async stuff
+ //
+ final ObjectSpecificationDefault targetObjSpec = (ObjectSpecificationDefault) specificationLoader.loadSpecification(method.getDeclaringClass());
+ final ObjectMember member = targetObjSpec.getMember(method);
- if(member == null) {
- return method.invoke(domainObject, args);
- }
+ if (member == null) {
+ return method.invoke(domainObject, args);
+ }
- if(!(member instanceof ObjectAction)) {
- throw new UnsupportedOperationException(
- "Only actions can be executed in the background "
- + "(method " + method.getName() + " represents a " + member.getFeatureType().name() + "')");
- }
+ if (!(member instanceof ObjectAction)) {
+ throw new UnsupportedOperationException(
+ "Only actions can be executed in the background "
+ + "(method " + method.getName() + " represents a " + member.getFeatureType().name() + "')");
+ }
- ObjectAction action = (ObjectAction) member;
+ ObjectAction action = (ObjectAction) member;
- val isisSession = isisSessionTracker.currentSession().orElseThrow(() -> new RuntimeException("No IsisSession is open"));
- val authSession = isisSession.getAuthenticationSession();
+ val isisSession = isisSessionTracker.currentSession().orElseThrow(() -> new RuntimeException("No IsisSession is open"));
+ val authSession = isisSession.getAuthenticationSession();
- final ManagedObject domainObjectAdapter = isisSession.getObjectManager().adapt(domainObject);
- final List<ManagedObject> argAdapters = Arrays.asList(adaptersFor(args));
+ final ManagedObject domainObjectAdapter = isisSession.getObjectManager().adapt(domainObject);
+ final List<ManagedObject> argAdapters = Arrays.asList(WrapperFactoryDefault.this.adaptersFor(args));
- final List<ManagedObject> targetList = Collections.singletonList(domainObjectAdapter);
- final CommandDto dto =
- commandDtoServiceInternal.asCommandDto(targetList, action, argAdapters);
- asyncControlService.init(asyncControl, method, dto.getTargets().getOid().get(0));
+ final List<ManagedObject> targetList = Collections.singletonList(domainObjectAdapter);
+ final CommandDto dto =
+ commandDtoServiceInternal.asCommandDto(targetList, action, argAdapters);
+ final OidDto oidDto = dto.getTargets().getOid().get(0);
- Future<?> submit = executorService.submit(() -> {
+ asyncControlService.init(asyncControl, method, Bookmark.from(oidDto));
- isisSessionFactory.runAuthenticated(authSession, () -> {
+ Future future = executorService.submit(new Runnable() {
+ @Override
+ public void run() {
- if (shouldValidateAsync(executionModesAsync)) {
- // TODO...
- }
- if (shouldExecuteAsync(executionModesAsync)) {
- commandExecutorService.executeCommand(dto);
+ isisSessionFactory.runAuthenticated(authSession, () -> {
+ commandExecutorService.executeCommand(dto);
+ });
}
-
});
- });
- asyncControlService.update(asyncControl, submit);
- return null;
-
+ asyncControlService.update(asyncControl, future);
+ return null;
+ }
}, false);
}
@Override
- public <T> T asyncMixin(
- Class<T> mixinClass, Object mixedIn,
- ImmutableEnumSet<ExecutionMode> modes,
- RuleCheckingPolicy ruleCheckingPolicy,
- ExecutorService executorService) {
-
- throw new RuntimeException("TODO");
+ public <T, R> T asyncMixin(Class<T> mixinClass, Object mixedIn, AsyncControl<R> asyncControl) {
+ throw new RuntimeException("TODO!!!");
}
private ManagedObject[] adaptersFor(final Object[] args) {
@@ -318,24 +301,6 @@ public class WrapperFactoryDefault implements WrapperFactory {
return CommandUtil.adaptersFor(args, objectManager);
}
- private static ImmutableEnumSet<ExecutionMode> determineExecutionModesSync(
- ImmutableEnumSet<ExecutionMode> executionModes,
- RuleCheckingPolicy ruleCheckingPolicy) {
- return executionModes.contains(ExecutionMode.SKIP_RULE_VALIDATION) ||
- ruleCheckingPolicy != RuleCheckingPolicy.IMMEDIATE
- ? ExecutionModes.NOOP
- : ExecutionModes.NO_EXECUTE;
- }
-
- private static ImmutableEnumSet<ExecutionMode> determineExecutionModesAsync(
- ImmutableEnumSet<ExecutionMode> executionModes,
- RuleCheckingPolicy ruleCheckingPolicy) {
- return executionModes.contains(ExecutionMode.SKIP_RULE_VALIDATION) ||
- RuleCheckingPolicy.IMMEDIATE == ruleCheckingPolicy
- ? join(executionModes, ExecutionMode.SKIP_RULE_VALIDATION)
- : executionModes;
- }
-
private static ImmutableEnumSet<ExecutionMode> join(
ImmutableEnumSet<ExecutionMode> executionModes,
ExecutionMode skipRuleValidation) {
diff --git a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/wrapper/handlers/AbstractCollectionInvocationHandler.java b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/wrapper/handlers/AbstractCollectionInvocationHandler.java
index 1f5ebbb..1eda159 100644
--- a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/wrapper/handlers/AbstractCollectionInvocationHandler.java
+++ b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/wrapper/handlers/AbstractCollectionInvocationHandler.java
@@ -44,7 +44,7 @@ abstract class AbstractCollectionInvocationHandler<T, C> extends DelegatingInvoc
super(otma.getMetaModelContext().getServiceRegistry(),
collectionOrMapToProxy,
- handler.getExecutionMode());
+ handler.getSyncControl());
this.collectionName = collectionName;
this.oneToManyAssociation = otma;
diff --git a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/wrapper/handlers/DelegatingInvocationHandlerDefault.java b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/wrapper/handlers/DelegatingInvocationHandlerDefault.java
index 272c10c..7ad4e7d 100644
--- a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/wrapper/handlers/DelegatingInvocationHandlerDefault.java
+++ b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/wrapper/handlers/DelegatingInvocationHandlerDefault.java
@@ -24,9 +24,8 @@ import java.lang.reflect.Method;
import org.apache.isis.applib.services.registry.ServiceRegistry;
import org.apache.isis.applib.services.wrapper.WrapperFactory;
-import org.apache.isis.applib.services.wrapper.control.ExecutionMode;
+import org.apache.isis.applib.services.wrapper.control.SyncControl;
import org.apache.isis.applib.services.wrapper.events.InteractionEvent;
-import org.apache.isis.core.commons.collections.ImmutableEnumSet;
import org.apache.isis.core.commons.internal._Constants;
import org.apache.isis.core.metamodel.objectmanager.ObjectManager;
import org.apache.isis.core.metamodel.objectmanager.load.ObjectLoader;
@@ -43,7 +42,7 @@ public class DelegatingInvocationHandlerDefault<T> implements DelegatingInvocati
// getter is API
@Getter(onMethod = @__(@Override)) private final T delegate;
@Getter protected final WrapperFactory wrapperFactory;
- @Getter private final ImmutableEnumSet<ExecutionMode> executionMode;
+ @Getter private final SyncControl syncControl;
protected final Method equalsMethod;
protected final Method hashCodeMethod;
@@ -56,7 +55,7 @@ public class DelegatingInvocationHandlerDefault<T> implements DelegatingInvocati
public DelegatingInvocationHandlerDefault(
final ServiceRegistry serviceRegistry,
final T delegate,
- final ImmutableEnumSet<ExecutionMode> executionMode) {
+ final SyncControl syncControl) {
if (delegate == null) {
throw new IllegalArgumentException("delegate must not be null");
@@ -64,7 +63,7 @@ public class DelegatingInvocationHandlerDefault<T> implements DelegatingInvocati
this.delegate = delegate;
this.wrapperFactory = serviceRegistry.lookupServiceElseFail(WrapperFactory.class);
this.objectManager = serviceRegistry.lookupServiceElseFail(ObjectManager.class);
- this.executionMode = executionMode;
+ this.syncControl = syncControl;
try {
equalsMethod = delegate.getClass().getMethod("equals", new Class[] { Object.class });
diff --git a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/wrapper/handlers/DomainObjectInvocationHandler.java b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/wrapper/handlers/DomainObjectInvocationHandler.java
index 9eb21b0..9523fe7 100644
--- a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/wrapper/handlers/DomainObjectInvocationHandler.java
+++ b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/wrapper/handlers/DomainObjectInvocationHandler.java
@@ -35,13 +35,13 @@ import org.apache.isis.applib.services.wrapper.InteractionException;
import org.apache.isis.applib.services.wrapper.InvalidException;
import org.apache.isis.applib.services.wrapper.control.ExecutionMode;
import org.apache.isis.applib.services.wrapper.WrappingObject;
+import org.apache.isis.applib.services.wrapper.control.SyncControl;
import org.apache.isis.applib.services.wrapper.events.CollectionAccessEvent;
import org.apache.isis.applib.services.wrapper.events.InteractionEvent;
import org.apache.isis.applib.services.wrapper.events.PropertyAccessEvent;
import org.apache.isis.applib.services.wrapper.events.UsabilityEvent;
import org.apache.isis.applib.services.wrapper.events.ValidityEvent;
import org.apache.isis.applib.services.wrapper.events.VisibilityEvent;
-import org.apache.isis.core.commons.collections.ImmutableEnumSet;
import org.apache.isis.core.commons.internal.base._NullSafe;
import org.apache.isis.core.commons.internal.collections._Arrays;
import org.apache.isis.core.commons.internal.collections._Lists;
@@ -73,7 +73,6 @@ import lombok.val;
public class DomainObjectInvocationHandler<T> extends DelegatingInvocationHandlerDefault<T> {
private final ProxyContextHandler proxy;
- private final ImmutableEnumSet<ExecutionMode> executionMode;
private final MetaModelContext mmContext;
/**
@@ -92,23 +91,20 @@ public class DomainObjectInvocationHandler<T> extends DelegatingInvocationHandle
protected Method __isis_wrappedMethod;
/**
- * The <tt>__isis_executionMode()</tt> method from {@link WrappingObject#__isis_executionMode()}.
+ * The <tt>__isis_executionModes()</tt> method from {@link WrappingObject#__isis_executionModes()}.
*/
- protected Method __isis_executionMode;
+ protected Method __isis_executionModes;
private EntityFacet entityFacet;
public DomainObjectInvocationHandler(
final MetaModelContext metaModelContext,
final T domainObject,
- final ImmutableEnumSet<ExecutionMode> mode,
- final ProxyContextHandler proxy) {
-
- super(metaModelContext.getServiceRegistry(), domainObject, mode);
+ final SyncControl syncControl, final ProxyContextHandler proxy) {
+ super(metaModelContext.getServiceRegistry(), domainObject, syncControl);
this.mmContext = metaModelContext;
this.proxy = proxy;
- this.executionMode = mode;
try {
titleMethod = domainObject.getClass().getMethod("title", new Class[]{});
@@ -118,16 +114,17 @@ public class DomainObjectInvocationHandler<T> extends DelegatingInvocationHandle
try {
__isis_saveMethod = WrappingObject.class.getMethod("__isis_save", new Class[]{});
__isis_wrappedMethod = WrappingObject.class.getMethod("__isis_wrapped", new Class[]{});
- __isis_executionMode = WrappingObject.class.getMethod("__isis_executionMode", new Class[]{});
+ __isis_executionModes = WrappingObject.class.getMethod("__isis_executionModes", new Class[]{});
- entityFacet = metaModelContext.getSpecification(domainObject.getClass())
- .getFacet(EntityFacet.class);
} catch (final NoSuchMethodException nsme) {
throw new IllegalStateException(
- "Could not locate reserved declared methods in the WrappingObject and WrappedObject interfaces",
+ "Could not locate reserved declared methods in the WrappingObject interfaces",
nsme);
}
+
+ entityFacet = metaModelContext.getSpecification(domainObject.getClass())
+ .getFacet(EntityFacet.class);
}
@Override
@@ -147,25 +144,24 @@ public class DomainObjectInvocationHandler<T> extends DelegatingInvocationHandle
final ManagedObject targetAdapter = getObjectManager().adapt(getDelegate());
- if (isTitleMethod(method)) {
+ if (method.equals(titleMethod)) {
return handleTitleMethod(targetAdapter);
}
final ObjectSpecification targetSpec = targetAdapter.getSpecification();
- final ObjectSpecification targetNoSpec = targetSpec;
// save method, through the proxy
- if (isSaveMethod(method)) {
- return handleSaveMethod(targetAdapter, targetNoSpec);
+ if (method.equals(__isis_saveMethod)) {
+ return handleSaveMethod(targetAdapter, targetSpec);
}
- if (isWrappedMethod(method)) {
+ if (method.equals(__isis_wrappedMethod)) {
return getDelegate();
}
- if (isExecutionModeMethod(method)) {
- return executionMode;
+ if (method.equals(__isis_executionModes)) {
+ return getSyncControl().getExecutionModes();
}
final ObjectMember objectMember = locateAndCheckMember(method);
@@ -772,22 +768,6 @@ public class DomainObjectInvocationHandler<T> extends DelegatingInvocationHandle
return member;
}
- protected boolean isTitleMethod(final Method method) {
- return method.equals(titleMethod);
- }
-
- protected boolean isSaveMethod(final Method method) {
- return method.equals(__isis_saveMethod);
- }
-
- protected boolean isWrappedMethod(final Method method) {
- return method.equals(__isis_wrappedMethod);
- }
-
- protected boolean isExecutionModeMethod(final Method method) {
- return method.equals(__isis_executionMode);
- }
-
// -- SPECIFICATION LOOKUP
private ObjectSpecificationDefault getJavaSpecificationOfOwningClass(final Method method) {
@@ -809,45 +789,39 @@ public class DomainObjectInvocationHandler<T> extends DelegatingInvocationHandle
// -- HELPER
private boolean shouldEnforceRules() {
- return !getExecutionMode().contains(ExecutionMode.SKIP_RULE_VALIDATION);
+ return !getSyncControl().getExecutionModes().contains(ExecutionMode.SKIP_RULE_VALIDATION);
}
private boolean shouldExecute() {
- return !getExecutionMode().contains(ExecutionMode.SKIP_EXECUTION);
- }
-
- private boolean shouldFailFast() {
- return !getExecutionMode().contains(ExecutionMode.SWALLOW_EXCEPTIONS);
+ return !getSyncControl().getExecutionModes().contains(ExecutionMode.SKIP_EXECUTION);
}
+
private void runValidationTask(Runnable task) {
if(!shouldEnforceRules()) {
return;
}
- if(shouldFailFast()) {
+ try {
task.run();
- } else {
- try {
- task.run();
- } catch(Exception ex) {
- // swallow
- }
+ } catch(Exception ex) {
+ handleException(ex);
}
}
-
+
+ private void handleException(Exception ex) {
+ getSyncControl().getExceptionHandler().accept(ex);
+ }
+
private <X> X runExecutionTask(Supplier<X> task) {
if(!shouldExecute()) {
return null;
}
- if(shouldFailFast()) {
+ try {
return task.get();
- } else {
- try {
- return task.get();
- } catch(Exception ex) {
- // swallow
- return null;
- }
+ } catch(Exception ex) {
+ handleException(ex);
+ // in case the exception handler doesn't throw
+ return null;
}
}
diff --git a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/wrapper/handlers/ProxyContextHandler.java b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/wrapper/handlers/ProxyContextHandler.java
index fb24725..f11ab15 100644
--- a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/wrapper/handlers/ProxyContextHandler.java
+++ b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/wrapper/handlers/ProxyContextHandler.java
@@ -22,8 +22,7 @@ package org.apache.isis.core.runtimeservices.wrapper.handlers;
import java.util.Collection;
import java.util.Map;
-import org.apache.isis.applib.services.wrapper.control.ExecutionMode;
-import org.apache.isis.core.commons.collections.ImmutableEnumSet;
+import org.apache.isis.applib.services.wrapper.control.SyncControl;
import org.apache.isis.core.metamodel.context.MetaModelContext;
import org.apache.isis.core.metamodel.spec.feature.OneToManyAssociation;
import org.apache.isis.core.runtimeservices.wrapper.proxy.ProxyCreator;
@@ -37,12 +36,12 @@ public class ProxyContextHandler {
@NonNull private final ProxyCreator proxyCreator;
- public <T> T proxy(MetaModelContext metaModelContext, T domainObject, ImmutableEnumSet<ExecutionMode> mode) {
+ public <T> T proxy(MetaModelContext metaModelContext, T domainObject, SyncControl syncControl) {
val invocationHandler = new DomainObjectInvocationHandler<T>(
metaModelContext,
domainObject,
- mode,
+ syncControl,
this);
return proxyCreator.instantiateProxy(invocationHandler);
diff --git a/core/runtimeservices/src/test/java/org/apache/isis/core/runtimeservices/wrapper/WrapperFactoryDefaultTest.java b/core/runtimeservices/src/test/java/org/apache/isis/core/runtimeservices/wrapper/WrapperFactoryDefaultTest.java
index bd5dd15..408f6c3 100644
--- a/core/runtimeservices/src/test/java/org/apache/isis/core/runtimeservices/wrapper/WrapperFactoryDefaultTest.java
+++ b/core/runtimeservices/src/test/java/org/apache/isis/core/runtimeservices/wrapper/WrapperFactoryDefaultTest.java
@@ -18,6 +18,8 @@
*/
package org.apache.isis.core.runtimeservices.wrapper;
+import org.assertj.core.api.Assertions;
+import org.hamcrest.CoreMatchers;
import org.jmock.auto.Mock;
import org.junit.Before;
import org.junit.Rule;
@@ -30,7 +32,7 @@ import static org.hamcrest.MatcherAssert.assertThat;
import org.apache.isis.applib.services.wrapper.control.ExecutionMode;
import org.apache.isis.applib.services.wrapper.WrappingObject;
-import org.apache.isis.applib.services.wrapper.control.ExecutionModes;
+import org.apache.isis.applib.services.wrapper.control.SyncControl;
import org.apache.isis.core.commons.collections.ImmutableEnumSet;
import org.apache.isis.core.commons.internal.plugins.codegen.ProxyFactoryService;
import org.apache.isis.core.internaltestsupport.jmocking.JUnitRuleMockery2;
@@ -43,10 +45,10 @@ public class WrapperFactoryDefaultTest {
}
@RequiredArgsConstructor
- private static class WrappedDomainObject extends DomainObject implements WrappingObject {
+ private static class WrappingDomainObject extends DomainObject implements WrappingObject {
private final DomainObject wrappedObject;
- private final ImmutableEnumSet<ExecutionMode> mode;
+ private final ImmutableEnumSet<ExecutionMode> modes;
@Override
public void __isis_save() {
@@ -58,8 +60,8 @@ public class WrapperFactoryDefaultTest {
}
@Override
- public ImmutableEnumSet<ExecutionMode> __isis_executionMode() {
- return mode;
+ public ImmutableEnumSet<ExecutionMode> __isis_executionModes() {
+ return modes;
}
}
@@ -70,7 +72,7 @@ public class WrapperFactoryDefaultTest {
private WrapperFactoryDefault wrapperFactory;
private DomainObject createProxyCalledWithDomainObject;
- private ImmutableEnumSet<ExecutionMode> createProxyCalledWithMode;
+ private SyncControl createProxyCalledWithSyncControl;
@Before
public void setUp() throws Exception {
@@ -83,8 +85,8 @@ public class WrapperFactoryDefaultTest {
}
@Override
- protected <T> T createProxy(T domainObject, ImmutableEnumSet<ExecutionMode> modes) {
- WrapperFactoryDefaultTest.this.createProxyCalledWithMode = modes;
+ protected <T> T createProxy(T domainObject, SyncControl syncControl) {
+ WrapperFactoryDefaultTest.this.createProxyCalledWithSyncControl = syncControl;
WrapperFactoryDefaultTest.this.createProxyCalledWithDomainObject = (DomainObject) domainObject;
return domainObject;
}
@@ -99,7 +101,7 @@ public class WrapperFactoryDefaultTest {
wrapperFactory.wrap(domainObject);
assertThat(createProxyCalledWithDomainObject, is(domainObject));
- assertThat(createProxyCalledWithMode, is(ExecutionModes.EXECUTE));
+ assertThat(createProxyCalledWithSyncControl, is(not(nullValue())));
}
@@ -107,10 +109,10 @@ public class WrapperFactoryDefaultTest {
public void wrap_ofWrapped_sameMode_returnsUnchanged() throws Exception {
// given
final DomainObject wrappedObject = new DomainObject();
- final DomainObject domainObject = new WrappedDomainObject(wrappedObject, ExecutionModes.EXECUTE);
+ final DomainObject domainObject = new WrappingDomainObject(wrappedObject, ImmutableEnumSet.noneOf(ExecutionMode.class));
// when
- final DomainObject wrappingObject = wrapperFactory.wrap(domainObject, ExecutionModes.EXECUTE);
+ final DomainObject wrappingObject = wrapperFactory.wrap(domainObject);
// then
assertThat(wrappingObject, is(domainObject));
@@ -121,15 +123,15 @@ public class WrapperFactoryDefaultTest {
public void wrap_ofWrapped_differentMode_delegates_to_createProxy() throws Exception {
// given
final DomainObject wrappedObject = new DomainObject();
- final DomainObject domainObject = new WrappedDomainObject(wrappedObject, ExecutionModes.EXECUTE);
+ final DomainObject domainObject = new WrappingDomainObject(wrappedObject, ImmutableEnumSet.noneOf(ExecutionMode.class));
// when
- final DomainObject wrappingObject = wrapperFactory.wrap(domainObject, ExecutionModes.SKIP_RULES);
+ final DomainObject wrappingObject = wrapperFactory.wrap(domainObject, SyncControl.create().withSkipRules());
// then
assertThat(wrappingObject, is(not(domainObject)));
assertThat(createProxyCalledWithDomainObject, is(wrappedObject));
- assertThat(createProxyCalledWithMode, is(ExecutionModes.SKIP_RULES));
+ Assertions.assertThat(createProxyCalledWithSyncControl.getExecutionModes()).contains(ExecutionMode.SKIP_RULE_VALIDATION);
}
}
\ No newline at end of file
diff --git a/examples/smoketests/src/test/java/org/apache/isis/testdomain/auditing/AuditerServiceTest.java b/examples/smoketests/src/test/java/org/apache/isis/testdomain/auditing/AuditerServiceTest.java
index 57505b3..4feadca 100644
--- a/examples/smoketests/src/test/java/org/apache/isis/testdomain/auditing/AuditerServiceTest.java
+++ b/examples/smoketests/src/test/java/org/apache/isis/testdomain/auditing/AuditerServiceTest.java
@@ -42,7 +42,6 @@ import org.apache.isis.applib.services.repository.RepositoryService;
import org.apache.isis.applib.services.wrapper.DisabledException;
import org.apache.isis.applib.services.wrapper.WrapperFactory;
import org.apache.isis.applib.services.wrapper.control.AsyncControl;
-import org.apache.isis.applib.services.wrapper.control.ExecutionModes;
import org.apache.isis.core.config.presets.IsisPresets;
import org.apache.isis.testdomain.Incubating;
import org.apache.isis.testdomain.Smoketest;
diff --git a/examples/smoketests/src/test/java/org/apache/isis/testdomain/commandexecution/WrapperAsyncTest.java b/examples/smoketests/src/test/java/org/apache/isis/testdomain/commandexecution/WrapperAsyncTest.java
index 1fd01a8..29e32b5 100644
--- a/examples/smoketests/src/test/java/org/apache/isis/testdomain/commandexecution/WrapperAsyncTest.java
+++ b/examples/smoketests/src/test/java/org/apache/isis/testdomain/commandexecution/WrapperAsyncTest.java
@@ -44,9 +44,7 @@ import org.apache.isis.applib.events.domain.AbstractDomainEvent.Phase;
import org.apache.isis.applib.services.factory.FactoryService;
import org.apache.isis.applib.services.repository.RepositoryService;
import org.apache.isis.applib.services.wrapper.control.AsyncControl;
-import org.apache.isis.applib.services.wrapper.control.RuleCheckingPolicy;
import org.apache.isis.applib.services.wrapper.WrapperFactory;
-import org.apache.isis.applib.services.wrapper.control.ExecutionModes;
import org.apache.isis.core.config.presets.IsisPresets;
import org.apache.isis.testdomain.Incubating;
import org.apache.isis.testdomain.Smoketest;
@@ -122,7 +120,9 @@ class WrapperAsyncTest {
actionDomainEventListener.prepareLatch();
// use of custom executor (optional)
- val control = AsyncControl.toReturn(JdoProduct.class).with(ExecutionModes.EXECUTE).with(RuleCheckingPolicy.ASYNC).with(Executors.newCachedThreadPool());
+ val control = AsyncControl.toReturn(JdoProduct.class)
+ .with(ExecutionModes.EXECUTE)
+ .with(Executors.newCachedThreadPool());
wrapper.async(inventoryManager, control)
.updateProductPrice(product, 123d);
diff --git a/examples/smoketests/src/test/java/org/apache/isis/testdomain/publishing/PublisherServiceTest.java b/examples/smoketests/src/test/java/org/apache/isis/testdomain/publishing/PublisherServiceTest.java
index 7a62d58..20e72dc 100644
--- a/examples/smoketests/src/test/java/org/apache/isis/testdomain/publishing/PublisherServiceTest.java
+++ b/examples/smoketests/src/test/java/org/apache/isis/testdomain/publishing/PublisherServiceTest.java
@@ -44,7 +44,6 @@ import org.apache.isis.applib.services.repository.RepositoryService;
import org.apache.isis.applib.services.wrapper.DisabledException;
import org.apache.isis.applib.services.wrapper.WrapperFactory;
import org.apache.isis.applib.services.wrapper.control.AsyncControl;
-import org.apache.isis.applib.services.wrapper.control.ExecutionModes;
import org.apache.isis.core.config.presets.IsisPresets;
import org.apache.isis.testdomain.Incubating;
import org.apache.isis.testdomain.Smoketest;
diff --git a/testing/fixtures/applib/src/main/java/org/apache/isis/testing/fixtures/applib/fixturescripts/FixtureScript.java b/testing/fixtures/applib/src/main/java/org/apache/isis/testing/fixtures/applib/fixturescripts/FixtureScript.java
index 7c5a69f..d499471 100644
--- a/testing/fixtures/applib/src/main/java/org/apache/isis/testing/fixtures/applib/fixturescripts/FixtureScript.java
+++ b/testing/fixtures/applib/src/main/java/org/apache/isis/testing/fixtures/applib/fixturescripts/FixtureScript.java
@@ -44,6 +44,7 @@ import org.apache.isis.applib.services.repository.RepositoryService;
import org.apache.isis.applib.services.user.UserService;
import org.apache.isis.applib.services.wrapper.control.ExecutionMode;
import org.apache.isis.applib.services.wrapper.WrapperFactory;
+import org.apache.isis.applib.services.wrapper.control.SyncControl;
import org.apache.isis.applib.services.xactn.TransactionService;
import org.apache.isis.core.commons.collections.ImmutableEnumSet;
import org.apache.isis.core.commons.internal.base._Casts;
@@ -779,10 +780,10 @@ public abstract class FixtureScript {
}
/**
- * Convenience method, simply delegates to {@link WrapperFactory#wrap(Object, EnumSet)}.
+ * Convenience method, simply delegates to {@link WrapperFactory#wrap(Object, SyncControl)}.
*/
- protected <T> T wrap(final T domainObject, final ImmutableEnumSet<ExecutionMode> executionMode) {
- return wrapperFactory.wrap(domainObject, executionMode);
+ protected <T> T wrap(final T domainObject, final SyncControl syncControl) {
+ return wrapperFactory.wrap(domainObject, syncControl);
}
/**