diff --git a/config/src/main/java/org/axonframework/config/MessageHandlerRegistrar.java b/config/src/main/java/org/axonframework/config/MessageHandlerRegistrar.java index 9d5406f0ff..dc956bcedd 100644 --- a/config/src/main/java/org/axonframework/config/MessageHandlerRegistrar.java +++ b/config/src/main/java/org/axonframework/config/MessageHandlerRegistrar.java @@ -19,7 +19,10 @@ import org.axonframework.common.Registration; import org.axonframework.lifecycle.Lifecycle; import org.axonframework.lifecycle.Phase; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import java.lang.invoke.MethodHandles; import java.util.function.BiFunction; import java.util.function.Function; import java.util.function.Supplier; @@ -39,6 +42,8 @@ */ public class MessageHandlerRegistrar implements Lifecycle { + private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); + private final Supplier configurationSupplier; private final Function messageHandlerBuilder; private final BiFunction messageHandlerSubscriber; @@ -90,6 +95,10 @@ public void start() { * through the {@link #start()} method. */ public void shutdown() { + if (handlerRegistration == null) { + logger.info("Shutting down a message handler registrar before it was started."); + return; + } handlerRegistration.cancel(); } } diff --git a/config/src/test/java/org/axonframework/config/DefaultConfigurerTest.java b/config/src/test/java/org/axonframework/config/DefaultConfigurerTest.java index 06e6b792cc..925d684f38 100644 --- a/config/src/test/java/org/axonframework/config/DefaultConfigurerTest.java +++ b/config/src/test/java/org/axonframework/config/DefaultConfigurerTest.java @@ -705,6 +705,17 @@ void registeringUpcastersReturnsUpcasterChainOverRulingRegisteredUpcasterChainCo verifyNoInteractions(testUpcasterChain); } + @Test + void shuttingDownTheConfigurationBeforeItStartedWithConfiguredMessageHandlersDoesNotCauseAnyExceptions() { + Configuration configuration = DefaultConfigurer.defaultConfiguration() + .registerCommandHandler(c -> new Object()) + .registerEventHandler(c -> new Object()) + .registerQueryHandler(c -> new Object()) + .registerMessageHandler(c -> new Object()) + .buildConfiguration(); + assertDoesNotThrow(configuration::shutdown); + } + @SuppressWarnings("unused") @Entity(name = "StubAggregate") private static class StubAggregate { diff --git a/config/src/test/java/org/axonframework/config/MessageHandlerRegistrarTest.java b/config/src/test/java/org/axonframework/config/MessageHandlerRegistrarTest.java index 4807fedf8b..45d12da493 100644 --- a/config/src/test/java/org/axonframework/config/MessageHandlerRegistrarTest.java +++ b/config/src/test/java/org/axonframework/config/MessageHandlerRegistrarTest.java @@ -65,36 +65,39 @@ void startRegistersCreatedMessageHandler(@Mock Configuration config) { assertTrue(isRegistered.get()); } - /** - * The thrown {@link NullPointerException} will always be wrapped in a {@link org.axonframework.lifecycle.LifecycleHandlerInvocationException} - * since the {@link MessageHandlerRegistrar#shutdown()} will be wrapped in a {@link LifecycleHandler}. - */ @Test - void shutdownThrowsNullPointerExceptionIfRegistrationDidNotHappen(@Mock Configuration config) { + void shutdownCancelsMessageHandlerRegistration(@Mock Configuration config) { + AtomicBoolean isCanceled = new AtomicBoolean(false); + MessageHandlerRegistrar testSubject = new MessageHandlerRegistrar( () -> config, c -> new SomeMessageHandler(), - (c, msgHandler) -> TEST_REGISTRATION_IMPLEMENTATION + (c, msgHandler) -> () -> { + isCanceled.set(true); + return false; + } ); + testSubject.start(); - assertThrows(NullPointerException.class, testSubject::shutdown); + testSubject.shutdown(); + + assertTrue(isCanceled.get()); } @Test - void shutdownCancelsMessageHandlerRegistration(@Mock Configuration config) { + void shutdownDoesNotThrowExceptionsIfWhenTheRegistrarHasNotStartedYet(@Mock Configuration config) { AtomicBoolean isCanceled = new AtomicBoolean(false); MessageHandlerRegistrar testSubject = new MessageHandlerRegistrar( - () -> config, c -> new SomeMessageHandler(), + () -> config, + c -> new SomeMessageHandler(), (c, msgHandler) -> () -> { isCanceled.set(true); return false; } ); - testSubject.start(); - - testSubject.shutdown(); - assertTrue(isCanceled.get()); + assertDoesNotThrow(testSubject::shutdown); + assertFalse(isCanceled.get()); } private static class SomeMessageHandler {