This is an automated email from the ASF dual-hosted git repository.

jbertram pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/activemq-artemis.git


The following commit(s) were added to refs/heads/main by this push:
     new b075cd6fc0 ARTEMIS-4537 Fix merge of multiple address setting matches
b075cd6fc0 is described below

commit b075cd6fc08e5e69fc4b887ff3af070c43ae6d6a
Author: Domenico Francesco Bruscino <[email protected]>
AuthorDate: Fri Dec 15 10:54:13 2023 +0100

    ARTEMIS-4537 Fix merge of multiple address setting matches
    
    Merge multiple address setting matches on a new instance to be idempotent.
---
 .../activemq/artemis/core/settings/Mergeable.java  |   4 +
 .../core/settings/impl/AddressSettings.java        | 262 +++------------------
 .../impl/HierarchicalObjectRepository.java         |  23 +-
 .../artemis/core/settings/AddressSettingsTest.java |  57 ++++-
 .../artemis/core/settings/RepositoryTest.java      | 202 ++++++++++++----
 .../integration/client/MessageExpirationTest.java  |   9 +-
 6 files changed, 250 insertions(+), 307 deletions(-)

diff --git 
a/artemis-server/src/main/java/org/apache/activemq/artemis/core/settings/Mergeable.java
 
b/artemis-server/src/main/java/org/apache/activemq/artemis/core/settings/Mergeable.java
index 0cfb344fad..6b855cafc8 100644
--- 
a/artemis-server/src/main/java/org/apache/activemq/artemis/core/settings/Mergeable.java
+++ 
b/artemis-server/src/main/java/org/apache/activemq/artemis/core/settings/Mergeable.java
@@ -21,5 +21,9 @@ package org.apache.activemq.artemis.core.settings;
  */
 public interface Mergeable<T> {
 
+   // Merge two object instances in one instance
    void merge(T merged);
+
+   // Merge two object instances in a new instance
+   T mergeCopy(T merged);
 }
diff --git 
a/artemis-server/src/main/java/org/apache/activemq/artemis/core/settings/impl/AddressSettings.java
 
b/artemis-server/src/main/java/org/apache/activemq/artemis/core/settings/impl/AddressSettings.java
index f1e50d62ea..bbbc74289d 100644
--- 
a/artemis-server/src/main/java/org/apache/activemq/artemis/core/settings/impl/AddressSettings.java
+++ 
b/artemis-server/src/main/java/org/apache/activemq/artemis/core/settings/impl/AddressSettings.java
@@ -531,6 +531,9 @@ public class AddressSettings implements 
Mergeable<AddressSettings>, Serializable
    }
    private Integer idCacheSize = null;
 
+   static {
+      metaBean.add(Integer.class, "queuePrefetch", (t, p) -> t.queuePrefetch = 
p, t -> t.queuePrefetch);
+   }
    //from amq5
    //make it transient
    private transient Integer queuePrefetch = null;
