You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by ah...@apache.org on 2020/12/03 16:51:55 UTC

[isis] branch master updated: ISIS-2464: overhaul of the SudoService

This is an automated email from the ASF dual-hosted git repository.

ahuber pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/isis.git


The following commit(s) were added to refs/heads/master by this push:
     new 188750c  ISIS-2464: overhaul of the SudoService
188750c is described below

commit 188750c922d30e639fad1c137eaf7a204622fab9
Author: Andi Huber <ah...@apache.org>
AuthorDate: Thu Dec 3 17:51:39 2020 +0100

    ISIS-2464: overhaul of the SudoService
    
    also re-integrate properly with the framework (on top of Interaction
    handling)
---
 .../isis/applib/services/sudo/SudoService.java     | 72 ++++++--------------
 .../command/CommandExecutorServiceDefault.java     |  8 +--
 .../runtimeservices/sudo/SudoServiceDefault.java   | 79 ++++++++++------------
 3 files changed, 59 insertions(+), 100 deletions(-)

diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/sudo/SudoService.java b/api/applib/src/main/java/org/apache/isis/applib/services/sudo/SudoService.java
index 621828b..10337da 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/services/sudo/SudoService.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/services/sudo/SudoService.java
@@ -16,14 +16,15 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-
 package org.apache.isis.applib.services.sudo;
 
-import java.util.List;
-import java.util.function.Supplier;
+import java.util.concurrent.Callable;
 
+import org.apache.isis.applib.services.user.UserMemento;
 import org.apache.isis.applib.services.user.UserService;
 
+import lombok.NonNull;
+
 /**
  * Intended only for use by fixture scripts and integration tests, allows a block of code to execute
  * while the {@link UserService}'s {@link UserService#getUser() getUser()} method returns the specified user/role
@@ -43,69 +44,38 @@ public interface SudoService {
     // end::refguide[]
     /**
      * Executes the supplied block, with the {@link UserService} returning the specified user.
-     *
-     * <p>
-     *    The roles of this user will be the same as the currently logged-in user.
-     * </p>
+     * @since 2.0
      */
     // tag::refguide[]
-    void sudo(                                              // <.>
-            String username,
-            final Runnable runnable);
+    <T> T call(                                             // <.>
+            @NonNull UserMemento user,
+            @NonNull Callable<T> supplier);
 
     // end::refguide[]
     /**
      * Executes the supplied block, with the {@link UserService} returning the specified user.
-     *
-     * <p>
-     *    The roles of this user will be the same as the currently logged-in user.
-     * </p>
-     */
-    // tag::refguide[]
-    <T> T sudo(                                             // <.>
-            String username,
-            final Supplier<T> supplier);
-
-    // end::refguide[]
-    /**
-     * Executes the supplied block, with the {@link UserService} returning the specified user with the specified roles.
-     */
-    // tag::refguide[]
-    void sudo(                                              // <.>
-            String username, List<String> roles,
-            final Runnable runnable);
-
-    // end::refguide[]
-    /**
-     * Executes the supplied block, with the {@link UserService} returning the specified user with the specified roles.
+     * @since 2.0
      */
     // tag::refguide[]
-    <T> T sudo(                                             // <.>
-            String username, List<String> roles,
-            final Supplier<T> supplier);
+    default void run(                                        // <.>
+            final @NonNull UserMemento user,
+            final @NonNull Runnable runnable) {
+        call(user, ()->{runnable.run(); return null;});
+    }
 
     // end::refguide[]
-
-    // tag::refguide-1[]
+    
+    
     /**
      * Allows the {@link SudoService} to notify other services/components that the effective user has been changed.
+     * @since 2.0
      */
