diff --git a/src/main/java/com/exactpro/th2/common/schema/factory/AbstractCommonFactory.java b/src/main/java/com/exactpro/th2/common/schema/factory/AbstractCommonFactory.java index 170920614..f2595d769 100644 --- a/src/main/java/com/exactpro/th2/common/schema/factory/AbstractCommonFactory.java +++ b/src/main/java/com/exactpro/th2/common/schema/factory/AbstractCommonFactory.java @@ -137,8 +137,10 @@ public abstract class AbstractCommonFactory implements AutoCloseable { private final Class> eventBatchRouterClass; private final Class grpcRouterClass; private final Class> notificationEventBatchRouterClass; - private final LazyProvider rabbitMqConnectionManager = - lazyAutocloseable("connection-manager", this::createRabbitMQConnectionManager); + private final LazyProvider rabbitMqPublishConnectionManager = + lazyAutocloseable("publish-connection-manager", this::createRabbitMQConnectionManager); + private final LazyProvider rabbitMqConsumeConnectionManager = + lazyAutocloseable("consume-connection-manager", this::createRabbitMQConnectionManager); private final LazyProvider routerContext = lazy("router-context", this::createMessageRouterContext); private final LazyProvider> messageRouterParsedBatch = @@ -648,7 +650,8 @@ private MessageRouterContext createMessageRouterContext() { @NotNull private MessageRouterContext createRouterContext(MessageRouterMonitor contextMonitor) { return new DefaultMessageRouterContext( - getRabbitMqConnectionManager(), + getRabbitMqPublishConnectionManager(), + getRabbitMqConsumeConnectionManager(), contextMonitor, getMessageRouterConfiguration(), getBoxConfiguration() @@ -663,8 +666,12 @@ protected ConnectionManager createRabbitMQConnectionManager() { return new ConnectionManager(getBoxConfiguration().getBoxName(), getRabbitMqConfiguration(), getConnectionManagerConfiguration()); } - protected ConnectionManager getRabbitMqConnectionManager() { - return rabbitMqConnectionManager.get(); + protected ConnectionManager getRabbitMqPublishConnectionManager() { + return rabbitMqPublishConnectionManager.get(); + } + + protected ConnectionManager getRabbitMqConsumeConnectionManager() { + return rabbitMqConsumeConnectionManager.get(); } public MessageID.Builder newMessageIDBuilder() { @@ -700,9 +707,15 @@ public void close() { } try { - rabbitMqConnectionManager.close(); + rabbitMqPublishConnectionManager.close(); + } catch (Exception e) { + LOGGER.error("Failed to close RabbitMQ publish connection", e); + } + + try { + rabbitMqConsumeConnectionManager.close(); } catch (Exception e) { - LOGGER.error("Failed to close RabbitMQ connection", e); + LOGGER.error("Failed to close RabbitMQ consume connection", e); } try { diff --git a/src/main/java/com/exactpro/th2/common/schema/message/MessageRouter.java b/src/main/java/com/exactpro/th2/common/schema/message/MessageRouter.java index c7c781de9..db9155034 100644 --- a/src/main/java/com/exactpro/th2/common/schema/message/MessageRouter.java +++ b/src/main/java/com/exactpro/th2/common/schema/message/MessageRouter.java @@ -39,7 +39,7 @@ public interface MessageRouter extends AutoCloseable { default void init(@NotNull ConnectionManager connectionManager, @NotNull MessageRouterConfiguration configuration) { Objects.requireNonNull(connectionManager, "Connection owner can not be null"); Objects.requireNonNull(configuration, "Configuration cannot be null"); - init(new DefaultMessageRouterContext(connectionManager, MessageRouterMonitor.DEFAULT_MONITOR, configuration, new BoxConfiguration())); + init(new DefaultMessageRouterContext(connectionManager, connectionManager, MessageRouterMonitor.DEFAULT_MONITOR, configuration, new BoxConfiguration())); } default void init(@NotNull MessageRouterContext context, @NotNull MessageRouter groupBatchRouter) { diff --git a/src/main/kotlin/com/exactpro/th2/common/schema/message/MessageRouterContext.kt b/src/main/kotlin/com/exactpro/th2/common/schema/message/MessageRouterContext.kt index d62f6da0d..67f8e68b0 100644 --- a/src/main/kotlin/com/exactpro/th2/common/schema/message/MessageRouterContext.kt +++ b/src/main/kotlin/com/exactpro/th2/common/schema/message/MessageRouterContext.kt @@ -20,7 +20,8 @@ import com.exactpro.th2.common.schema.message.configuration.MessageRouterConfigu import com.exactpro.th2.common.schema.message.impl.rabbitmq.connection.ConnectionManager interface MessageRouterContext { - val connectionManager: ConnectionManager + val publishConnectionManager: ConnectionManager + val consumeConnectionManager: ConnectionManager val routerMonitor: MessageRouterMonitor val configuration: MessageRouterConfiguration val boxConfiguration: BoxConfiguration diff --git a/src/main/kotlin/com/exactpro/th2/common/schema/message/impl/context/DefaultMessageRouterContext.kt b/src/main/kotlin/com/exactpro/th2/common/schema/message/impl/context/DefaultMessageRouterContext.kt index 4e19a1f4a..dc503d422 100644 --- a/src/main/kotlin/com/exactpro/th2/common/schema/message/impl/context/DefaultMessageRouterContext.kt +++ b/src/main/kotlin/com/exactpro/th2/common/schema/message/impl/context/DefaultMessageRouterContext.kt @@ -22,7 +22,8 @@ import com.exactpro.th2.common.schema.message.configuration.MessageRouterConfigu import com.exactpro.th2.common.schema.message.impl.rabbitmq.connection.ConnectionManager class DefaultMessageRouterContext( - override val connectionManager: ConnectionManager, + override val publishConnectionManager: ConnectionManager, + override val consumeConnectionManager: ConnectionManager, override val routerMonitor: MessageRouterMonitor, override val configuration: MessageRouterConfiguration, override val boxConfiguration: BoxConfiguration diff --git a/src/main/kotlin/com/exactpro/th2/common/schema/message/impl/rabbitmq/AbstractRabbitRouter.kt b/src/main/kotlin/com/exactpro/th2/common/schema/message/impl/rabbitmq/AbstractRabbitRouter.kt index 8d9eaac6a..91bc224ea 100644 --- a/src/main/kotlin/com/exactpro/th2/common/schema/message/impl/rabbitmq/AbstractRabbitRouter.kt +++ b/src/main/kotlin/com/exactpro/th2/common/schema/message/impl/rabbitmq/AbstractRabbitRouter.kt @@ -44,10 +44,10 @@ abstract class AbstractRabbitRouter : MessageRouter { get() = context.configuration protected val publishConnectionManager: ConnectionManager - get() = context.connectionManager + get() = context.publishConnectionManager protected val consumeConnectionManager: ConnectionManager - get() = context.connectionManager + get() = context.consumeConnectionManager private val boxConfiguration: BoxConfiguration get() = context.boxConfiguration diff --git a/src/main/kotlin/com/exactpro/th2/common/schema/message/impl/rabbitmq/notification/NotificationEventBatchRouter.kt b/src/main/kotlin/com/exactpro/th2/common/schema/message/impl/rabbitmq/notification/NotificationEventBatchRouter.kt index 55f34115c..619788469 100644 --- a/src/main/kotlin/com/exactpro/th2/common/schema/message/impl/rabbitmq/notification/NotificationEventBatchRouter.kt +++ b/src/main/kotlin/com/exactpro/th2/common/schema/message/impl/rabbitmq/notification/NotificationEventBatchRouter.kt @@ -33,13 +33,13 @@ class NotificationEventBatchRouter : NotificationRouter { override fun init(context: MessageRouterContext) { sender = NotificationEventBatchSender( - context.connectionManager, + context.publishConnectionManager, context.configuration.globalNotification.exchange ) - queue = context.connectionManager.queueExclusiveDeclareAndBind( + queue = context.consumeConnectionManager.queueExclusiveDeclareAndBind( context.configuration.globalNotification.exchange ) - subscriber = NotificationEventBatchSubscriber(context.connectionManager, queue) + subscriber = NotificationEventBatchSubscriber(context.consumeConnectionManager, queue) } override fun send(message: EventBatch) { diff --git a/src/test/kotlin/com/exactpro/th2/common/schema/message/impl/rabbitmq/AbstractRabbitRouterIntegrationTest.kt b/src/test/kotlin/com/exactpro/th2/common/schema/message/impl/rabbitmq/AbstractRabbitRouterIntegrationTest.kt index 115b1587a..38247b0b8 100644 --- a/src/test/kotlin/com/exactpro/th2/common/schema/message/impl/rabbitmq/AbstractRabbitRouterIntegrationTest.kt +++ b/src/test/kotlin/com/exactpro/th2/common/schema/message/impl/rabbitmq/AbstractRabbitRouterIntegrationTest.kt @@ -61,43 +61,46 @@ class AbstractRabbitRouterIntegrationTest { rabbitMQContainer.start() K_LOGGER.info { "Started with port ${rabbitMQContainer.amqpPort}, rest ${rabbitMQContainer.httpUrl} ${rabbitMQContainer.adminUsername} ${rabbitMQContainer.adminPassword} " } - createConnectionManager(rabbitMQContainer).use { firstManager -> - createRouter(firstManager).use { firstRouter -> - val messageA = "test-message-a" - val messageB = "test-message-b" - val messageC = "test-message-c" - val messageD = "test-message-d" - - val queue = ArrayBlockingQueue(4) - - firstRouter.send(messageA) - firstRouter.send(messageB) - firstRouter.send(messageC) - firstRouter.send(messageD) - - connectAndCheck( - rabbitMQContainer, queue, listOf( - Expectation(messageA, false, ManualAckDeliveryCallback.Confirmation::confirm), - Expectation(messageB, false, ManualAckDeliveryCallback.Confirmation::reject), - Expectation(messageC, false) { }, - Expectation(messageD, false) { }, + createConnectionManager(rabbitMQContainer).use { publishManager -> + createConnectionManager(rabbitMQContainer).use { consumeManager -> + + createRouter(publishManager, consumeManager).use { firstRouter -> + val messageA = "test-message-a" + val messageB = "test-message-b" + val messageC = "test-message-c" + val messageD = "test-message-d" + + val queue = ArrayBlockingQueue(4) + + firstRouter.send(messageA) + firstRouter.send(messageB) + firstRouter.send(messageC) + firstRouter.send(messageD) + + connectAndCheck( + rabbitMQContainer, queue, listOf( + Expectation(messageA, false, ManualAckDeliveryCallback.Confirmation::confirm), + Expectation(messageB, false, ManualAckDeliveryCallback.Confirmation::reject), + Expectation(messageC, false) { }, + Expectation(messageD, false) { }, + ) ) - ) - connectAndCheck( - rabbitMQContainer, queue, listOf( - Expectation(messageC, true, ManualAckDeliveryCallback.Confirmation::confirm), - Expectation(messageD, true) { }, + connectAndCheck( + rabbitMQContainer, queue, listOf( + Expectation(messageC, true, ManualAckDeliveryCallback.Confirmation::confirm), + Expectation(messageD, true) { }, + ) ) - ) - connectAndCheck( - rabbitMQContainer, queue, listOf( - Expectation(messageD, true, ManualAckDeliveryCallback.Confirmation::reject), + connectAndCheck( + rabbitMQContainer, queue, listOf( + Expectation(messageD, true, ManualAckDeliveryCallback.Confirmation::reject), + ) ) - ) - connectAndCheck(rabbitMQContainer, queue, emptyList()) + connectAndCheck(rabbitMQContainer, queue, emptyList()) + } } } } @@ -108,48 +111,50 @@ class AbstractRabbitRouterIntegrationTest { queue: ArrayBlockingQueue, expectations: List, ) { - createConnectionManager(rabbitMQContainer).use { manager -> - createRouter(manager).use { router -> - val monitor = router.subscribeWithManualAck({ deliveryMetadata, message, confirmation -> - queue.put( - Delivery( - message, - deliveryMetadata.isRedelivered, - confirmation + createConnectionManager(rabbitMQContainer).use { publishManager -> + createConnectionManager(rabbitMQContainer).use { consumeManager -> + createRouter(publishManager, consumeManager).use { router -> + val monitor = router.subscribeWithManualAck({ deliveryMetadata, message, confirmation -> + queue.put( + Delivery( + message, + deliveryMetadata.isRedelivered, + confirmation + ) ) - ) - }) - - try { - expectations.forEach { expectation -> - val delivery = assertNotNull(queue.poll(1, TimeUnit.SECONDS)) - assertEquals(expectation.message, delivery.message, "Message") - assertEquals(expectation.redelivery, delivery.redelivery, "Redelivery flag") - expectation.action.invoke(delivery.confirmation) + }) + + try { + expectations.forEach { expectation -> + val delivery = assertNotNull(queue.poll(1, TimeUnit.SECONDS)) + assertEquals(expectation.message, delivery.message, "Message") + assertEquals(expectation.redelivery, delivery.redelivery, "Redelivery flag") + expectation.action.invoke(delivery.confirmation) + } + + assertNull(queue.poll(1, TimeUnit.SECONDS)) + } finally { + monitor.unsubscribe() } - - assertNull(queue.poll(1, TimeUnit.SECONDS)) - } finally { - monitor.unsubscribe() } - } - createRouter(manager).use { router -> - val monitor = router.subscribeWithManualAck({ deliveryMetadata, message, confirmation -> - queue.put( - Delivery( - message, - deliveryMetadata.isRedelivered, - confirmation + createRouter(publishManager, consumeManager).use { router -> + val monitor = router.subscribeWithManualAck({ deliveryMetadata, message, confirmation -> + queue.put( + Delivery( + message, + deliveryMetadata.isRedelivered, + confirmation + ) ) - ) - }) + }) - try { - // RabbitMQ doesn't resend messages after resubscribe using the same connection and channel - assertNull(queue.poll(1, TimeUnit.SECONDS)) - } finally { - monitor.unsubscribe() + try { + // RabbitMQ doesn't resend messages after resubscribe using the same connection and channel + assertNull(queue.poll(1, TimeUnit.SECONDS)) + } finally { + monitor.unsubscribe() + } } } } @@ -175,14 +180,15 @@ class AbstractRabbitRouterIntegrationTest { ), ) - private fun createRouter(connectionManager: ConnectionManager) = RabbitCustomRouter( + private fun createRouter(publishConnectionManager: ConnectionManager, consumeConnectionManager: ConnectionManager) = RabbitCustomRouter( "test-custom-tag", arrayOf("test-label"), TestMessageConverter() ).apply { init( DefaultMessageRouterContext( - connectionManager, + publishConnectionManager, + consumeConnectionManager, mock { }, MessageRouterConfiguration( mapOf( diff --git a/src/test/kotlin/com/exactpro/th2/common/schema/message/impl/rabbitmq/AbstractRabbitRouterTest.kt b/src/test/kotlin/com/exactpro/th2/common/schema/message/impl/rabbitmq/AbstractRabbitRouterTest.kt index e5fa77b6d..49723228a 100644 --- a/src/test/kotlin/com/exactpro/th2/common/schema/message/impl/rabbitmq/AbstractRabbitRouterTest.kt +++ b/src/test/kotlin/com/exactpro/th2/common/schema/message/impl/rabbitmq/AbstractRabbitRouterTest.kt @@ -48,7 +48,13 @@ private const val TEST_EXCLUSIVE_QUEUE = "test-exclusive-queue" class AbstractRabbitRouterTest { private val connectionConfiguration = ConnectionManagerConfiguration() private val managerMonitor: ExclusiveSubscriberMonitor = mock { } - private val connectionManager: ConnectionManager = mock { + private val publishConnectionManager: ConnectionManager = mock { + on { configuration }.thenReturn(connectionConfiguration) + on { basicConsume(any(), any(), any()) }.thenReturn(managerMonitor) + on { queueDeclare() }.thenAnswer { "$TEST_EXCLUSIVE_QUEUE-${exclusiveQueueCounter.incrementAndGet()}" } + } + + private val consumeConnectionManager: ConnectionManager = mock { on { configuration }.thenReturn(connectionConfiguration) on { basicConsume(any(), any(), any()) }.thenReturn(managerMonitor) on { queueDeclare() }.thenAnswer { "$TEST_EXCLUSIVE_QUEUE-${exclusiveQueueCounter.incrementAndGet()}" } @@ -81,7 +87,8 @@ class AbstractRabbitRouterTest { @AfterEach fun afterEach() { - verifyNoMoreInteractions(connectionManager) + verifyNoMoreInteractions(publishConnectionManager) + verifyNoMoreInteractions(consumeConnectionManager) verifyNoMoreInteractions(managerMonitor) } @@ -90,7 +97,7 @@ class AbstractRabbitRouterTest { val monitor = router.subscribe(mock { }, "1") assertNotNull(monitor) { "monitor must not be null" } - verify(connectionManager).basicConsume(eq("queue1"), any(), any()) + verify(consumeConnectionManager).basicConsume(eq("queue1"), any(), any()) } @Test @@ -98,7 +105,7 @@ class AbstractRabbitRouterTest { val monitor = router.subscribeWithManualAck(mock { }, "1") assertNotNull(monitor) { "monitor must not be null" } - verify(connectionManager).basicConsume(eq("queue1"), any(), any()) + verify(consumeConnectionManager).basicConsume(eq("queue1"), any(), any()) } @Test @@ -106,14 +113,14 @@ class AbstractRabbitRouterTest { val monitor = router.subscribeAll(mock { }) assertNotNull(monitor) { "monitor must not be null" } - verify(connectionManager).basicConsume(eq("queue1"), any(), any()) - verify(connectionManager).basicConsume(eq("queue2"), any(), any()) + verify(consumeConnectionManager).basicConsume(eq("queue1"), any(), any()) + verify(consumeConnectionManager).basicConsume(eq("queue2"), any(), any()) } @Test fun `unsubscribe after subscribe`() { val monitor = router.subscribe(mock { }, "1") - clearInvocations(connectionManager) + clearInvocations(consumeConnectionManager) clearInvocations(managerMonitor) monitor.unsubscribe() @@ -123,7 +130,7 @@ class AbstractRabbitRouterTest { @Test fun `unsubscribe after subscribe with manual ack`() { val monitor = router.subscribeWithManualAck(mock { }, "1") - clearInvocations(connectionManager) + clearInvocations(consumeConnectionManager) clearInvocations(managerMonitor) monitor.unsubscribe() @@ -133,7 +140,7 @@ class AbstractRabbitRouterTest { @Test fun `unsubscribe after subscribe to exclusive queue`() { val monitor = router.subscribeExclusive(mock { }) - clearInvocations(connectionManager) + clearInvocations(consumeConnectionManager) clearInvocations(managerMonitor) monitor.unsubscribe() @@ -144,39 +151,39 @@ class AbstractRabbitRouterTest { fun `subscribes after unsubscribe`() { router.subscribe(mock { }, "1") .unsubscribe() - clearInvocations(connectionManager) + clearInvocations(consumeConnectionManager) clearInvocations(managerMonitor) val monitor = router.subscribe(mock { }, "1") assertNotNull(monitor) { "monitor must not be null" } - verify(connectionManager).basicConsume(eq("queue1"), any(), any()) + verify(consumeConnectionManager).basicConsume(eq("queue1"), any(), any()) } @Test fun `subscribes with manual ack after unsubscribe`() { router.subscribeWithManualAck(mock { }, "1") .unsubscribe() - clearInvocations(connectionManager) + clearInvocations(consumeConnectionManager) clearInvocations(managerMonitor) val monitor = router.subscribeWithManualAck(mock { }, "1") assertNotNull(monitor) { "monitor must not be null" } - verify(connectionManager).basicConsume(eq("queue1"), any(), any()) + verify(consumeConnectionManager).basicConsume(eq("queue1"), any(), any()) } @Test fun `subscribes when subscribtion active`() { router.subscribe(mock { }, "1") - clearInvocations(connectionManager) + clearInvocations(consumeConnectionManager) clearInvocations(managerMonitor) assertThrows(RuntimeException::class.java) { router.subscribe(mock { }, "1") } } @Test - fun `subscribes with manual ack when subscribtion active`() { + fun `subscribes with manual ack when subscription active`() { router.subscribeWithManualAck(mock { }, "1") - clearInvocations(connectionManager) + clearInvocations(consumeConnectionManager) clearInvocations(managerMonitor) assertThrows(RuntimeException::class.java) { router.subscribeWithManualAck(mock { }, "1") } @@ -187,8 +194,8 @@ class AbstractRabbitRouterTest { val monitorA = router.subscribeExclusive(mock { }) val monitorB = router.subscribeExclusive(mock { }) - verify(connectionManager, times(2)).queueDeclare() - verify(connectionManager, times(2)).basicConsume( + verify(consumeConnectionManager, times(2)).queueDeclare() + verify(consumeConnectionManager, times(2)).basicConsume( argThat { matches(Regex("$TEST_EXCLUSIVE_QUEUE-\\d+")) }, any(), any() @@ -250,7 +257,8 @@ class AbstractRabbitRouterTest { ).apply { init( DefaultMessageRouterContext( - connectionManager, + publishConnectionManager, + consumeConnectionManager, mock { }, MessageRouterConfiguration(pins, GlobalNotificationConfiguration()), BaseTest.BOX_CONFIGURATION diff --git a/src/test/kotlin/com/exactpro/th2/common/schema/message/impl/rabbitmq/group/IntegrationTestRabbitMessageBatchRouter.kt b/src/test/kotlin/com/exactpro/th2/common/schema/message/impl/rabbitmq/group/IntegrationTestRabbitMessageBatchRouter.kt index 3f654b9fe..0dd44ec8b 100644 --- a/src/test/kotlin/com/exactpro/th2/common/schema/message/impl/rabbitmq/group/IntegrationTestRabbitMessageBatchRouter.kt +++ b/src/test/kotlin/com/exactpro/th2/common/schema/message/impl/rabbitmq/group/IntegrationTestRabbitMessageBatchRouter.kt @@ -104,6 +104,7 @@ class IntegrationTestRabbitMessageGroupBatchRouter { .apply { init( DefaultMessageRouterContext( + connectionManager, connectionManager, mock { }, MessageRouterConfiguration(), diff --git a/src/test/kotlin/com/exactpro/th2/common/schema/message/impl/rabbitmq/group/TestRabbitMessageBatchRouter.kt b/src/test/kotlin/com/exactpro/th2/common/schema/message/impl/rabbitmq/group/TestRabbitMessageBatchRouter.kt index e6840fec6..ed05dc4b2 100644 --- a/src/test/kotlin/com/exactpro/th2/common/schema/message/impl/rabbitmq/group/TestRabbitMessageBatchRouter.kt +++ b/src/test/kotlin/com/exactpro/th2/common/schema/message/impl/rabbitmq/group/TestRabbitMessageBatchRouter.kt @@ -297,6 +297,7 @@ class TestRabbitMessageGroupBatchRouter { private fun createRouter(pins: Map): MessageRouter = RabbitMessageGroupBatchRouter().apply { init(DefaultMessageRouterContext( + connectionManager, connectionManager, mock { }, MessageRouterConfiguration(pins, GlobalNotificationConfiguration()), diff --git a/src/test/kotlin/com/exactpro/th2/common/schema/message/impl/rabbitmq/transport/TransportGroupBatchRouterIntegrationTest.kt b/src/test/kotlin/com/exactpro/th2/common/schema/message/impl/rabbitmq/transport/TransportGroupBatchRouterIntegrationTest.kt index 119c18c7b..60d61522e 100644 --- a/src/test/kotlin/com/exactpro/th2/common/schema/message/impl/rabbitmq/transport/TransportGroupBatchRouterIntegrationTest.kt +++ b/src/test/kotlin/com/exactpro/th2/common/schema/message/impl/rabbitmq/transport/TransportGroupBatchRouterIntegrationTest.kt @@ -110,6 +110,7 @@ class TransportGroupBatchRouterIntegrationTest { .apply { init( DefaultMessageRouterContext( + connectionManager, connectionManager, mock { }, MessageRouterConfiguration(), diff --git a/src/test/kotlin/com/exactpro/th2/common/schema/message/impl/rabbitmq/transport/TransportGroupBatchRouterTest.kt b/src/test/kotlin/com/exactpro/th2/common/schema/message/impl/rabbitmq/transport/TransportGroupBatchRouterTest.kt index 27987afc2..fc094109b 100644 --- a/src/test/kotlin/com/exactpro/th2/common/schema/message/impl/rabbitmq/transport/TransportGroupBatchRouterTest.kt +++ b/src/test/kotlin/com/exactpro/th2/common/schema/message/impl/rabbitmq/transport/TransportGroupBatchRouterTest.kt @@ -283,6 +283,7 @@ class TransportGroupBatchRouterTest { TransportGroupBatchRouter().apply { init( DefaultMessageRouterContext( + connectionManager, connectionManager, mock { }, MessageRouterConfiguration(pins, GlobalNotificationConfiguration()),