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 2018/06/27 08:08:04 UTC

[isis] 03/04: ISIS-1960: Action background execution built-in default:

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

commit 9332cdd9a6a536cbe769770808d4e3ca16afbd74
Author: Andi Huber <ah...@apache.org>
AuthorDate: Wed Jun 27 09:31:33 2018 +0200

    ISIS-1960: Action background execution built-in default:
    
    wait for current thread's transaction to complete before executing
    background tasks
    
    Task-Url: https://issues.apache.org/jira/browse/ISIS-1960
---
 .../applib/services/xactn/TransactionService.java  | 10 ++-
 .../PersistenceSessionServiceInternal.java         | 11 ++--
 .../PersistenceSessionServiceInternalNoop.java     |  8 +++
 .../services/xactn/TransactionServiceDefault.java  |  9 ++-
 .../background/BackgroundCommandExecution.java     | 26 ++------
 .../background/ForkingInvocationHandler.java       | 12 ++++
 .../PersistenceSessionServiceInternalDefault.java  |  7 +++
 .../system/persistence/PersistenceSessionBase.java |  2 +-
 .../system/transaction/IsisTransaction.java        | 73 ++++++++++------------
 .../system/transaction/IsisTransactionManager.java | 14 ++---
 10 files changed, 94 insertions(+), 78 deletions(-)

diff --git a/core/applib/src/main/java/org/apache/isis/applib/services/xactn/TransactionService.java b/core/applib/src/main/java/org/apache/isis/applib/services/xactn/TransactionService.java
index 124dba5..d6de35b 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/services/xactn/TransactionService.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/services/xactn/TransactionService.java
@@ -19,6 +19,8 @@
 
 package org.apache.isis.applib.services.xactn;
 
+import java.util.concurrent.CountDownLatch;
+
 import org.apache.isis.applib.annotation.Programmatic;
 import org.apache.isis.applib.services.command.Command;
 import org.apache.isis.applib.services.command.CommandContext;
