You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@activemq.apache.org by jb...@apache.org on 2021/01/25 19:35:31 UTC

[activemq-artemis] branch master updated: ARTEMIS-3008 mngmnt op to reload config file

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

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


The following commit(s) were added to refs/heads/master by this push:
     new 4fbc8bf  ARTEMIS-3008 mngmnt op to reload config file
     new 126e961  This closes #3358
4fbc8bf is described below

commit 4fbc8bf67db427a66d3c55eaf83f661618872dcb
Author: Justin Bertram <jb...@apache.org>
AuthorDate: Tue Nov 24 10:57:02 2020 -0600

    ARTEMIS-3008 mngmnt op to reload config file
---
 .../api/core/management/ActiveMQServerControl.java |   3 +
 .../management/impl/ActiveMQServerControlImpl.java |   5 +
 .../artemis/core/server/ActiveMQServer.java        |   6 +-
 .../core/server/impl/ActiveMQServerImpl.java       |  36 ++---
 docs/user-manual/en/configuration-index.md         |  11 +-
 .../integration/jms/ProgrammaticRedeployTest.java  | 124 ++++++++++++++++
 .../ActiveMQServerControlUsingCoreTest.java        |   5 +
 .../reload-address-queues-programmatic.xml         | 160 +++++++++++++++++++++
 .../reload-address-queues-updated-programmatic.xml | 141 ++++++++++++++++++
 9 files changed, 467 insertions(+), 24 deletions(-)

diff --git a/artemis-core-client/src/main/java/org/apache/activemq/artemis/api/core/management/ActiveMQServerControl.java b/artemis-core-client/src/main/java/org/apache/activemq/artemis/api/core/management/ActiveMQServerControl.java
index d3f4473..e981444 100644
--- a/artemis-core-client/src/main/java/org/apache/activemq/artemis/api/core/management/ActiveMQServerControl.java
+++ b/artemis-core-client/src/main/java/org/apache/activemq/artemis/api/core/management/ActiveMQServerControl.java
@@ -1903,5 +1903,8 @@ public interface ActiveMQServerControl {
                   @Parameter(name = "password", desc = "User's password") String password,
                   @Parameter(name = "roles", desc = "User's role (comma separated)") String roles,
                   @Parameter(name = "plaintext", desc = "whether or not to store the password in plaintext or hash it") boolean plaintext) throws Exception;
+
+   @Operation(desc = "forces the broker to reload its configuration file", impact = MBeanOperationInfo.ACTION)
+   void reloadConfigurationFile() throws Exception;
 }
 
diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/management/impl/ActiveMQServerControlImpl.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/management/impl/ActiveMQServerControlImpl.java
index 46129f0..8306a6d 100644
--- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/management/impl/ActiveMQServerControlImpl.java
+++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/management/impl/ActiveMQServerControlImpl.java
@@ -4385,5 +4385,10 @@ public class ActiveMQServerControlImpl extends AbstractControl implements Active
       String path = configurationUrl.getPath();
       return new PropertiesLoginModuleConfigurator(getSecurityDomain(), path.substring(0, path.lastIndexOf("/")));
    }
+
+   @Override
+   public void reloadConfigurationFile() throws Exception {
+      server.reloadConfigurationFile();
+   }
 }
 
diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/ActiveMQServer.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/ActiveMQServer.java
index 9580adc..2eb7cd0 100644
--- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/ActiveMQServer.java
+++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/ActiveMQServer.java
@@ -54,7 +54,7 @@ import org.apache.activemq.artemis.core.server.impl.AddressInfo;
 import org.apache.activemq.artemis.core.server.impl.ConnectorsService;
 import org.apache.activemq.artemis.core.server.management.ManagementService;
 import org.apache.activemq.artemis.core.server.metrics.MetricsManager;
-import org.apache.activemq.artemis.core.server.plugin.ActiveMQServerFederationPlugin;
+import org.apache.activemq.artemis.core.server.mirror.MirrorController;
 import org.apache.activemq.artemis.core.server.plugin.ActiveMQPluginRunnable;
 import org.apache.activemq.artemis.core.server.plugin.ActiveMQServerAddressPlugin;
 import org.apache.activemq.artemis.core.server.plugin.ActiveMQServerBasePlugin;
