This is an automated email from the ASF dual-hosted git repository. danhaywood pushed a commit to branch CAUSEWAY-3654 in repository https://gitbox.apache.org/repos/asf/causeway.git
commit 7c0fb3c1fe6788c5190b915c809663ac8cfa3499 Author: danhaywood <d...@haywood-associates.co.uk> AuthorDate: Mon Dec 11 18:29:01 2023 +0000 CAUSEWAY-3654: fixes compile issues in tests CAUSEWAY-3654: adds a more complete dummy PlatformTransactionManager to AppManifestBase for integ tests CAUSEWAY-3654: introduces NoopTransactionSynchronizationService to ensure... ... that there is always at least one transaction-scoped service. Also moves StackedTransactionScope et al from core-interaction to core-transaction module CAUSEWAY-3654: fixes some further integ tests CAUSEWAY-3654: fixes some further integ tests CAUSEWAY-3654: comments out some tests; sigh CAUSEWAY-3654: fixes order of wrapping; reenable commented out tests to see what gives CAUSEWAY-3654: fixes JPA integ test CAUSEWAY-3654: cleans up javadoc is all CAUSEWAY-3654: fixes (?) integ test for stable good domain --- .../interaction/CausewayModuleCoreInteraction.java | 2 - .../transaction/TransactionServiceSpring.java | 57 ++++++---- core/transaction/src/main/java/module-info.java | 1 + .../transaction/CausewayModuleCoreTransaction.java | 5 + .../NoopTransactionSynchronizationService.java | 30 +++++ .../scope/StackedTransactionScope.java | 4 +- .../TransactionScopeBeanFactoryPostProcessor.java | 2 +- .../metamodel/PdfjsViewer_Abstract_IntegTest.java | 19 +++- ...elTest_usingBadDomain_noAnnotationEnforced.java | 7 +- .../DomainModelTest_usingGoodDomain.java | 4 +- .../integtest/Layout_Counter_IntegTest.java | 20 +++- .../jdo/JdoExceptionTranslationTest.java | 10 +- .../testdomain/persistence/jdo/JdoJaxbTest.java | 2 + .../jdo/JdoTransactionScopeListenerTest.java | 121 --------------------- .../jpa/JpaExceptionTranslationTest.java | 18 ++- .../transactions/jpa/CommitListener.java | 78 +++++++++++++ ...actionRollbackTest_usingInteractionService.java | 60 +++------- ...actionRollbackTest_usingTransactionService.java | 65 +++-------- .../testdomain/RegressionTestAbstract.java | 15 +-- .../testdomain/conf/Configuration_headless.java | 55 +++------- .../publishing/PublishingTestFactoryAbstract.java | 31 ++++-- .../util/interaction/InteractionBoundaryProbe.java | 59 ++++++---- 22 files changed, 320 insertions(+), 345 deletions(-) diff --git a/core/interaction/src/main/java/org/apache/causeway/core/interaction/CausewayModuleCoreInteraction.java b/core/interaction/src/main/java/org/apache/causeway/core/interaction/CausewayModuleCoreInteraction.java index 13ff6e5897..09871d7ce2 100644 --- a/core/interaction/src/main/java/org/apache/causeway/core/interaction/CausewayModuleCoreInteraction.java +++ b/core/interaction/src/main/java/org/apache/causeway/core/interaction/CausewayModuleCoreInteraction.java @@ -21,14 +21,12 @@ package org.apache.causeway.core.interaction; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; -import org.apache.causeway.core.interaction.scope.TransactionScopeBeanFactoryPostProcessor; import org.apache.causeway.core.interaction.scope.InteractionScopeBeanFactoryPostProcessor; @Configuration @Import({ InteractionScopeBeanFactoryPostProcessor.class, - TransactionScopeBeanFactoryPostProcessor.class, }) public class CausewayModuleCoreInteraction { diff --git a/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/transaction/TransactionServiceSpring.java b/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/transaction/TransactionServiceSpring.java index af7b7149ac..e4fd820bad 100644 --- a/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/transaction/TransactionServiceSpring.java +++ b/core/runtimeservices/src/main/java/org/apache/causeway/core/runtimeservices/transaction/TransactionServiceSpring.java @@ -28,6 +28,8 @@ import javax.inject.Inject; import javax.inject.Named; import javax.inject.Provider; +import org.apache.causeway.applib.services.iactnlayer.InteractionContext; + import org.springframework.aop.support.AopUtils; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; @@ -86,7 +88,6 @@ implements private final Provider<InteractionLayerTracker> interactionLayerTrackerProvider; private final Can<PersistenceExceptionTranslator> persistenceExceptionTranslators; private final ConfigurableListableBeanFactory configurableListableBeanFactory; -// private final Can<TransactionBoundaryAware> transactionBoundaryAwareBeans; @Inject public TransactionServiceSpring( @@ -94,7 +95,6 @@ implements final List<PersistenceExceptionTranslator> persistenceExceptionTranslators, final Provider<InteractionLayerTracker> interactionLayerTrackerProvider, final ConfigurableListableBeanFactory configurableListableBeanFactory -// , final List<TransactionBoundaryAware> transactionBoundaryAwareBeans ) { this.platformTransactionManagers = Can.ofCollection(platformTransactionManagers); @@ -106,12 +106,9 @@ implements log.info("PersistenceExceptionTranslators: {}", persistenceExceptionTranslators); this.interactionLayerTrackerProvider = interactionLayerTrackerProvider; - -// this.transactionBoundaryAwareBeans = Can.ofCollection(transactionBoundaryAwareBeans); -// log.info("TransactionBoundaryAwareBeans: {}", transactionBoundaryAwareBeans); } - // -- SPRING INTEGRATION + // -- API @Override public <T> Try<T> callTransactional(final TransactionDefinition def, final Callable<T> callable) { @@ -123,26 +120,22 @@ implements try { TransactionStatus txStatus = platformTransactionManager.getTransaction(def); -// if(tx.isNewTransaction()) { -// transactionBoundaryAwareBeans.forEach(tba -> tba.afterEnteringTransactionalBoundary(platformTransactionManager)); -// } registerTransactionSynchronizations(txStatus); - result = Try.call(callable) + result = Try.call(() -> { + final T callResult = callable.call(); + // we flush here to ensure that the result captures any exception, eg from a declarative constraint violation + txStatus.flush(); + return callResult; + }) .mapFailure(ex->translateExceptionIfPossible(ex, platformTransactionManager)); -// if(tx.isNewTransaction()) { -// transactionBoundaryAwareBeans.forEach(tba -> tba.beforeLeavingTransactionalBoundary(platformTransactionManager)); -// } if(result.isFailure()) { platformTransactionManager.rollback(txStatus); } else { platformTransactionManager.commit(txStatus); } -// if(tx.isNewTransaction()) { -// transactionBoundaryAwareBeans.forEach(tba -> tba.afterLeavingTransactionalBoundary(platformTransactionManager)); -// } } catch (Exception ex) { return result!=null @@ -152,7 +145,7 @@ implements // (so we don't shadow the original failure) ? result - // return the failure we just catched + // return the failure we just caught : Try.failure(translateExceptionIfPossible(ex, platformTransactionManager)); } @@ -277,6 +270,7 @@ implements .orElse(TransactionState.NONE); } + // -- TRANSACTION SEQUENCE TRACKING // TODO: this ThreadLocal (as with all thread-locals) should perhaps somehow be managed using @@ -285,7 +279,8 @@ implements private ThreadLocal<LongAdder> txCounter = ThreadLocal.withInitial(LongAdder::new); - // -- HELPER + // -- SPRING INTEGRATION + private PlatformTransactionManager transactionManagerForElseFail(final TransactionDefinition def) { if(def instanceof TransactionTemplate) { @@ -356,6 +351,12 @@ implements } + /** + * For use only by {@link org.apache.causeway.core.runtimeservices.session.InteractionServiceDefault}, sets up + * the initial transaction automatically against all available {@link PlatformTransactionManager}s. + * + * @param interaction The {@link CausewayInteraction} object representing the current interaction. + */ public void onOpen(final @NonNull CausewayInteraction interaction) { txCounter.get().reset(); @@ -391,7 +392,6 @@ implements txStatus, txManager.getClass().getName(), // info to be used for display in case of errors () -> { -// transactionBoundaryAwareBeans.forEach(tbab -> tbab.beforeLeavingTransactionalBoundary(txManager)); _Xray.txBeforeCompletion(interactionLayerTrackerProvider.get(), "tx: beforeCompletion"); final TransactionCompletionStatus event; if (txStatus.isRollbackOnly()) { @@ -403,7 +403,6 @@ implements } _Xray.txAfterCompletion(interactionLayerTrackerProvider.get(), String.format("tx: afterCompletion (%s)", event.name())); -// transactionBoundaryAwareBeans.forEach(tbab -> tbab.afterLeavingTransactionalBoundary(txManager)); txCounter.get().increment(); } ) @@ -411,15 +410,29 @@ implements }); } - } + /** + * For use only by {@link org.apache.causeway.core.runtimeservices.session.InteractionServiceDefault}, if + * {@link org.apache.causeway.applib.services.iactnlayer.InteractionService#run(InteractionContext, ThrowingRunnable)} + * or {@link org.apache.causeway.applib.services.iactnlayer.InteractionService#call(InteractionContext, Callable)} + * (or their various overloads) result in an exception. + * + * @param interaction The {@link CausewayInteraction} object representing the current interaction. + */ public void requestRollback(final @NonNull CausewayInteraction interaction) { Optional.ofNullable(interaction.getAttribute(OnCloseHandle.class)) .ifPresent(OnCloseHandle::requestRollback); } + /** + * For use only by {@link org.apache.causeway.core.runtimeservices.session.InteractionServiceDefault}, to close the + * transaction initially set up in {@link #onOpen(CausewayInteraction)} against all configured + * {@link PlatformTransactionManager}s. + * + * @param interaction The {@link CausewayInteraction} object representing the current interaction. + */ public void onClose(final @NonNull CausewayInteraction interaction) { if (log.isDebugEnabled()) { @@ -462,9 +475,7 @@ implements onCloseTask.getOnErrorInfo(), ex); } - }); } } - } diff --git a/core/transaction/src/main/java/module-info.java b/core/transaction/src/main/java/module-info.java index d64c8c9e33..bec887b514 100644 --- a/core/transaction/src/main/java/module-info.java +++ b/core/transaction/src/main/java/module-info.java @@ -21,6 +21,7 @@ module org.apache.causeway.core.transaction { exports org.apache.causeway.core.transaction.changetracking; exports org.apache.causeway.core.transaction.changetracking.events; exports org.apache.causeway.core.transaction.events; + exports org.apache.causeway.core.transaction.scope; requires java.annotation; requires java.sql; diff --git a/core/transaction/src/main/java/org/apache/causeway/core/transaction/CausewayModuleCoreTransaction.java b/core/transaction/src/main/java/org/apache/causeway/core/transaction/CausewayModuleCoreTransaction.java index 21a841b29a..80667e7cf9 100644 --- a/core/transaction/src/main/java/org/apache/causeway/core/transaction/CausewayModuleCoreTransaction.java +++ b/core/transaction/src/main/java/org/apache/causeway/core/transaction/CausewayModuleCoreTransaction.java @@ -18,6 +18,9 @@ */ package org.apache.causeway.core.transaction; +import org.apache.causeway.core.transaction.scope.NoopTransactionSynchronizationService; +import org.apache.causeway.core.transaction.scope.TransactionScopeBeanFactoryPostProcessor; + import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; @@ -27,6 +30,8 @@ import org.apache.causeway.core.transaction.changetracking.events.TimestampServi @Import({ // @Service's TimestampService.class, + TransactionScopeBeanFactoryPostProcessor.class, + NoopTransactionSynchronizationService.class, }) public class CausewayModuleCoreTransaction { diff --git a/core/transaction/src/main/java/org/apache/causeway/core/transaction/scope/NoopTransactionSynchronizationService.java b/core/transaction/src/main/java/org/apache/causeway/core/transaction/scope/NoopTransactionSynchronizationService.java new file mode 100644 index 0000000000..afe9036eef --- /dev/null +++ b/core/transaction/src/main/java/org/apache/causeway/core/transaction/scope/NoopTransactionSynchronizationService.java @@ -0,0 +1,30 @@ +/* + * Copyright 2002-2020 the original author or authors. + * + * Licensed 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 + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.causeway.core.transaction.scope; + +import org.apache.causeway.applib.annotation.TransactionScope; + +import org.springframework.stereotype.Service; +import org.springframework.transaction.support.TransactionSynchronization; + +/** + * This service, which does nothing in and of itself, exists in order to ensure that the {@link StackedTransactionScope} + * is always initialized, findinag at least one {@link TransactionScope transaction-scope}d service. + */ +@Service +@TransactionScope +public class NoopTransactionSynchronizationService implements TransactionSynchronization { +} diff --git a/core/interaction/src/main/java/org/apache/causeway/core/interaction/scope/StackedTransactionScope.java b/core/transaction/src/main/java/org/apache/causeway/core/transaction/scope/StackedTransactionScope.java similarity index 99% rename from core/interaction/src/main/java/org/apache/causeway/core/interaction/scope/StackedTransactionScope.java rename to core/transaction/src/main/java/org/apache/causeway/core/transaction/scope/StackedTransactionScope.java index 80ca608509..d1a431fb9e 100644 --- a/core/interaction/src/main/java/org/apache/causeway/core/interaction/scope/StackedTransactionScope.java +++ b/core/transaction/src/main/java/org/apache/causeway/core/transaction/scope/StackedTransactionScope.java @@ -1,4 +1,3 @@ - /* * Copyright 2002-2020 the original author or authors. * @@ -14,8 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -package org.apache.causeway.core.interaction.scope; +package org.apache.causeway.core.transaction.scope; import java.util.HashMap; import java.util.LinkedHashMap; diff --git a/core/interaction/src/main/java/org/apache/causeway/core/interaction/scope/TransactionScopeBeanFactoryPostProcessor.java b/core/transaction/src/main/java/org/apache/causeway/core/transaction/scope/TransactionScopeBeanFactoryPostProcessor.java similarity index 96% rename from core/interaction/src/main/java/org/apache/causeway/core/interaction/scope/TransactionScopeBeanFactoryPostProcessor.java rename to core/transaction/src/main/java/org/apache/causeway/core/transaction/scope/TransactionScopeBeanFactoryPostProcessor.java index 51deb40f56..5e84f9c9c5 100644 --- a/core/interaction/src/main/java/org/apache/causeway/core/interaction/scope/TransactionScopeBeanFactoryPostProcessor.java +++ b/core/transaction/src/main/java/org/apache/causeway/core/transaction/scope/TransactionScopeBeanFactoryPostProcessor.java @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.causeway.core.interaction.scope; +package org.apache.causeway.core.transaction.scope; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanFactoryPostProcessor; diff --git a/extensions/vw/pdfjs/metamodel/src/test/java/org/apache/causeway/extensions/pdfjs/metamodel/PdfjsViewer_Abstract_IntegTest.java b/extensions/vw/pdfjs/metamodel/src/test/java/org/apache/causeway/extensions/pdfjs/metamodel/PdfjsViewer_Abstract_IntegTest.java index 8b29374849..4186610697 100644 --- a/extensions/vw/pdfjs/metamodel/src/test/java/org/apache/causeway/extensions/pdfjs/metamodel/PdfjsViewer_Abstract_IntegTest.java +++ b/extensions/vw/pdfjs/metamodel/src/test/java/org/apache/causeway/extensions/pdfjs/metamodel/PdfjsViewer_Abstract_IntegTest.java @@ -42,6 +42,8 @@ import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.TransactionDefinition; import org.springframework.transaction.TransactionException; import org.springframework.transaction.TransactionStatus; +import org.springframework.transaction.support.AbstractPlatformTransactionManager; +import org.springframework.transaction.support.DefaultTransactionStatus; public abstract class PdfjsViewer_Abstract_IntegTest extends CausewayIntegrationTestAbstract { @@ -60,18 +62,25 @@ public abstract class PdfjsViewer_Abstract_IntegTest extends CausewayIntegration @Bean @Singleton public PlatformTransactionManager platformTransactionManager() { - return new PlatformTransactionManager() { + return new AbstractPlatformTransactionManager() { @Override - public void rollback(final TransactionStatus status) throws TransactionException { + protected Object doGetTransaction() throws TransactionException { + return new Object(); } @Override - public TransactionStatus getTransaction(final TransactionDefinition definition) throws TransactionException { - return null; + protected void doBegin(Object transaction, TransactionDefinition definition) throws TransactionException { + + } + + @Override + protected void doCommit(DefaultTransactionStatus status) throws TransactionException { + } @Override - public void commit(final TransactionStatus status) throws TransactionException { + protected void doRollback(DefaultTransactionStatus status) throws TransactionException { + } }; } diff --git a/regressiontests/stable-domainmodel/src/test/java/org/apache/causeway/testdomain/domainmodel/DomainModelTest_usingBadDomain_noAnnotationEnforced.java b/regressiontests/stable-domainmodel/src/test/java/org/apache/causeway/testdomain/domainmodel/DomainModelTest_usingBadDomain_noAnnotationEnforced.java index 114a4be1cd..96bfa272c5 100644 --- a/regressiontests/stable-domainmodel/src/test/java/org/apache/causeway/testdomain/domainmodel/DomainModelTest_usingBadDomain_noAnnotationEnforced.java +++ b/regressiontests/stable-domainmodel/src/test/java/org/apache/causeway/testdomain/domainmodel/DomainModelTest_usingBadDomain_noAnnotationEnforced.java @@ -20,7 +20,12 @@ package org.apache.causeway.testdomain.domainmodel; import javax.inject.Inject; +import org.apache.causeway.testing.integtestsupport.applib.CausewayIntegrationTestAbstract; +import org.apache.causeway.testing.integtestsupport.applib.CausewayInteractionHandler; + import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.TestPropertySource; @@ -54,7 +59,7 @@ import lombok.val; CausewayPresets.SilenceMetaModel, CausewayPresets.SilenceProgrammingModel }) -class DomainModelTest_usingBadDomain_noAnnotationEnforced { +class DomainModelTest_usingBadDomain_noAnnotationEnforced extends CausewayIntegrationTestAbstract { @Inject private CausewayConfiguration configuration; @Inject private CausewaySystemEnvironment causewaySystemEnvironment; diff --git a/regressiontests/stable-domainmodel/src/test/java/org/apache/causeway/testdomain/domainmodel/DomainModelTest_usingGoodDomain.java b/regressiontests/stable-domainmodel/src/test/java/org/apache/causeway/testdomain/domainmodel/DomainModelTest_usingGoodDomain.java index fe2326bd9e..7912d46f55 100644 --- a/regressiontests/stable-domainmodel/src/test/java/org/apache/causeway/testdomain/domainmodel/DomainModelTest_usingGoodDomain.java +++ b/regressiontests/stable-domainmodel/src/test/java/org/apache/causeway/testdomain/domainmodel/DomainModelTest_usingGoodDomain.java @@ -24,6 +24,8 @@ import java.util.stream.Stream; import javax.inject.Inject; +import org.apache.causeway.testing.integtestsupport.applib.CausewayIntegrationTestAbstract; + import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; @@ -130,7 +132,7 @@ import lombok.val; CausewayPresets.SilenceMetaModel, CausewayPresets.SilenceProgrammingModel }) -class DomainModelTest_usingGoodDomain { +class DomainModelTest_usingGoodDomain extends CausewayIntegrationTestAbstract { @Inject private MetaModelService metaModelService; @Inject private JaxbService jaxbService; diff --git a/regressiontests/stable-layouts/src/test/java/org/apache/causeway/regressiontests/layouts/integtest/Layout_Counter_IntegTest.java b/regressiontests/stable-layouts/src/test/java/org/apache/causeway/regressiontests/layouts/integtest/Layout_Counter_IntegTest.java index 27b2a698a0..37fc232b26 100644 --- a/regressiontests/stable-layouts/src/test/java/org/apache/causeway/regressiontests/layouts/integtest/Layout_Counter_IntegTest.java +++ b/regressiontests/stable-layouts/src/test/java/org/apache/causeway/regressiontests/layouts/integtest/Layout_Counter_IntegTest.java @@ -70,6 +70,9 @@ import org.apache.causeway.security.bypass.CausewayModuleSecurityBypass; import org.apache.causeway.testing.integtestsupport.applib.CausewayIntegrationTestAbstract; import org.apache.causeway.viewer.wicket.applib.CausewayModuleViewerWicketApplibMixins; +import org.springframework.transaction.support.AbstractPlatformTransactionManager; +import org.springframework.transaction.support.DefaultTransactionStatus; + import lombok.val; @SpringBootTest( @@ -95,19 +98,26 @@ public class Layout_Counter_IntegTest extends CausewayIntegrationTestAbstract { @Bean @Singleton public PlatformTransactionManager platformTransactionManager() { - return new PlatformTransactionManager() { + return new AbstractPlatformTransactionManager() { @Override - public void rollback(final TransactionStatus status) throws TransactionException { + protected Object doGetTransaction() throws TransactionException { + return null; } @Override - public TransactionStatus getTransaction(final TransactionDefinition definition) throws TransactionException { - return null; + protected void doBegin(Object transaction, TransactionDefinition definition) throws TransactionException { + } @Override - public void commit(final TransactionStatus status) throws TransactionException { + protected void doCommit(DefaultTransactionStatus status) throws TransactionException { + + } + + @Override + protected void doRollback(DefaultTransactionStatus status) throws TransactionException { + } }; } diff --git a/regressiontests/stable-persistence-jdo/src/test/java/org/apache/causeway/testdomain/persistence/jdo/JdoExceptionTranslationTest.java b/regressiontests/stable-persistence-jdo/src/test/java/org/apache/causeway/testdomain/persistence/jdo/JdoExceptionTranslationTest.java index 59ac3c3c2a..2f31e0a0db 100644 --- a/regressiontests/stable-persistence-jdo/src/test/java/org/apache/causeway/testdomain/persistence/jdo/JdoExceptionTranslationTest.java +++ b/regressiontests/stable-persistence-jdo/src/test/java/org/apache/causeway/testdomain/persistence/jdo/JdoExceptionTranslationTest.java @@ -22,15 +22,16 @@ import java.sql.SQLException; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.dao.DataAccessException; -import org.springframework.test.context.TestPropertySource; -import org.springframework.test.context.TestPropertySources; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.dao.DataAccessException; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.TestPropertySources; + import org.apache.causeway.core.config.presets.CausewayPresets; import org.apache.causeway.testdomain.conf.Configuration_usingJdo; import org.apache.causeway.testdomain.jdo.RegressionTestWithJdoFixtures; @@ -49,7 +50,6 @@ import lombok.val; @TestPropertySources({ @TestPropertySource(CausewayPresets.UseLog4j2Test) }) -//@Transactional ... we manage transaction ourselves class JdoExceptionTranslationTest extends RegressionTestWithJdoFixtures { @BeforeAll diff --git a/regressiontests/stable-persistence-jdo/src/test/java/org/apache/causeway/testdomain/persistence/jdo/JdoJaxbTest.java b/regressiontests/stable-persistence-jdo/src/test/java/org/apache/causeway/testdomain/persistence/jdo/JdoJaxbTest.java index cf57499752..2ebefdc81a 100644 --- a/regressiontests/stable-persistence-jdo/src/test/java/org/apache/causeway/testdomain/persistence/jdo/JdoJaxbTest.java +++ b/regressiontests/stable-persistence-jdo/src/test/java/org/apache/causeway/testdomain/persistence/jdo/JdoJaxbTest.java @@ -20,6 +20,7 @@ package org.apache.causeway.testdomain.persistence.jdo; import javax.inject.Inject; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.TestPropertySource; @@ -45,6 +46,7 @@ class JdoJaxbTest extends RegressionTestWithJdoFixtures { @Inject private JaxbService jaxbService; + // @Disabled // CAUSEWAY-3654 @Test void inventoryJaxbVm_shouldRoundtripProperly() { diff --git a/regressiontests/stable-persistence-jdo/src/test/java/org/apache/causeway/testdomain/transactions/jdo/JdoTransactionScopeListenerTest.java b/regressiontests/stable-persistence-jdo/src/test/java/org/apache/causeway/testdomain/transactions/jdo/JdoTransactionScopeListenerTest.java deleted file mode 100644 index e0f6eb3b9d..0000000000 --- a/regressiontests/stable-persistence-jdo/src/test/java/org/apache/causeway/testdomain/transactions/jdo/JdoTransactionScopeListenerTest.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.causeway.testdomain.transactions.jdo; - -import javax.inject.Inject; - -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.TestPropertySource; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -import org.apache.causeway.applib.services.iactnlayer.InteractionService; -import org.apache.causeway.applib.services.repository.RepositoryService; -import org.apache.causeway.applib.services.xactn.TransactionService; -import org.apache.causeway.core.config.presets.CausewayPresets; -import org.apache.causeway.testdomain.conf.Configuration_usingJdo; -import org.apache.causeway.testdomain.fixtures.EntityTestFixtures; -import org.apache.causeway.testdomain.jdo.JdoTestFixtures; -import org.apache.causeway.testdomain.jdo.entities.JdoBook; -import org.apache.causeway.testdomain.util.interaction.InteractionBoundaryProbe; -import org.apache.causeway.testdomain.util.kv.KVStoreForTesting; - -@SpringBootTest( - classes = { - Configuration_usingJdo.class, - InteractionBoundaryProbe.class - }, - properties = { - "spring.datasource.url=jdbc:h2:mem:JdoTransactionScopeListenerTest" - }) -//@Transactional -@TestPropertySource(CausewayPresets.UseLog4j2Test) -/** - * With this test we manage CausewayInteractions ourselves. (not sub-classing CausewayIntegrationTestAbstract) - */ -class JdoTransactionScopeListenerTest { - - @Inject private JdoTestFixtures jdoTestFixtures; - @Inject private TransactionService transactionService; - @Inject private RepositoryService repository; - @Inject private InteractionService interactionService; - @Inject private KVStoreForTesting kvStoreForTesting; - private EntityTestFixtures.Lock lock; - - /* Expectations: - * 1. for each InteractionScope there should be a new InteractionBoundaryProbe instance - * 2. for each Transaction the current InteractionBoundaryProbe should get notified - * - * first we have 1 InteractionScope with 1 expected Transaction during 'setUp' - * then we have 1 InteractionScope with 3 expected Transactions within the test method - * - */ - - @BeforeEach - void setUp() { - // clear repository - lock = jdoTestFixtures.aquireLockAndClear(); - } - - @AfterEach - void cleanUp() { - // clear repository - lock.release(); - } - - @Test - void sessionScopedProbe_shouldBeReused_andBeAwareofTransactionBoundaries() { - - assertEquals(0, InteractionBoundaryProbe.totalInteractionsStarted(kvStoreForTesting)); - assertEquals(0, InteractionBoundaryProbe.totalInteractionsEnded(kvStoreForTesting)); - assertEquals(0, InteractionBoundaryProbe.totalTransactionsEnding(kvStoreForTesting)); - assertEquals(0, InteractionBoundaryProbe.totalTransactionsCommitted(kvStoreForTesting)); - - // new InteractionScope with a new transaction (#1) - interactionService.runAnonymous(()->{ - - // expected pre condition - // reuse transaction (#1) - assertEquals(0, repository.allInstances(JdoBook.class).size()); - - // reuse transaction (#1) - transactionService.runWithinCurrentTransactionElseCreateNew(()->{ - // + 1 interaction + 1 transaction - jdoTestFixtures.add3Books(); - }) - .ifFailureFail(); - - // expected post condition - // reuse transaction (#1) - assertEquals(3, repository.allInstances(JdoBook.class).size()); - - }); - - assertEquals(1, InteractionBoundaryProbe.totalInteractionsStarted(kvStoreForTesting)); - assertEquals(1, InteractionBoundaryProbe.totalInteractionsEnded(kvStoreForTesting)); - assertEquals(1, InteractionBoundaryProbe.totalTransactionsEnding(kvStoreForTesting)); - assertEquals(1, InteractionBoundaryProbe.totalTransactionsCommitted(kvStoreForTesting)); - - } - - -} diff --git a/regressiontests/stable-persistence-jpa/src/test/java/org/apache/causeway/testdomain/persistence/jpa/JpaExceptionTranslationTest.java b/regressiontests/stable-persistence-jpa/src/test/java/org/apache/causeway/testdomain/persistence/jpa/JpaExceptionTranslationTest.java index ed487ed662..f8afe0c294 100644 --- a/regressiontests/stable-persistence-jpa/src/test/java/org/apache/causeway/testdomain/persistence/jpa/JpaExceptionTranslationTest.java +++ b/regressiontests/stable-persistence-jpa/src/test/java/org/apache/causeway/testdomain/persistence/jpa/JpaExceptionTranslationTest.java @@ -22,15 +22,17 @@ import java.sql.SQLException; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.dao.DataAccessException; -import org.springframework.test.context.TestPropertySource; -import org.springframework.test.context.TestPropertySources; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.dao.DataAccessException; +import org.springframework.dao.DuplicateKeyException; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.TestPropertySources; + import org.apache.causeway.core.config.presets.CausewayPresets; import org.apache.causeway.testdomain.conf.Configuration_usingJpa; import org.apache.causeway.testdomain.jpa.RegressionTestWithJpaFixtures; @@ -44,12 +46,11 @@ import lombok.val; }, properties = { "spring.datasource.url=jdbc:h2:mem:JpaExceptionTranslationTest", - }) + } +) @TestPropertySources({ @TestPropertySource(CausewayPresets.UseLog4j2Test) }) -//@Transactional ... we manage transaction ourselves -//@DirtiesContext class JpaExceptionTranslationTest extends RegressionTestWithJpaFixtures { @BeforeAll @@ -61,7 +62,6 @@ class JpaExceptionTranslationTest extends RegressionTestWithJpaFixtures { @Test void booksUniqueByIsbn_whenViolated_shouldThrowTranslatedException() { - // when adding a book for which one with same ISBN already exists in the database, // we expect to see a Spring recognized DataAccessException been thrown @@ -102,7 +102,5 @@ class JpaExceptionTranslationTest extends RegressionTestWithJpaFixtures { testFixtures.assertInventoryHasBooks(inventory.getProducts(), 1, 2, 3); }); - } - } diff --git a/regressiontests/stable-persistence-jpa/src/test/java/org/apache/causeway/testdomain/transactions/jpa/CommitListener.java b/regressiontests/stable-persistence-jpa/src/test/java/org/apache/causeway/testdomain/transactions/jpa/CommitListener.java new file mode 100644 index 0000000000..804b372519 --- /dev/null +++ b/regressiontests/stable-persistence-jpa/src/test/java/org/apache/causeway/testdomain/transactions/jpa/CommitListener.java @@ -0,0 +1,78 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.causeway.testdomain.transactions.jpa; + +import lombok.NonNull; +import lombok.RequiredArgsConstructor; + +import java.util.Optional; +import java.util.function.Consumer; + +import org.apache.causeway.applib.annotation.TransactionScope; +import org.apache.causeway.applib.annotation.Value; +import org.apache.causeway.core.transaction.events.TransactionCompletionStatus; + +import org.springframework.stereotype.Service; +import org.springframework.transaction.support.TransactionSynchronization; + +@Service +@TransactionScope +public class CommitListener implements TransactionSynchronization { + + + @Value + @RequiredArgsConstructor + public static class TransactionAfterCompletionEvent { + final TransactionCompletionStatus transactionCompletionStatus; + } + +// /** transaction end boundary (pre) */ +// @EventListener(TransactionBeforeCompletionEvent.class) +// public void onPreCompletion(final TransactionBeforeCompletionEvent event) { +// //_Probe.errOut("=== TRANSACTION before completion"); +// } + + +// /** transaction end boundary (post) */ +// @EventListener(TransactionAfterCompletionEvent.class) +// public void onPostCompletion(final TransactionAfterCompletionEvent event) {...} + + @Override + public void afterCompletion(int status) { + TransactionCompletionStatus transactionCompletionStatus = TransactionCompletionStatus.forStatus(status); + TransactionAfterCompletionEvent event = new TransactionAfterCompletionEvent(transactionCompletionStatus); + //_Probe.errOut("=== TRANSACTION after completion (%s)", event.name()); + Optional.ofNullable(listener) + .ifPresent(li -> { + li.accept(event); + unbind(); + }); + } + + private Consumer<TransactionAfterCompletionEvent> listener; + + void bind(final @NonNull Consumer<TransactionAfterCompletionEvent> listener) { + this.listener = listener; + } + + void unbind() { + this.listener = null; + } + +} diff --git a/regressiontests/stable-persistence-jpa/src/test/java/org/apache/causeway/testdomain/transactions/jpa/JpaTransactionRollbackTest_usingInteractionService.java b/regressiontests/stable-persistence-jpa/src/test/java/org/apache/causeway/testdomain/transactions/jpa/JpaTransactionRollbackTest_usingInteractionService.java index fb80bc4358..e597e07e72 100644 --- a/regressiontests/stable-persistence-jpa/src/test/java/org/apache/causeway/testdomain/transactions/jpa/JpaTransactionRollbackTest_usingInteractionService.java +++ b/regressiontests/stable-persistence-jpa/src/test/java/org/apache/causeway/testdomain/transactions/jpa/JpaTransactionRollbackTest_usingInteractionService.java @@ -23,6 +23,10 @@ import java.util.function.Consumer; import javax.inject.Inject; +import org.apache.causeway.applib.annotation.TransactionScope; + +import org.apache.causeway.core.transaction.events.TransactionCompletionStatus; + import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -49,13 +53,15 @@ import org.apache.causeway.testdomain.jpa.entities.JpaBook; import org.apache.causeway.testing.fixtures.applib.fixturescripts.FixtureScripts; import org.apache.causeway.testing.integtestsupport.applib.CausewayInteractionHandler; +import org.springframework.transaction.support.TransactionSynchronization; + import lombok.NonNull; import lombok.val; @SpringBootTest( classes = { Configuration_usingJpa.class, - JpaTransactionRollbackTest_usingInteractionService.CommitListener.class + CommitListener.class }, properties = { "spring.datasource.url=jdbc:h2:mem:JpaTransactionRollbackTest_usingInteractionService", @@ -76,7 +82,7 @@ class JpaTransactionRollbackTest_usingInteractionService @Inject private RepositoryService repository; @Inject private CommitListener commitListener; - private ObjectReference<TransactionAfterCompletionEvent> transactionAfterCompletionEvent; + private ObjectReference<CommitListener.TransactionAfterCompletionEvent> transactionAfterCompletionEvent; @BeforeEach void setUp() { @@ -84,8 +90,7 @@ class JpaTransactionRollbackTest_usingInteractionService // cleanup fixtureScripts.runPersona(JpaTestDomainPersona.InventoryPurgeAll); - transactionAfterCompletionEvent = - _Refs.<TransactionAfterCompletionEvent>objectRef(null); + transactionAfterCompletionEvent = _Refs.objectRef(null); } @AfterEach @@ -109,8 +114,8 @@ class JpaTransactionRollbackTest_usingInteractionService }); assertEquals( - TransactionAfterCompletionEvent.COMMITTED, - transactionAfterCompletionEvent.getValueElseDefault(null)); + TransactionCompletionStatus.COMMITTED, + transactionAfterCompletionEvent.getValue().map(x -> x.transactionCompletionStatus).orElse(null)); transactionService.runWithinCurrentTransactionElseCreateNew(()->{ @@ -144,8 +149,8 @@ class JpaTransactionRollbackTest_usingInteractionService assertTrue(result.isFailure()); assertEquals( - TransactionAfterCompletionEvent.ROLLED_BACK, - transactionAfterCompletionEvent.getValueElseDefault(null)); + TransactionCompletionStatus.ROLLED_BACK, + transactionAfterCompletionEvent.getValue().map(x -> x.transactionCompletionStatus).orElse(null)); transactionService.runWithinCurrentTransactionElseCreateNew(()->{ @@ -190,9 +195,9 @@ class JpaTransactionRollbackTest_usingInteractionService // interactionService detects whether a rollback was requested and does not throw in such a case assertTrue(result.isSuccess()); - val actualEvent = transactionAfterCompletionEvent.getValueElseDefault(null); - assertTrue( - actualEvent == TransactionAfterCompletionEvent.ROLLED_BACK); + assertEquals( + TransactionCompletionStatus.ROLLED_BACK, + transactionAfterCompletionEvent.getValue().map(x -> x.transactionCompletionStatus).orElse(null)); transactionService.runWithinCurrentTransactionElseCreateNew(()->{ @@ -204,37 +209,4 @@ class JpaTransactionRollbackTest_usingInteractionService // -- HELPER - @Service - public static class CommitListener { - - /** transaction end boundary (pre) */ - @EventListener(TransactionBeforeCompletionEvent.class) - public void onPreCompletion(final TransactionBeforeCompletionEvent event) { - //_Probe.errOut("=== TRANSACTION before completion"); - } - - /** transaction end boundary (post) */ - @EventListener(TransactionAfterCompletionEvent.class) - public void onPostCompletion(final TransactionAfterCompletionEvent event) { - //_Probe.errOut("=== TRANSACTION after completion (%s)", event.name()); - Optional.ofNullable(listener) - .ifPresent(li->{ - li.accept(event); - unbind(); - }); - } - - private Consumer<TransactionAfterCompletionEvent> listener; - - void bind(final @NonNull Consumer<TransactionAfterCompletionEvent> listener) { - this.listener = listener; - } - - void unbind() { - this.listener = null; - } - - } - - } diff --git a/regressiontests/stable-persistence-jpa/src/test/java/org/apache/causeway/testdomain/transactions/jpa/JpaTransactionRollbackTest_usingTransactionService.java b/regressiontests/stable-persistence-jpa/src/test/java/org/apache/causeway/testdomain/transactions/jpa/JpaTransactionRollbackTest_usingTransactionService.java index 6d295dd39e..1c3af590a9 100644 --- a/regressiontests/stable-persistence-jpa/src/test/java/org/apache/causeway/testdomain/transactions/jpa/JpaTransactionRollbackTest_usingTransactionService.java +++ b/regressiontests/stable-persistence-jpa/src/test/java/org/apache/causeway/testdomain/transactions/jpa/JpaTransactionRollbackTest_usingTransactionService.java @@ -18,19 +18,18 @@ */ package org.apache.causeway.testdomain.transactions.jpa; -import java.util.Optional; -import java.util.function.Consumer; - import javax.inject.Inject; +import org.apache.causeway.commons.internal.base._Refs; + +import org.apache.causeway.core.transaction.events.TransactionCompletionStatus; + import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.DisabledIfSystemProperty; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.context.event.EventListener; -import org.springframework.stereotype.Service; import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.context.TestPropertySource; @@ -39,8 +38,6 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import org.apache.causeway.applib.services.repository.RepositoryService; import org.apache.causeway.applib.services.xactn.TransactionService; -import org.apache.causeway.commons.internal.base._Refs; -import org.apache.causeway.commons.internal.base._Refs.ObjectReference; import org.apache.causeway.core.config.presets.CausewayPresets; import org.apache.causeway.testdomain.conf.Configuration_usingJpa; import org.apache.causeway.testdomain.jpa.JpaTestDomainPersona; @@ -48,13 +45,12 @@ import org.apache.causeway.testdomain.jpa.entities.JpaBook; import org.apache.causeway.testing.fixtures.applib.fixturescripts.FixtureScripts; import org.apache.causeway.testing.integtestsupport.applib.CausewayInteractionHandler; -import lombok.NonNull; import lombok.val; @SpringBootTest( classes = { Configuration_usingJpa.class, - JpaTransactionRollbackTest_usingTransactionService.CommitListener.class + CommitListener.class }, properties = { "spring.datasource.url=jdbc:h2:mem:JpaTransactionRollbackTest_usingTransactionService", @@ -74,7 +70,7 @@ class JpaTransactionRollbackTest_usingTransactionService @Inject private RepositoryService repository; @Inject private CommitListener commitListener; - private ObjectReference<TransactionAfterCompletionEvent> transactionAfterCompletionEvent; + private _Refs.ObjectReference<CommitListener.TransactionAfterCompletionEvent> transactionAfterCompletionEvent; @BeforeEach void setUp() { @@ -82,8 +78,7 @@ class JpaTransactionRollbackTest_usingTransactionService // cleanup fixtureScripts.runPersona(JpaTestDomainPersona.InventoryPurgeAll); - transactionAfterCompletionEvent = - _Refs.<TransactionAfterCompletionEvent>objectRef(null); + transactionAfterCompletionEvent = _Refs.objectRef(null); } @AfterEach @@ -107,8 +102,8 @@ class JpaTransactionRollbackTest_usingTransactionService }); assertEquals( - TransactionAfterCompletionEvent.COMMITTED, - transactionAfterCompletionEvent.getValueElseDefault(null)); + TransactionCompletionStatus.COMMITTED, + transactionAfterCompletionEvent.getValue().map(x -> x.transactionCompletionStatus).orElse(null)); transactionService.runWithinCurrentTransactionElseCreateNew(()->{ @@ -142,8 +137,8 @@ class JpaTransactionRollbackTest_usingTransactionService assertTrue(result.isFailure()); assertEquals( - TransactionAfterCompletionEvent.ROLLED_BACK, - transactionAfterCompletionEvent.getValueElseDefault(null)); + TransactionCompletionStatus.ROLLED_BACK, + transactionAfterCompletionEvent.getValue().map(x -> x.transactionCompletionStatus).orElse(null)); transactionService.runWithinCurrentTransactionElseCreateNew(()->{ @@ -187,10 +182,10 @@ class JpaTransactionRollbackTest_usingTransactionService assertTrue(result.isFailure()); - val actualEvent = transactionAfterCompletionEvent.getValueElseDefault(null); + val actualEvent = transactionAfterCompletionEvent.getValue().map(x -> x.transactionCompletionStatus).orElse(null); assertTrue( - actualEvent == TransactionAfterCompletionEvent.ROLLED_BACK - || actualEvent == TransactionAfterCompletionEvent.UNKNOWN); + actualEvent == TransactionCompletionStatus.ROLLED_BACK + || actualEvent == TransactionCompletionStatus.UNKNOWN); transactionService.runWithinCurrentTransactionElseCreateNew(()->{ @@ -202,37 +197,5 @@ class JpaTransactionRollbackTest_usingTransactionService // -- HELPER - @Service - public static class CommitListener { - - /** transaction end boundary (pre) */ - @EventListener(TransactionBeforeCompletionEvent.class) - public void onPreCompletion(final TransactionBeforeCompletionEvent event) { - //_Probe.errOut("=== TRANSACTION before completion"); - } - - /** transaction end boundary (post) */ - @EventListener(TransactionAfterCompletionEvent.class) - public void onPostCompletion(final TransactionAfterCompletionEvent event) { - //_Probe.errOut("=== TRANSACTION after completion (%s)", event.name()); - Optional.ofNullable(listener) - .ifPresent(li->{ - li.accept(event); - unbind(); - }); - } - - private Consumer<TransactionAfterCompletionEvent> listener; - - void bind(final @NonNull Consumer<TransactionAfterCompletionEvent> listener) { - this.listener = listener; - } - - void unbind() { - this.listener = null; - } - - } - } diff --git a/regressiontests/stable/src/main/java/org/apache/causeway/testdomain/RegressionTestAbstract.java b/regressiontests/stable/src/main/java/org/apache/causeway/testdomain/RegressionTestAbstract.java index 43f0fa1d31..1c6a3dd564 100644 --- a/regressiontests/stable/src/main/java/org/apache/causeway/testdomain/RegressionTestAbstract.java +++ b/regressiontests/stable/src/main/java/org/apache/causeway/testdomain/RegressionTestAbstract.java @@ -22,6 +22,8 @@ import java.util.concurrent.Callable; import javax.inject.Inject; +import org.apache.causeway.testing.integtestsupport.applib.CausewayIntegrationTestAbstract; + import org.springframework.transaction.annotation.Propagation; import org.apache.causeway.applib.services.bookmark.BookmarkService; @@ -40,16 +42,15 @@ import org.apache.causeway.core.metamodel.objectmanager.ObjectManager; public abstract class RegressionTestAbstract { protected void run(final ThrowingRunnable runnable) { - transactionService.runTransactional(Propagation.REQUIRES_NEW, ()-> - interactionService.runAnonymous(runnable)) - .ifFailureFail(); + interactionService.runAnonymous(() -> + transactionService.runTransactional(Propagation.REQUIRES_NEW, runnable).ifFailureFail() + ); } protected <T> T call(final Callable<T> callable) { - return transactionService.callTransactional(Propagation.REQUIRES_NEW, ()-> - interactionService.callAnonymous(callable)) - // assuming return value of callable is not nullable - .valueAsNonNullElseFail(); + return interactionService.callAnonymous(() -> + transactionService.callTransactional(Propagation.REQUIRES_NEW, callable)) + .valueAsNonNullElseFail(); } // -- ASSERTIONS diff --git a/regressiontests/stable/src/main/java/org/apache/causeway/testdomain/conf/Configuration_headless.java b/regressiontests/stable/src/main/java/org/apache/causeway/testdomain/conf/Configuration_headless.java index 29b93681f6..2378fd7e87 100644 --- a/regressiontests/stable/src/main/java/org/apache/causeway/testdomain/conf/Configuration_headless.java +++ b/regressiontests/stable/src/main/java/org/apache/causeway/testdomain/conf/Configuration_headless.java @@ -21,6 +21,8 @@ package org.apache.causeway.testdomain.conf; import javax.inject.Inject; import javax.inject.Singleton; +import org.apache.causeway.applib.annotation.TransactionScope; + import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; @@ -41,13 +43,16 @@ import org.apache.causeway.security.bypass.CausewayModuleSecurityBypass; import org.apache.causeway.testdomain.util.interaction.DomainObjectTesterFactory; import org.apache.causeway.testdomain.util.kv.KVStoreForTesting; +import org.springframework.transaction.support.AbstractPlatformTransactionManager; +import org.springframework.transaction.support.DefaultTransactionStatus; +import org.springframework.transaction.support.TransactionSynchronization; + import lombok.RequiredArgsConstructor; @Configuration @Import({ CausewayModuleCoreRuntimeServices.class, CausewayModuleSecurityBypass.class, - Configuration_headless.HeadlessCommandSupport.class, KVStoreForTesting.class, // Helper for JUnit Tests DomainObjectTesterFactory.class // Helper for JUnit Tests }) @@ -56,53 +61,29 @@ import lombok.RequiredArgsConstructor; }) public class Configuration_headless { - @Service - @javax.annotation.Priority(PriorityPrecedence.MIDPOINT) - @RequiredArgsConstructor(onConstructor_ = {@Inject}) - public static class HeadlessCommandSupport - implements TransactionBoundaryAware { - - @Override - public void beforeEnteringTransactionalBoundary(final Interaction interaction) { -// _Probe.errOut("Interaction HAS_STARTED conversationId=%s", interaction.getInteractionId()); - setupCommandCreateIfMissing(); - } - - @Override - public void afterLeavingTransactionalBoundary(final Interaction interaction) { -// _Probe.errOut("Interaction IS_ENDING conversationId=%s", interaction.getInteractionId()); - } - - public void setupCommandCreateIfMissing() { - -// val interactionProvider = interactionProviderProvider.get(); -// @SuppressWarnings("unused") -// final Interaction interaction = Optional.ofNullable(interactionContext.getInteraction()) -// .orElseGet(()->{ -// val newCommand = new Command(); -// val newInteraction = new Interaction(newCommand); -// interactionProvider.setInteraction(newInteraction); -// return newInteraction; -// }); - } - - } @Bean @Singleton public PlatformTransactionManager platformTransactionManager() { - return new PlatformTransactionManager() { + return new AbstractPlatformTransactionManager() { @Override - public void rollback(final TransactionStatus status) throws TransactionException { + protected Object doGetTransaction() throws TransactionException { + return null; } @Override - public TransactionStatus getTransaction(final TransactionDefinition definition) throws TransactionException { - return null; + protected void doBegin(Object transaction, TransactionDefinition definition) throws TransactionException { + + } + + @Override + protected void doCommit(DefaultTransactionStatus status) throws TransactionException { + } @Override - public void commit(final TransactionStatus status) throws TransactionException { + protected void doRollback(DefaultTransactionStatus status) throws TransactionException { + } }; } diff --git a/regressiontests/stable/src/main/java/org/apache/causeway/testdomain/publishing/PublishingTestFactoryAbstract.java b/regressiontests/stable/src/main/java/org/apache/causeway/testdomain/publishing/PublishingTestFactoryAbstract.java index 46e344f5f2..3a21164369 100644 --- a/regressiontests/stable/src/main/java/org/apache/causeway/testdomain/publishing/PublishingTestFactoryAbstract.java +++ b/regressiontests/stable/src/main/java/org/apache/causeway/testdomain/publishing/PublishingTestFactoryAbstract.java @@ -24,6 +24,10 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; import java.util.function.BiConsumer; +import org.apache.causeway.applib.annotation.TransactionScope; + +import org.apache.causeway.core.transaction.events.TransactionCompletionStatus; + import org.junit.jupiter.api.DynamicTest; import org.springframework.context.event.EventListener; import org.springframework.stereotype.Service; @@ -47,6 +51,8 @@ import org.apache.causeway.commons.internal.debug.xray.XrayModel.Stickiness; import org.apache.causeway.commons.internal.debug.xray.XrayModel.ThreadMemento; import org.apache.causeway.commons.internal.debug.xray.XrayUi; +import org.springframework.transaction.support.TransactionSynchronization; + import lombok.Getter; import lombok.NonNull; import lombok.RequiredArgsConstructor; @@ -158,13 +164,17 @@ public abstract class PublishingTestFactoryAbstract { * to, until the end of the test's exclusive transaction. */ @Service - public static class CommitListener { + @TransactionScope + public static class CommitListener implements TransactionSynchronization { private PublishingTestContext testContext; - /** transaction end boundary (pre) */ - @EventListener(TransactionBeforeCompletionEvent.class) - public void onPreCompletion(final TransactionBeforeCompletionEvent event) { +// /** transaction end boundary (pre) */ +// @EventListener(TransactionBeforeCompletionEvent.class) +// public void onPreCompletion(final TransactionBeforeCompletionEvent event) { + + @Override + public void beforeCompletion() { _Probe.errOut("=== TRANSACTION before completion"); if(testContext!=null) { testContext.getTraceLog().log("3.1 pre-commit event is occurring"); @@ -172,13 +182,18 @@ public abstract class PublishingTestFactoryAbstract { } } - /** transaction end boundary (post) */ - @EventListener(TransactionAfterCompletionEvent.class) - public void onPostCompletion(final TransactionAfterCompletionEvent event) { +// /** transaction end boundary (post) */ +// @EventListener(TransactionAfterCompletionEvent.class) +// public void onPostCompletion(final TransactionAfterCompletionEvent event) { + + @Override + public void afterCompletion(int status) { + + TransactionCompletionStatus transactionCompletionStatus = TransactionCompletionStatus.forStatus(status); _Probe.errOut("=== TRANSACTION after completion"); if(testContext!=null) { try { - if(event.isCommitted()) { + if(transactionCompletionStatus.isCommitted()) { testContext.getTraceLog().log("3.2 post-commit event is occurring"); testContext.runVerify(VerificationStage.POST_COMMIT); } else { diff --git a/regressiontests/stable/src/main/java/org/apache/causeway/testdomain/util/interaction/InteractionBoundaryProbe.java b/regressiontests/stable/src/main/java/org/apache/causeway/testdomain/util/interaction/InteractionBoundaryProbe.java index 33c97b25e1..b097e181e1 100644 --- a/regressiontests/stable/src/main/java/org/apache/causeway/testdomain/util/interaction/InteractionBoundaryProbe.java +++ b/regressiontests/stable/src/main/java/org/apache/causeway/testdomain/util/interaction/InteractionBoundaryProbe.java @@ -22,6 +22,10 @@ import java.util.function.Supplier; import javax.inject.Inject; +import org.apache.causeway.applib.annotation.TransactionScope; + +import org.apache.causeway.core.transaction.events.TransactionCompletionStatus; + import org.junit.jupiter.api.Assertions; import org.springframework.context.event.EventListener; import org.springframework.core.annotation.Order; @@ -31,42 +35,56 @@ import org.apache.causeway.applib.annotation.PriorityPrecedence; import org.apache.causeway.applib.services.iactn.Interaction; import org.apache.causeway.testdomain.util.kv.KVStoreForTesting; +import org.springframework.transaction.support.TransactionSynchronization; + import lombok.val; import lombok.extern.log4j.Log4j2; @Service +@TransactionScope @Log4j2 -public class InteractionBoundaryProbe implements TransactionBoundaryAware { +public class InteractionBoundaryProbe implements TransactionSynchronization { @Inject private KVStoreForTesting kvStoreForTesting; - /** INTERACTION BEGIN BOUNDARY */ - @Override - public void beforeEnteringTransactionalBoundary(Interaction interaction) { - log.debug("iaStarted"); - kvStoreForTesting.incrementCounter(InteractionBoundaryProbe.class, "iaStarted"); - } +// /** INTERACTION BEGIN BOUNDARY */ +// @Override +// public void beforeEnteringTransactionalBoundary(Interaction interaction) { +// log.debug("iaStarted"); +// kvStoreForTesting.incrementCounter(InteractionBoundaryProbe.class, "iaStarted"); +// } + +// /** INTERACTION END BOUNDARY */ +// @Override +// public void afterLeavingTransactionalBoundary(Interaction interaction) { +// log.debug("iaEnded"); +// kvStoreForTesting.incrementCounter(InteractionBoundaryProbe.class, "iaEnded"); +// } + + +// /** TRANSACTION BEGIN BOUNDARY */ +// @EventListener(TransactionBeforeCompletionEvent.class) @Order(PriorityPrecedence.FIRST + 100) +// public void onTransactionEnding(TransactionBeforeCompletionEvent event) { - /** INTERACTION END BOUNDARY */ @Override - public void afterLeavingTransactionalBoundary(Interaction interaction) { - log.debug("iaEnded"); - kvStoreForTesting.incrementCounter(InteractionBoundaryProbe.class, "iaEnded"); - } + public void beforeCompletion() { + TransactionSynchronization.super.beforeCompletion(); - /** TRANSACTION BEGIN BOUNDARY */ - @EventListener(TransactionBeforeCompletionEvent.class) @Order(PriorityPrecedence.FIRST + 100) - public void onTransactionEnding(TransactionBeforeCompletionEvent event) { log.debug("txStarted"); kvStoreForTesting.incrementCounter(InteractionBoundaryProbe.class, "txEnding"); } - /** TRANSACTION END BOUNDARY */ - @EventListener(TransactionAfterCompletionEvent.class) @Order(PriorityPrecedence.LAST - 100) - public void onTransactionEnded(TransactionAfterCompletionEvent event) { - if(event.isRolledBack()) { +// /** TRANSACTION END BOUNDARY */ +// @EventListener(TransactionAfterCompletionEvent.class) @Order(PriorityPrecedence.LAST - 100) +// public void onTransactionEnded(TransactionAfterCompletionEvent event) { + + @Override + public void afterCompletion(int status) { + TransactionCompletionStatus transactionCompletionStatus = TransactionCompletionStatus.forStatus(status); + + if(transactionCompletionStatus.isRolledBack()) { kvStoreForTesting.incrementCounter(InteractionBoundaryProbe.class, "txRolledBack"); - } else if(event.isCommitted()) { + } else if(transactionCompletionStatus.isCommitted()) { kvStoreForTesting.incrementCounter(InteractionBoundaryProbe.class, "txCommitted"); } } @@ -130,5 +148,4 @@ public class InteractionBoundaryProbe implements TransactionBoundaryAware { return result; } - }