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 2016/08/10 14:24:54 UTC

[1/2] activemq-artemis git commit: ARTEMIS-601 Implementing reload manager on JMS Destinations and Address Settings

Repository: activemq-artemis
Updated Branches:
  refs/heads/master 155a345d3 -> 2b710229e


ARTEMIS-601 Implementing reload manager on JMS Destinations and Address Settings


Project: http://git-wip-us.apache.org/repos/asf/activemq-artemis/repo
Commit: http://git-wip-us.apache.org/repos/asf/activemq-artemis/commit/04d48203
Tree: http://git-wip-us.apache.org/repos/asf/activemq-artemis/tree/04d48203
Diff: http://git-wip-us.apache.org/repos/asf/activemq-artemis/diff/04d48203

Branch: refs/heads/master
Commit: 04d482037c6dcd7b6272fbc83a6ce5de7886d311
Parents: 155a345
Author: Clebert Suconic <cl...@apache.org>
Authored: Tue Aug 9 22:37:14 2016 -0400
Committer: Clebert Suconic <cl...@apache.org>
Committed: Wed Aug 10 10:03:40 2016 -0400

----------------------------------------------------------------------
 .../jms/server/config/JMSConfiguration.java     |   6 +
 .../config/impl/FileJMSConfiguration.java       |   1 +
 .../config/impl/JMSConfigurationImpl.java       |  14 ++
 .../jms/server/impl/JMSServerManagerImpl.java   |  37 +++++
 .../artemis/core/server/ActiveMQServer.java     |   3 +
 .../core/server/impl/ActiveMQServerImpl.java    |  49 ++----
 .../core/server/reload/ReloadCallback.java      |  24 +++
 .../core/server/reload/ReloadManager.java       |  29 ++++
 .../core/server/reload/ReloadManagerImpl.java   | 165 +++++++++++++++++++
 .../artemis/core/reload/ReloadManagerTest.java  |  89 ++++++++++
 .../tests/integration/jms/RedeployTest.java     |  97 +++++++++++
 .../src/test/resources/reload-test-jms.xml      | 112 +++++++++++++
 .../test/resources/reload-test-updated-jms.xml  | 114 +++++++++++++
 13 files changed, 708 insertions(+), 32 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/04d48203/artemis-jms-server/src/main/java/org/apache/activemq/artemis/jms/server/config/JMSConfiguration.java
----------------------------------------------------------------------
diff --git a/artemis-jms-server/src/main/java/org/apache/activemq/artemis/jms/server/config/JMSConfiguration.java b/artemis-jms-server/src/main/java/org/apache/activemq/artemis/jms/server/config/JMSConfiguration.java
index 3fd0298..8c8f7e0 100644
--- a/artemis-jms-server/src/main/java/org/apache/activemq/artemis/jms/server/config/JMSConfiguration.java
+++ b/artemis-jms-server/src/main/java/org/apache/activemq/artemis/jms/server/config/JMSConfiguration.java
@@ -16,6 +16,7 @@
  */
 package org.apache.activemq.artemis.jms.server.config;
 