@@ -59,7 +61,13 @@ public interface TransactionService {
     @Programmatic
     TransactionState getTransactionState();
 
-
+    /**
+     * Return a latch, that allows threads to wait on the current transaction to complete.
+     */
+    @Programmatic
+    CountDownLatch currentTransactionLatch(); 
+    
+    
     /**
      * Intended only for use by fixture scripts and integration tests.
      *
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/persistsession/PersistenceSessionServiceInternal.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/persistsession/PersistenceSessionServiceInternal.java
index daa1b69..572af70 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/persistsession/PersistenceSessionServiceInternal.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/persistsession/PersistenceSessionServiceInternal.java
@@ -17,13 +17,14 @@
 package org.apache.isis.core.metamodel.services.persistsession;
 
 import java.util.List;
+import java.util.concurrent.CountDownLatch;
 
 import org.apache.isis.applib.annotation.Programmatic;
 import org.apache.isis.applib.query.Query;
 import org.apache.isis.applib.services.bookmark.Bookmark;
 import org.apache.isis.applib.services.bookmark.BookmarkService;
-import org.apache.isis.applib.services.xactn.Transaction;
 import org.apache.isis.applib.services.command.Command;
+import org.apache.isis.applib.services.xactn.Transaction;
 import org.apache.isis.applib.services.xactn.TransactionState;
 import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
 import org.apache.isis.core.metamodel.adapter.mgr.AdapterManager;
@@ -120,13 +121,13 @@ public interface PersistenceSessionServiceInternal extends AdapterManager {
 
     @Programmatic
     Transaction currentTransaction();
-
+    
+    @Programmatic
+	CountDownLatch currentTransactionLatch();
 
     @Programmatic
     TransactionState getTransactionState();
 
-    
-
     // -- makePersistent, remove
 
     /**
@@ -174,6 +175,4 @@ public interface PersistenceSessionServiceInternal extends AdapterManager {
     void executeWithinTransaction(TransactionalClosure transactionalClosure);
 
 
-    
-
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/persistsession/PersistenceSessionServiceInternalNoop.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/persistsession/PersistenceSessionServiceInternalNoop.java
index 086400b..1016a20 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/persistsession/PersistenceSessionServiceInternalNoop.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/persistsession/PersistenceSessionServiceInternalNoop.java
@@ -19,6 +19,7 @@
 package org.apache.isis.core.metamodel.services.persistsession;
 
 import java.util.List;
+import java.util.concurrent.CountDownLatch;
 
 import org.apache.isis.applib.annotation.DomainService;
 import org.apache.isis.applib.annotation.NatureOfService;
@@ -145,6 +146,11 @@ public class PersistenceSessionServiceInternalNoop implements PersistenceSession
     public Transaction currentTransaction() {
         throw new UnsupportedOperationException("Not supported by this implementation of PersistenceSessionServiceInternal");
     }
+    
+	@Override
+	public CountDownLatch currentTransactionLatch() {
+		throw new UnsupportedOperationException("Not supported by this implementation of PersistenceSessionServiceInternal");
+	}
 
     @Override
     public void remove(final ObjectAdapter adapter) {
@@ -170,4 +176,6 @@ public class PersistenceSessionServiceInternalNoop implements PersistenceSession
     public TransactionState getTransactionState() {
         throw new UnsupportedOperationException("Not supported by this implementation of PersistenceSessionServiceInternal");
     }
+
+
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/xactn/TransactionServiceDefault.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/xactn/TransactionServiceDefault.java
index 0848d8b..d3ddf28 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/xactn/TransactionServiceDefault.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/xactn/TransactionServiceDefault.java
@@ -19,11 +19,13 @@
 
 package org.apache.isis.core.metamodel.services.xactn;
 
+import java.util.concurrent.CountDownLatch;
+
 import org.apache.isis.applib.annotation.DomainService;
 import org.apache.isis.applib.annotation.NatureOfService;
+import org.apache.isis.applib.services.command.Command;
 import org.apache.isis.applib.services.xactn.Transaction;
 import org.apache.isis.applib.services.xactn.TransactionService;
-import org.apache.isis.applib.services.command.Command;
 import org.apache.isis.applib.services.xactn.TransactionState;
 import org.apache.isis.core.commons.exceptions.IsisException;
 import org.apache.isis.core.metamodel.services.persistsession.PersistenceSessionServiceInternal;
@@ -87,6 +89,11 @@ public class TransactionServiceDefault implements TransactionService {
     public Transaction currentTransaction() {
         return persistenceSessionServiceInternal.currentTransaction();
     }
+    
+	@Override
+	public CountDownLatch currentTransactionLatch() {
+    	return persistenceSessionServiceInternal.currentTransactionLatch(); 
+	}
 
     @Override
     public TransactionState getTransactionState() {
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/services/background/BackgroundCommandExecution.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/services/background/BackgroundCommandExecution.java
index 0d5ec9d..6ac2ed2 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/services/background/BackgroundCommandExecution.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/services/background/BackgroundCommandExecution.java
@@ -18,33 +18,15 @@ package org.apache.isis.core.runtime.services.background;
 
 import java.util.List;
 
-import com.google.common.collect.Lists;
-
-import org.apache.isis.applib.services.bookmark.Bookmark;
-import org.apache.isis.applib.services.bookmark.BookmarkService;
-import org.apache.isis.applib.services.clock.ClockService;
 import org.apache.isis.applib.services.command.Command;
-import org.apache.isis.applib.services.command.Command.Executor;
-import org.apache.isis.applib.services.iactn.Interaction;
-import org.apache.isis.applib.services.iactn.InteractionContext;
-import org.apache.isis.applib.services.jaxb.JaxbService;
-import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
-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.spec.ObjectSpecification;
-import org.apache.isis.core.metamodel.spec.feature.Contributed;
-import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
-import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation;
-import org.apache.isis.core.metamodel.spec.feature.OneToOneAssociation;
-import org.apache.isis.core.runtime.sessiontemplate.AbstractIsisSessionTemplate;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
 import org.apache.isis.applib.services.command.CommandExecutorService;
 import org.apache.isis.applib.services.command.CommandWithDto;
 import org.apache.isis.core.runtime.system.persistence.PersistenceSession;
 import org.apache.isis.core.runtime.system.transaction.IsisTransactionManager;
-import org.apache.isis.core.runtime.system.transaction.TransactionalClosure;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.Lists;
 
 /**
  * Intended to be used as a base class for executing queued up {@link Command background action}s.
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/services/background/ForkingInvocationHandler.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/services/background/ForkingInvocationHandler.java
index aa4bbc3..8fa7a34 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/services/background/ForkingInvocationHandler.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/services/background/ForkingInvocationHandler.java
@@ -20,9 +20,14 @@ import static org.apache.isis.commons.internal.base._With.requires;
 
 import java.lang.reflect.InvocationHandler;
 import java.lang.reflect.Method;
+import java.util.Optional;
+import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.ExecutorService;
 
 import org.apache.isis.core.runtime.system.context.IsisContext;
+import org.apache.isis.core.runtime.system.session.IsisSession;
+import org.apache.isis.core.runtime.system.session.IsisSessionFactory;
+import org.apache.isis.core.runtime.system.transaction.IsisTransaction;
 
 /**
  * Package private invocation handler that executes actions in the background using a ExecutorService
@@ -61,9 +66,16 @@ class ForkingInvocationHandler<T> implements InvocationHandler {
             domainObject = mixedInIfAny;
         }
         
+        final CountDownLatch countDownLatch = Optional.ofNullable(IsisContext.getSessionFactory())
+        		.map(IsisSessionFactory::getCurrentSession)
+        		.map(IsisSession::getCurrentTransaction)
+        		.map(IsisTransaction::countDownLatch)
+        		.orElse(new CountDownLatch(0));
+        
         backgroundExecutorService.submit(()->{
         	
         	try {
+        		countDownLatch.await(); // wait for current transaction of the calling thread to complete
         		
         		IsisContext.getSessionFactory().doInSession(
         			()->proxyMethod.invoke(domainObject, args));
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/services/persistsession/PersistenceSessionServiceInternalDefault.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/services/persistsession/PersistenceSessionServiceInternalDefault.java
index 480f440..c26445c 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/services/persistsession/PersistenceSessionServiceInternalDefault.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/services/persistsession/PersistenceSessionServiceInternalDefault.java
@@ -22,6 +22,7 @@ import static java.util.Objects.requireNonNull;
 import static java.util.Optional.ofNullable;
 
 import java.util.List;
+import java.util.concurrent.CountDownLatch;
 
 import org.apache.isis.applib.NonRecoverableException;
 import org.apache.isis.applib.annotation.DomainService;
@@ -181,6 +182,12 @@ public class PersistenceSessionServiceInternalDefault implements PersistenceSess
     public Transaction currentTransaction() {
         return getTransactionManager().getCurrentTransaction();
     }
+    
+	@Override
+	public CountDownLatch currentTransactionLatch() {
+    	IsisTransaction transaction = getTransactionManager().getCurrentTransaction();
+    	return transaction==null ? new CountDownLatch(0) : transaction.countDownLatch(); 
+	}
 
     @Override
     public <T> List<ObjectAdapter> allMatchingQuery(final Query<T> query) {
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/PersistenceSessionBase.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/PersistenceSessionBase.java
index d10abe5..b75e1b7 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/PersistenceSessionBase.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/PersistenceSessionBase.java
@@ -119,7 +119,7 @@ abstract class PersistenceSessionBase implements PersistenceSession {
         // sub-components
         final AdapterManager adapterManager = this;
         this.persistenceQueryFactory = new PersistenceQueryFactory(adapterManager, this.specificationLoader);
-        this.transactionManager = new IsisTransactionManager(this, authenticationSession, servicesInjector);
+        this.transactionManager = new IsisTransactionManager(this, /*authenticationSession,*/ servicesInjector);
 
         this.state = State.NOT_INITIALIZED;
 
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/transaction/IsisTransaction.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/transaction/IsisTransaction.java
index 96c9fa2..6ebe65d 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/transaction/IsisTransaction.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/transaction/IsisTransaction.java
@@ -21,19 +21,14 @@ package org.apache.isis.core.runtime.system.transaction;
 
 import java.util.List;
 import java.util.UUID;
