From acc5bcc4240f97c23293b4873e6715d2ea84821b Mon Sep 17 00:00:00 2001 From: Timothy Bish Date: Tue, 3 Mar 2026 14:19:14 -0500 Subject: [PATCH] ARTEMIS-5911 Ensure core federation ignores AMQP federation configuration When parsing the Core federation XML elements we need to ensure that AMQP broker connections with federation configuration does not get picked up as that creates empty configuration entries in the broker configuration. --- .../impl/FileConfigurationParser.java | 19 +- .../impl/FileConfigurationParserTest.java | 192 ++++++++++++++++++ 2 files changed, 204 insertions(+), 7 deletions(-) diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/deployers/impl/FileConfigurationParser.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/deployers/impl/FileConfigurationParser.java index 30e64d6ae41..c75e2dc1e6f 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/deployers/impl/FileConfigurationParser.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/deployers/impl/FileConfigurationParser.java @@ -671,19 +671,24 @@ public void parseMainConfig(final Element e, final Configuration config) throws } } + // Ensure AMQP federation configuration isn't picked up here by core federation + // configuration parsing, any AMQP federation configuration would generate empty + // Core federation configurations that would not create active federations. NodeList federations = e.getElementsByTagName("federations"); for (int i = 0; i < federations.getLength(); i++) { - Element fedNode = (Element) federations.item(i); - parseFederationsConfiguration(fedNode, config); - } + Element federationElement = (Element) federations.item(i); - NodeList fedNodes = e.getElementsByTagName("federation"); + // Handle attributes at the federations level and then add each nested federation. + parseFederationsConfiguration(federationElement, config); - for (int i = 0; i < fedNodes.getLength(); i++) { - Element fedNode = (Element) fedNodes.item(i); + for (int j = 0; j < federationElement.getChildNodes().getLength(); ++j) { + Node node = federationElement.getChildNodes().item(j); - parseFederationConfiguration(fedNode, config); + if (node.getNodeName().equalsIgnoreCase("federation")) { + parseFederationConfiguration((Element) node, config); + } + } } NodeList gaNodes = e.getElementsByTagName("grouping-handler"); diff --git a/artemis-server/src/test/java/org/apache/activemq/artemis/core/config/impl/FileConfigurationParserTest.java b/artemis-server/src/test/java/org/apache/activemq/artemis/core/config/impl/FileConfigurationParserTest.java index b820fd83b7f..7f85aaf4849 100644 --- a/artemis-server/src/test/java/org/apache/activemq/artemis/core/config/impl/FileConfigurationParserTest.java +++ b/artemis-server/src/test/java/org/apache/activemq/artemis/core/config/impl/FileConfigurationParserTest.java @@ -34,6 +34,8 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; +import java.util.function.Function; +import java.util.stream.Collectors; import org.apache.activemq.artemis.api.config.ActiveMQDefaultConfiguration; import org.apache.activemq.artemis.api.core.SimpleString; @@ -501,6 +503,196 @@ public void testDefaultBridgeProducerWindowSize() throws Exception { assertEquals(ActiveMQDefaultConfiguration.getDefaultBridgeProducerWindowSize(), bconfig.getProducerWindowSize()); } + @Test + public void testCoreFederationIgnoresAMQPFederationConfigurations() throws Exception { + FileConfigurationParser parser = new FileConfigurationParser(); + String middlePart = """ + + + + + + + + + + + + + + class-another + + + + + + + + + + class-name + + + + class-another + + + + + + + something + + + + + + + + + + + + + + connector1 + + + + + true + + + + + + + + + + + + + + + + + + connector1 + + + + + true + + + + + + + + + + + + + + connector1 + + + + + + true + + + + + + + + + + + + org.foo.FederationTransformer3 + + + + + + + + connector1 + + + + + + true + + + + connector1 + + + + + + + + + org.foo.FederationTransformer4 + + + + + """; + + String configStr = FIRST_PART + middlePart + LAST_PART; + ByteArrayInputStream input = new ByteArrayInputStream(configStr.getBytes(StandardCharsets.UTF_8)); + + Configuration config = parser.parseMainConfig(input); + + assertEquals(4, config.getFederationConfigurations().size()); + + final Map federations = + config.getFederationConfigurations().stream() + .collect(Collectors.toMap(c -> c.getName(), Function.identity())); + + assertTrue(federations.containsKey("federation1")); + + final FederationConfiguration configuration1 = federations.get("federation1"); + + assertEquals(2, configuration1.getUpstreamConfigurations().size()); + assertEquals(0, configuration1.getDownstreamConfigurations().size()); + assertEquals(0, configuration1.getTransformerConfigurations().size()); + + assertTrue(federations.containsKey("federation2")); + + final FederationConfiguration configuration2 = federations.get("federation2"); + + assertEquals(2, configuration2.getUpstreamConfigurations().size()); + assertEquals(0, configuration2.getDownstreamConfigurations().size()); + assertEquals(0, configuration2.getTransformerConfigurations().size()); + + assertTrue(federations.containsKey("federation3")); + + final FederationConfiguration configuration3 = federations.get("federation3"); + + assertEquals(2, configuration3.getUpstreamConfigurations().size()); + assertEquals(0, configuration3.getDownstreamConfigurations().size()); + assertEquals(1, configuration3.getTransformerConfigurations().size()); + + assertTrue(federations.containsKey("federation4")); + + final FederationConfiguration configuration4 = federations.get("federation4"); + + assertEquals(1, configuration4.getUpstreamConfigurations().size()); + assertEquals(1, configuration4.getDownstreamConfigurations().size()); + assertEquals(1, configuration4.getTransformerConfigurations().size()); + } + @Test public void testParsingOverflowPageSize() throws Exception { testParsingOverFlow("""