+import java.net.URL;
 import java.util.List;
 
 public interface JMSConfiguration {
@@ -35,4 +36,9 @@ public interface JMSConfiguration {
    String getDomain();
 
    JMSConfiguration setDomain(String domain);
+
+   URL getConfigurationUrl();
+
+   JMSConfiguration setConfigurationUrl(URL configurationUrl);
+
 }

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/04d48203/artemis-jms-server/src/main/java/org/apache/activemq/artemis/jms/server/config/impl/FileJMSConfiguration.java
----------------------------------------------------------------------
diff --git a/artemis-jms-server/src/main/java/org/apache/activemq/artemis/jms/server/config/impl/FileJMSConfiguration.java b/artemis-jms-server/src/main/java/org/apache/activemq/artemis/jms/server/config/impl/FileJMSConfiguration.java
index f17568d..a0c81f9 100644
--- a/artemis-jms-server/src/main/java/org/apache/activemq/artemis/jms/server/config/impl/FileJMSConfiguration.java
+++ b/artemis-jms-server/src/main/java/org/apache/activemq/artemis/jms/server/config/impl/FileJMSConfiguration.java
@@ -60,6 +60,7 @@ public class FileJMSConfiguration extends JMSConfigurationImpl implements Deploy
    @Override
    public void parse(Element config, URL url) throws Exception {
       parseConfiguration(config);
+      setConfigurationUrl(url);
       parsed = true;
    }
 

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/04d48203/artemis-jms-server/src/main/java/org/apache/activemq/artemis/jms/server/config/impl/JMSConfigurationImpl.java
----------------------------------------------------------------------
diff --git a/artemis-jms-server/src/main/java/org/apache/activemq/artemis/jms/server/config/impl/JMSConfigurationImpl.java b/artemis-jms-server/src/main/java/org/apache/activemq/artemis/jms/server/config/impl/JMSConfigurationImpl.java
index 406fb3b..6959098 100644
--- a/artemis-jms-server/src/main/java/org/apache/activemq/artemis/jms/server/config/impl/JMSConfigurationImpl.java
+++ b/artemis-jms-server/src/main/java/org/apache/activemq/artemis/jms/server/config/impl/JMSConfigurationImpl.java
@@ -16,6 +16,7 @@
  */
 package org.apache.activemq.artemis.jms.server.config.impl;
 
+import java.net.URL;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -35,6 +36,8 @@ public class JMSConfigurationImpl implements JMSConfiguration {
 
    private String domain = ActiveMQDefaultConfiguration.getDefaultJmxDomain();
 
+   private URL configurationUrl;
+
    // JMSConfiguration implementation -------------------------------
 
    public JMSConfigurationImpl() {
@@ -83,4 +86,15 @@ public class JMSConfigurationImpl implements JMSConfiguration {
       this.domain = domain;
       return this;
    }
+
+   @Override
+   public URL getConfigurationUrl() {
+      return configurationUrl;
+   }
+
+   @Override
+   public JMSConfiguration setConfigurationUrl(URL configurationUrl) {
+      this.configurationUrl = configurationUrl;
+      return this;
+   }
 }

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/04d48203/artemis-jms-server/src/main/java/org/apache/activemq/artemis/jms/server/impl/JMSServerManagerImpl.java
----------------------------------------------------------------------
diff --git a/artemis-jms-server/src/main/java/org/apache/activemq/artemis/jms/server/impl/JMSServerManagerImpl.java b/artemis-jms-server/src/main/java/org/apache/activemq/artemis/jms/server/impl/JMSServerManagerImpl.java
index b15dba3..364bb75 100644
--- a/artemis-jms-server/src/main/java/org/apache/activemq/artemis/jms/server/impl/JMSServerManagerImpl.java
+++ b/artemis-jms-server/src/main/java/org/apache/activemq/artemis/jms/server/impl/JMSServerManagerImpl.java
@@ -21,7 +21,11 @@ import javax.json.JsonArrayBuilder;
 import javax.json.JsonObject;
 import javax.naming.NamingException;
 import javax.transaction.xa.Xid;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
 import java.net.InetAddress;
+import java.net.URL;
 import java.net.UnknownHostException;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -59,6 +63,8 @@ import org.apache.activemq.artemis.core.server.QueueCreator;
 import org.apache.activemq.artemis.core.server.QueueDeleter;
 import org.apache.activemq.artemis.core.server.impl.ActiveMQServerImpl;
 import org.apache.activemq.artemis.core.server.management.Notification;
+import org.apache.activemq.artemis.core.server.reload.ReloadCallback;
+import org.apache.activemq.artemis.core.server.reload.ReloadManager;
 import org.apache.activemq.artemis.core.settings.impl.AddressSettings;
 import org.apache.activemq.artemis.core.transaction.ResourceManager;
 import org.apache.activemq.artemis.core.transaction.Transaction;
@@ -82,6 +88,7 @@ import org.apache.activemq.artemis.jms.server.config.JMSConfiguration;
 import org.apache.activemq.artemis.jms.server.config.JMSQueueConfiguration;
 import org.apache.activemq.artemis.jms.server.config.TopicConfiguration;
 import org.apache.activemq.artemis.jms.server.config.impl.ConnectionFactoryConfigurationImpl;
+import org.apache.activemq.artemis.jms.server.config.impl.FileJMSConfiguration;
 import org.apache.activemq.artemis.jms.server.management.JMSManagementService;
 import org.apache.activemq.artemis.jms.server.management.JMSNotificationType;
 import org.apache.activemq.artemis.jms.server.management.impl.JMSManagementServiceImpl;
@@ -91,6 +98,8 @@ import org.apache.activemq.artemis.utils.JsonLoader;
 import org.apache.activemq.artemis.utils.SelectorTranslator;
 import org.apache.activemq.artemis.utils.TimeAndCounterIDGenerator;
 import org.apache.activemq.artemis.utils.TypedProperties;
+import org.apache.activemq.artemis.utils.XMLUtil;
+import org.w3c.dom.Element;
 
 /**
  * A Deployer used to create and add to Bindings queues, topics and connection
@@ -204,6 +213,8 @@ public class JMSServerManagerImpl implements JMSServerManager, ActivateCallback
          // do not clear the cachedCommands - HORNETQ-1047
 
          recoverBindings();
+
+
       }
       catch (Exception e) {
          active = false;
@@ -394,6 +405,11 @@ public class JMSServerManagerImpl implements JMSServerManager, ActivateCallback
        */
       startCalled = true;
       server.start();
+      ReloadManager reloadManager = server.getReloadManager();
+      if (config != null && config.getConfigurationUrl() != null && reloadManager != null) {
+         reloadManager.addCallback(config.getConfigurationUrl(), new JMSReloader());
+      }
+
 
    }
 
@@ -1741,4 +1757,25 @@ public class JMSServerManagerImpl implements JMSServerManager, ActivateCallback
          }
       }
    }