-
-import com.google.common.collect.Lists;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import java.util.concurrent.CountDownLatch;
 
 import org.apache.isis.applib.annotation.Programmatic;
 import org.apache.isis.applib.services.HasTransactionId;
 import org.apache.isis.applib.services.WithTransactionScope;
 import org.apache.isis.applib.services.xactn.Transaction;
 import org.apache.isis.applib.services.xactn.TransactionState;
-import org.apache.isis.core.commons.authentication.AuthenticationSession;
-import org.apache.isis.core.commons.authentication.MessageBroker;
+import org.apache.isis.commons.internal.collections._Lists;
 import org.apache.isis.core.commons.components.TransactionScopedComponent;
 import org.apache.isis.core.commons.exceptions.IsisException;
 import org.apache.isis.core.commons.util.ToString;
@@ -45,6 +40,10 @@ import org.apache.isis.core.runtime.persistence.objectstore.transaction.DestroyO
 import org.apache.isis.core.runtime.persistence.objectstore.transaction.PersistenceCommand;
 import org.apache.isis.core.runtime.services.auditing.AuditingServiceInternal;
 import org.apache.isis.core.runtime.services.persistsession.PersistenceSessionServiceInternalDefault;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.Lists;
 
 /**
  * Used by the {@link IsisTransactionManager} to captures a set of changes to be
@@ -163,11 +162,11 @@ public class IsisTransaction implements TransactionScopedComponent, Transaction
 
     private final UUID interactionId;
     private final int sequence;
-    private final AuthenticationSession authenticationSession;
+//    private final AuthenticationSession authenticationSession;
 
-    private final List<PersistenceCommand> persistenceCommands = Lists.newArrayList();
+    private final List<PersistenceCommand> persistenceCommands = _Lists.newArrayList();
     private final IsisTransactionManager transactionManager;
-    private final MessageBroker messageBroker;
+//    private final MessageBroker messageBroker;
     private final PublishingServiceInternal publishingServiceInternal;
     private final AuditingServiceInternal auditingServiceInternal;
 
@@ -178,18 +177,18 @@ public class IsisTransaction implements TransactionScopedComponent, Transaction
     public IsisTransaction(
             final UUID interactionId,
             final int sequence,
-            final AuthenticationSession authenticationSession,
+            /*final AuthenticationSession authenticationSession,*/
             final ServicesInjector servicesInjector) {
 
         this.interactionId = interactionId;
         this.sequence = sequence;
-        this.authenticationSession = authenticationSession;
+//        this.authenticationSession = authenticationSession;
 
         final PersistenceSessionServiceInternalDefault persistenceSessionService = servicesInjector
                 .lookupServiceElseFail(PersistenceSessionServiceInternalDefault.class);
         this.transactionManager = persistenceSessionService.getTransactionManager();
 
-        this.messageBroker = authenticationSession.getMessageBroker();
+//        this.messageBroker = authenticationSession.getMessageBroker();
         this.publishingServiceInternal = servicesInjector.lookupServiceElseFail(PublishingServiceInternal.class);
         this.auditingServiceInternal = servicesInjector.lookupServiceElseFail(AuditingServiceInternal.class);
 
@@ -200,8 +199,6 @@ public class IsisTransaction implements TransactionScopedComponent, Transaction
         LOG.debug("new transaction {}", this);
     }
 