-    interface Spi {
+    // tag::refguide-1[]
+    interface Listener {
 
-        // end::refguide-1[]
-        /**
-         * Any implementation of the {@link SudoService} should call this method on all implementations of the
-         * {@link Spi} service whenever {@link SudoService#sudo(String, List, Supplier)} (or its overloads)
-         * is called.
-         *
-         * <p>
-         *     Modelled after Shiro security's <a href="https://shiro.apache.org/static/1.2.6/apidocs/org/apache/shiro/subject/Subject.html#runAs-org.apache.shiro.subject.PrincipalCollection-">runAs</a> support.
-         * </p>
-         */
-        // tag::refguide-1[]
-        void runAs(String username, List<String> roles);    // <.>
+        void beforeCall(@NonNull UserMemento user);          // <.>
 
-        void releaseRunAs();                                // <.>
+        void afterCall();                                    // <.>
     }
     // end::refguide-1[]
 
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 7ff753b..e298f39 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
@@ -44,6 +44,7 @@ import org.apache.isis.applib.services.command.CommandOutcomeHandler;
 import org.apache.isis.applib.services.iactn.Interaction;
 import org.apache.isis.applib.services.iactn.InteractionContext;
 import org.apache.isis.applib.services.sudo.SudoService;
+import org.apache.isis.applib.services.user.UserMemento;
 import org.apache.isis.applib.services.xactn.TransactionService;
 import org.apache.isis.applib.util.schema.CommandDtoUtils;
 import org.apache.isis.applib.util.schema.CommonDtoUtils;
@@ -149,8 +150,8 @@ public class CommandExecutorServiceDefault implements CommandExecutorService {
         try {
             val result = transactionService.executeWithinTransaction(
                 () -> sudoPolicy == SudoPolicy.SWITCH
-                    ? sudoService.sudo(
-                        dto.getUser(),
+                    ? sudoService.call(
+                        UserMemento.ofName(dto.getUser()),
                         () -> doExecuteCommand(dto))
                     : doExecuteCommand(dto));
 
@@ -211,8 +212,7 @@ public class CommandExecutorServiceDefault implements CommandExecutorService {
                 } else {
                     head = InteractionHead.simple(targetAdapter);
                 }
-                val resultAdapter = objectAction.execute(head
-                        , argAdapters, InteractionInitiatedBy.FRAMEWORK);
+                val resultAdapter = objectAction.execute(head, argAdapters, InteractionInitiatedBy.FRAMEWORK);
 
                 // flush any Isis PersistenceCommands pending
                 // (else might get transient objects for the return value)
diff --git a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/sudo/SudoServiceDefault.java b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/sudo/SudoServiceDefault.java
index 930d16c..c26b4a0 100644
--- a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/sudo/SudoServiceDefault.java
+++ b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/sudo/SudoServiceDefault.java
@@ -19,8 +19,7 @@
 
 package org.apache.isis.core.runtimeservices.sudo;
 
-import java.util.List;
-import java.util.function.Supplier;
+import java.util.concurrent.Callable;
 
 import javax.inject.Inject;
 import javax.inject.Named;
@@ -31,73 +30,63 @@ import org.springframework.core.annotation.Order;
 import org.springframework.stereotype.Service;
 
 import org.apache.isis.applib.annotation.OrderPrecedence;
+import org.apache.isis.applib.services.registry.ServiceRegistry;
 import org.apache.isis.applib.services.sudo.SudoService;
+import org.apache.isis.applib.services.user.UserMemento;
+import org.apache.isis.commons.collections.Can;
+import org.apache.isis.core.runtime.iactn.IsisInteractionFactory;
+import org.apache.isis.core.security.authentication.standard.SimpleSession;
+
+import lombok.NonNull;
+import lombok.RequiredArgsConstructor;
+import lombok.val;
+
+import jakarta.annotation.PostConstruct;
 
 @Service
 @Named("isisRuntimeServices.SudoServiceDefault")
 @Order(OrderPrecedence.MIDPOINT)
 @Primary
 @Qualifier("Default")
+@RequiredArgsConstructor(onConstructor_ = {@Inject})
 public class SudoServiceDefault implements SudoService {
 
-    @Inject private List<SudoService.Spi> spiServices;
-    
-    @Override
-    public void sudo(final String username, final Runnable runnable) {
-        try {
-            runAs(username, null);
-            runnable.run();
-        } finally {
-            releaseRunAs();
-        }
-    }
+    private final IsisInteractionFactory interactionFactory;
 
-    @Override
-    public <T> T sudo(final String username, final Supplier<T> supplier) {
-        try {
-            runAs(username, null);
-            return supplier.get();
-        } finally {
-            releaseRunAs();
-        }
-    }
+    private Can<SudoService.Listener> sudoListeners = Can.empty();
 
     @Override
-    public void sudo(final String username, final List<String> roles, final Runnable runnable) {
+    public <T> T call(final @NonNull UserMemento user, final @NonNull Callable<T> callable) {
+
         try {
-            runAs(username, roles);
-            runnable.run();
+            beforeCall(user);
+            return interactionFactory.callAuthenticated(SimpleSession.validOf(user), callable);
         } finally {
-            releaseRunAs();
+            afterCall();
         }
     }
 
-    @Override
-    public <T> T sudo(final String username, final List<String> roles, final Supplier<T> supplier) {
-        try {
-            runAs(username, roles);
-            return supplier.get();
-        } finally {
-            releaseRunAs();
-        }
+    @PostConstruct @Inject
+    public void init(final ServiceRegistry serviceRegistry) {
+        this.sudoListeners = serviceRegistry.select(SudoService.Listener.class);
     }
 
-    private void runAs(final String username, final List<String> roles) {
-        if(spiServices != null) {
-            for (SudoService.Spi spiService : spiServices) {
-                spiService.runAs(username, roles);
-            }
+    // -- HELPER
+
+    private void beforeCall(final @NonNull UserMemento user) {
+        for (val sudoListener : sudoListeners) {
+            sudoListener.beforeCall(user);
         }
     }
 
-    private void releaseRunAs() {
-        if(spiServices != null) {
-            for (SudoService.Spi spiService : spiServices) {
-                spiService.releaseRunAs();
-            }
+    private void afterCall() {
+        for (val sudoListener : sudoListeners) {
+            sudoListener.afterCall();
         }
     }
 
-    
+
+
+
 
 }