+
+   private final class JMSReloader implements ReloadCallback {
+      @Override
+      public void reload(URL url) throws Exception {
+         InputStream input = url.openStream();
+         Reader reader = new InputStreamReader(input);
+         String xml = XMLUtil.readerToString(reader);
+         xml = XMLUtil.replaceSystemProps(xml);
+         Element e = XMLUtil.stringToElement(xml);
+
+         if (config instanceof FileJMSConfiguration) {
+            ((FileJMSConfiguration)config).parse(e, url);
+
+            JMSServerManagerImpl.this.deploy();
+         }
+
+
+
+      }
+   }
+
 }

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/04d48203/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/ActiveMQServer.java
----------------------------------------------------------------------
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 af2f7cf..b777ced 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
@@ -41,6 +41,7 @@ import org.apache.activemq.artemis.core.server.group.GroupingHandler;
 import org.apache.activemq.artemis.core.server.impl.Activation;
 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.reload.ReloadManager;
 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;
@@ -379,6 +380,8 @@ public interface ActiveMQServer extends ActiveMQComponent {
    * */
    void removeProtocolManagerFactory(ProtocolManagerFactory factory);
 
+   ReloadManager getReloadManager();
+
    ActiveMQServer createBackupServer(Configuration configuration);
 
    void addScaledDownNode(SimpleString scaledDownNodeId);

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/04d48203/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/impl/ActiveMQServerImpl.java
----------------------------------------------------------------------
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 cc9ef1d..7edd985 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
@@ -129,6 +129,9 @@ import org.apache.activemq.artemis.core.server.group.impl.LocalGroupingHandler;
 import org.apache.activemq.artemis.core.server.group.impl.RemoteGroupingHandler;
 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.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.settings.HierarchicalRepository;
 import org.apache.activemq.artemis.core.settings.impl.AddressSettings;
 import org.apache.activemq.artemis.core.settings.impl.HierarchicalObjectRepository;
@@ -244,6 +247,8 @@ public class ActiveMQServerImpl implements ActiveMQServer {
 
    private MemoryManager memoryManager;
 
+   private ReloadManager reloadManager;
+
    /**
     * This will be set by the JMS Queue Manager.
     */
@@ -374,6 +379,10 @@ public class ActiveMQServerImpl implements ActiveMQServer {
       this.serviceRegistry = serviceRegistry == null ? new ServiceRegistryImpl() : serviceRegistry;
    }
 
+   public ReloadManager getReloadManager() {
+      return reloadManager;
+   }
+
    // life-cycle methods
    // ----------------------------------------------------------------
 
@@ -453,8 +462,10 @@ public class ActiveMQServerImpl implements ActiveMQServer {
          connectorsService = new ConnectorsService(configuration, storageManager, scheduledPool, postOffice, serviceRegistry);
          connectorsService.start();
 
+         this.reloadManager = new ReloadManagerImpl(getScheduledPool(), configuration.getConfigurationFileRefreshPeriod());
+
          if (configuration.getConfigurationUrl() != null && getScheduledPool() != null) {
-            getScheduledPool().scheduleWithFixedDelay(new ConfigurationFileReloader(this), configuration.getConfigurationFileRefreshPeriod(), configuration.getConfigurationFileRefreshPeriod(), TimeUnit.MILLISECONDS);
+            reloadManager.addCallback(configuration.getConfigurationUrl(), new ConfigurationFileReloader());
          }
       }
       finally {
@@ -2358,38 +2369,12 @@ public class ActiveMQServerImpl implements ActiveMQServer {
 
    }
 
-   private final class ConfigurationFileReloader implements Runnable {
-      long lastModified;
-      boolean first = true;
-      ActiveMQServer server;
-
-      ConfigurationFileReloader(ActiveMQServer server) {
-         this.server = server;
-      }
-
+   private final class ConfigurationFileReloader implements ReloadCallback {
       @Override
-      public void run() {
-         try {
-            URL url = server.getConfiguration().getConfigurationUrl();
-            long currentLastModified = new File(url.getPath()).lastModified();
-            if (first) {
-               first = false;
-               lastModified = currentLastModified;
-               return;
-            }
-            if (currentLastModified > lastModified) {
-               if (ActiveMQServerLogger.LOGGER.isDebugEnabled()) {
-                  ActiveMQServerLogger.LOGGER.debug("Configuration file change detected. Reloading...");
-               }
-               Configuration config = new FileConfigurationParser().parseMainConfig(url.openStream());
-               securityRepository.swap(config.getSecurityRoles().entrySet());
-
-               lastModified = currentLastModified;
-            }
-         }
-         catch (Exception e) {
-            ActiveMQServerLogger.LOGGER.configurationReloadFailed(e);
-         }
+      public void reload(URL uri) throws Exception {
+         Configuration config = new FileConfigurationParser().parseMainConfig(uri.openStream());
+         securityRepository.swap(config.getSecurityRoles().entrySet());
+         addressSettingsRepository.swap(config.getAddressesSettings().entrySet());
       }
    }
 }

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/04d48203/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/reload/ReloadCallback.java
----------------------------------------------------------------------
diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/reload/ReloadCallback.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/reload/ReloadCallback.java
new file mode 100644
index 0000000..cc4f5df
--- /dev/null
+++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/reload/ReloadCallback.java
@@ -0,0 +1,24 @@
+/**
+ * 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.core.server.reload;
+
+import java.net.URL;
+
+public interface ReloadCallback {
+   void reload(URL uri) throws Exception;
+}

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/04d48203/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/reload/ReloadManager.java
----------------------------------------------------------------------
diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/reload/ReloadManager.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/reload/ReloadManager.java
new file mode 100644
index 0000000..0dfe6a7
--- /dev/null
+++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/reload/ReloadManager.java
@@ -0,0 +1,29 @@
+/**
+ * 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.core.server.reload;
+
+import java.net.URL;
+
+import org.apache.activemq.artemis.core.server.ActiveMQComponent;
+
+public interface ReloadManager extends ActiveMQComponent {
+   void addCallback(URL uri, ReloadCallback callback);
+
+   /** Callback for the next tick */
+   void setTick(Runnable callback);
+}

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/04d48203/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/reload/ReloadManagerImpl.java
----------------------------------------------------------------------
diff --git a/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/reload/ReloadManagerImpl.java b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/reload/ReloadManagerImpl.java
new file mode 100644
index 0000000..0ccbea1
--- /dev/null
+++ b/artemis-server/src/main/java/org/apache/activemq/artemis/core/server/reload/ReloadManagerImpl.java
@@ -0,0 +1,165 @@
+/**
+ * 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.core.server.reload;
+
+import java.io.File;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.activemq.artemis.core.server.ActiveMQServerLogger;
+import org.jboss.logging.Logger;
+
+public class ReloadManagerImpl implements ReloadManager {
+   private static final Logger logger = Logger.getLogger(ReloadManagerImpl.class);
+
+   private final ScheduledExecutorService scheduledExecutorService;
+   private final long checkPeriod;
+   private ScheduledFuture future;
+   private volatile Runnable tick;
+
+   private Map<URL, ReloadRegistry> registry = new HashMap<>();
+
+   public ReloadManagerImpl(ScheduledExecutorService scheduledExecutorService, long checkPeriod) {
+      this.scheduledExecutorService = scheduledExecutorService;
+      this.checkPeriod = checkPeriod;
+   }
+
+   @Override
+   public synchronized void start() {
+      if (future != null) {
+         return;
+      }
+      future = scheduledExecutorService.scheduleWithFixedDelay(new ConfigurationFileReloader(), checkPeriod, checkPeriod, TimeUnit.MILLISECONDS);
+   }
+
+   @Override
+   public synchronized void setTick(Runnable tick) {
+      this.tick = tick;
+   }
+
+   @Override
+   public synchronized void stop() {
+      if (future == null) {
+         return; // no big deal
+      }
+
+      future.cancel(false);
+      future = null;
+
+   }
+
+   @Override
+   public synchronized boolean isStarted() {
+      return future != null;
+   }
+
+   @Override
+   public synchronized void addCallback(URL uri, ReloadCallback callback) {
+      if (future == null) {
+         start();
+      }
+      ReloadRegistry uriRegistry = getRegistry(uri);
+      uriRegistry.add(callback);
+   }
+
+   private synchronized void tick() {
+      for (ReloadRegistry item : registry.values()) {
+         item.check();
+      }
+
+      if (tick != null) {
+         tick.run();
+         tick = null;
+      }
+   }
+
+   private ReloadRegistry getRegistry(URL uri) {
+      ReloadRegistry uriRegistry = registry.get(uri);
+      if (uriRegistry == null) {
+         uriRegistry = new ReloadRegistry(uri);
+         registry.put(uri, uriRegistry);
+      }
+
+      return uriRegistry;
+   }
+
+
+
+   private final class ConfigurationFileReloader implements Runnable {
+      @Override
+      public void run() {
+         try {
+            tick();
+         }
+         catch (Exception e) {
+            ActiveMQServerLogger.LOGGER.configurationReloadFailed(e);
+         }
+      }
+   }
+
+   class ReloadRegistry {
+      private final File file;
+      private final URL uri;
+      private volatile long lastModified;
+
+      private final List<ReloadCallback> callbacks = new LinkedList<>();
+
+      ReloadRegistry(URL uri) {
+         this.file = new File(uri.getPath());
+         this.uri = uri;
+      }
+
+      public void check()  {
+
+         long fileModified = file.lastModified();
+
+         if (logger.isDebugEnabled()) {
+            logger.debug("Validating lastModified " + lastModified + " modified = " + fileModified + " on " + uri);
+         }
+
+         if (lastModified > 0 && fileModified > lastModified) {
+
+            for (ReloadCallback callback : callbacks) {
+               try {
+                  callback.reload(uri);
+               }
+               catch (Throwable e) {
+                  ActiveMQServerLogger.LOGGER.configurationReloadFailed(e);
+               }
+            }
+         }
+
+         this.lastModified = fileModified;
+      }
+
+
+      public List<ReloadCallback> getCallbacks() {
+         return callbacks;
+      }
+
+      public void add(ReloadCallback callback) {
+         callbacks.add(callback);
+      }
+   }
+}

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/04d48203/artemis-server/src/test/java/org/apache/activemq/artemis/core/reload/ReloadManagerTest.java
----------------------------------------------------------------------
diff --git a/artemis-server/src/test/java/org/apache/activemq/artemis/core/reload/ReloadManagerTest.java b/artemis-server/src/test/java/org/apache/activemq/artemis/core/reload/ReloadManagerTest.java
new file mode 100644
index 0000000..181604f
--- /dev/null
+++ b/artemis-server/src/test/java/org/apache/activemq/artemis/core/reload/ReloadManagerTest.java
@@ -0,0 +1,89 @@
+/**
+ * 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.core.reload;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.activemq.artemis.core.server.reload.ReloadCallback;
+import org.apache.activemq.artemis.core.server.reload.ReloadManagerImpl;
+import org.apache.activemq.artemis.tests.util.ActiveMQTestBase;
+import org.apache.activemq.artemis.utils.ReusableLatch;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+public class ReloadManagerTest extends ActiveMQTestBase {
+
+   private ScheduledExecutorService scheduledExecutorService;
+
+   private ReloadManagerImpl manager;
+
+   @Before
+   public void startScheduled() {
+      scheduledExecutorService = new ScheduledThreadPoolExecutor(5);
+      manager = new ReloadManagerImpl(scheduledExecutorService, 100);
+   }
+
+   @After
+   public void stopScheduled() {
+      manager.stop();
+      scheduledExecutorService.shutdown();
+      scheduledExecutorService = null;
+   }
+
+   @Test
+   public void testUpdate() throws Exception {
+
+      File file = new File(getTemporaryDir(), "checkFile.tst");
+      internalTest(manager, file);
+
+   }
+
+   @Test
+   public void testUpdateWithSpace() throws Exception {
+      File spaceDir = new File(getTemporaryDir(), "./with space");
+      spaceDir.mkdirs();
+      File file = new File(spaceDir, "checkFile.tst");
+      internalTest(manager, file);
+   }
+
+   private void internalTest(ReloadManagerImpl manager, File file) throws IOException, InterruptedException {
+      file.createNewFile();
+
+      final ReusableLatch latch = new ReusableLatch(1);
+
+      manager.addCallback(file.toURL(), new ReloadCallback() {
+         @Override
+         public void reload(URL uri) {
+            latch.countDown();
+         }
+      });
+
+      Assert.assertFalse(latch.await(1, TimeUnit.SECONDS));
+
+      file.setLastModified(System.currentTimeMillis());
+
+      Assert.assertTrue(latch.await(1, TimeUnit.SECONDS));
+   }
+}

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/04d48203/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/jms/RedeployTest.java
----------------------------------------------------------------------
diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/jms/RedeployTest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/jms/RedeployTest.java
new file mode 100644
index 0000000..c106897
--- /dev/null
+++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/jms/RedeployTest.java
@@ -0,0 +1,97 @@
+/**
+ * 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.Connection;
+import javax.jms.JMSException;
+import javax.jms.MessageConsumer;
+import javax.jms.Queue;
+import javax.jms.Session;
+import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardCopyOption;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory;
+import org.apache.activemq.artemis.jms.server.embedded.EmbeddedJMS;
+import org.apache.activemq.artemis.tests.util.ActiveMQTestBase;
+import org.apache.activemq.artemis.utils.ReusableLatch;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class RedeployTest extends ActiveMQTestBase {
+
+   @Test
+   public void testRedeploy() throws Exception {
+      Path brokerXML = getTestDirfile().toPath().resolve("broker.xml");
+      URL url1 = RedeployTest.class.getClassLoader().getResource("reload-test-jms.xml");
+      URL url2 = RedeployTest.class.getClassLoader().getResource("reload-test-updated-jms.xml");
+      Files.copy(url1.openStream(), brokerXML);
+
+      EmbeddedJMS embeddedJMS = new EmbeddedJMS();
+      embeddedJMS.setConfigResourcePath(brokerXML.toUri().toString());
+      embeddedJMS.start();
+
+      final ReusableLatch latch = new ReusableLatch(1);
+
+      Runnable tick = new Runnable() {
+         @Override
+         public void run() {
+            latch.countDown();
+         }
+      };
+
+      embeddedJMS.getActiveMQServer().getReloadManager().setTick(tick);
+
+      try {
+         latch.await(10, TimeUnit.SECONDS);
+         Assert.assertEquals("jms.queue.DLQ", embeddedJMS.getActiveMQServer().getAddressSettingsRepository().getMatch("jms").getDeadLetterAddress().toString());
+         Assert.assertEquals("jms.queue.ExpiryQueue", embeddedJMS.getActiveMQServer().getAddressSettingsRepository().getMatch("jms").getExpiryAddress().toString());
+         Assert.assertFalse(tryConsume());
+         Files.copy(url2.openStream(), brokerXML, StandardCopyOption.REPLACE_EXISTING);
+         brokerXML.toFile().setLastModified(System.currentTimeMillis() + 1000);
+         latch.setCount(1);
+         embeddedJMS.getActiveMQServer().getReloadManager().setTick(tick);
+         latch.await(10, TimeUnit.SECONDS);
+
+         Assert.assertTrue(tryConsume());
+
+         Assert.assertEquals("jms.queue.NewQueue", embeddedJMS.getActiveMQServer().getAddressSettingsRepository().getMatch("jms").getDeadLetterAddress().toString());
+         Assert.assertEquals("jms.queue.NewQueue", embeddedJMS.getActiveMQServer().getAddressSettingsRepository().getMatch("jms").getExpiryAddress().toString());
+
+      }
+      finally {
+         embeddedJMS.stop();
+      }
+   }
+
+   private boolean tryConsume() throws JMSException {
+      try (ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory();
+           Connection connection = factory.createConnection();
+           Session session = connection.createSession(Session.AUTO_ACKNOWLEDGE)) {
+         Queue queue = session.createQueue("NewQueue");
+         MessageConsumer consumer = session.createConsumer(queue);
+         return true;
+      }
+      catch (JMSException e) {
+         return false;
+      }
+
+   }
+}

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/04d48203/tests/integration-tests/src/test/resources/reload-test-jms.xml
----------------------------------------------------------------------
diff --git a/tests/integration-tests/src/test/resources/reload-test-jms.xml b/tests/integration-tests/src/test/resources/reload-test-jms.xml
new file mode 100644
index 0000000..9d56984
--- /dev/null
+++ b/tests/integration-tests/src/test/resources/reload-test-jms.xml
@@ -0,0 +1,112 @@
+<?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">
+
+   <jms xmlns="urn:activemq:jms">
+      <queue name="DLQ"/>
+      <queue name="ExpiryQueue"/>
+
+   </jms>
+
+   <core xmlns="urn:activemq:core">
+
+      <name>0.0.0.0</name>
+
+      <configuration-file-refresh-period>100</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-jms-queues>false</auto-create-jms-queues>
+            <dead-letter-address>jms.queue.DLQ</dead-letter-address>
+            <expiry-address>jms.queue.ExpiryQueue</expiry-address>
+            <redelivery-delay>0</redelivery-delay>
+            <max-size-bytes>10485760</max-size-bytes>
+            <message-counter-history-day-limit>10</message-counter-history-day-limit>
+            <address-full-policy>BLOCK</address-full-policy>
+         </address-setting>
+      </address-settings>
+   </core>
+</configuration>

http://git-wip-us.apache.org/repos/asf/activemq-artemis/blob/04d48203/tests/integration-tests/src/test/resources/reload-test-updated-jms.xml
----------------------------------------------------------------------
diff --git a/tests/integration-tests/src/test/resources/reload-test-updated-jms.xml b/tests/integration-tests/src/test/resources/reload-test-updated-jms.xml
new file mode 100644
index 0000000..3e6e329
--- /dev/null
+++ b/tests/integration-tests/src/test/resources/reload-test-updated-jms.xml
@@ -0,0 +1,114 @@
+<?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">
+
+   <jms xmlns="urn:activemq:jms">
+      <queue name="DLQ"/>
+      <queue name="ExpiryQueue"/>
+      <queue name="NewQueue"/>
+
+   </jms>
+
+   <core xmlns="urn:activemq:core">
+
+      <name>0.0.0.0</name>
+
+      <configuration-file-refresh-period>100</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="consume" 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-jms-queues>false</auto-create-jms-queues>
+            <dead-letter-address>jms.queue.NewQueue</dead-letter-address>
+            <expiry-address>jms.queue.NewQueue</expiry-address>
+            <redelivery-delay>0</redelivery-delay>
+            <max-size-bytes>10485760</max-size-bytes>
+            <message-counter-history-day-limit>10</message-counter-history-day-limit>
+            <address-full-policy>BLOCK</address-full-policy>
+         </address-setting>
+      </address-settings>
+   </core>
+</configuration>


[2/2] activemq-artemis git commit: This closes #711

Posted by jb...@apache.org.
This closes #711


Project: http://git-wip-us.apache.org/repos/asf/activemq-artemis/repo
Commit: http://git-wip-us.apache.org/repos/asf/activemq-artemis/commit/2b710229
Tree: http://git-wip-us.apache.org/repos/asf/activemq-artemis/tree/2b710229
Diff: http://git-wip-us.apache.org/repos/asf/activemq-artemis/diff/2b710229

Branch: refs/heads/master
Commit: 2b710229e28df805c3e361b052a28fc238c4b7a7
Parents: 155a345 04d4820
Author: jbertram <jb...@apache.org>
Authored: Wed Aug 10 09:24:02 2016 -0500
Committer: jbertram <jb...@apache.org>
Committed: Wed Aug 10 09:24:02 2016 -0500

----------------------------------------------------------------------
 .../jms/server/config/JMSConfiguration.java     |   6 +
 .../config/impl/FileJMSConfiguration.java       |   1 +
 .../config/impl/JMSConfigurationImpl.java       |  14 ++
 .../jms/server/impl/JMSServerManagerImpl.java   |  37 +++++
 .../artemis/core/server/ActiveMQServer.java     |   3 +
 .../core/server/impl/ActiveMQServerImpl.java    |  49 ++----
 .../core/server/reload/ReloadCallback.java      |  24 +++
 .../core/server/reload/ReloadManager.java       |  29 ++++
 .../core/server/reload/ReloadManagerImpl.java   | 165 +++++++++++++++++++
 .../artemis/core/reload/ReloadManagerTest.java  |  89 ++++++++++
 .../tests/integration/jms/RedeployTest.java     |  97 +++++++++++
 .../src/test/resources/reload-test-jms.xml      | 112 +++++++++++++
 .../test/resources/reload-test-updated-jms.xml  | 114 +++++++++++++
 13 files changed, 708 insertions(+), 32 deletions(-)
----------------------------------------------------------------------