@@ -1279,243 +1282,38 @@ public class AddressSettings implements 
Mergeable<AddressSettings>, Serializable
    }
 
    /**
-    * merge 2 objects in to 1
+    * Merge two AddressSettings instances in one instance
     *
     * @param merged
     */
    @Override
    public void merge(final AddressSettings merged) {
-      if (maxDeliveryAttempts == null) {
-         maxDeliveryAttempts = merged.maxDeliveryAttempts;
-      }
-      if (dropMessagesWhenFull == null) {
-         dropMessagesWhenFull = merged.dropMessagesWhenFull;
-      }
-      if (maxSizeBytes == null) {
-         maxSizeBytes = merged.maxSizeBytes;
-      }
-      if (maxSizeMessages == null) {
-         maxSizeMessages = merged.maxSizeMessages;
-      }
-      if (maxReadPageBytes == null) {
-         maxReadPageBytes = merged.maxReadPageBytes;
-      }
-      if (maxReadPageMessages == null) {
-         maxReadPageMessages = merged.maxReadPageMessages;
-      }
-      if (pageCacheMaxSize == null) {
-         pageCacheMaxSize = merged.pageCacheMaxSize;
-      }
-      if (pageSizeBytes == null) {
-         pageSizeBytes = merged.pageSizeBytes;
-      }
-      if (messageCounterHistoryDayLimit == null) {
-         messageCounterHistoryDayLimit = merged.messageCounterHistoryDayLimit;
-      }
-      if (redeliveryDelay == null) {
-         redeliveryDelay = merged.redeliveryDelay;
-      }
-      if (redeliveryMultiplier == null) {
-         redeliveryMultiplier = merged.redeliveryMultiplier;
-      }
-      if (redeliveryCollisionAvoidanceFactor == null) {
-         redeliveryCollisionAvoidanceFactor = 
merged.redeliveryCollisionAvoidanceFactor;
-      }
-      if (maxRedeliveryDelay == null) {
-         maxRedeliveryDelay = merged.maxRedeliveryDelay;
-      }
-      if (deadLetterAddress == null) {
-         deadLetterAddress = merged.deadLetterAddress;
-      }
-      if (expiryAddress == null) {
-         expiryAddress = merged.expiryAddress;
-      }
-      if (expiryDelay == null) {
-         expiryDelay = merged.expiryDelay;
-      }
-      if (minExpiryDelay == null) {
-         minExpiryDelay = merged.minExpiryDelay;
-      }
-      if (maxExpiryDelay == null) {
-         maxExpiryDelay = merged.maxExpiryDelay;
-      }
-      if (redistributionDelay == null) {
-         redistributionDelay = merged.redistributionDelay;
-      }
-      if (sendToDLAOnNoRoute == null) {
-         sendToDLAOnNoRoute = merged.sendToDLAOnNoRoute;
-      }
-      if (addressFullMessagePolicy == null) {
-         addressFullMessagePolicy = merged.addressFullMessagePolicy;
-      }
-      if (slowConsumerThreshold == null) {
-         slowConsumerThreshold = merged.slowConsumerThreshold;
-      }
-      if (slowConsumerThresholdMeasurementUnit == null) {
-         slowConsumerThresholdMeasurementUnit = 
merged.slowConsumerThresholdMeasurementUnit;
-      }
-      if (slowConsumerCheckPeriod == null) {
-         slowConsumerCheckPeriod = merged.slowConsumerCheckPeriod;
-      }
-      if (slowConsumerPolicy == null) {
-         slowConsumerPolicy = merged.slowConsumerPolicy;
-      }
-      if (autoCreateJmsQueues == null) {
-         autoCreateJmsQueues = merged.autoCreateJmsQueues;
-      }
-      if (autoDeleteJmsQueues == null) {
-         autoDeleteJmsQueues = merged.autoDeleteJmsQueues;
-      }
-      if (autoCreateJmsTopics == null) {
-         autoCreateJmsTopics = merged.autoCreateJmsTopics;
-      }
-      if (autoDeleteJmsTopics == null) {
-         autoDeleteJmsTopics = merged.autoDeleteJmsTopics;
-      }
-      if (autoCreateQueues == null) {
-         autoCreateQueues = merged.autoCreateQueues;
-      }
-      if (autoDeleteQueues == null) {
-         autoDeleteQueues = merged.autoDeleteQueues;
-      }
-      if (autoDeleteCreatedQueues == null) {
-         autoDeleteCreatedQueues = merged.autoDeleteCreatedQueues;
-      }
-      if (autoDeleteQueuesDelay == null) {
-         autoDeleteQueuesDelay = merged.autoDeleteQueuesDelay;
-      }
-      if (autoDeleteQueuesSkipUsageCheck == null) {
-         autoDeleteQueuesSkipUsageCheck = 
merged.autoDeleteQueuesSkipUsageCheck;
-      }
-      if (autoDeleteQueuesMessageCount == null) {
-         autoDeleteQueuesMessageCount = merged.autoDeleteQueuesMessageCount;
-      }
-      if (configDeleteQueues == null) {
-         configDeleteQueues = merged.configDeleteQueues;
-      }
-      if (autoCreateAddresses == null) {
-         autoCreateAddresses = merged.autoCreateAddresses;
-      }
-      if (autoDeleteAddresses == null) {
-         autoDeleteAddresses = merged.autoDeleteAddresses;
-      }
-      if (autoDeleteAddressesDelay == null) {
-         autoDeleteAddressesDelay = merged.autoDeleteAddressesDelay;
-      }
-      if (autoDeleteAddressesSkipUsageCheck == null) {
-         autoDeleteAddressesSkipUsageCheck = 
merged.autoDeleteAddressesSkipUsageCheck;
-      }
-      if (configDeleteAddresses == null) {
-         configDeleteAddresses = merged.configDeleteAddresses;
-      }
-      if (configDeleteDiverts == null) {
-         configDeleteDiverts = merged.configDeleteDiverts;
-      }
-      if (managementBrowsePageSize == null) {
-         managementBrowsePageSize = merged.managementBrowsePageSize;
-      }
-      if (managementMessageAttributeSizeLimit == null) {
-         managementMessageAttributeSizeLimit = 
merged.managementMessageAttributeSizeLimit;
-      }
-      if (queuePrefetch == null) {
-         queuePrefetch = merged.queuePrefetch;
-      }
-      if (maxSizeBytesRejectThreshold == null) {
-         maxSizeBytesRejectThreshold = merged.maxSizeBytesRejectThreshold;
-      }
-      if (defaultMaxConsumers == null) {
-         defaultMaxConsumers = merged.defaultMaxConsumers;
-      }
-      if (defaultPurgeOnNoConsumers == null) {
-         defaultPurgeOnNoConsumers = merged.defaultPurgeOnNoConsumers;
-      }
-      if (defaultQueueRoutingType == null) {
-         defaultQueueRoutingType = merged.defaultQueueRoutingType;
-      }
-      if (defaultAddressRoutingType == null) {
-         defaultAddressRoutingType = merged.defaultAddressRoutingType;
-      }
-      if (defaultExclusiveQueue == null) {
-         defaultExclusiveQueue = merged.defaultExclusiveQueue;
-      }
-      if (defaultConsumerWindowSize == null) {
-         defaultConsumerWindowSize = merged.defaultConsumerWindowSize;
-      }
-      if (defaultLastValueQueue == null) {
-         defaultLastValueQueue = merged.defaultLastValueQueue;
-      }
-      if (defaultLastValueKey == null) {
-         defaultLastValueKey = merged.defaultLastValueKey;
-      }
-      if (defaultNonDestructive == null) {
-         defaultNonDestructive = merged.defaultNonDestructive;
-      }
-      if (defaultConsumersBeforeDispatch == null) {
-         defaultConsumersBeforeDispatch = 
merged.defaultConsumersBeforeDispatch;
-      }
-      if (defaultDelayBeforeDispatch == null) {
-         defaultDelayBeforeDispatch = merged.defaultDelayBeforeDispatch;
-      }
-      if (defaultGroupRebalance == null) {
-         defaultGroupRebalance = merged.defaultGroupRebalance;
-      }
-      if (defaultGroupRebalancePauseDispatch == null) {
-         defaultGroupRebalancePauseDispatch = 
merged.defaultGroupRebalancePauseDispatch;
-      }
-      if (defaultGroupBuckets == null) {
-         defaultGroupBuckets = merged.defaultGroupBuckets;
-      }
-      if (defaultGroupFirstKey == null) {
-         defaultGroupFirstKey = merged.defaultGroupFirstKey;
-      }
-      if (defaultRingSize == null) {
-         defaultRingSize = merged.defaultRingSize;
-      }
-      if (retroactiveMessageCount == null) {
-         retroactiveMessageCount = merged.retroactiveMessageCount;
-      }
-      if (autoCreateDeadLetterResources == null) {
-         autoCreateDeadLetterResources = merged.autoCreateDeadLetterResources;
-      }
-      if (deadLetterQueuePrefix == null) {
-         deadLetterQueuePrefix = merged.deadLetterQueuePrefix;
-      }
-      if (deadLetterQueueSuffix == null) {
-         deadLetterQueueSuffix = merged.deadLetterQueueSuffix;
-      }
-      if (autoCreateExpiryResources == null) {
-         autoCreateExpiryResources = merged.autoCreateExpiryResources;
-      }
-      if (expiryQueuePrefix == null) {
-         expiryQueuePrefix = merged.expiryQueuePrefix;
-      }
-      if (expiryQueueSuffix == null) {
-         expiryQueueSuffix = merged.expiryQueueSuffix;
-      }
-      if (enableMetrics == null) {
-         enableMetrics = merged.enableMetrics;
-      }
-      if (enableIngressTimestamp == null) {
-         enableIngressTimestamp = merged.enableIngressTimestamp;
-      }
-      if (pageFullMessagePolicy == null) {
-         pageFullMessagePolicy = merged.pageFullMessagePolicy;
-      }
-      if (pageLimitBytes == null) {
-         pageLimitBytes = merged.pageLimitBytes;
-      }
-      if (pageLimitMessages == null) {
-         pageLimitMessages = merged.pageLimitMessages;
-      }
-      if (idCacheSize == null) {
-         idCacheSize = merged.idCacheSize;
-      }
-      if (prefetchPageMessages == null) {
-         prefetchPageMessages = merged.prefetchPageMessages;
-      }
-      if (prefetchPageBytes == null) {
-         prefetchPageBytes = merged.prefetchPageBytes;
-      }
+      metaBean.forEach((type, name, setter, getter, gate) -> {
+         if (getter.apply(AddressSettings.this) == null) {
+            setter.accept(this, getter.apply(merged));
+         }
+      });
+   }
+
+   /**
+    * Merge two AddressSettings instances in a new instance
+    *
+    * @param merged
+    */
+   @Override
+   public AddressSettings mergeCopy(final AddressSettings merged) {
+      AddressSettings target = new AddressSettings();
+
+      metaBean.forEach((type, name, setter, getter, gate) -> {
+         Object sourceValue = getter.apply(AddressSettings.this);
+         if (sourceValue != null) {
+            setter.accept(target, sourceValue);
+         } else {
+            setter.accept(target, getter.apply(merged));
+         }
+      });
+
+      return target;
    }
 
    @Override
