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 2019/06/22 08:07:44 UTC
[isis] branch v2 updated: ISIS-2125: replaces the
TransactionServiceDefault with a new TransactionServiceSpring that utilizes
sprint-tx API
This is an automated email from the ASF dual-hosted git repository.
ahuber pushed a commit to branch v2
in repository https://gitbox.apache.org/repos/asf/isis.git
The following commit(s) were added to refs/heads/v2 by this push:
new 4efd9b0 ISIS-2125: replaces the TransactionServiceDefault with a new TransactionServiceSpring that utilizes sprint-tx API
4efd9b0 is described below
commit 4efd9b07d0dfe167614fbdbe90dbb95e0b2f258c
Author: Andi Huber <ah...@apache.org>
AuthorDate: Sat Jun 22 10:07:33 2019 +0200
ISIS-2125: replaces the TransactionServiceDefault with a new
TransactionServiceSpring that utilizes sprint-tx API
- however, the nextTransaction() call is still delegated to the old
service, unfortunately this concept is not present in Spring's tx API
- remove the transaction latch from ps-internal
- deal with the fact that IsisSession.close(), as handled by Spring when
processing @PreDestroy, runs on a different thread than that, that
opened the session.
Task-Url: https://issues.apache.org/jira/browse/ISIS-2125
---
.../isis/applib/services/xactn/Transaction.java | 21 ++++++
.../isis/applib/services/xactn/TransactionId.java | 6 ++
.../applib/services/xactn/TransactionService.java | 1 -
.../commons/internal/collections/_Multimaps.java | 8 +++
.../isis/commons/internal/context/_Context.java | 6 +-
.../internal/context/_Context_ThreadLocal.java | 81 +++++++++++++++++++---
.../PersistenceSessionServiceInternal.java | 5 +-
.../IsisPlatformTransactionManagerForJdo.java | 27 ++++++--
...eDefault.java => TransactionServiceLegacy.java} | 42 +++++------
.../services/xactn/TransactionServiceSpring.java | 39 +++++++----
.../context/session/RuntimeEventService.java | 5 +-
.../JdoPersistenceLifecycleService.java | 1 +
.../core/runtime/system/session/IsisSession.java | 17 ++++-
.../system/session/IsisSessionFactoryDefault.java | 14 +++-
.../system/transaction/IsisTransactionObject.java | 6 +-
.../PersistenceSessionServiceInternalDefault.java | 15 ++--
.../server/resources/DomainResourceHelper.java | 2 +
.../isis/testdomain/tests/AuditerServiceTest.java | 9 +--
.../testdomain/tests/JdoBootstrappingTest.java | 31 +++++++--
.../tests/SpringServiceProvisioningTest.java | 2 +
.../isis/testdomain/tests/builtin-IsisBoot.json | 1 -
21 files changed, 248 insertions(+), 91 deletions(-)
diff --git a/core/applib/src/main/java/org/apache/isis/applib/services/xactn/Transaction.java b/core/applib/src/main/java/org/apache/isis/applib/services/xactn/Transaction.java
index 886fae5..1c69df0 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/services/xactn/Transaction.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/services/xactn/Transaction.java
@@ -46,5 +46,26 @@ public interface Transaction {
@Programmatic
TransactionState getTransactionState();
+
+ // -- FACTORIES
+
+ public static Transaction noop() {
+ return new Transaction() {
+
+ @Override
+ public TransactionState getTransactionState() {
+ return TransactionState.NONE;
+ }
+
+ @Override
+ public TransactionId getId() {
+ return null;
+ }
+
+ @Override
+ public void flush() {
+ }
+ };
+ }
}
diff --git a/core/applib/src/main/java/org/apache/isis/applib/services/xactn/TransactionId.java b/core/applib/src/main/java/org/apache/isis/applib/services/xactn/TransactionId.java
index 25216c0..007349e 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/services/xactn/TransactionId.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/services/xactn/TransactionId.java
@@ -18,4 +18,10 @@ public final class TransactionId implements HasUniqueId {
*/
private final int sequence;
+ private final static TransactionId EMPTY = TransactionId.of(UUID.fromString("0000-00-00-00-000000"), 0);
+
+ public static TransactionId empty() {
+ return EMPTY;
+ }
+
}
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 f698998..77db6d1 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
@@ -72,7 +72,6 @@ public interface TransactionService {
@Programmatic
CountDownLatch currentTransactionLatch();
-
/**
* Intended only for use by fixture scripts and integration tests.
*
diff --git a/core/commons/src/main/java/org/apache/isis/commons/internal/collections/_Multimaps.java b/core/commons/src/main/java/org/apache/isis/commons/internal/collections/_Multimaps.java
index 7d4f291..bad67c2 100644
--- a/core/commons/src/main/java/org/apache/isis/commons/internal/collections/_Multimaps.java
+++ b/core/commons/src/main/java/org/apache/isis/commons/internal/collections/_Multimaps.java
@@ -28,6 +28,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Supplier;
/**
@@ -224,6 +225,13 @@ public class _Multimaps {
public static <K1, K2, V> MapMultimap<K1, K2, V> newMapMultimap(){
return newMapMultimap(HashMap<K1, Map<K2, V>>::new, HashMap::new);
}
+
+ /**
+ * @return ConcurrentHashMap of HashMaps
+ */
+ public static <K1, K2, V> MapMultimap<K1, K2, V> newConcurrentMapMultimap(){
+ return newMapMultimap(ConcurrentHashMap<K1, Map<K2, V>>::new, HashMap::new);
+ }
diff --git a/core/commons/src/main/java/org/apache/isis/commons/internal/context/_Context.java b/core/commons/src/main/java/org/apache/isis/commons/internal/context/_Context.java
index 118e084..1edfdde 100644
--- a/core/commons/src/main/java/org/apache/isis/commons/internal/context/_Context.java
+++ b/core/commons/src/main/java/org/apache/isis/commons/internal/context/_Context.java
@@ -243,6 +243,7 @@ public final class _Context {
closeAnyClosables(_Lists.newArrayList(singletonMap.values()));
singletonMap.clear();
+ _Context_ThreadLocal.clear();
}
}
@@ -265,9 +266,10 @@ public final class _Context {
* Puts {@code payload} onto the current thread's map.
* @param type - the key into the thread-local store
* @param payload
+ * @return a Runnable which, when run, removes any references to payload
*/
- public static <T> void threadLocalPut(Class<? super T> type, T payload) {
- _Context_ThreadLocal.put(type, payload);
+ public static <T> Runnable threadLocalPut(Class<? super T> type, T payload) {
+ return _Context_ThreadLocal.put(type, payload);
}
diff --git a/core/commons/src/main/java/org/apache/isis/commons/internal/context/_Context_ThreadLocal.java b/core/commons/src/main/java/org/apache/isis/commons/internal/context/_Context_ThreadLocal.java
index aa98fdd..eeae901 100644
--- a/core/commons/src/main/java/org/apache/isis/commons/internal/context/_Context_ThreadLocal.java
+++ b/core/commons/src/main/java/org/apache/isis/commons/internal/context/_Context_ThreadLocal.java
@@ -21,12 +21,14 @@ package org.apache.isis.commons.internal.context;
import static org.apache.isis.commons.internal.base._With.requires;
-import java.util.HashMap;
import java.util.Map;
import org.apache.isis.commons.internal.base._Casts;
+import org.apache.isis.commons.internal.collections._Maps;
+import org.apache.isis.commons.internal.collections._Multimaps;
import org.apache.isis.core.commons.collections.Bin;
+import lombok.Value;
import lombok.val;
/**
@@ -39,19 +41,36 @@ import lombok.val;
* <b>WARNING</b>: Do <b>NOT</b> use any of the classes provided by this package! <br/>
* These may be changed or removed without notice!
* </p>
+ *
* @since 2.0.0-M3
+ *
*/
final class _Context_ThreadLocal {
// -- MIXINS
- static <T> void put(Class<? super T> type, T variant) {
+ @Value(staticConstructor = "of")
+ private final static class ThreadKey {
+ long threadId;
+ int threadHashCode;
+ static ThreadKey of(Thread thread) {
+ return of(thread.getId(), thread.hashCode());
+ }
+ }
+
+ static <T> Runnable put(Class<? super T> type, T variant) {
requires(type, "type");
requires(variant, "variant");
- THREAD_LOCAL_MAP.get()
+
+ val threadLocalMap = getOrCreateThreadLocalMap();
+ threadLocalMap
.compute(type, (k, v) -> v == null
? Bin.<T>ofSingleton(variant)
: Bin.<T>concat(_Casts.uncheckedCast(v), variant));
+
+ val key = THREAD_LOCAL_MAP_KEY.get();
+
+ return ()->{MAPS_BY_KEY.remove(key);};
}
static <T> Bin<T> select(Class<? super T> type, Class<? super T> instanceOf) {
@@ -64,30 +83,70 @@ final class _Context_ThreadLocal {
}
static <T> Bin<T> get(Class<? super T> type) {
- val bin = THREAD_LOCAL_MAP.get().get(type);
- if(bin!=null) {
- return _Casts.uncheckedCast(bin);
+ val threadLocalMap = getThreadLocalMap();
+ if(threadLocalMap==null) {
+ return Bin.empty();
}
- return Bin.empty();
+ val bin = threadLocalMap.get(type);
+ if(bin==null) {
+ return Bin.empty();
+ }
+ return _Casts.uncheckedCast(bin);
}
static void clear(Class<?> type) {
- THREAD_LOCAL_MAP.get().remove(type);
+ val threadLocalMap = getThreadLocalMap();
+ if(threadLocalMap==null) {
+ return;
+ }
+ threadLocalMap.remove(type);
}
static void cleanupThread() {
- THREAD_LOCAL_MAP.remove();
+ val key = THREAD_LOCAL_MAP_KEY.get();
+ THREAD_LOCAL_MAP_KEY.remove();
+ MAPS_BY_KEY.remove(key);
}
// -- HELPER
private _Context_ThreadLocal(){}
+
+ static void clear() {
+ MAPS_BY_KEY.clear();
+ }
+
+// /**
+// * Inheritable... allows to have concurrent computations utilizing the ForkJoinPool.
+// */
+// private final static ThreadLocal<Map<Class<?>, Bin<?>>> THREAD_LOCAL_MAP =
+// InheritableThreadLocal.withInitial(HashMap::new);
/**
* Inheritable... allows to have concurrent computations utilizing the ForkJoinPool.
*/
- private final static ThreadLocal<Map<Class<?>, Bin<?>>> THREAD_LOCAL_MAP =
- InheritableThreadLocal.withInitial(HashMap::new);
+ private final static ThreadLocal<ThreadKey> THREAD_LOCAL_MAP_KEY =
+ InheritableThreadLocal.withInitial(()->ThreadKey.of(Thread.currentThread()));
+
+
+ private final static _Multimaps.MapMultimap<ThreadKey, Class<?>, Bin<?>> MAPS_BY_KEY =
+ _Multimaps.newConcurrentMapMultimap();
+
+ private static Map<Class<?>, Bin<?>> getThreadLocalMap() {
+ val key = THREAD_LOCAL_MAP_KEY.get(); // non-null
+ val threadLocalMap = MAPS_BY_KEY.get(key); // might be null
+ return threadLocalMap;
+ }
+ private static Map<Class<?>, Bin<?>> getOrCreateThreadLocalMap() {
+ val key = THREAD_LOCAL_MAP_KEY.get(); // non-null
+ val threadLocalMap = MAPS_BY_KEY.get(key); // might be null
+ if(threadLocalMap!=null) {
+ return threadLocalMap;
+ }
+ val map = _Maps.<Class<?>, Bin<?>>newHashMap();
+ MAPS_BY_KEY.put(key, map);
+ return map;
+ }
}
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 1f60330..c6c150a 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,7 +17,6 @@
package org.apache.isis.core.metamodel.services.persistsession;
import java.util.List;
-import java.util.concurrent.CountDownLatch;
import java.util.function.Supplier;
import org.apache.isis.applib.query.Query;
@@ -93,8 +92,6 @@ public interface PersistenceSessionServiceInternal extends ObjectAdapterProvider
Transaction currentTransaction();
- CountDownLatch currentTransactionLatch();
-
TransactionState getTransactionState();
// -- makePersistent, remove
@@ -135,8 +132,10 @@ public interface PersistenceSessionServiceInternal extends ObjectAdapterProvider
*/
<T> ObjectAdapter firstMatchingQuery(Query<T> query);
+ @Deprecated //TODO[2125] use new TransactionServiceSpring instead
void executeWithinTransaction(Runnable task);
+ @Deprecated //TODO[2125] use new TransactionServiceSpring instead
<T> T executeWithinTransaction(Supplier<T> task);
}
diff --git a/core/plugins/jdo-common/src/main/java/org/apache/isis/jdo/transaction/IsisPlatformTransactionManagerForJdo.java b/core/plugins/jdo-common/src/main/java/org/apache/isis/jdo/transaction/IsisPlatformTransactionManagerForJdo.java
index 9862cf3..0272c77 100644
--- a/core/plugins/jdo-common/src/main/java/org/apache/isis/jdo/transaction/IsisPlatformTransactionManagerForJdo.java
+++ b/core/plugins/jdo-common/src/main/java/org/apache/isis/jdo/transaction/IsisPlatformTransactionManagerForJdo.java
@@ -21,12 +21,15 @@ package org.apache.isis.jdo.transaction;
import javax.inject.Inject;
import javax.inject.Singleton;
+import org.apache.isis.applib.services.registry.ServiceRegistry;
+import org.apache.isis.applib.services.xactn.Transaction;
import org.apache.isis.core.metamodel.services.persistsession.PersistenceSessionServiceInternal;
import org.apache.isis.core.runtime.system.internal.InitialisationSession;
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.IsisTransactionAspectSupport;
import org.apache.isis.core.runtime.system.transaction.IsisTransactionObject;
+import org.apache.isis.core.security.authentication.AuthenticationSession;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionException;
import org.springframework.transaction.support.AbstractPlatformTransactionManager;
@@ -42,17 +45,29 @@ public class IsisPlatformTransactionManagerForJdo extends AbstractPlatformTransa
@Inject private IsisSessionFactory isisSessionFactory;
@Inject private PersistenceSessionServiceInternal persistenceSessionServiceInternal;
+ @Inject private ServiceRegistry serviceRegistry;
@Override
protected Object doGetTransaction() throws TransactionException {
- log.debug("doGetTransaction");
- if(IsisSession.isInSession()) {
- val transactionBeforeBegin = persistenceSessionServiceInternal.currentTransaction();
- return IsisTransactionObject.of(transactionBeforeBegin);
+ val isInSession = IsisSession.isInSession();
+ log.debug("doGetTransaction isInSession={}", isInSession);
+
+ if(!isInSession) {
+
+ // get authenticationSession from IoC, or fallback to InitialisationSession
+ val authenticationSession = serviceRegistry.select(AuthenticationSession.class)
+ .getFirst()
+ .orElseGet(InitialisationSession::new);
+
+ log.debug("open new session authenticationSession={}", authenticationSession);
+
+ isisSessionFactory.openSession(authenticationSession);
+ val transactionBeforeBegin = (Transaction)null;
+ return IsisTransactionObject.of(transactionBeforeBegin);
} else {
- isisSessionFactory.openSession(new InitialisationSession()); //FIXME this is only for integration testing
- return IsisTransactionObject.of(null);
+ val transactionBeforeBegin = persistenceSessionServiceInternal.currentTransaction();
+ return IsisTransactionObject.of(transactionBeforeBegin);
}
}
diff --git a/core/runtime-services/src/main/java/org/apache/isis/core/runtime/services/xactn/TransactionServiceDefault.java b/core/runtime-services/src/main/java/org/apache/isis/core/runtime/services/xactn/TransactionServiceLegacy.java
similarity index 79%
rename from core/runtime-services/src/main/java/org/apache/isis/core/runtime/services/xactn/TransactionServiceDefault.java
rename to core/runtime-services/src/main/java/org/apache/isis/core/runtime/services/xactn/TransactionServiceLegacy.java
index 1d259bb..3c845c0 100644
--- a/core/runtime-services/src/main/java/org/apache/isis/core/runtime/services/xactn/TransactionServiceDefault.java
+++ b/core/runtime-services/src/main/java/org/apache/isis/core/runtime/services/xactn/TransactionServiceLegacy.java
@@ -19,11 +19,8 @@
package org.apache.isis.core.runtime.services.xactn;
-import java.util.concurrent.CountDownLatch;
import java.util.function.Supplier;
-import javax.inject.Singleton;
-
import org.apache.isis.applib.services.command.Command;
import org.apache.isis.applib.services.xactn.Transaction;
import org.apache.isis.applib.services.xactn.TransactionId;
@@ -35,19 +32,19 @@ import org.apache.isis.core.runtime.system.context.IsisContext;
import org.apache.isis.core.runtime.system.transaction.IsisTransaction;
import org.apache.isis.core.runtime.system.transaction.IsisTransactionManagerJdoInternal;
+import lombok.NonNull;
+import lombok.RequiredArgsConstructor;
import lombok.val;
-@Singleton
-public class TransactionServiceDefault implements TransactionService {
-
+@RequiredArgsConstructor(staticName = "of")
+class TransactionServiceLegacy {
- @Override
- public void flushTransaction() {
+ void flushTransaction() {
persistenceSessionServiceInternal.flush();
}
- @Override
- public void nextTransaction(TransactionService.Policy policy, final Command commandIfAny) {
+
+ void nextTransaction(TransactionService.Policy policy, final Command commandIfAny) {
final TransactionState transactionState = currentTransactionState();
switch (transactionState) {
case NONE:
@@ -77,13 +74,13 @@ public class TransactionServiceDefault implements TransactionService {
persistenceSessionServiceInternal.beginTran(commandIfAny);
}
- @Override
- public void executeWithinTransaction(Runnable task) {
+
+ void executeWithinTransaction(Runnable task) {
isisTransactionManager().executeWithinTransaction(task);
}
- @Override
- public <T> T executeWithinTransaction(Supplier<T> task) {
+
+ <T> T executeWithinTransaction(Supplier<T> task) {
return isisTransactionManager().executeWithinTransaction(task);
}
@@ -91,19 +88,14 @@ public class TransactionServiceDefault implements TransactionService {
return IsisContext.getTransactionManagerJdo().get();
}
- @Override
- public TransactionId currentTransactionId() {
+
+ TransactionId currentTransactionId() {
val tx = currentTransaction();
return tx!=null ? tx.getId() : null;
}
- @Override
- public CountDownLatch currentTransactionLatch() {
- return persistenceSessionServiceInternal.currentTransactionLatch();
- }
-
- @Override
- public TransactionState currentTransactionState() {
+
+ TransactionState currentTransactionState() {
return persistenceSessionServiceInternal.getTransactionState();
}
@@ -113,8 +105,8 @@ public class TransactionServiceDefault implements TransactionService {
return persistenceSessionServiceInternal.currentTransaction();
}
- @javax.inject.Inject
- PersistenceSessionServiceInternal persistenceSessionServiceInternal;
+ @NonNull
+ private final PersistenceSessionServiceInternal persistenceSessionServiceInternal;
}
diff --git a/core/runtime-services/src/main/java/org/apache/isis/core/runtime/services/xactn/TransactionServiceSpring.java b/core/runtime-services/src/main/java/org/apache/isis/core/runtime/services/xactn/TransactionServiceSpring.java
index 4ad6c9e..814f0d6 100644
--- a/core/runtime-services/src/main/java/org/apache/isis/core/runtime/services/xactn/TransactionServiceSpring.java
+++ b/core/runtime-services/src/main/java/org/apache/isis/core/runtime/services/xactn/TransactionServiceSpring.java
@@ -22,7 +22,8 @@ package org.apache.isis.core.runtime.services.xactn;
import java.util.concurrent.CountDownLatch;
import java.util.function.Supplier;
-import javax.enterprise.inject.Vetoed;
+import javax.annotation.PostConstruct;
+import javax.inject.Inject;
import javax.inject.Singleton;
import org.apache.isis.applib.services.command.Command;
@@ -30,6 +31,8 @@ import org.apache.isis.applib.services.xactn.TransactionId;
import org.apache.isis.applib.services.xactn.TransactionService;
import org.apache.isis.applib.services.xactn.TransactionState;
import org.apache.isis.commons.internal.exceptions._Exceptions;
+import org.apache.isis.core.metamodel.services.persistsession.PersistenceSessionServiceInternal;
+import org.apache.isis.core.runtime.system.transaction.IsisTransaction;
import org.apache.isis.core.runtime.system.transaction.IsisTransactionAspectSupport;
import org.apache.isis.core.runtime.system.transaction.IsisTransactionObject;
import org.springframework.transaction.PlatformTransactionManager;
@@ -41,16 +44,25 @@ import org.springframework.transaction.support.TransactionTemplate;
import lombok.val;
import lombok.extern.log4j.Log4j2;
-@Vetoed @Deprecated//does not work
+@Singleton
@Log4j2
public class TransactionServiceSpring implements TransactionService {
+ @Inject private PersistenceSessionServiceInternal persistenceSessionServiceInternal;
+
// single TransactionTemplate shared amongst all methods in this instance
private final TransactionTemplate transactionTemplate;
+ private TransactionServiceLegacy legacyTransactionService;
// use constructor-injection to supply the PlatformTransactionManager
public TransactionServiceSpring(PlatformTransactionManager transactionManager) {
this.transactionTemplate = new TransactionTemplate(transactionManager);
+
+ }
+
+ @PostConstruct
+ public void init() {
+ this.legacyTransactionService = TransactionServiceLegacy.of(persistenceSessionServiceInternal);
}
@Override
@@ -108,22 +120,23 @@ public class TransactionServiceSpring implements TransactionService {
}
@Override
- public CountDownLatch currentTransactionLatch() {
+ public void nextTransaction(Policy policy, Command command) {
- log.warn("not implemented");
- _Exceptions.throwNotImplemented();
+ log.warn("deprecated");
+ //_Exceptions.throwNotImplemented();
- // TODO Auto-generated method stub
- return null;
+ legacyTransactionService.nextTransaction(policy, command);
}
-
+
@Override
- public void nextTransaction(Policy policy, Command command) {
- // TODO Auto-generated method stub
+ public CountDownLatch currentTransactionLatch() {
- log.warn("not implemented");
- _Exceptions.throwNotImplemented();
+ val txObject = IsisTransactionAspectSupport.currentTransactionObject();
+ if(txObject==null || txObject.getCurrentTransaction()==null) {
+ return new CountDownLatch(0);
+ }
+ return ((IsisTransaction)txObject.getCurrentTransaction()).countDownLatch();
}
@Override
@@ -163,4 +176,6 @@ public class TransactionServiceSpring implements TransactionService {
}
+
+
}
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/context/session/RuntimeEventService.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/context/session/RuntimeEventService.java
index 1b680e9..2233c37 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/context/session/RuntimeEventService.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/context/session/RuntimeEventService.java
@@ -30,7 +30,8 @@ import org.apache.isis.core.runtime.system.session.IsisSession;
/**
*
* @since 2.0.0-M3
- *
+ * @implNote listeners to runtime events are hard-wired, because these events are already fired
+ * during bootstrapping, when event handling might not work properly yet.
*/
@Singleton
public class RuntimeEventService {
@@ -44,8 +45,6 @@ public class RuntimeEventService {
// -- APP
- //FIXME[2112] events are fired but not received
-
public void fireAppPreMetamodel() {
//appLifecycleEvents.fire(AppLifecycleEvent.of(AppLifecycleEvent.EventType.appPreMetamodel));
listener.onAppLifecycleEvent(AppLifecycleEvent.of(AppLifecycleEvent.EventType.appPreMetamodel));
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/JdoPersistenceLifecycleService.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/JdoPersistenceLifecycleService.java
index f8a89e3..dab9bc1 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/JdoPersistenceLifecycleService.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/JdoPersistenceLifecycleService.java
@@ -119,6 +119,7 @@ public class JdoPersistenceLifecycleService {
PersistenceSession.current(PersistenceSession.class)
.getSingleton()
.ifPresent(PersistenceSession::close);
+ _Context.threadLocalClear(PersistenceSession.class);
}
// private void flushSession() {
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/session/IsisSession.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/session/IsisSession.java
index 2011fbf..cad9388 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/session/IsisSession.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/session/IsisSession.java
@@ -51,7 +51,14 @@ public class IsisSession extends RuntimeContextBase {
*/
@Getter private long openedAtSystemNanos = -1L;
- public IsisSession(
+ /**
+ *
+ * @param runtimeEventService
+ * @param authenticationSession
+ * @implNote package private constructor, to let only IsisSessionFactory have access to it,
+ * since it must keep track of all opened sessions
+ */
+ IsisSession(
final RuntimeEventService runtimeEventService,
final AuthenticationSession authenticationSession) {
@@ -99,10 +106,12 @@ public class IsisSession extends RuntimeContextBase {
}
// -- OPEN
+
+ private Runnable cleanupHandle;
void open() {
openedAtSystemNanos = System.nanoTime();
- _Context.threadLocalPut(IsisSession.class, this);
+ cleanupHandle = _Context.threadLocalPut(IsisSession.class, this);
runtimeEventService.fireSessionOpened(this);
}
@@ -113,7 +122,9 @@ public class IsisSession extends RuntimeContextBase {
*/
void close() {
runtimeEventService.fireSessionClosing(this);
- _Context.threadLocalCleanup();
+ if(cleanupHandle!=null) {
+ cleanupHandle.run();
+ }
}
// -- FLUSH
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/session/IsisSessionFactoryDefault.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/session/IsisSessionFactoryDefault.java
index 438f96e..e831874 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/session/IsisSessionFactoryDefault.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/session/IsisSessionFactoryDefault.java
@@ -24,6 +24,7 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
+import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.stream.Stream;
@@ -39,6 +40,7 @@ import org.apache.isis.applib.services.i18n.TranslationService;
import org.apache.isis.applib.services.registry.ServiceRegistry;
import org.apache.isis.applib.services.title.TitleService;
import org.apache.isis.commons.internal.base._Blackhole;
+import org.apache.isis.commons.internal.collections._Sets;
import org.apache.isis.commons.internal.context._Context;
import org.apache.isis.commons.ioc.BeanAdapter;
import org.apache.isis.config.IsisConfiguration;
@@ -56,8 +58,8 @@ import org.apache.isis.core.runtime.system.context.session.RuntimeEventService;
import org.apache.isis.core.runtime.system.internal.InitialisationSession;
import org.apache.isis.core.runtime.system.internal.IsisLocaleInitializer;
import org.apache.isis.core.runtime.system.internal.IsisTimeZoneInitializer;
-import org.apache.isis.core.runtime.system.transaction.IsisTransactionManagerJdoInternal;
import org.apache.isis.core.runtime.system.transaction.IsisTransactionManagerException;
+import org.apache.isis.core.runtime.system.transaction.IsisTransactionManagerJdoInternal;
import org.apache.isis.core.runtime.threadpool.ThreadPoolSupport;
import org.apache.isis.core.security.authentication.AuthenticationSession;
import org.apache.isis.core.security.authentication.manager.AuthenticationManager;
@@ -257,12 +259,15 @@ public class IsisSessionFactoryDefault implements IsisSessionFactory {
@PreDestroy
@Override
public void destroyServicesAndShutdown() {
+ // call might originate from a different thread than main
destroyServices();
shutdown();
}
// --
+ private final Set<IsisSession> openSessions = _Sets.newHashSet();
+
@Override
public IsisSession openSession(final AuthenticationSession authenticationSession) {
@@ -270,6 +275,7 @@ public class IsisSessionFactoryDefault implements IsisSessionFactory {
val isisSession = new IsisSession(runtimeEventService, authenticationSession);
isisSession.open();
+ openSessions.add(isisSession);
return isisSession;
}
@@ -281,6 +287,7 @@ public class IsisSessionFactoryDefault implements IsisSessionFactory {
return;
}
existingSessionIfAny.close();
+ openSessions.remove(existingSessionIfAny);
}
@Override
@@ -367,6 +374,11 @@ public class IsisSessionFactoryDefault implements IsisSessionFactory {
}
private void shutdown() {
+
+ // just in case we still have an open session, must also work if called from a different thread than 'main'
+ openSessions.forEach(IsisSession::close);
+ openSessions.clear();
+
runtimeEventService.fireAppPreDestroy();
authenticationManager.shutdown();
//specificationLoader.shutdown(); //[2112] lifecycle is managed by IoC
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/transaction/IsisTransactionObject.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/transaction/IsisTransactionObject.java
index 925a776..c3ca9ed 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/transaction/IsisTransactionObject.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/transaction/IsisTransactionObject.java
@@ -27,8 +27,9 @@ import lombok.Data;
@Data @AllArgsConstructor(staticName = "of")
public class IsisTransactionObject implements SmartTransactionObject {
+
Transaction currentTransaction;
-
+
@Override
public boolean isRollbackOnly() {
return currentTransaction.getTransactionState().mustAbort();
@@ -43,8 +44,9 @@ public class IsisTransactionObject implements SmartTransactionObject {
public TransactionId getTransactionId() {
if(currentTransaction!=null) {
- currentTransaction.getId();
+ return currentTransaction.getId();
}
return null;
}
+
}
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/transaction/PersistenceSessionServiceInternalDefault.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/transaction/PersistenceSessionServiceInternalDefault.java
index 02b2f30..88dcaa9 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/transaction/PersistenceSessionServiceInternalDefault.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/transaction/PersistenceSessionServiceInternalDefault.java
@@ -18,8 +18,11 @@
*/
package org.apache.isis.core.runtime.system.transaction;
+import static java.util.Objects.requireNonNull;
+import static org.apache.isis.commons.internal.base._With.acceptIfPresent;
+import static org.apache.isis.commons.internal.base._With.mapIfPresentElse;
+
import java.util.List;
-import java.util.concurrent.CountDownLatch;
import java.util.function.Supplier;
import javax.inject.Singleton;
@@ -45,10 +48,6 @@ import org.apache.isis.core.runtime.system.context.IsisContext;
import org.apache.isis.core.runtime.system.persistence.PersistenceSession;
import org.apache.isis.core.runtime.system.session.IsisSessionFactory;
-import static java.util.Objects.requireNonNull;
-import static org.apache.isis.commons.internal.base._With.acceptIfPresent;
-import static org.apache.isis.commons.internal.base._With.mapIfPresentElse;
-
@Singleton
public class PersistenceSessionServiceInternalDefault
implements PersistenceSessionServiceInternal {
@@ -167,12 +166,6 @@ implements PersistenceSessionServiceInternal {
}
@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) {
return getPersistenceSession().allMatchingQuery(query);
}
diff --git a/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/resources/DomainResourceHelper.java b/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/resources/DomainResourceHelper.java
index 75bac90..64c3abc 100644
--- a/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/resources/DomainResourceHelper.java
+++ b/core/viewer-restfulobjects-server/src/main/java/org/apache/isis/viewer/restfulobjects/server/resources/DomainResourceHelper.java
@@ -40,6 +40,8 @@ import org.apache.isis.core.metamodel.spec.feature.OneToOneAssociation;
import org.apache.isis.core.metamodel.specloader.SpecificationLoader;
import org.apache.isis.core.runtime.memento.Data;
import org.apache.isis.core.runtime.persistence.FixturesInstalledState;
+import org.apache.isis.core.runtime.system.context.IsisContext;
+import org.apache.isis.core.runtime.system.transaction.IsisTransactionAspectSupport;
import org.apache.isis.core.security.authentication.AuthenticationSession;
import org.apache.isis.viewer.restfulobjects.applib.JsonRepresentation;
import org.apache.isis.viewer.restfulobjects.applib.client.RestfulResponse;
diff --git a/example/misc/smoketest/src/test/java/org/apache/isis/testdomain/tests/AuditerServiceTest.java b/example/misc/smoketest/src/test/java/org/apache/isis/testdomain/tests/AuditerServiceTest.java
index c7bd309..225b0f9 100644
--- a/example/misc/smoketest/src/test/java/org/apache/isis/testdomain/tests/AuditerServiceTest.java
+++ b/example/misc/smoketest/src/test/java/org/apache/isis/testdomain/tests/AuditerServiceTest.java
@@ -58,6 +58,7 @@ import lombok.extern.log4j.Log4j2;
properties = {
"logging.config=log4j2-test.xml",
"logging.level.org.apache.isis.jdo.transaction.IsisPlatformTransactionManagerForJdo=DEBUG",
+ "logging.level.org.apache.isis.core.runtime.system.transaction.IsisTransaction=DEBUG",
// "isis.reflector.introspector.parallelize=false",
// "logging.level.org.apache.isis.core.metamodel.specloader.specimpl.ObjectSpecificationAbstract=TRACE"
})
@@ -134,17 +135,17 @@ class AuditerServiceTest {
.append(propertyName).append(",").append("preValue=").append(preValue).append(",")
.append("postValue=").append(postValue).append(";");
- log.info("audit {}", history.toString());
+ log.debug("audit {}", history.toString());
}
void clearHistory() {
- log.info("clearing");
+ log.debug("clearing");
history = new StringBuilder();
- log.info("cleared");
+ log.debug("cleared");
}
String getHistory() {
- log.info("get");
+ log.debug("get {}", history.toString());
return history.toString();
}
diff --git a/example/misc/smoketest/src/test/java/org/apache/isis/testdomain/tests/JdoBootstrappingTest.java b/example/misc/smoketest/src/test/java/org/apache/isis/testdomain/tests/JdoBootstrappingTest.java
index 9aee72d..a21e8f4 100644
--- a/example/misc/smoketest/src/test/java/org/apache/isis/testdomain/tests/JdoBootstrappingTest.java
+++ b/example/misc/smoketest/src/test/java/org/apache/isis/testdomain/tests/JdoBootstrappingTest.java
@@ -20,6 +20,7 @@ package org.apache.isis.testdomain.tests;
import static org.junit.Assert.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
import java.sql.SQLException;
import java.util.HashSet;
@@ -28,14 +29,19 @@ import java.util.Set;
import javax.inject.Inject;
import org.apache.isis.applib.services.repository.RepositoryService;
+import org.apache.isis.core.runtime.system.session.IsisSession;
import org.apache.isis.jdo.transaction.IsisPlatformTransactionManagerForJdo;
import org.apache.isis.runtime.spring.IsisBoot;
import org.apache.isis.testdomain.jdo.Book;
import org.apache.isis.testdomain.jdo.Inventory;
import org.apache.isis.testdomain.jdo.JdoTestDomainModule;
import org.apache.isis.testdomain.jdo.Product;
+import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.MethodOrderer;
+import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestMethodOrder;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.annotation.Rollback;
import org.springframework.transaction.annotation.Transactional;
@@ -54,16 +60,24 @@ import lombok.val;
// "isis.reflector.introspector.parallelize=false",
//"logging.level.org.apache.isis.core.metamodel.specloader.specimpl.ObjectSpecificationAbstract=TRACE"
})
-@Transactional
+@Transactional @TestMethodOrder(MethodOrderer.OrderAnnotation.class)
class JdoBootstrappingTest {
@Inject private RepositoryService repository;
@BeforeAll
- static void launchH2Console() throws SQLException {
- // for troubleshooting ...
+ static void beforeAll() throws SQLException {
+ //XXX is it actually the case that tests might run in parallel?
+ //assertFalse(IsisSession.isInSession()); // expected pre condition
+ // launch H2Console for troubleshooting ...
// Util_H2Console.main(null);
}
+
+ @AfterAll
+ static void afterAll() throws SQLException {
+// assertFalse(IsisSession.isInSession()); // expected post condition
+ }
+
void cleanUp() {
@@ -85,9 +99,9 @@ class JdoBootstrappingTest {
repository.persist(inventory);
}
- @Test @Rollback(false)
+ @Test @Order(1) @Rollback(false)
void sampleInventoryShouldBeSetUp() {
-
+
// given - expected pre condition: no inventories
cleanUp();
@@ -99,7 +113,7 @@ class JdoBootstrappingTest {
// then - expected post condition: ONE inventory
- val inventories =repository.allInstances(Inventory.class);
+ val inventories = repository.allInstances(Inventory.class);
assertEquals(1, inventories.size());
val inventory = inventories.get(0);
@@ -111,5 +125,10 @@ class JdoBootstrappingTest {
assertEquals("Sample Book", product.getName());
}
+
+ @Test @Order(2) @Rollback(false)
+ void aSecondRunShouldWorkAsWell() {
+ sampleInventoryShouldBeSetUp();
+ }
}
diff --git a/example/misc/smoketest/src/test/java/org/apache/isis/testdomain/tests/SpringServiceProvisioningTest.java b/example/misc/smoketest/src/test/java/org/apache/isis/testdomain/tests/SpringServiceProvisioningTest.java
index 202f891..0e4018e 100644
--- a/example/misc/smoketest/src/test/java/org/apache/isis/testdomain/tests/SpringServiceProvisioningTest.java
+++ b/example/misc/smoketest/src/test/java/org/apache/isis/testdomain/tests/SpringServiceProvisioningTest.java
@@ -31,6 +31,7 @@ import org.apache.isis.commons.internal.resources._Json;
import org.apache.isis.commons.internal.resources._Resources;
import org.apache.isis.commons.ioc.BeanAdapter;
import org.apache.isis.core.runtime.system.context.IsisContext;
+import org.apache.isis.jdo.transaction.IsisPlatformTransactionManagerForJdo;
import org.apache.isis.runtime.spring.IsisBoot;
import org.apache.isis.testdomain.jdo.JdoTestDomainModule;
import org.junit.jupiter.api.BeforeEach;
@@ -43,6 +44,7 @@ import lombok.val;
classes = {
IsisBoot.class,
JdoTestDomainModule.class,
+ IsisPlatformTransactionManagerForJdo.class,
},
properties = {
"logging.config=log4j2-test.xml",
diff --git a/example/misc/smoketest/src/test/resources/org/apache/isis/testdomain/tests/builtin-IsisBoot.json b/example/misc/smoketest/src/test/resources/org/apache/isis/testdomain/tests/builtin-IsisBoot.json
index 3e92663..034a034 100644
--- a/example/misc/smoketest/src/test/resources/org/apache/isis/testdomain/tests/builtin-IsisBoot.json
+++ b/example/misc/smoketest/src/test/resources/org/apache/isis/testdomain/tests/builtin-IsisBoot.json
@@ -23,7 +23,6 @@
"org.apache.isis.core.runtime.services.menubars.MenuBarsLoaderServiceDefault",
"org.apache.isis.core.runtime.services.menubars.bootstrap3.MenuBarsServiceBS3",
"org.apache.isis.core.runtime.services.message.MessageServiceDefault",
- "org.apache.isis.core.runtime.services.xactn.TransactionServiceDefault",
"org.apache.isis.core.runtime.services.xmlsnapshot.XmlSnapshotServiceDefault",
"org.apache.isis.core.security.authentication.standard.AuthenticationManagerStandard",
"org.apache.isis.core.wrapper.WrapperFactoryDefault"