From 1d3fd650086522bb6da2b3c387f87e300fbca2e5 Mon Sep 17 00:00:00 2001 From: Nicolas Filotto Date: Thu, 14 Sep 2023 18:40:00 +0200 Subject: [PATCH] ARTEMIS-4270 Allow hierarchy of wildcard bindings In case the bindings "news.#" and "news.europe.#" are registered, only the first one matches with the address "news.europe" while both are supposed to match. Those changes are meant to get rid of this limitation. --- .../core/postoffice/impl/AddressPartNode.java | 17 +++--- .../integration/jms/client/MessageTest.java | 38 +++++++++++++ .../impl/WildcardAddressManagerUnitTest.java | 53 +++++++++++++++++++ 3 files changed, 97 insertions(+), 11 deletions(-) diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/postoffice/impl/AddressPartNode.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/postoffice/impl/AddressPartNode.java index 122abc0210..4c2d2bdc9a 100644 --- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/postoffice/impl/AddressPartNode.java +++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/postoffice/impl/AddressPartNode.java @@ -225,10 +225,9 @@ public final class AddressPartNode { // non wildcard paths, match any expanded wildcards in the map public void visitMatchingWildcards(final String[] paths, final int startIndex, final AddressMapVisitor collector) throws Exception { - boolean canVisitAnyDescendent = true; AddressPartNode node = this; - AddressPartNode anyDescendentNode = null; - AddressPartNode anyChildNode = null; + AddressPartNode anyDescendentNode; + AddressPartNode anyChildNode; final int size = paths.length; for (int i = startIndex; i < size && node != null; i++) { @@ -240,7 +239,6 @@ public final class AddressPartNode { anyDescendentNode.visitValues(collector); // match tail with current path, such that ANY_DESCENDENT can match zero anyDescendentNode.visitPathTailMatch(paths, i, collector); - canVisitAnyDescendent = false; } anyChildNode = node.getChild(ANY_CHILD); @@ -260,13 +258,10 @@ public final class AddressPartNode { node.visitValues(collector); - if (canVisitAnyDescendent) { - - // allow zero node any descendant at the end of path node - anyDescendentNode = node.getChild(ANY_DESCENDENT); - if (anyDescendentNode != null) { - anyDescendentNode.visitValues(collector); - } + // allow zero node any descendant at the end of path node + anyDescendentNode = node.getChild(ANY_DESCENDENT); + if (anyDescendentNode != null) { + anyDescendentNode.visitValues(collector); } } } diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/jms/client/MessageTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/jms/client/MessageTest.java index 20595ca560..adcb9315b1 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/jms/client/MessageTest.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/jms/client/MessageTest.java @@ -24,6 +24,8 @@ import javax.jms.MessageProducer; import javax.jms.Queue; import javax.jms.Session; import javax.jms.StreamMessage; +import javax.jms.TextMessage; +import javax.jms.Topic; import java.lang.invoke.MethodHandles; @@ -253,6 +255,42 @@ public class MessageTest extends JMSTestBase { } } + /** + * @see ARTEMIS-4270 + */ + @Test + public void testWildcardRoutingHierarchyWithMultipleConsumers() throws Exception { + Topic parentTopic = createTopic(true, "a.#"); + Topic childTopic = createTopic(true, "a.b.#"); + try (Connection conn = cf.createConnection()) { + conn.start(); + + try (Session session = conn.createSession(false, Session.CLIENT_ACKNOWLEDGE)) { + MessageConsumer parentConsumer = session.createConsumer(parentTopic); + MessageConsumer childConsumer = session.createConsumer(childTopic); + + MessageProducer producer = session.createProducer(null); + + producer.send(session.createTopic("a.b.c"), session.createTextMessage("m1")); + producer.send(session.createTopic("a.b"), session.createTextMessage("m2")); + + Message m = parentConsumer.receive(5_000); + assertTrue(m instanceof TextMessage); + assertEquals("m1", ((TextMessage) m).getText()); + m = parentConsumer.receive(5_000); + assertTrue(m instanceof TextMessage); + assertEquals("m2", ((TextMessage) m).getText()); + + m = childConsumer.receive(5_000); + assertTrue(m instanceof TextMessage); + assertEquals("m1", ((TextMessage) m).getText()); + m = childConsumer.receive(5_000); + assertTrue(m instanceof TextMessage); + assertEquals("m2", ((TextMessage) m).getText()); + } + } + } + // https://issues.jboss.org/browse/HORNETQ-988 @Test public void testShouldNotThrowException() throws Exception { diff --git a/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/postoffice/impl/WildcardAddressManagerUnitTest.java b/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/postoffice/impl/WildcardAddressManagerUnitTest.java index 58c0ddf30b..a2eace09f5 100644 --- a/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/postoffice/impl/WildcardAddressManagerUnitTest.java +++ b/tests/unit-tests/src/test/java/org/apache/activemq/artemis/tests/unit/core/postoffice/impl/WildcardAddressManagerUnitTest.java @@ -221,6 +221,59 @@ public class WildcardAddressManagerUnitTest extends ActiveMQTestBase { } + @Test + public void testSingleWordWildCardAddressBindingsForRouting() throws Exception { + WildcardAddressManager ad = new WildcardAddressManager(new BindingFactoryFake(), null, null); + ad.addAddressInfo(new AddressInfo(SimpleString.toSimpleString("news.*"), RoutingType.MULTICAST)); + ad.addAddressInfo(new AddressInfo(SimpleString.toSimpleString("news.*.sport"), RoutingType.MULTICAST)); + ad.addBinding(new BindingFake("news.*", "one")); + ad.addBinding(new BindingFake("news.*.sport", "two")); + + Collection bindings = ad.getBindingsForRoutingAddress(SimpleString.toSimpleString("news.europe")).getBindings(); + assertEquals(1, bindings.size()); + assertEquals("one", bindings.iterator().next().getUniqueName().toString()); + bindings = ad.getBindingsForRoutingAddress(SimpleString.toSimpleString("news.usa")).getBindings(); + assertEquals(1, bindings.size()); + assertEquals("one", bindings.iterator().next().getUniqueName().toString()); + bindings = ad.getBindingsForRoutingAddress(SimpleString.toSimpleString("news.europe.sport")).getBindings(); + assertEquals(1, bindings.size()); + assertEquals("two", bindings.iterator().next().getUniqueName().toString()); + bindings = ad.getBindingsForRoutingAddress(SimpleString.toSimpleString("news.usa.sport")).getBindings(); + assertEquals(1, bindings.size()); + assertEquals("two", bindings.iterator().next().getUniqueName().toString()); + assertNull(ad.getBindingsForRoutingAddress(SimpleString.toSimpleString("news.europe.fr.sport"))); + } + + @Test + public void testAnyWordsWildCardAddressBindingsForRouting() throws Exception { + WildcardAddressManager ad = new WildcardAddressManager(new BindingFactoryFake(), null, null); + ad.addAddressInfo(new AddressInfo(SimpleString.toSimpleString("news.europe.#"), RoutingType.MULTICAST)); + ad.addBinding(new BindingFake("news.europe.#", "one")); + + assertEquals(1, ad.getBindingsForRoutingAddress(SimpleString.toSimpleString("news.europe")).getBindings().size()); + assertEquals(1, ad.getBindingsForRoutingAddress(SimpleString.toSimpleString("news.europe.sport")).getBindings().size()); + assertEquals(1, ad.getBindingsForRoutingAddress(SimpleString.toSimpleString("news.europe.politics.fr")).getBindings().size()); + assertNull(ad.getBindingsForRoutingAddress(SimpleString.toSimpleString("news.usa"))); + assertNull(ad.getBindingsForRoutingAddress(SimpleString.toSimpleString("europe"))); + } + + @Test + public void testAnyWordsMultipleWildCardsAddressBindingsForRouting() throws Exception { + WildcardAddressManager ad = new WildcardAddressManager(new BindingFactoryFake(), null, null); + ad.addAddressInfo(new AddressInfo(SimpleString.toSimpleString("news.#"), RoutingType.MULTICAST)); + ad.addAddressInfo(new AddressInfo(SimpleString.toSimpleString("news.europe.#"), RoutingType.MULTICAST)); + ad.addBinding(new BindingFake("news.#", "one")); + ad.addBinding(new BindingFake("news.europe.#", "two")); + + assertEquals(2, ad.getBindingsForRoutingAddress(SimpleString.toSimpleString("news.europe")).getBindings().size()); + assertEquals(2, ad.getBindingsForRoutingAddress(SimpleString.toSimpleString("news.europe.sport")).getBindings().size()); + assertEquals(2, ad.getBindingsForRoutingAddress(SimpleString.toSimpleString("news.europe.politics.fr")).getBindings().size()); + + Collection bindings = ad.getBindingsForRoutingAddress(SimpleString.toSimpleString("news.usa")).getBindings(); + assertEquals(1, bindings.size()); + assertEquals("one", bindings.iterator().next().getUniqueName().toString()); + assertNull(ad.getBindingsForRoutingAddress(SimpleString.toSimpleString("europe"))); + } @Test public void testNumberOfBindingsThatMatch() throws Exception {