@@ -63,12 +63,12 @@ import org.apache.activemq.artemis.core.server.plugin.ActiveMQServerBridgePlugin
 import org.apache.activemq.artemis.core.server.plugin.ActiveMQServerConnectionPlugin;
 import org.apache.activemq.artemis.core.server.plugin.ActiveMQServerConsumerPlugin;
 import org.apache.activemq.artemis.core.server.plugin.ActiveMQServerCriticalPlugin;
+import org.apache.activemq.artemis.core.server.plugin.ActiveMQServerFederationPlugin;
 import org.apache.activemq.artemis.core.server.plugin.ActiveMQServerMessagePlugin;
 import org.apache.activemq.artemis.core.server.plugin.ActiveMQServerQueuePlugin;
 import org.apache.activemq.artemis.core.server.plugin.ActiveMQServerResourcePlugin;
 import org.apache.activemq.artemis.core.server.plugin.ActiveMQServerSessionPlugin;
 import org.apache.activemq.artemis.core.server.reload.ReloadManager;
-import org.apache.activemq.artemis.core.server.mirror.MirrorController;
 import org.apache.activemq.artemis.core.settings.HierarchicalRepository;
 import org.apache.activemq.artemis.core.settings.impl.AddressSettings;
 import org.apache.activemq.artemis.core.transaction.ResourceManager;
@@ -929,4 +929,6 @@ public interface ActiveMQServer extends ServiceComponent {
    String getInternalNamingPrefix();
 
    double getDiskStoreUsage();
+
+   void reloadConfigurationFile() throws Exception;
 }
diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ActiveMQServerImpl.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ActiveMQServerImpl.java
index 5c50982..baab78b 100644
--- a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ActiveMQServerImpl.java
+++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ActiveMQServerImpl.java
@@ -157,6 +157,7 @@ import org.apache.activemq.artemis.core.server.impl.jdbc.JdbcNodeManager;
 import org.apache.activemq.artemis.core.server.management.ManagementService;
 import org.apache.activemq.artemis.core.server.management.impl.ManagementServiceImpl;
 import org.apache.activemq.artemis.core.server.metrics.MetricsManager;
+import org.apache.activemq.artemis.core.server.mirror.MirrorController;
 import org.apache.activemq.artemis.core.server.plugin.ActiveMQPluginRunnable;
 import org.apache.activemq.artemis.core.server.plugin.ActiveMQServerAddressPlugin;
 import org.apache.activemq.artemis.core.server.plugin.ActiveMQServerBasePlugin;
@@ -170,10 +171,8 @@ import org.apache.activemq.artemis.core.server.plugin.ActiveMQServerMessagePlugi
 import org.apache.activemq.artemis.core.server.plugin.ActiveMQServerQueuePlugin;
 import org.apache.activemq.artemis.core.server.plugin.ActiveMQServerResourcePlugin;
 import org.apache.activemq.artemis.core.server.plugin.ActiveMQServerSessionPlugin;
-import org.apache.activemq.artemis.core.server.reload.ReloadCallback;
 import org.apache.activemq.artemis.core.server.reload.ReloadManager;
 import org.apache.activemq.artemis.core.server.reload.ReloadManagerImpl;
-import org.apache.activemq.artemis.core.server.mirror.MirrorController;
 import org.apache.activemq.artemis.core.server.transformer.Transformer;
 import org.apache.activemq.artemis.core.settings.HierarchicalRepository;
 import org.apache.activemq.artemis.core.settings.impl.AddressFullMessagePolicy;