-    
-
     // -- transactionId
 
     @Programmatic
@@ -223,6 +220,7 @@ public class IsisTransaction implements TransactionScopedComponent, Transaction
     }
 
     
+    private final CountDownLatch countDownLatch = new CountDownLatch(1);
 
     // -- state
 
@@ -234,6 +232,9 @@ public class IsisTransaction implements TransactionScopedComponent, Transaction
 
     private void setState(final State state) {
         this.state = state;
+        if(state.isComplete()) {
+        	countDownLatch.countDown();
+        }
     }
 
     @Override
@@ -251,12 +252,8 @@ public class IsisTransaction implements TransactionScopedComponent, Transaction
         return transactionState;
     }
 
-
-    
-
     // -- commands
 
-
     /**
      * Add the non-null command to the list of commands to execute at the end of
      * the transaction.
@@ -320,8 +317,6 @@ public class IsisTransaction implements TransactionScopedComponent, Transaction
         removeCommand(CreateObjectCommand.class, onObject);
     }
 
-    
-
     // -- flush
 
     public final void flush() {
@@ -446,9 +441,6 @@ public class IsisTransaction implements TransactionScopedComponent, Transaction
         setState(State.COMMITTED);
     }
 
-
-    
-
     // -- abortCause, markAsAborted
 
     /**
@@ -494,11 +486,6 @@ public class IsisTransaction implements TransactionScopedComponent, Transaction
         clearAbortCause();
     }
 
-
-
-
-    
-
     // -- toString
 
     @Override
@@ -512,21 +499,29 @@ public class IsisTransaction implements TransactionScopedComponent, Transaction
         return str;
     }
 
-    
-
     // -- getMessageBroker
 
+//    /**
+//     * The {@link org.apache.isis.core.commons.authentication.MessageBroker} for this transaction.
+//     * 
+//     * <p>
+//     * Injected in constructor
+//     *
+//     * @deprecated - obtain the {@link org.apache.isis.core.commons.authentication.MessageBroker} instead from the {@link AuthenticationSession}.
+//     */
+//    public MessageBroker getMessageBroker() {
+//        return messageBroker;
+//    }
+    
+    // -- countDownLatch
+
     /**
-     * The {@link org.apache.isis.core.commons.authentication.MessageBroker} for this transaction.
+     * Returns a latch that allows threads to wait on. The latch count drops to zero once this transaction completes.
      * 
-     * <p>
-     * Injected in constructor
-     *
-     * @deprecated - obtain the {@link org.apache.isis.core.commons.authentication.MessageBroker} instead from the {@link AuthenticationSession}.
      */