diff --git 
a/artemis-server/src/main/java/org/apache/activemq/artemis/core/settings/impl/HierarchicalObjectRepository.java
 
b/artemis-server/src/main/java/org/apache/activemq/artemis/core/settings/impl/HierarchicalObjectRepository.java
index d63a1a9172..cf568deff4 100644
--- 
a/artemis-server/src/main/java/org/apache/activemq/artemis/core/settings/impl/HierarchicalObjectRepository.java
+++ 
b/artemis-server/src/main/java/org/apache/activemq/artemis/core/settings/impl/HierarchicalObjectRepository.java
@@ -24,6 +24,7 @@ import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
@@ -288,21 +289,23 @@ public class HierarchicalObjectRepository<T> implements 
HierarchicalRepository<T
     * @return
     */
    private T merge(final Collection<Match<T>> orderedMatches) {
-      T actualMatch = null;
-      for (Match<T> match : orderedMatches) {
-         if (actualMatch == null || 
!Mergeable.class.isAssignableFrom(actualMatch.getClass())) {
-            actualMatch = match.getValue();
-            if (!Mergeable.class.isAssignableFrom(actualMatch.getClass())) {
-               break;
-            }
-         } else {
-            ((Mergeable) actualMatch).merge(match.getValue());
+      Iterator<Match<T>> matchIterator = orderedMatches.iterator();
+
+      T result = null;
+      if (matchIterator.hasNext()) {
+         Match<T> match = matchIterator.next();
+         result = match.getValue();
+
+         while (matchIterator.hasNext() && 
Mergeable.class.isAssignableFrom(result.getClass())) {
+            match = matchIterator.next();
+            result = ((Mergeable<T>)result).mergeCopy(match.getValue());
             if (match.isLiteral()) {
                break;
             }
          }
       }
-      return actualMatch;
+
+      return result;
    }
 
    /**
diff --git 
a/artemis-server/src/test/java/org/apache/activemq/artemis/core/settings/AddressSettingsTest.java
 
b/artemis-server/src/test/java/org/apache/activemq/artemis/core/settings/AddressSettingsTest.java
index 0614f97376..30b4fe388c 100644
--- 
a/artemis-server/src/test/java/org/apache/activemq/artemis/core/settings/AddressSettingsTest.java
+++ 
b/artemis-server/src/test/java/org/apache/activemq/artemis/core/settings/AddressSettingsTest.java
@@ -62,6 +62,15 @@ public class AddressSettingsTest extends ActiveMQTestBase {
 
    @Test
    public void testSingleMerge() {
+      testSingleMerge(false);
+   }
+
+   @Test
+   public void testSingleMergeCopy() {
+      testSingleMerge(true);
+   }
+
+   private void testSingleMerge(boolean copy) {
       AddressSettings addressSettings = new AddressSettings();
       AddressSettings addressSettingsToMerge = new AddressSettings();
       SimpleString DLQ = new SimpleString("testDLQ");
@@ -82,7 +91,11 @@ public class AddressSettingsTest extends ActiveMQTestBase {
       addressSettingsToMerge.setMaxExpiryDelay(777L);
       addressSettingsToMerge.setIDCacheSize(5);
 
-      addressSettings.merge(addressSettingsToMerge);
+      if (copy) {
+         addressSettings = addressSettings.mergeCopy(addressSettingsToMerge);
+      } else {
+         addressSettings.merge(addressSettingsToMerge);
+      }
       Assert.assertEquals(addressSettings.getDeadLetterAddress(), DLQ);
       Assert.assertEquals(addressSettings.getExpiryAddress(), exp);
       Assert.assertEquals(addressSettings.getMaxDeliveryAttempts(), 1000);
@@ -102,6 +115,15 @@ public class AddressSettingsTest extends ActiveMQTestBase {
 
    @Test
    public void testMultipleMerge() {
+      testMultipleMerge(false);
+   }
+
+   @Test
+   public void testMultipleMergeCopy() {
+      testSingleMerge(true);
+   }
+
+   private void testMultipleMerge(boolean copy) {
       AddressSettings addressSettings = new AddressSettings();
       AddressSettings addressSettingsToMerge = new AddressSettings();
       SimpleString DLQ = new SimpleString("testDLQ");
@@ -113,7 +135,11 @@ public class AddressSettingsTest extends ActiveMQTestBase {
       addressSettingsToMerge.setMessageCounterHistoryDayLimit(1002);
       
addressSettingsToMerge.setAddressFullMessagePolicy(AddressFullMessagePolicy.DROP);
       addressSettingsToMerge.setMaxSizeBytesRejectThreshold(10 * 1024);
-      addressSettings.merge(addressSettingsToMerge);
+      if (copy) {
+         addressSettings = addressSettings.mergeCopy(addressSettingsToMerge);
+      } else {
+         addressSettings.merge(addressSettingsToMerge);
+      }
 
       AddressSettings addressSettingsToMerge2 = new AddressSettings();
       SimpleString exp2 = new SimpleString("testExpiryQueue2");
@@ -121,7 +147,11 @@ public class AddressSettingsTest extends ActiveMQTestBase {
       addressSettingsToMerge2.setMaxSizeBytes(2001);
       addressSettingsToMerge2.setRedeliveryDelay(2003);
       addressSettingsToMerge2.setRedeliveryMultiplier(2.5);
-      addressSettings.merge(addressSettingsToMerge2);
+      if (copy) {
+         addressSettings = addressSettings.mergeCopy(addressSettingsToMerge2);
+      } else {
+         addressSettings.merge(addressSettingsToMerge2);
+      }
 
       Assert.assertEquals(addressSettings.getDeadLetterAddress(), DLQ);
       Assert.assertEquals(addressSettings.getExpiryAddress(), exp);
@@ -136,6 +166,15 @@ public class AddressSettingsTest extends ActiveMQTestBase {
 
    @Test
    public void testMultipleMergeAll() {
+      testMultipleMergeAll(false);
+   }
+
+   @Test
+   public void testMultipleMergeAllCopy() {
+      testMultipleMergeAll(true);
+   }
+
+   private void testMultipleMergeAll(boolean copy) {
       AddressSettings addressSettings = new AddressSettings();
       AddressSettings addressSettingsToMerge = new AddressSettings();
       SimpleString DLQ = new SimpleString("testDLQ");
@@ -146,7 +185,11 @@ public class AddressSettingsTest extends ActiveMQTestBase {
       addressSettingsToMerge.setRedeliveryDelay(1003);
       addressSettingsToMerge.setRedeliveryMultiplier(1.0);
       
addressSettingsToMerge.setAddressFullMessagePolicy(AddressFullMessagePolicy.DROP);
-      addressSettings.merge(addressSettingsToMerge);
+      if (copy) {
+         addressSettings = addressSettings.mergeCopy(addressSettingsToMerge);
+      } else {
+         addressSettings.merge(addressSettingsToMerge);
+      }
 
       AddressSettings addressSettingsToMerge2 = new AddressSettings();
       SimpleString exp2 = new SimpleString("testExpiryQueue2");
@@ -160,7 +203,11 @@ public class AddressSettingsTest extends ActiveMQTestBase {
       addressSettingsToMerge2.setRedeliveryMultiplier(2.0);
       addressSettingsToMerge2.setMaxRedeliveryDelay(5000);
       
addressSettingsToMerge.setAddressFullMessagePolicy(AddressFullMessagePolicy.PAGE);
-      addressSettings.merge(addressSettingsToMerge2);
+      if (copy) {
+         addressSettings = addressSettings.mergeCopy(addressSettingsToMerge2);
+      } else {
+         addressSettings.merge(addressSettingsToMerge2);
+      }
 
       Assert.assertEquals(addressSettings.getDeadLetterAddress(), DLQ);
       Assert.assertEquals(addressSettings.getExpiryAddress(), exp);
diff --git 
a/artemis-server/src/test/java/org/apache/activemq/artemis/core/settings/RepositoryTest.java
 
b/artemis-server/src/test/java/org/apache/activemq/artemis/core/settings/RepositoryTest.java
index e4389748b8..bc9cba1476 100644
--- 
a/artemis-server/src/test/java/org/apache/activemq/artemis/core/settings/RepositoryTest.java
+++ 
b/artemis-server/src/test/java/org/apache/activemq/artemis/core/settings/RepositoryTest.java
@@ -17,14 +17,17 @@
 package org.apache.activemq.artemis.core.settings;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
 import java.util.concurrent.atomic.AtomicInteger;
 
 import org.apache.activemq.artemis.core.config.WildcardConfiguration;
 import org.apache.activemq.artemis.core.security.Role;
+import org.apache.activemq.artemis.core.settings.impl.AddressSettings;
 import 
org.apache.activemq.artemis.core.settings.impl.HierarchicalObjectRepository;
 import org.apache.activemq.artemis.tests.util.ActiveMQTestBase;
-import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
@@ -41,14 +44,6 @@ public class RepositoryTest extends ActiveMQTestBase {
       securityRepository = new HierarchicalObjectRepository<>();
    }
 
-   @Override
-   @After
-   public void tearDown() throws Exception {
-      super.tearDown();
-
-      DummyMergeable.reset();
-   }
-
    @Test
    public void testDefault() {
       securityRepository.setDefault(new HashSet<Role>());
@@ -86,18 +81,16 @@ public class RepositoryTest extends ActiveMQTestBase {
       repo.addMatch("a.#", new DummyMergeable(2));
       repo.addMatch("a.b", new DummyMergeable(3));
 
-      repo.getMatch("a.b");
-      assertTrue(DummyMergeable.contains(0));
-      assertFalse(DummyMergeable.contains(1));
-      assertTrue(DummyMergeable.contains(2));
-      assertTrue(DummyMergeable.contains(3));
-
-      DummyMergeable.reset();
-      repo.getMatch("a.#");
-      assertTrue(DummyMergeable.contains(0));
-      assertTrue(DummyMergeable.contains(1));
-      assertFalse(DummyMergeable.contains(2));
-      assertFalse(DummyMergeable.contains(3));
+      DummyMergeable abDummyMatch = repo.getMatch("a.b");
+      Assert.assertEquals(2, abDummyMatch.getMergedItems().size());
+      Assert.assertEquals(3, abDummyMatch.getId());
+      Assert.assertEquals(2, abDummyMatch.getMergedItems().get(0).getId());
+      Assert.assertEquals(0, abDummyMatch.getMergedItems().get(1).getId());
+
+      DummyMergeable aDummyMatch = repo.getMatch("a.#");
+      Assert.assertEquals(1, aDummyMatch.getMergedItems().size());
+      Assert.assertEquals(1, aDummyMatch.getId());
+      Assert.assertEquals(0, aDummyMatch.getMergedItems().get(0).getId());
    }
 
    @Test
@@ -263,23 +256,23 @@ public class RepositoryTest extends ActiveMQTestBase {
       repository.addMatch("a.b.c.#", new DummyMergeable(6));
       repository.addMatch("a.b.*.d", new DummyMergeable(7));
       repository.addMatch("a.b.c.*", new DummyMergeable(8));
-      repository.getMatch("a.b.c.d");
-      Assert.assertEquals(5, DummyMergeable.timesMerged);
-      Assert.assertTrue(DummyMergeable.contains(1));
-      Assert.assertTrue(DummyMergeable.contains(2));
-      Assert.assertTrue(DummyMergeable.contains(4));
-      Assert.assertTrue(DummyMergeable.contains(7));
-      Assert.assertTrue(DummyMergeable.contains(8));
-      DummyMergeable.reset();
-      repository.getMatch("a.b.c");
-      Assert.assertEquals(3, DummyMergeable.timesMerged);
-      Assert.assertTrue(DummyMergeable.contains(1));
-      Assert.assertTrue(DummyMergeable.contains(2));
-      Assert.assertTrue(DummyMergeable.contains(4));
-      DummyMergeable.reset();
-      repository.getMatch("z");
-      Assert.assertEquals(0, DummyMergeable.timesMerged);
-      DummyMergeable.reset();
+      DummyMergeable abcdDummyMatch = repository.getMatch("a.b.c.d");
+      Assert.assertEquals(5, abcdDummyMatch.getMergedItems().size());
+      Assert.assertEquals(8, abcdDummyMatch.getId());
+      Assert.assertEquals(7, abcdDummyMatch.getMergedItems().get(0).getId());
+      Assert.assertEquals(6, abcdDummyMatch.getMergedItems().get(1).getId());
+      Assert.assertEquals(4, abcdDummyMatch.getMergedItems().get(2).getId());
+      Assert.assertEquals(2, abcdDummyMatch.getMergedItems().get(3).getId());
+      Assert.assertEquals(1, abcdDummyMatch.getMergedItems().get(4).getId());
+      DummyMergeable abcDummyMatch = repository.getMatch("a.b.c");
+      Assert.assertEquals(3, abcDummyMatch.getMergedItems().size());
+      Assert.assertEquals(6, abcDummyMatch.getId());
+      Assert.assertEquals(4, abcDummyMatch.getMergedItems().get(0).getId());
+      Assert.assertEquals(2, abcDummyMatch.getMergedItems().get(1).getId());
+      Assert.assertEquals(1, abcDummyMatch.getMergedItems().get(2).getId());
+      DummyMergeable zDummyMatch = repository.getMatch("z");
+      Assert.assertEquals(0, zDummyMatch.getMergedItems().size());
+      Assert.assertEquals(1, zDummyMatch.getId());
    }
 
    @Test
@@ -340,32 +333,137 @@ public class RepositoryTest extends ActiveMQTestBase {
       }
    }
 
-   static class DummyMergeable implements Mergeable {
+   @Test
+   public void testMatchMergeIdempotence() {
+      HierarchicalRepository<DummyMergeable> repository = new 
HierarchicalObjectRepository<>();
+      repository.addMatch("foo.*", new DummyMergeable(0, Map.of("s0", "x")));
+      repository.addMatch("foo.0.#", new DummyMergeable(1, Map.of("so", "a", 
"s1", "a")));
+      repository.addMatch("foo.1.#", new DummyMergeable(2, Map.of("so", "b", 
"s1", "b")));
+
+      DummyMergeable fooxMatch = repository.getMatch("foo.x");
+      Assert.assertEquals(0, fooxMatch.getId());
+      Assert.assertEquals(0, fooxMatch.getMergedItems().size());
+      Assert.assertEquals("x", fooxMatch.getSettings().get("s0"));
+      Assert.assertNull(fooxMatch.getSettings().get("s1"));
+
+      DummyMergeable foo1Match = repository.getMatch("foo.0");
+      Assert.assertEquals(0, foo1Match.getId());
+      Assert.assertEquals(1, foo1Match.getMergedItems().size());
+      Assert.assertEquals("x", fooxMatch.getSettings().get("s0"));
+      Assert.assertEquals("a", foo1Match.getSettings().get("s1"));
+
+      DummyMergeable foo2Match = repository.getMatch("foo.1");
+      Assert.assertEquals(0, foo2Match.getId());
+      Assert.assertEquals(1, foo2Match.getMergedItems().size());
+      Assert.assertEquals("x", fooxMatch.getSettings().get("s0"));
+      Assert.assertEquals("b", foo2Match.getSettings().get("s1"));
+
+      DummyMergeable fooxBisMatch = repository.getMatch("foo.x");
+      Assert.assertEquals(0, fooxBisMatch.getId());
+      Assert.assertEquals(0, fooxBisMatch.getMergedItems().size());
+      Assert.assertEquals("x", fooxBisMatch.getSettings().get("s0"));
+      Assert.assertNull(fooxBisMatch.getSettings().get("s1"));
+
+      DummyMergeable foo1BisMatch = repository.getMatch("foo.0");
+      Assert.assertEquals(0, foo1BisMatch.getId());
+      Assert.assertEquals(1, foo1BisMatch.getMergedItems().size());
+      Assert.assertEquals("x", foo1BisMatch.getSettings().get("s0"));
+      Assert.assertEquals("a", foo1BisMatch.getSettings().get("s1"));
+
+      DummyMergeable foo2BisMatch = repository.getMatch("foo.1");
+      Assert.assertEquals(0, foo2BisMatch.getId());
+      Assert.assertEquals(1, foo2BisMatch.getMergedItems().size());
+      Assert.assertEquals("x", foo2BisMatch.getSettings().get("s0"));
+      Assert.assertEquals("b", foo2BisMatch.getSettings().get("s1"));
+   }
 
-      static int timesMerged = 0;
+   @Test
+   public void testAddressSettingsMergeIdempotence() {
+      AddressSettings foox = new 
AddressSettings().setMaxRedeliveryDelay(10000);
+      AddressSettings foo0 = new 
AddressSettings().setMaxRedeliveryDelay(20000).setMaxExpiryDelay(20000L);
+      AddressSettings foo1 = new 
AddressSettings().setMaxRedeliveryDelay(30000).setMaxExpiryDelay(30000L);
+
+      HierarchicalRepository<AddressSettings> repository = new 
HierarchicalObjectRepository<>();
+      repository.addMatch("foo.*", foox);
+      repository.addMatch("foo.0.#", foo0);
+      repository.addMatch("foo.1.#", foo1);
+
+      AddressSettings fooxMatch = repository.getMatch("foo.x");
+      Assert.assertEquals(10000, fooxMatch.getMaxRedeliveryDelay());
+      
Assert.assertEquals(Long.valueOf(AddressSettings.DEFAULT_MAX_EXPIRY_DELAY), 
fooxMatch.getMaxExpiryDelay());
+
+      AddressSettings foo0Match = repository.getMatch("foo.0");
+      Assert.assertEquals(10000, foo0Match.getMaxRedeliveryDelay());
+      Assert.assertEquals(Long.valueOf(20000), foo0Match.getMaxExpiryDelay());
+
+      AddressSettings foo1Match = repository.getMatch("foo.1");
+      Assert.assertEquals(10000, foo1Match.getMaxRedeliveryDelay());
+      Assert.assertEquals(Long.valueOf(30000), foo1Match.getMaxExpiryDelay());
+
+      AddressSettings fooxBisMatch = repository.getMatch("foo.x");
+      Assert.assertEquals(10000, fooxBisMatch.getMaxRedeliveryDelay());
+      
Assert.assertEquals(Long.valueOf(AddressSettings.DEFAULT_MAX_EXPIRY_DELAY), 
fooxBisMatch.getMaxExpiryDelay());
+
+      AddressSettings foo0BisMatch = repository.getMatch("foo.0");
+      Assert.assertEquals(10000, foo0BisMatch.getMaxRedeliveryDelay());
+      Assert.assertEquals(Long.valueOf(20000), 
foo0BisMatch.getMaxExpiryDelay());
+
+      AddressSettings foo1BisMatch = repository.getMatch("foo.1");
+      Assert.assertEquals(10000, foo1BisMatch.getMaxRedeliveryDelay());
+      Assert.assertEquals(Long.valueOf(30000), 
foo1BisMatch.getMaxExpiryDelay());
+   }
 
-      static ArrayList<Integer> merged = new ArrayList<>();
+   static class DummyMergeable implements Mergeable<DummyMergeable> {
+      private final int id;
+      private final Map<String,String> settings;
+      private final List<DummyMergeable> mergedItems;
 
-      private final Integer id;
+      public int getId() {
+         return id;
+      }
 
-      static void reset() {
-         DummyMergeable.timesMerged = 0;
-         DummyMergeable.merged = new ArrayList<>();
+      public Map<String, String> getSettings() {
+         return settings;
       }
 
-      static boolean contains(final Integer i) {
-         return DummyMergeable.merged.contains(i);
+      public List<DummyMergeable> getMergedItems() {
+         return mergedItems;
       }
 
-      DummyMergeable(final Integer id) {
+      DummyMergeable(final int id) {
          this.id = id;
+         this.settings = new HashMap<>();
+         this.mergedItems = new ArrayList<>();
+      }
+
+      DummyMergeable(final int id, final Map<String,String> settings) {
+         this.id = id;
+         this.settings = settings;
+         this.mergedItems = new ArrayList<>();
+      }
+
+      DummyMergeable(DummyMergeable item) {
+         this.id = item.id;
+         this.settings = new HashMap<>(item.settings);
+         this.mergedItems = new ArrayList<>(item.mergedItems);
       }
 
       @Override
-      public void merge(final Object merged) {
-         DummyMergeable.timesMerged++;
-         DummyMergeable.merged.add(id);
-         DummyMergeable.merged.add(((DummyMergeable) merged).id);
+      public void merge(final DummyMergeable merged) {
+         for (Map.Entry<String, String> entry : merged.settings.entrySet()) {
+            this.settings.putIfAbsent(entry.getKey(), entry.getValue());
+         }
+         this.mergedItems.add(merged);
+      }
+
+      @Override
+      public DummyMergeable mergeCopy(DummyMergeable merged) {
+         DummyMergeable target = new DummyMergeable(this);
+         for (Map.Entry<String, String> entry : merged.settings.entrySet()) {
+            target.settings.putIfAbsent(entry.getKey(), entry.getValue());
+         }
+         target.mergedItems.add(merged);
+         return target;
       }
    }
 }
diff --git 
a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/client/MessageExpirationTest.java
 
b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/client/MessageExpirationTest.java
index fb3be03d54..2aefb8c1a5 100644
--- 
a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/client/MessageExpirationTest.java
+++ 
b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/client/MessageExpirationTest.java
@@ -242,14 +242,7 @@ public class MessageExpirationTest extends 
ActiveMQTestBase {
       final SimpleString expiryAddress = RandomUtil.randomSimpleString();
       SimpleString expiryQueue = RandomUtil.randomSimpleString();
 
-      server.getAddressSettingsRepository().addMatch(address.toString(), new 
AddressSettings() {
-         private static final long serialVersionUID = -6476053400596299130L;
-
-         @Override
-         public SimpleString getExpiryAddress() {
-            return expiryAddress;
-         }
-      });
+      server.getAddressSettingsRepository().addMatch(address.toString(), new 
AddressSettings().setExpiryAddress(expiryAddress));
 
       session.createQueue(new 
QueueConfiguration(queue).setAddress(address).setDurable(false));
       session.createQueue(new 
QueueConfiguration(expiryQueue).setAddress(expiryAddress).setDurable(false));

Reply via email to