@@ -3103,7 +3102,7 @@ public class ActiveMQServerImpl implements ActiveMQServer {
       this.reloadManager = new ReloadManagerImpl(getScheduledPool(), executorFactory.getExecutor(), configuration.getConfigurationFileRefreshPeriod());
 
       if (configuration.getConfigurationUrl() != null && getScheduledPool() != null) {
-         reloadManager.addCallback(configuration.getConfigurationUrl(), new ConfigurationFileReloader());
+         reloadManager.addCallback(configuration.getConfigurationUrl(), uri -> reloadConfigurationFile(uri));
       }
 
       if (System.getProperty("logging.configuration") != null) {
@@ -4190,22 +4189,23 @@ public class ActiveMQServerImpl implements ActiveMQServer {
 
    }
 
-   private final class ConfigurationFileReloader implements ReloadCallback {
+   @Override
+   public void reloadConfigurationFile() throws Exception {
+      reloadConfigurationFile(configuration.getConfigurationUrl());
+   }
 
-      @Override
-      public void reload(URL uri) throws Exception {
-         Configuration config = new FileConfigurationParser().parseMainConfig(uri.openStream());
-         LegacyJMSConfiguration legacyJMSConfiguration = new LegacyJMSConfiguration(config);
-         legacyJMSConfiguration.parseConfiguration(uri.openStream());
-         configuration.setSecurityRoles(config.getSecurityRoles());
-         configuration.setAddressesSettings(config.getAddressesSettings());
-         configuration.setDivertConfigurations(config.getDivertConfigurations());
-         configuration.setAddressConfigurations(config.getAddressConfigurations());
-         configuration.setQueueConfigs(config.getQueueConfigs());
-         configurationReloadDeployed.set(false);
-         if (isActive()) {
-            deployReloadableConfigFromConfiguration();
-         }
+   private void reloadConfigurationFile(URL uri) throws Exception {
+      Configuration config = new FileConfigurationParser().parseMainConfig(uri.openStream());
+      LegacyJMSConfiguration legacyJMSConfiguration = new LegacyJMSConfiguration(config);
+      legacyJMSConfiguration.parseConfiguration(uri.openStream());
+      configuration.setSecurityRoles(config.getSecurityRoles());
+      configuration.setAddressesSettings(config.getAddressesSettings());
+      configuration.setDivertConfigurations(config.getDivertConfigurations());
+      configuration.setAddressConfigurations(config.getAddressConfigurations());
+      configuration.setQueueConfigs(config.getQueueConfigs());
+      configurationReloadDeployed.set(false);
+      if (isActive()) {
+         deployReloadableConfigFromConfiguration();
       }
    }
 
diff --git a/docs/user-manual/en/configuration-index.md b/docs/user-manual/en/configuration-index.md
index d245220..4027a50 100644
--- a/docs/user-manual/en/configuration-index.md
+++ b/docs/user-manual/en/configuration-index.md
@@ -50,10 +50,13 @@ For further information on XInclude see:
 
 Certain changes in `broker.xml` can be picked up at runtime as discussed in the [Configuration Reload](config-reload.md)
 chapter. Changes made directly to files which are included in `broker.xml` via `xi:include` will not be automatically
-picked up unless the file timestamp on `broker.xml` is also modified. For example, if `broker.xml` is including
-`my-address-settings.xml` and `my-address-settings.xml` is modified those changes won't be loaded until the user uses
-something like the [touch](https://en.wikipedia.org/wiki/Touch_%28Unix%29) command to update the `broker.xml` file's
-timestamp to trigger a reload.
+reloaded. For example, if `broker.xml` is including `my-address-settings.xml` and `my-address-settings.xml` is modified
+those changes won't be reloaded automatically. To force a reload in this situation there are 2 main options: 
+
+1. Use the `reloadConfiguration` management operation on the `ActiveMQServerControl`.
+2. Update the timestamp on `broker.xml` using something like the [touch](https://en.wikipedia.org/wiki/Touch_%28Unix%29)
+   command. The next time the broker inspects `broker.xml` for automatic reload it will see the updated timestamp and
+   trigger a reload of `broker.xml` and all its included files.
 
 ### System properties
 
diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/jms/ProgrammaticRedeployTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/jms/ProgrammaticRedeployTest.java
new file mode 100644
index 0000000..14fb9d4
--- /dev/null
+++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/jms/ProgrammaticRedeployTest.java
@@ -0,0 +1,124 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.activemq.artemis.tests.integration.jms;
+
+import javax.jms.ConnectionFactory;
+import javax.jms.JMSContext;
+import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardCopyOption;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import org.apache.activemq.artemis.api.core.SimpleString;
+import org.apache.activemq.artemis.core.postoffice.QueueBinding;
+import org.apache.activemq.artemis.core.server.embedded.EmbeddedActiveMQ;
+import org.apache.activemq.artemis.core.server.impl.AddressInfo;
+import org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory;
+import org.apache.activemq.artemis.tests.util.ActiveMQTestBase;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class ProgrammaticRedeployTest extends ActiveMQTestBase {
+
+   @Test
+   /**
+    * This is basically a copy of org.apache.activemq.artemis.tests.integration.jms.RedeployTest#testRedeployAddressQueue().
+    * However, this test disables automatic configuration reload and uses the management API to do it instead.
+    */
+   public void testRedeployAddressQueue() throws Exception {
+      Path brokerXML = getTestDirfile().toPath().resolve("broker.xml");
+      URL url1 = ProgrammaticRedeployTest.class.getClassLoader().getResource("reload-address-queues-programmatic.xml");
+      URL url2 = ProgrammaticRedeployTest.class.getClassLoader().getResource("reload-address-queues-updated-programmatic.xml");
+      Files.copy(url1.openStream(), brokerXML);
+
+      EmbeddedActiveMQ embeddedActiveMQ = new EmbeddedActiveMQ();
+      embeddedActiveMQ.setConfigResourcePath(brokerXML.toUri().toString());
+      embeddedActiveMQ.start();
+
+      ConnectionFactory connectionFactory = new ActiveMQConnectionFactory();
+      try (JMSContext jmsContext = connectionFactory.createContext()) {
+         jmsContext.createSharedDurableConsumer(jmsContext.createTopic("config_test_consumer_created_queues"),"mySub").receive(100);
+      }
+
+      try {
+         Assert.assertTrue(listQueuesNamesForAddress(embeddedActiveMQ, "config_test_consumer_created_queues").contains("mySub"));
+
+         Assert.assertNotNull(getAddressInfo(embeddedActiveMQ, "config_test_address_removal_no_queue"));
+         Assert.assertNotNull(getAddressInfo(embeddedActiveMQ, "config_test_address_removal"));
+         Assert.assertNotNull(getAddressInfo(embeddedActiveMQ, "config_test_queue_removal"));
+         Assert.assertTrue(listQueuesNamesForAddress(embeddedActiveMQ, "config_test_queue_removal").contains("config_test_queue_removal_queue_1"));
+         Assert.assertTrue(listQueuesNamesForAddress(embeddedActiveMQ, "config_test_queue_removal").contains("config_test_queue_removal_queue_2"));
+
+         Assert.assertNotNull(getAddressInfo(embeddedActiveMQ, "permanent_test_address_removal"));
+         Assert.assertNotNull(getAddressInfo(embeddedActiveMQ, "permanent_test_queue_removal"));
+         Assert.assertTrue(listQueuesNamesForAddress(embeddedActiveMQ, "permanent_test_queue_removal").contains("permanent_test_queue_removal_queue_1"));
+         Assert.assertTrue(listQueuesNamesForAddress(embeddedActiveMQ, "permanent_test_queue_removal").contains("permanent_test_queue_removal_queue_2"));
+
+         Assert.assertNotNull(getAddressInfo(embeddedActiveMQ, "config_test_queue_change"));
+         Assert.assertTrue(listQueuesNamesForAddress(embeddedActiveMQ, "config_test_queue_change").contains("config_test_queue_change_queue"));
+         Assert.assertEquals(10, getQueue(embeddedActiveMQ, "config_test_queue_change_queue").getMaxConsumers());
+         Assert.assertEquals(false, getQueue(embeddedActiveMQ, "config_test_queue_change_queue").isPurgeOnNoConsumers());
+
+         Files.copy(url2.openStream(), brokerXML, StandardCopyOption.REPLACE_EXISTING);
+         brokerXML.toFile().setLastModified(System.currentTimeMillis() + 1000);
+
+         embeddedActiveMQ.getActiveMQServer().reloadConfigurationFile();
+
+         //Ensure queues created by clients (NOT by broker.xml are not removed when we reload).
+         Assert.assertTrue(listQueuesNamesForAddress(embeddedActiveMQ, "config_test_consumer_created_queues").contains("mySub"));
+
+         Assert.assertNull(getAddressInfo(embeddedActiveMQ, "config_test_address_removal_no_queue"));
+         Assert.assertNull(getAddressInfo(embeddedActiveMQ, "config_test_address_removal"));
+         Assert.assertNotNull(getAddressInfo(embeddedActiveMQ, "config_test_queue_removal"));
+         Assert.assertTrue(listQueuesNamesForAddress(embeddedActiveMQ, "config_test_queue_removal").contains("config_test_queue_removal_queue_1"));
+         Assert.assertFalse(listQueuesNamesForAddress(embeddedActiveMQ, "config_test_queue_removal").contains("config_test_queue_removal_queue_2"));
+
+         Assert.assertNotNull(getAddressInfo(embeddedActiveMQ, "permanent_test_address_removal"));
+         Assert.assertNotNull(getAddressInfo(embeddedActiveMQ, "permanent_test_queue_removal"));
+         Assert.assertTrue(listQueuesNamesForAddress(embeddedActiveMQ, "permanent_test_queue_removal").contains("permanent_test_queue_removal_queue_1"));
+         Assert.assertTrue(listQueuesNamesForAddress(embeddedActiveMQ, "permanent_test_queue_removal").contains("permanent_test_queue_removal_queue_2"));
+
+         Assert.assertNotNull(getAddressInfo(embeddedActiveMQ, "config_test_queue_change"));
+         Assert.assertTrue(listQueuesNamesForAddress(embeddedActiveMQ, "config_test_queue_change").contains("config_test_queue_change_queue"));
+         Assert.assertEquals(1, getQueue(embeddedActiveMQ, "config_test_queue_change_queue").getMaxConsumers());
+         Assert.assertEquals(true, getQueue(embeddedActiveMQ, "config_test_queue_change_queue").isPurgeOnNoConsumers());
+
+         Assert.assertNull(getAddressInfo(embeddedActiveMQ, "config_test_queue_change_queue"));
+         Assert.assertNull(getAddressInfo(embeddedActiveMQ, "config_test_queue_removal_queue_1"));
+      } finally {
+         embeddedActiveMQ.stop();
+      }
+   }
+
+   private AddressInfo getAddressInfo(EmbeddedActiveMQ embeddedActiveMQ, String address) {
+      return embeddedActiveMQ.getActiveMQServer().getPostOffice().getAddressInfo(SimpleString.toSimpleString(address));
+   }
+
+   private org.apache.activemq.artemis.core.server.Queue getQueue(EmbeddedActiveMQ embeddedActiveMQ, String queueName) throws Exception {
+      QueueBinding queueBinding = (QueueBinding) embeddedActiveMQ.getActiveMQServer().getPostOffice().getBinding(SimpleString.toSimpleString(queueName));
+      return queueBinding == null ? null : queueBinding.getQueue();
+   }
+
+   private List<String> listQueuesNamesForAddress(EmbeddedActiveMQ embeddedActiveMQ, String address) throws Exception {
+      return embeddedActiveMQ.getActiveMQServer().getPostOffice().listQueuesForAddress(SimpleString.toSimpleString(address)).stream().map(
+          org.apache.activemq.artemis.core.server.Queue::getName).map(SimpleString::toString).collect(Collectors.toList());
+   }
+
+}
diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/ActiveMQServerControlUsingCoreTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/ActiveMQServerControlUsingCoreTest.java
index 5d04f6c..882e5ca 100644
--- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/ActiveMQServerControlUsingCoreTest.java
+++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/management/ActiveMQServerControlUsingCoreTest.java
@@ -447,6 +447,11 @@ public class ActiveMQServerControlUsingCoreTest extends ActiveMQServerControlTes
          }
 
          @Override
+         public void reloadConfigurationFile() throws Exception {
+            proxy.invokeOperation("reloadConfigurationFile");
+         }
+
+         @Override
          public String getUptime() {
             return null;
          }
diff --git a/tests/integration-tests/src/test/resources/reload-address-queues-programmatic.xml b/tests/integration-tests/src/test/resources/reload-address-queues-programmatic.xml
new file mode 100644
index 0000000..05cce1d
--- /dev/null
+++ b/tests/integration-tests/src/test/resources/reload-address-queues-programmatic.xml
@@ -0,0 +1,160 @@
+<?xml version='1.0'?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<configuration xmlns="urn:activemq"
+               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+               xsi:schemaLocation="urn:activemq /schema/artemis-configuration.xsd">
+
+   <core xmlns="urn:activemq:core">
+
+      <name>0.0.0.0</name>
+
+      <configuration-file-refresh-period>9223372036854775807</configuration-file-refresh-period>
+
+      <persistence-enabled>false</persistence-enabled>
+
+      <security-enabled>false</security-enabled>
+
+      <!-- this could be ASYNCIO or NIO
+       -->
+      <journal-type>NIO</journal-type>
+
+      <paging-directory>./data/paging</paging-directory>
+
+      <bindings-directory>./data/bindings</bindings-directory>
+
+      <journal-directory>./data/journal</journal-directory>
+
+      <large-messages-directory>./data/large-messages</large-messages-directory>
+
+      <journal-min-files>2</journal-min-files>
+
+      <journal-pool-files>-1</journal-pool-files>
+
+      <!--
+       This value was determined through a calculation.
+       Your system could perform 25 writes per millisecond
+       on the current journal configuration.
+       That translates as a sync write every 40000 nanoseconds
+      -->
+      <journal-buffer-timeout>40000</journal-buffer-timeout>
+
+
+      <acceptors>
+         <!-- Default ActiveMQ Artemis Acceptor.  Multi-protocol adapter.  Currently supports ActiveMQ Artemis Core, OpenWire, STOMP, AMQP, MQTT, and HornetQ Core. -->
+         <!-- performance tests have shown that openWire performs best with these buffer sizes -->
+         <acceptor name="artemis">tcp://0.0.0.0:61616?tcpSendBufferSize=1048576;tcpReceiveBufferSize=1048576</acceptor>
+
+         <!-- AMQP Acceptor.  Listens on default AMQP port for AMQP traffic.-->
+         <acceptor name="amqp">tcp://0.0.0.0:5672?protocols=AMQP</acceptor>
+
+         <!-- STOMP Acceptor. -->
+         <acceptor name="stomp">tcp://0.0.0.0:61613?protocols=STOMP</acceptor>
+
+         <!-- HornetQ Compatibility Acceptor.  Enables HornetQ Core and STOMP for legacy HornetQ clients. -->
+         <acceptor name="hornetq">tcp://0.0.0.0:5445?protocols=HORNETQ,STOMP</acceptor>
+
+         <!-- MQTT Acceptor -->
+         <acceptor name="mqtt">tcp://0.0.0.0:1883?protocols=MQTT</acceptor>
+
+      </acceptors>
+
+
+      <security-settings>
+         <security-setting match="#">
+            <permission type="createNonDurableQueue" roles="a"/>
+            <permission type="deleteNonDurableQueue" roles="a"/>
+            <permission type="createDurableQueue" roles="a"/>
+            <permission type="deleteDurableQueue" roles="a"/>
+            <permission type="browse" roles="a"/>
+            <permission type="send" roles="a"/>
+            <!-- we need this otherwise ./artemis data imp wouldn't work -->
+            <permission type="manage" roles="a"/>
+         </security-setting>
+      </security-settings>
+
+      <address-settings>
+         <!--default for catch all-->
+         <address-setting match="#">
+            <auto-create-queues>false</auto-create-queues>
+            <dead-letter-address>DLQ</dead-letter-address>
+            <expiry-address>ExpiryQueue</expiry-address>
+            <redelivery-delay>0</redelivery-delay>
+            <max-size-bytes>10Mb</max-size-bytes>
+            <message-counter-history-day-limit>10</message-counter-history-day-limit>
+            <address-full-policy>BLOCK</address-full-policy>
+         </address-setting>
+         
+         <address-setting match="config_#">
+            <auto-create-queues>false</auto-create-queues>
+            <dead-letter-address>DLQ</dead-letter-address>
+            <expiry-address>ExpiryQueue</expiry-address>
+            <redelivery-delay>0</redelivery-delay>
+            <max-size-bytes>10Mb</max-size-bytes>
+            <message-counter-history-day-limit>10</message-counter-history-day-limit>
+            <address-full-policy>BLOCK</address-full-policy>
+            <config-delete-queues>FORCE</config-delete-queues>
+            <config-delete-addresses>FORCE</config-delete-addresses>
+         </address-setting>
+      </address-settings>
+
+      <wildcard-addresses>
+         <delimiter>_</delimiter>
+      </wildcard-addresses>
+
+      <addresses>
+         <address name="config_test_consumer_created_queues">
+            <multicast>
+            </multicast>
+         </address>
+         <address name="config_test_queue_removal">
+            <multicast>
+               <queue name="config_test_queue_removal_queue_1"/>
+               <queue name="config_test_queue_removal_queue_2"/>
+            </multicast>
+         </address>
+         <address name="config_test_address_removal">
+            <multicast>
+               <queue name="config_test_address_removal_queue"/>
+            </multicast>
+         </address>
+         <address name="config_test_address_removal_no_queue">
+            <multicast>
+            </multicast>
+         </address>
+         <address name="permanent_test_queue_removal">
+            <multicast>
+               <queue name="permanent_test_queue_removal_queue_1"/>
+               <queue name="permanent_test_queue_removal_queue_2"/>
+            </multicast>
+         </address>
+         <address name="permanent_test_address_removal">
+            <multicast>
+               <queue name="permanent_test_address_removal_queue"/>
+            </multicast>
+         </address>
+         <address name="config_test_queue_change">
+            <multicast>
+               <queue name="config_test_queue_change_queue" max-consumers="10" purge-on-no-consumers="false" />
+            </multicast>
+         </address>
+      </addresses>
+   </core>
+</configuration>
diff --git a/tests/integration-tests/src/test/resources/reload-address-queues-updated-programmatic.xml b/tests/integration-tests/src/test/resources/reload-address-queues-updated-programmatic.xml
new file mode 100644
index 0000000..8e4575f
--- /dev/null
+++ b/tests/integration-tests/src/test/resources/reload-address-queues-updated-programmatic.xml
@@ -0,0 +1,141 @@
+<?xml version='1.0'?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<configuration xmlns="urn:activemq"
+               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+               xsi:schemaLocation="urn:activemq /schema/artemis-configuration.xsd">
+
+   <core xmlns="urn:activemq:core">
+
+      <name>0.0.0.0</name>
+
+      <configuration-file-refresh-period>9223372036854775807</configuration-file-refresh-period>
+
+      <persistence-enabled>false</persistence-enabled>
+
+      <security-enabled>false</security-enabled>
+
+      <!-- this could be ASYNCIO or NIO
+       -->
+      <journal-type>NIO</journal-type>
+
+      <paging-directory>./data/paging</paging-directory>
+
+      <bindings-directory>./data/bindings</bindings-directory>
+
+      <journal-directory>./data/journal</journal-directory>
+
+      <large-messages-directory>./data/large-messages</large-messages-directory>
+
+      <journal-min-files>2</journal-min-files>
+
+      <journal-pool-files>-1</journal-pool-files>
+
+      <!--
+       This value was determined through a calculation.
+       Your system could perform 25 writes per millisecond
+       on the current journal configuration.
+       That translates as a sync write every 40000 nanoseconds
+      -->
+      <journal-buffer-timeout>40000</journal-buffer-timeout>
+
+
+      <acceptors>
+         <!-- Default ActiveMQ Artemis Acceptor.  Multi-protocol adapter.  Currently supports ActiveMQ Artemis Core, OpenWire, STOMP, AMQP, MQTT, and HornetQ Core. -->
+         <!-- performance tests have shown that openWire performs best with these buffer sizes -->
+         <acceptor name="artemis">tcp://0.0.0.0:61616?tcpSendBufferSize=1048576;tcpReceiveBufferSize=1048576</acceptor>
+
+         <!-- AMQP Acceptor.  Listens on default AMQP port for AMQP traffic.-->
+         <acceptor name="amqp">tcp://0.0.0.0:5672?protocols=AMQP</acceptor>
+
+         <!-- STOMP Acceptor. -->
+         <acceptor name="stomp">tcp://0.0.0.0:61613?protocols=STOMP</acceptor>
+
+         <!-- HornetQ Compatibility Acceptor.  Enables HornetQ Core and STOMP for legacy HornetQ clients. -->
+         <acceptor name="hornetq">tcp://0.0.0.0:5445?protocols=HORNETQ,STOMP</acceptor>
+
+         <!-- MQTT Acceptor -->
+         <acceptor name="mqtt">tcp://0.0.0.0:1883?protocols=MQTT</acceptor>
+
+      </acceptors>
+
+
+      <security-settings>
+         <security-setting match="#">
+            <permission type="createNonDurableQueue" roles="a"/>
+            <permission type="deleteNonDurableQueue" roles="a"/>
+            <permission type="createDurableQueue" roles="a"/>
+            <permission type="deleteDurableQueue" roles="a"/>
+            <permission type="browse" roles="a"/>
+            <permission type="send" roles="a"/>
+            <!-- we need this otherwise ./artemis data imp wouldn't work -->
+            <permission type="manage" roles="a"/>
+         </security-setting>
+      </security-settings>
+
+      <address-settings>
+         <!--default for catch all-->
+         <address-setting match="#">
+            <redelivery-delay>0</redelivery-delay>
+            <max-size-bytes>10Mb</max-size-bytes>
+            <message-counter-history-day-limit>10</message-counter-history-day-limit>
+            <address-full-policy>BLOCK</address-full-policy>
+         </address-setting>
+         
+         <address-setting match="config_#">
+            <auto-create-queues>false</auto-create-queues>
+            <dead-letter-address>DLQ</dead-letter-address>
+            <expiry-address>ExpiryQueue</expiry-address>
+            <redelivery-delay>0</redelivery-delay>
+            <max-size-bytes>10Mb</max-size-bytes>
+            <message-counter-history-day-limit>10</message-counter-history-day-limit>
+            <address-full-policy>BLOCK</address-full-policy>
+            <config-delete-queues>FORCE</config-delete-queues>
+            <config-delete-addresses>FORCE</config-delete-addresses>
+         </address-setting>
+      </address-settings>
+
+      <wildcard-addresses>
+         <delimiter>_</delimiter>
+      </wildcard-addresses>
+
+      <addresses>
+         <address name="config_test_consumer_created_queues">
+            <multicast>
+            </multicast>
+         </address>
+         <address name="config_test_queue_removal">
+            <multicast>
+               <queue name="config_test_queue_removal_queue_1"/>
+            </multicast>
+         </address>
+         <address name="permanent_test_queue_removal">
+            <multicast>
+               <queue name="permanent_test_queue_removal_queue_1"/>
+            </multicast>
+         </address>
+         <address name="config_test_queue_change">
+            <multicast>
+               <queue name="config_test_queue_change_queue" max-consumers="1" purge-on-no-consumers="true" />
+            </multicast>
+         </address>
+      </addresses>
+   </core>
+</configuration>