-    public MessageBroker getMessageBroker() {
-        return messageBroker;
-    }
+	public CountDownLatch countDownLatch() {
+		return countDownLatch;
+	}
 
     
 
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/transaction/IsisTransactionManager.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/transaction/IsisTransactionManager.java
index 166a4e4..a8b9a87 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/transaction/IsisTransactionManager.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/transaction/IsisTransactionManager.java
@@ -21,20 +21,18 @@ package org.apache.isis.core.runtime.system.transaction;
 
 import java.util.UUID;
 
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
 import org.apache.isis.applib.services.command.Command;
 import org.apache.isis.applib.services.command.CommandContext;
 import org.apache.isis.applib.services.iactn.Interaction;
 import org.apache.isis.applib.services.iactn.InteractionContext;
-import org.apache.isis.core.commons.authentication.AuthenticationSession;
 import org.apache.isis.core.commons.components.SessionScopedComponent;
 import org.apache.isis.core.commons.exceptions.IsisException;
 import org.apache.isis.core.metamodel.services.ServicesInjector;
 import org.apache.isis.core.runtime.persistence.objectstore.transaction.PersistenceCommand;
 import org.apache.isis.core.runtime.system.persistence.PersistenceSession;
 import org.apache.isis.core.runtime.system.session.IsisSession;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 public class IsisTransactionManager implements SessionScopedComponent {
 
@@ -52,7 +50,7 @@ public class IsisTransactionManager implements SessionScopedComponent {
     // -- constructor, fields
 
     private final PersistenceSession persistenceSession;
-    private final AuthenticationSession authenticationSession;
+    //private final AuthenticationSession authenticationSession;
     private final ServicesInjector servicesInjector;
 
     private final CommandContext commandContext;
@@ -60,11 +58,11 @@ public class IsisTransactionManager implements SessionScopedComponent {
 
     public IsisTransactionManager(
             final PersistenceSession persistenceSession,
-            final AuthenticationSession authenticationSession,
+            /*final AuthenticationSession authenticationSession,*/
             final ServicesInjector servicesInjector) {
 
         this.persistenceSession = persistenceSession;
-        this.authenticationSession = authenticationSession;
+        //this.authenticationSession = authenticationSession;
         this.servicesInjector = servicesInjector;
 
         this.commandContext = this.servicesInjector.lookupServiceElseFail(CommandContext.class);
@@ -239,7 +237,7 @@ public class IsisTransactionManager implements SessionScopedComponent {
             final UUID transactionId = command.getTransactionId();
 
             this.currentTransaction = new IsisTransaction(transactionId,
-                    interaction.next(Interaction.Sequence.TRANSACTION.id()), authenticationSession, servicesInjector);
+                    interaction.next(Interaction.Sequence.TRANSACTION.id()), /*authenticationSession,*/ servicesInjector);
             transactionLevel = 0;
 
             persistenceSession.startTransaction();