You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@knox.apache.org by mo...@apache.org on 2018/01/11 17:39:13 UTC

[46/53] [abbrv] knox git commit: KNOX-998 - Merge from trunk 0.14.0 code

http://git-wip-us.apache.org/repos/asf/knox/blob/e766b3b7/gateway-discovery-ambari/src/test/java/org/apache/hadoop/gateway/topology/discovery/ambari/AmbariConfigurationMonitorTest.java
----------------------------------------------------------------------
diff --git a/gateway-discovery-ambari/src/test/java/org/apache/hadoop/gateway/topology/discovery/ambari/AmbariConfigurationMonitorTest.java b/gateway-discovery-ambari/src/test/java/org/apache/hadoop/gateway/topology/discovery/ambari/AmbariConfigurationMonitorTest.java
deleted file mode 100644
index 2d8b276..0000000
--- a/gateway-discovery-ambari/src/test/java/org/apache/hadoop/gateway/topology/discovery/ambari/AmbariConfigurationMonitorTest.java
+++ /dev/null
@@ -1,319 +0,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
- * <p>
- * http://www.apache.org/licenses/LICENSE-2.0
- * <p>
- * 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.hadoop.gateway.topology.discovery.ambari;
-
-import org.apache.commons.io.FileUtils;
-import org.apache.hadoop.gateway.config.GatewayConfig;
-import org.apache.hadoop.gateway.topology.discovery.ServiceDiscoveryConfig;
-import org.easymock.EasyMock;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-import java.io.File;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.UUID;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-
-public class AmbariConfigurationMonitorTest {
-
-    private File dataDir = null;
-
-    @Before
-    public void setup() throws Exception {
-        File targetDir = new File( System.getProperty("user.dir"), "target");
-        File tempDir = new File(targetDir, this.getClass().getName() + "__data__" + UUID.randomUUID());
-        FileUtils.forceMkdir(tempDir);
-        dataDir = tempDir;
-    }
-
-    @After
-    public void tearDown() throws Exception {
-        dataDir.delete();
-    }
-
-    @Test
-    public void testPollingMonitor() throws Exception {
-        final String addr1 = "http://host1:8080";
-        final String addr2 = "http://host2:8080";
-        final String cluster1Name = "Cluster_One";
-        final String cluster2Name = "Cluster_Two";
-
-
-        GatewayConfig config = EasyMock.createNiceMock(GatewayConfig.class);
-        EasyMock.expect(config.getGatewayDataDir()).andReturn(dataDir.getAbsolutePath()).anyTimes();
-        EasyMock.expect(config.getClusterMonitorPollingInterval(AmbariConfigurationMonitor.getType()))
-                .andReturn(10)
-                .anyTimes();
-        EasyMock.replay(config);
-
-        // Create the monitor
-        TestableAmbariConfigurationMonitor monitor = new TestableAmbariConfigurationMonitor(config);
-
-        // Clear the system property now that the monitor has been initialized
-        System.clearProperty(AmbariConfigurationMonitor.INTERVAL_PROPERTY_NAME);
-
-
-        // Sequence of config changes for testing monitoring for updates
-        Map<String, Map<String, List<List<AmbariCluster.ServiceConfiguration>>>> updateConfigurations = new HashMap<>();
-
-        updateConfigurations.put(addr1, new HashMap<>());
-        updateConfigurations.get(addr1).put(cluster1Name, Arrays.asList(Arrays.asList(createTestServiceConfig("zoo.cfg", "3"),
-                                                                                      createTestServiceConfig("hive-site", "2")),
-                                                                        Arrays.asList(createTestServiceConfig("zoo.cfg", "3"),
-                                                                                      createTestServiceConfig("hive-site", "3")),
-                                                                        Arrays.asList(createTestServiceConfig("zoo.cfg", "2"),
-                                                                                      createTestServiceConfig("hive-site", "1"))));
-
-        updateConfigurations.put(addr2, new HashMap<>());
-        updateConfigurations.get(addr2).put(cluster2Name, Arrays.asList(Arrays.asList(createTestServiceConfig("zoo.cfg", "1"),
-                                                                                      createTestServiceConfig("hive-site", "1")),
-                                                                        Collections.singletonList(createTestServiceConfig("zoo.cfg", "1")),
-                                                                        Arrays.asList(createTestServiceConfig("zoo.cfg", "1"),
-                                                                                      createTestServiceConfig("hive-site", "2"))));
-
-        updateConfigurations.get(addr2).put(cluster1Name, Arrays.asList(Arrays.asList(createTestServiceConfig("zoo.cfg", "2"),
-                                                                                      createTestServiceConfig("hive-site", "4")),
-                                                                        Arrays.asList(createTestServiceConfig("zoo.cfg", "3"),
-                                                                                      createTestServiceConfig("hive-site", "4"),
-                                                                                      createTestServiceConfig("yarn-site", "1")),
-                                                                        Arrays.asList(createTestServiceConfig("zoo.cfg", "1"),
-                                                                                      createTestServiceConfig("hive-site", "2"))));
-
-        Map<String, Map<String, Integer>> configChangeIndex = new HashMap<>();
-        configChangeIndex.put(addr1, new HashMap<>());
-        configChangeIndex.get(addr1).put(cluster1Name, 0);
-        configChangeIndex.get(addr1).put(cluster2Name, 0);
-        configChangeIndex.put(addr2, new HashMap<>());
-        configChangeIndex.get(addr2).put(cluster2Name, 0);
-
-        // Setup the initial test update data
-        // Cluster 1 data change
-        monitor.addTestConfigVersion(addr1, cluster1Name, "zoo.cfg", "2");
-        monitor.addTestConfigVersion(addr1, cluster1Name, "hive-site", "1");
-
-        // Cluster 2 NO data change
-        monitor.addTestConfigVersion(addr2, cluster1Name, "zoo.cfg", "1");
-        monitor.addTestConfigVersion(addr2, cluster1Name, "hive-site", "1");
-
-        // Cluster 3 data change
-        monitor.addTestConfigVersion(addr2, cluster2Name, "zoo.cfg", "1");
-        monitor.addTestConfigVersion(addr2, cluster2Name, "hive-site", "2");
-
-        Map<String, Map<String, AmbariCluster.ServiceConfiguration>> initialAmbariClusterConfigs = new HashMap<>();
-
-        Map<String, AmbariCluster.ServiceConfiguration> cluster1Configs = new HashMap<>();
-        AmbariCluster.ServiceConfiguration zooCfg = createTestServiceConfig("zoo.cfg", "1");
-        cluster1Configs.put("ZOOKEEPER", zooCfg);
-
-        AmbariCluster.ServiceConfiguration hiveSite = createTestServiceConfig("hive-site", "1");
-        cluster1Configs.put("Hive", hiveSite);
-
-        initialAmbariClusterConfigs.put(cluster1Name, cluster1Configs);
-        AmbariCluster cluster1 = createTestCluster(cluster1Name, initialAmbariClusterConfigs);
-
-        // Tell the monitor about the cluster configurations
-        monitor.addClusterConfigVersions(cluster1, createTestDiscoveryConfig(addr1));
-
-        monitor.addClusterConfigVersions(createTestCluster(cluster2Name, initialAmbariClusterConfigs),
-                                         createTestDiscoveryConfig(addr2));
-
-        monitor.addClusterConfigVersions(createTestCluster(cluster1Name, initialAmbariClusterConfigs),
-                                         createTestDiscoveryConfig(addr2));
-
-        final Map<String, Map<String, Integer>> changeNotifications = new HashMap<>();
-        monitor.addListener((src, cname) -> {
-//            System.out.println("Cluster config changed: " + cname + " @ " + src);
-            // Record the notification
-            Integer notificationCount  = changeNotifications.computeIfAbsent(src, s -> new HashMap<>())
-                                                            .computeIfAbsent(cname, c -> Integer.valueOf(0));
-            changeNotifications.get(src).put(cname, (notificationCount+=1));
-
-            // Update the config version
-            int changeIndex = configChangeIndex.get(src).get(cname);
-            if (changeIndex < updateConfigurations.get(src).get(cname).size()) {
-                List<AmbariCluster.ServiceConfiguration> changes = updateConfigurations.get(src).get(cname).get(changeIndex);
-
-//                System.out.println("Applying config update " + changeIndex + " to " + cname + " @ " + src + " ...");
-                for (AmbariCluster.ServiceConfiguration change : changes) {
-                    monitor.updateConfigState(src, cname, change.getType(), change.getVersion());
-//                    System.out.println("    Updated " + change.getType() + " to version " + change.getVersion());
-                }
-
-                // Increment the change index
-                configChangeIndex.get(src).replace(cname, changeIndex + 1);
-
-//                System.out.println("Monitor config updated for " + cname + " @ " + src + " : " + changeIndex );
-            }
-        });
-
-        try {
-            monitor.start();
-
-            long expiration = System.currentTimeMillis() + (1000 * 30);
-            while (!areChangeUpdatesExhausted(updateConfigurations, configChangeIndex)
-                                                                        && (System.currentTimeMillis() < expiration)) {
-                try {
-                    Thread.sleep(5);
-                } catch (InterruptedException e) {
-                    //
-                }
-            }
-
-        } finally {
-            monitor.stop();
-        }
-
-        assertNotNull("Expected changes to have been reported for source 1.",
-                      changeNotifications.get(addr1));
-
-        assertEquals("Expected changes to have been reported.",
-                     3, changeNotifications.get(addr1).get(cluster1Name).intValue());
-
-        assertNotNull("Expected changes to have been reported for source 2.",
-                      changeNotifications.get(addr2));
-
-        assertEquals("Expected changes to have been reported.",
-                     3, changeNotifications.get(addr2).get(cluster2Name).intValue());
-
-        assertNull("Expected changes to have been reported.",
-                   changeNotifications.get(addr2).get(cluster1Name));
-    }
-
-
-    private static boolean areChangeUpdatesExhausted(Map<String, Map<String, List<List<AmbariCluster.ServiceConfiguration>>>> updates,
-                                              Map<String, Map<String, Integer>> configChangeIndeces) {
-        boolean isExhausted = true;
-
-        for (String address : updates.keySet()) {
-            Map<String, List<List<AmbariCluster.ServiceConfiguration>>> clusterConfigs = updates.get(address);
-            for (String clusterName : clusterConfigs.keySet()) {
-                Integer configChangeCount = clusterConfigs.get(clusterName).size();
-                if (configChangeIndeces.get(address).containsKey(clusterName)) {
-                    if (configChangeIndeces.get(address).get(clusterName) < configChangeCount) {
-                        isExhausted = false;
-                        break;
-                    }
-                }
-            }
-        }
-
-        return isExhausted;
-    }
-
-    /**
-     *
-     * @param name           The cluster name
-     * @param serviceConfigs A map of service configurations (keyed by service name)
-     *
-     * @return
-     */
-    private AmbariCluster createTestCluster(String name,
-                                            Map<String, Map<String, AmbariCluster.ServiceConfiguration>> serviceConfigs) {
-        AmbariCluster c = EasyMock.createNiceMock(AmbariCluster.class);
-        EasyMock.expect(c.getName()).andReturn(name).anyTimes();
-        EasyMock.expect(c.getServiceConfigurations()).andReturn(serviceConfigs).anyTimes();
-        EasyMock.replay(c);
-        return c;
-    }
-
-    private AmbariCluster.ServiceConfiguration createTestServiceConfig(String name, String version) {
-        AmbariCluster.ServiceConfiguration sc = EasyMock.createNiceMock(AmbariCluster.ServiceConfiguration.class);
-        EasyMock.expect(sc.getType()).andReturn(name).anyTimes();
-        EasyMock.expect(sc.getVersion()).andReturn(version).anyTimes();
-        EasyMock.replay(sc);
-        return sc;
-    }
-
-    private ServiceDiscoveryConfig createTestDiscoveryConfig(String address) {
-        return createTestDiscoveryConfig(address, null, null);
-    }
-
-    private ServiceDiscoveryConfig createTestDiscoveryConfig(String address, String username, String pwdAlias) {
-        ServiceDiscoveryConfig sdc = EasyMock.createNiceMock(ServiceDiscoveryConfig.class);
-        EasyMock.expect(sdc.getAddress()).andReturn(address).anyTimes();
-        EasyMock.expect(sdc.getUser()).andReturn(username).anyTimes();
-        EasyMock.expect(sdc.getPasswordAlias()).andReturn(pwdAlias).anyTimes();
-        EasyMock.replay(sdc);
-        return sdc;
-    }
-
-    /**
-     * AmbariConfigurationMonitor extension that replaces the collection of updated configuration data with a static
-     * mechanism rather than the REST invocation mechanism.
-     */
-    private static final class TestableAmbariConfigurationMonitor extends AmbariConfigurationMonitor {
-
-        Map<String, Map<String, Map<String, String>>> configVersionData = new HashMap<>();
-
-        TestableAmbariConfigurationMonitor(GatewayConfig config) {
-            super(config, null);
-        }
-
-        void addTestConfigVersion(String address, String clusterName, String configType, String configVersion) {
-            configVersionData.computeIfAbsent(address, a -> new HashMap<>())
-                             .computeIfAbsent(clusterName, cl -> new HashMap<>())
-                             .put(configType, configVersion);
-        }
-
-        void addTestConfigVersions(String address, String clusterName, Map<String, String> configVersions) {
-            configVersionData.computeIfAbsent(address, a -> new HashMap<>())
-                             .computeIfAbsent(clusterName, cl -> new HashMap<>())
-                             .putAll(configVersions);
-        }
-
-        void updateTestConfigVersion(String address, String clusterName, String configType, String updatedVersions) {
-            configVersionData.computeIfAbsent(address, a -> new HashMap<>())
-                             .computeIfAbsent(clusterName, cl -> new HashMap<>())
-                             .replace(configType, updatedVersions);
-        }
-
-        void updateTestConfigVersions(String address, String clusterName, Map<String, String> updatedVersions) {
-            configVersionData.computeIfAbsent(address, a -> new HashMap<>())
-                             .computeIfAbsent(clusterName, cl -> new HashMap<>())
-                             .replaceAll((k,v) -> updatedVersions.get(k));
-        }
-
-        void updateConfigState(String address, String clusterName, String configType, String configVersion) {
-            configVersionsLock.writeLock().lock();
-            try {
-                if (ambariClusterConfigVersions.containsKey(address)) {
-                    ambariClusterConfigVersions.get(address).get(clusterName).replace(configType, configVersion);
-                }
-            } finally {
-                configVersionsLock.writeLock().unlock();
-            }
-        }
-
-        @Override
-        Map<String, String> getUpdatedConfigVersions(String address, String clusterName) {
-            Map<String, Map<String, String>> clusterConfigVersions = configVersionData.get(address);
-            if (clusterConfigVersions != null) {
-                return clusterConfigVersions.get(clusterName);
-            }
-            return null;
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/knox/blob/e766b3b7/gateway-discovery-ambari/src/test/java/org/apache/knox/gateway/topology/discovery/ambari/AmbariConfigurationMonitorTest.java
----------------------------------------------------------------------
diff --git a/gateway-discovery-ambari/src/test/java/org/apache/knox/gateway/topology/discovery/ambari/AmbariConfigurationMonitorTest.java b/gateway-discovery-ambari/src/test/java/org/apache/knox/gateway/topology/discovery/ambari/AmbariConfigurationMonitorTest.java
new file mode 100644
index 0000000..7411545
--- /dev/null
+++ b/gateway-discovery-ambari/src/test/java/org/apache/knox/gateway/topology/discovery/ambari/AmbariConfigurationMonitorTest.java
@@ -0,0 +1,319 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.knox.gateway.topology.discovery.ambari;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.knox.gateway.config.GatewayConfig;
+import org.apache.knox.gateway.topology.discovery.ServiceDiscoveryConfig;
+import org.easymock.EasyMock;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.File;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+public class AmbariConfigurationMonitorTest {
+
+    private File dataDir = null;
+
+    @Before
+    public void setup() throws Exception {
+        File targetDir = new File( System.getProperty("user.dir"), "target");
+        File tempDir = new File(targetDir, this.getClass().getName() + "__data__" + UUID.randomUUID());
+        FileUtils.forceMkdir(tempDir);
+        dataDir = tempDir;
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        dataDir.delete();
+    }
+
+    @Test
+    public void testPollingMonitor() throws Exception {
+        final String addr1 = "http://host1:8080";
+        final String addr2 = "http://host2:8080";
+        final String cluster1Name = "Cluster_One";
+        final String cluster2Name = "Cluster_Two";
+
+
+        GatewayConfig config = EasyMock.createNiceMock(GatewayConfig.class);
+        EasyMock.expect(config.getGatewayDataDir()).andReturn(dataDir.getAbsolutePath()).anyTimes();
+        EasyMock.expect(config.getClusterMonitorPollingInterval(AmbariConfigurationMonitor.getType()))
+                .andReturn(10)
+                .anyTimes();
+        EasyMock.replay(config);
+
+        // Create the monitor
+        TestableAmbariConfigurationMonitor monitor = new TestableAmbariConfigurationMonitor(config);
+
+        // Clear the system property now that the monitor has been initialized
+        System.clearProperty(AmbariConfigurationMonitor.INTERVAL_PROPERTY_NAME);
+
+
+        // Sequence of config changes for testing monitoring for updates
+        Map<String, Map<String, List<List<AmbariCluster.ServiceConfiguration>>>> updateConfigurations = new HashMap<>();
+
+        updateConfigurations.put(addr1, new HashMap<>());
+        updateConfigurations.get(addr1).put(cluster1Name, Arrays.asList(Arrays.asList(createTestServiceConfig("zoo.cfg", "3"),
+                                                                                      createTestServiceConfig("hive-site", "2")),
+                                                                        Arrays.asList(createTestServiceConfig("zoo.cfg", "3"),
+                                                                                      createTestServiceConfig("hive-site", "3")),
+                                                                        Arrays.asList(createTestServiceConfig("zoo.cfg", "2"),
+                                                                                      createTestServiceConfig("hive-site", "1"))));
+
+        updateConfigurations.put(addr2, new HashMap<>());
+        updateConfigurations.get(addr2).put(cluster2Name, Arrays.asList(Arrays.asList(createTestServiceConfig("zoo.cfg", "1"),
+                                                                                      createTestServiceConfig("hive-site", "1")),
+                                                                        Collections.singletonList(createTestServiceConfig("zoo.cfg", "1")),
+                                                                        Arrays.asList(createTestServiceConfig("zoo.cfg", "1"),
+                                                                                      createTestServiceConfig("hive-site", "2"))));
+
+        updateConfigurations.get(addr2).put(cluster1Name, Arrays.asList(Arrays.asList(createTestServiceConfig("zoo.cfg", "2"),
+                                                                                      createTestServiceConfig("hive-site", "4")),
+                                                                        Arrays.asList(createTestServiceConfig("zoo.cfg", "3"),
+                                                                                      createTestServiceConfig("hive-site", "4"),
+                                                                                      createTestServiceConfig("yarn-site", "1")),
+                                                                        Arrays.asList(createTestServiceConfig("zoo.cfg", "1"),
+                                                                                      createTestServiceConfig("hive-site", "2"))));
+
+        Map<String, Map<String, Integer>> configChangeIndex = new HashMap<>();
+        configChangeIndex.put(addr1, new HashMap<>());
+        configChangeIndex.get(addr1).put(cluster1Name, 0);
+        configChangeIndex.get(addr1).put(cluster2Name, 0);
+        configChangeIndex.put(addr2, new HashMap<>());
+        configChangeIndex.get(addr2).put(cluster2Name, 0);
+
+        // Setup the initial test update data
+        // Cluster 1 data change
+        monitor.addTestConfigVersion(addr1, cluster1Name, "zoo.cfg", "2");
+        monitor.addTestConfigVersion(addr1, cluster1Name, "hive-site", "1");
+
+        // Cluster 2 NO data change
+        monitor.addTestConfigVersion(addr2, cluster1Name, "zoo.cfg", "1");
+        monitor.addTestConfigVersion(addr2, cluster1Name, "hive-site", "1");
+
+        // Cluster 3 data change
+        monitor.addTestConfigVersion(addr2, cluster2Name, "zoo.cfg", "1");
+        monitor.addTestConfigVersion(addr2, cluster2Name, "hive-site", "2");
+
+        Map<String, Map<String, AmbariCluster.ServiceConfiguration>> initialAmbariClusterConfigs = new HashMap<>();
+
+        Map<String, AmbariCluster.ServiceConfiguration> cluster1Configs = new HashMap<>();
+        AmbariCluster.ServiceConfiguration zooCfg = createTestServiceConfig("zoo.cfg", "1");
+        cluster1Configs.put("ZOOKEEPER", zooCfg);
+
+        AmbariCluster.ServiceConfiguration hiveSite = createTestServiceConfig("hive-site", "1");
+        cluster1Configs.put("Hive", hiveSite);
+
+        initialAmbariClusterConfigs.put(cluster1Name, cluster1Configs);
+        AmbariCluster cluster1 = createTestCluster(cluster1Name, initialAmbariClusterConfigs);
+
+        // Tell the monitor about the cluster configurations
+        monitor.addClusterConfigVersions(cluster1, createTestDiscoveryConfig(addr1));
+
+        monitor.addClusterConfigVersions(createTestCluster(cluster2Name, initialAmbariClusterConfigs),
+                                         createTestDiscoveryConfig(addr2));
+
+        monitor.addClusterConfigVersions(createTestCluster(cluster1Name, initialAmbariClusterConfigs),
+                                         createTestDiscoveryConfig(addr2));
+
+        final Map<String, Map<String, Integer>> changeNotifications = new HashMap<>();
+        monitor.addListener((src, cname) -> {
+//            System.out.println("Cluster config changed: " + cname + " @ " + src);
+            // Record the notification
+            Integer notificationCount  = changeNotifications.computeIfAbsent(src, s -> new HashMap<>())
+                                                            .computeIfAbsent(cname, c -> Integer.valueOf(0));
+            changeNotifications.get(src).put(cname, (notificationCount+=1));
+
+            // Update the config version
+            int changeIndex = configChangeIndex.get(src).get(cname);
+            if (changeIndex < updateConfigurations.get(src).get(cname).size()) {
+                List<AmbariCluster.ServiceConfiguration> changes = updateConfigurations.get(src).get(cname).get(changeIndex);
+
+//                System.out.println("Applying config update " + changeIndex + " to " + cname + " @ " + src + " ...");
+                for (AmbariCluster.ServiceConfiguration change : changes) {
+                    monitor.updateConfigState(src, cname, change.getType(), change.getVersion());
+//                    System.out.println("    Updated " + change.getType() + " to version " + change.getVersion());
+                }
+
+                // Increment the change index
+                configChangeIndex.get(src).replace(cname, changeIndex + 1);
+
+//                System.out.println("Monitor config updated for " + cname + " @ " + src + " : " + changeIndex );
+            }
+        });
+
+        try {
+            monitor.start();
+
+            long expiration = System.currentTimeMillis() + (1000 * 30);
+            while (!areChangeUpdatesExhausted(updateConfigurations, configChangeIndex)
+                                                                        && (System.currentTimeMillis() < expiration)) {
+                try {
+                    Thread.sleep(5);
+                } catch (InterruptedException e) {
+                    //
+                }
+            }
+
+        } finally {
+            monitor.stop();
+        }
+
+        assertNotNull("Expected changes to have been reported for source 1.",
+                      changeNotifications.get(addr1));
+
+        assertEquals("Expected changes to have been reported.",
+                     3, changeNotifications.get(addr1).get(cluster1Name).intValue());
+
+        assertNotNull("Expected changes to have been reported for source 2.",
+                      changeNotifications.get(addr2));
+
+        assertEquals("Expected changes to have been reported.",
+                     3, changeNotifications.get(addr2).get(cluster2Name).intValue());
+
+        assertNull("Expected changes to have been reported.",
+                   changeNotifications.get(addr2).get(cluster1Name));
+    }
+
+
+    private static boolean areChangeUpdatesExhausted(Map<String, Map<String, List<List<AmbariCluster.ServiceConfiguration>>>> updates,
+                                              Map<String, Map<String, Integer>> configChangeIndeces) {
+        boolean isExhausted = true;
+
+        for (String address : updates.keySet()) {
+            Map<String, List<List<AmbariCluster.ServiceConfiguration>>> clusterConfigs = updates.get(address);
+            for (String clusterName : clusterConfigs.keySet()) {
+                Integer configChangeCount = clusterConfigs.get(clusterName).size();
+                if (configChangeIndeces.get(address).containsKey(clusterName)) {
+                    if (configChangeIndeces.get(address).get(clusterName) < configChangeCount) {
+                        isExhausted = false;
+                        break;
+                    }
+                }
+            }
+        }
+
+        return isExhausted;
+    }
+
+    /**
+     *
+     * @param name           The cluster name
+     * @param serviceConfigs A map of service configurations (keyed by service name)
+     *
+     * @return
+     */
+    private AmbariCluster createTestCluster(String name,
+                                            Map<String, Map<String, AmbariCluster.ServiceConfiguration>> serviceConfigs) {
+        AmbariCluster c = EasyMock.createNiceMock(AmbariCluster.class);
+        EasyMock.expect(c.getName()).andReturn(name).anyTimes();
+        EasyMock.expect(c.getServiceConfigurations()).andReturn(serviceConfigs).anyTimes();
+        EasyMock.replay(c);
+        return c;
+    }
+
+    private AmbariCluster.ServiceConfiguration createTestServiceConfig(String name, String version) {
+        AmbariCluster.ServiceConfiguration sc = EasyMock.createNiceMock(AmbariCluster.ServiceConfiguration.class);
+        EasyMock.expect(sc.getType()).andReturn(name).anyTimes();
+        EasyMock.expect(sc.getVersion()).andReturn(version).anyTimes();
+        EasyMock.replay(sc);
+        return sc;
+    }
+
+    private ServiceDiscoveryConfig createTestDiscoveryConfig(String address) {
+        return createTestDiscoveryConfig(address, null, null);
+    }
+
+    private ServiceDiscoveryConfig createTestDiscoveryConfig(String address, String username, String pwdAlias) {
+        ServiceDiscoveryConfig sdc = EasyMock.createNiceMock(ServiceDiscoveryConfig.class);
+        EasyMock.expect(sdc.getAddress()).andReturn(address).anyTimes();
+        EasyMock.expect(sdc.getUser()).andReturn(username).anyTimes();
+        EasyMock.expect(sdc.getPasswordAlias()).andReturn(pwdAlias).anyTimes();
+        EasyMock.replay(sdc);
+        return sdc;
+    }
+
+    /**
+     * AmbariConfigurationMonitor extension that replaces the collection of updated configuration data with a static
+     * mechanism rather than the REST invocation mechanism.
+     */
+    private static final class TestableAmbariConfigurationMonitor extends AmbariConfigurationMonitor {
+
+        Map<String, Map<String, Map<String, String>>> configVersionData = new HashMap<>();
+
+        TestableAmbariConfigurationMonitor(GatewayConfig config) {
+            super(config, null);
+        }
+
+        void addTestConfigVersion(String address, String clusterName, String configType, String configVersion) {
+            configVersionData.computeIfAbsent(address, a -> new HashMap<>())
+                             .computeIfAbsent(clusterName, cl -> new HashMap<>())
+                             .put(configType, configVersion);
+        }
+
+        void addTestConfigVersions(String address, String clusterName, Map<String, String> configVersions) {
+            configVersionData.computeIfAbsent(address, a -> new HashMap<>())
+                             .computeIfAbsent(clusterName, cl -> new HashMap<>())
+                             .putAll(configVersions);
+        }
+
+        void updateTestConfigVersion(String address, String clusterName, String configType, String updatedVersions) {
+            configVersionData.computeIfAbsent(address, a -> new HashMap<>())
+                             .computeIfAbsent(clusterName, cl -> new HashMap<>())
+                             .replace(configType, updatedVersions);
+        }
+
+        void updateTestConfigVersions(String address, String clusterName, Map<String, String> updatedVersions) {
+            configVersionData.computeIfAbsent(address, a -> new HashMap<>())
+                             .computeIfAbsent(clusterName, cl -> new HashMap<>())
+                             .replaceAll((k,v) -> updatedVersions.get(k));
+        }
+
+        void updateConfigState(String address, String clusterName, String configType, String configVersion) {
+            configVersionsLock.writeLock().lock();
+            try {
+                if (ambariClusterConfigVersions.containsKey(address)) {
+                    ambariClusterConfigVersions.get(address).get(clusterName).replace(configType, configVersion);
+                }
+            } finally {
+                configVersionsLock.writeLock().unlock();
+            }
+        }
+
+        @Override
+        Map<String, String> getUpdatedConfigVersions(String address, String clusterName) {
+            Map<String, Map<String, String>> clusterConfigVersions = configVersionData.get(address);
+            if (clusterConfigVersions != null) {
+                return clusterConfigVersions.get(clusterName);
+            }
+            return null;
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/e766b3b7/gateway-server/src/main/java/org/apache/hadoop/gateway/services/topology/impl/DefaultClusterConfigurationMonitorService.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/main/java/org/apache/hadoop/gateway/services/topology/impl/DefaultClusterConfigurationMonitorService.java b/gateway-server/src/main/java/org/apache/hadoop/gateway/services/topology/impl/DefaultClusterConfigurationMonitorService.java
deleted file mode 100644
index 342ce11..0000000
--- a/gateway-server/src/main/java/org/apache/hadoop/gateway/services/topology/impl/DefaultClusterConfigurationMonitorService.java
+++ /dev/null
@@ -1,81 +0,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
- * <p>
- * http://www.apache.org/licenses/LICENSE-2.0
- * <p>
- * 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.hadoop.gateway.services.topology.impl;
-
-import org.apache.hadoop.gateway.config.GatewayConfig;
-import org.apache.hadoop.gateway.services.ServiceLifecycleException;
-import org.apache.hadoop.gateway.services.security.AliasService;
-import org.apache.hadoop.gateway.topology.ClusterConfigurationMonitorService;
-import org.apache.hadoop.gateway.topology.discovery.ClusterConfigurationMonitor;
-import org.apache.hadoop.gateway.topology.discovery.ClusterConfigurationMonitorProvider;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.ServiceLoader;
-
-
-public class DefaultClusterConfigurationMonitorService implements ClusterConfigurationMonitorService {
-
-    private AliasService aliasService = null;
-
-    private Map<String, ClusterConfigurationMonitor> monitors = new HashMap<>();
-
-    @Override
-    public void init(GatewayConfig config, Map<String, String> options) throws ServiceLifecycleException {
-        ServiceLoader<ClusterConfigurationMonitorProvider> providers =
-                                                        ServiceLoader.load(ClusterConfigurationMonitorProvider.class);
-        for (ClusterConfigurationMonitorProvider provider : providers) {
-            // Check the gateway configuration to determine if this type of monitor is enabled
-            if (config.isClusterMonitorEnabled(provider.getType())) {
-                ClusterConfigurationMonitor monitor = provider.newInstance(config, aliasService);
-                if (monitor != null) {
-                    monitors.put(provider.getType(), monitor);
-                }
-            }
-        }
-    }
-
-    @Override
-    public void start() {
-        for (ClusterConfigurationMonitor monitor : monitors.values()) {
-            monitor.start();
-        }
-    }
-
-    @Override
-    public void stop() {
-        for (ClusterConfigurationMonitor monitor : monitors.values()) {
-            monitor.stop();
-        }
-    }
-
-    @Override
-    public ClusterConfigurationMonitor getMonitor(String type) {
-        return monitors.get(type);
-    }
-
-    @Override
-    public void addListener(ClusterConfigurationMonitor.ConfigurationChangeListener listener) {
-        for (ClusterConfigurationMonitor monitor : monitors.values()) {
-            monitor.addListener(listener);
-        }
-    }
-
-    public void setAliasService(AliasService aliasService) {
-        this.aliasService = aliasService;
-    }
-}

http://git-wip-us.apache.org/repos/asf/knox/blob/e766b3b7/gateway-server/src/main/java/org/apache/hadoop/gateway/topology/monitor/DefaultConfigurationMonitorProvider.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/main/java/org/apache/hadoop/gateway/topology/monitor/DefaultConfigurationMonitorProvider.java b/gateway-server/src/main/java/org/apache/hadoop/gateway/topology/monitor/DefaultConfigurationMonitorProvider.java
deleted file mode 100644
index 7b34e3d..0000000
--- a/gateway-server/src/main/java/org/apache/hadoop/gateway/topology/monitor/DefaultConfigurationMonitorProvider.java
+++ /dev/null
@@ -1,31 +0,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
- * <p>
- * http://www.apache.org/licenses/LICENSE-2.0
- * <p>
- * 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.hadoop.gateway.topology.monitor;
-
-import org.apache.hadoop.gateway.config.GatewayConfig;
-import org.apache.hadoop.gateway.services.config.client.RemoteConfigurationRegistryClientService;
-
-
-public class DefaultConfigurationMonitorProvider implements RemoteConfigurationMonitorProvider {
-
-    @Override
-    public RemoteConfigurationMonitor newInstance(final GatewayConfig                            config,
-                                                  final RemoteConfigurationRegistryClientService clientService) {
-        return new DefaultRemoteConfigurationMonitor(config, clientService);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/knox/blob/e766b3b7/gateway-server/src/main/java/org/apache/hadoop/gateway/topology/monitor/DefaultRemoteConfigurationMonitor.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/main/java/org/apache/hadoop/gateway/topology/monitor/DefaultRemoteConfigurationMonitor.java b/gateway-server/src/main/java/org/apache/hadoop/gateway/topology/monitor/DefaultRemoteConfigurationMonitor.java
deleted file mode 100644
index af60058..0000000
--- a/gateway-server/src/main/java/org/apache/hadoop/gateway/topology/monitor/DefaultRemoteConfigurationMonitor.java
+++ /dev/null
@@ -1,228 +0,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
- * <p>
- * http://www.apache.org/licenses/LICENSE-2.0
- * <p>
- * 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.hadoop.gateway.topology.monitor;
-
-import org.apache.commons.io.FileUtils;
-import org.apache.hadoop.gateway.GatewayMessages;
-import org.apache.hadoop.gateway.config.GatewayConfig;
-import org.apache.hadoop.gateway.i18n.messages.MessagesFactory;
-import org.apache.hadoop.gateway.services.config.client.RemoteConfigurationRegistryClient.ChildEntryListener;
-import org.apache.hadoop.gateway.services.config.client.RemoteConfigurationRegistryClient.EntryListener;
-import org.apache.hadoop.gateway.services.config.client.RemoteConfigurationRegistryClient;
-import org.apache.hadoop.gateway.services.config.client.RemoteConfigurationRegistryClientService;
-import org.apache.zookeeper.ZooDefs;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-
-class DefaultRemoteConfigurationMonitor implements RemoteConfigurationMonitor {
-
-    private static final String NODE_KNOX = "/knox";
-    private static final String NODE_KNOX_CONFIG = NODE_KNOX + "/config";
-    private static final String NODE_KNOX_PROVIDERS = NODE_KNOX_CONFIG + "/shared-providers";
-    private static final String NODE_KNOX_DESCRIPTORS = NODE_KNOX_CONFIG + "/descriptors";
-
-    private static GatewayMessages log = MessagesFactory.get(GatewayMessages.class);
-
-    // N.B. This is ZooKeeper-specific, and should be abstracted when another registry is supported
-    private static final RemoteConfigurationRegistryClient.EntryACL AUTHENTICATED_USERS_ALL;
-    static {
-        AUTHENTICATED_USERS_ALL = new RemoteConfigurationRegistryClient.EntryACL() {
-            public String getId() {
-                return "";
-            }
-
-            public String getType() {
-                return "auth";
-            }
-
-            public Object getPermissions() {
-                return ZooDefs.Perms.ALL;
-            }
-
-            public boolean canRead() {
-                return true;
-            }
-
-            public boolean canWrite() {
-                return true;
-            }
-        };
-    }
-
-    private RemoteConfigurationRegistryClient client = null;
-
-    private File providersDir;
-    private File descriptorsDir;
-
-    /**
-     * @param config                The gateway configuration
-     * @param registryClientService The service from which the remote registry client should be acquired.
-     */
-    DefaultRemoteConfigurationMonitor(GatewayConfig                            config,
-                                      RemoteConfigurationRegistryClientService registryClientService) {
-        this.providersDir   = new File(config.getGatewayProvidersConfigDir());
-        this.descriptorsDir = new File(config.getGatewayDescriptorsDir());
-
-        if (registryClientService != null) {
-            String clientName = config.getRemoteConfigurationMonitorClientName();
-            if (clientName != null) {
-                this.client = registryClientService.get(clientName);
-                if (this.client == null) {
-                    log.unresolvedClientConfigurationForRemoteMonitoring(clientName);
-                }
-            } else {
-                log.missingClientConfigurationForRemoteMonitoring();
-            }
-        }
-    }
-
-    @Override
-    public void start() throws Exception {
-        if (client == null) {
-            throw new IllegalStateException("Failed to acquire a remote configuration registry client.");
-        }
-
-        final String monitorSource = client.getAddress();
-        log.startingRemoteConfigurationMonitor(monitorSource);
-
-        // Ensure the existence of the expected entries and their associated ACLs
-        ensureEntries();
-
-        // Confirm access to the remote provider configs directory znode
-        List<String> providerConfigs = client.listChildEntries(NODE_KNOX_PROVIDERS);
-        if (providerConfigs == null) {
-            // Either the ZNode does not exist, or there is an authentication problem
-            throw new IllegalStateException("Unable to access remote path: " + NODE_KNOX_PROVIDERS);
-        }
-
-        // Confirm access to the remote descriptors directory znode
-        List<String> descriptors = client.listChildEntries(NODE_KNOX_DESCRIPTORS);
-        if (descriptors == null) {
-            // Either the ZNode does not exist, or there is an authentication problem
-            throw new IllegalStateException("Unable to access remote path: " + NODE_KNOX_DESCRIPTORS);
-        }
-
-        // Register a listener for provider config znode additions/removals
-        client.addChildEntryListener(NODE_KNOX_PROVIDERS, new ConfigDirChildEntryListener(providersDir));
-
-        // Register a listener for descriptor znode additions/removals
-        client.addChildEntryListener(NODE_KNOX_DESCRIPTORS, new ConfigDirChildEntryListener(descriptorsDir));
-
-        log.monitoringRemoteConfigurationSource(monitorSource);
-    }
-
-
-    @Override
-    public void stop() throws Exception {
-        client.removeEntryListener(NODE_KNOX_PROVIDERS);
-        client.removeEntryListener(NODE_KNOX_DESCRIPTORS);
-    }
-
-    private void ensureEntries() {
-        ensureEntry(NODE_KNOX);
-        ensureEntry(NODE_KNOX_CONFIG);
-        ensureEntry(NODE_KNOX_PROVIDERS);
-        ensureEntry(NODE_KNOX_DESCRIPTORS);
-    }
-
-    private void ensureEntry(String name) {
-        if (!client.entryExists(name)) {
-            client.createEntry(name);
-        } else {
-            // Validate the ACL
-            List<RemoteConfigurationRegistryClient.EntryACL> entryACLs = client.getACL(name);
-            for (RemoteConfigurationRegistryClient.EntryACL entryACL : entryACLs) {
-                // N.B. This is ZooKeeper-specific, and should be abstracted when another registry is supported
-                // For now, check for ZooKeeper world:anyone with ANY permissions (even read-only)
-                if (entryACL.getType().equals("world") && entryACL.getId().equals("anyone")) {
-                    log.suspectWritableRemoteConfigurationEntry(name);
-
-                    // If the client is authenticated, but "anyone" can write the content, then the content may not
-                    // be trustworthy.
-                    if (client.isAuthenticationConfigured()) {
-                        log.correctingSuspectWritableRemoteConfigurationEntry(name);
-
-                        // Replace the existing ACL with one that permits only authenticated users
-                        client.setACL(name, Collections.singletonList(AUTHENTICATED_USERS_ALL));
-                  }
-                }
-            }
-        }
-    }
-
-    private static class ConfigDirChildEntryListener implements ChildEntryListener {
-        File localDir;
-
-        ConfigDirChildEntryListener(File localDir) {
-            this.localDir = localDir;
-        }
-
-        @Override
-        public void childEvent(RemoteConfigurationRegistryClient client, Type type, String path) {
-            File localFile = new File(localDir, path.substring(path.lastIndexOf("/") + 1));
-
-            switch (type) {
-                case REMOVED:
-                    FileUtils.deleteQuietly(localFile);
-                    log.deletedRemoteConfigFile(localDir.getName(), localFile.getName());
-                    try {
-                        client.removeEntryListener(path);
-                    } catch (Exception e) {
-                        log.errorRemovingRemoteConfigurationListenerForPath(path, e);
-                    }
-                    break;
-                case ADDED:
-                    try {
-                        client.addEntryListener(path, new ConfigEntryListener(localDir));
-                    } catch (Exception e) {
-                        log.errorAddingRemoteConfigurationListenerForPath(path, e);
-                    }
-                    break;
-            }
-        }
-    }
-
-    private static class ConfigEntryListener implements EntryListener {
-        private File localDir;
-
-        ConfigEntryListener(File localDir) {
-            this.localDir = localDir;
-        }
-
-        @Override
-        public void entryChanged(RemoteConfigurationRegistryClient client, String path, byte[] data) {
-            File localFile = new File(localDir, path.substring(path.lastIndexOf("/")));
-            if (data != null) {
-                try {
-                    FileUtils.writeByteArrayToFile(localFile, data);
-                    log.downloadedRemoteConfigFile(localDir.getName(), localFile.getName());
-                } catch (IOException e) {
-                    log.errorDownloadingRemoteConfiguration(path, e);
-                }
-            } else {
-                FileUtils.deleteQuietly(localFile);
-                log.deletedRemoteConfigFile(localDir.getName(), localFile.getName());
-            }
-        }
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/knox/blob/e766b3b7/gateway-server/src/main/java/org/apache/hadoop/gateway/topology/monitor/RemoteConfigurationMonitorFactory.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/main/java/org/apache/hadoop/gateway/topology/monitor/RemoteConfigurationMonitorFactory.java b/gateway-server/src/main/java/org/apache/hadoop/gateway/topology/monitor/RemoteConfigurationMonitorFactory.java
deleted file mode 100644
index 4d2df45..0000000
--- a/gateway-server/src/main/java/org/apache/hadoop/gateway/topology/monitor/RemoteConfigurationMonitorFactory.java
+++ /dev/null
@@ -1,74 +0,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
- * <p>
- * http://www.apache.org/licenses/LICENSE-2.0
- * <p>
- * 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.hadoop.gateway.topology.monitor;
-
-import org.apache.hadoop.gateway.GatewayMessages;
-import org.apache.hadoop.gateway.GatewayServer;
-import org.apache.hadoop.gateway.config.GatewayConfig;
-import org.apache.hadoop.gateway.i18n.messages.MessagesFactory;
-import org.apache.hadoop.gateway.services.GatewayServices;
-import org.apache.hadoop.gateway.services.config.client.RemoteConfigurationRegistryClientService;
-
-import java.util.ServiceLoader;
-
-public class RemoteConfigurationMonitorFactory {
-
-    private static final GatewayMessages log = MessagesFactory.get(GatewayMessages.class);
-
-    private static RemoteConfigurationRegistryClientService remoteConfigRegistryClientService = null;
-
-    public static void setClientService(RemoteConfigurationRegistryClientService clientService) {
-        remoteConfigRegistryClientService = clientService;
-    }
-
-    private static RemoteConfigurationRegistryClientService getClientService() {
-        if (remoteConfigRegistryClientService == null) {
-            GatewayServices services = GatewayServer.getGatewayServices();
-            if (services != null) {
-                remoteConfigRegistryClientService = services.getService(GatewayServices.REMOTE_REGISTRY_CLIENT_SERVICE);
-            }
-        }
-
-        return remoteConfigRegistryClientService;
-    }
-
-    /**
-     *
-     * @param config The GatewayConfig
-     *
-     * @return The first RemoteConfigurationMonitor extension that is found.
-     */
-    public static RemoteConfigurationMonitor get(GatewayConfig config) {
-        RemoteConfigurationMonitor rcm = null;
-
-        ServiceLoader<RemoteConfigurationMonitorProvider> providers =
-                                                 ServiceLoader.load(RemoteConfigurationMonitorProvider.class);
-        for (RemoteConfigurationMonitorProvider provider : providers) {
-            try {
-                rcm = provider.newInstance(config, getClientService());
-                if (rcm != null) {
-                    break;
-                }
-            } catch (Exception e) {
-                log.remoteConfigurationMonitorInitFailure(e.getLocalizedMessage(), e);
-            }
-        }
-
-        return rcm;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/knox/blob/e766b3b7/gateway-server/src/main/java/org/apache/knox/gateway/services/CLIGatewayServices.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/main/java/org/apache/knox/gateway/services/CLIGatewayServices.java b/gateway-server/src/main/java/org/apache/knox/gateway/services/CLIGatewayServices.java
index a1ed549..f168d44 100644
--- a/gateway-server/src/main/java/org/apache/knox/gateway/services/CLIGatewayServices.java
+++ b/gateway-server/src/main/java/org/apache/knox/gateway/services/CLIGatewayServices.java
@@ -24,7 +24,7 @@ import org.apache.knox.gateway.descriptor.FilterParamDescriptor;
 import org.apache.knox.gateway.descriptor.ResourceDescriptor;
 import org.apache.knox.gateway.i18n.messages.MessagesFactory;
 import org.apache.knox.gateway.service.config.remote.RemoteConfigurationRegistryClientServiceFactory;
-import org.apache.hadoop.gateway.services.config.client.RemoteConfigurationRegistryClientService;
+import org.apache.knox.gateway.services.config.client.RemoteConfigurationRegistryClientService;
 import org.apache.knox.gateway.services.topology.impl.DefaultTopologyService;
 import org.apache.knox.gateway.services.security.impl.DefaultAliasService;
 import org.apache.knox.gateway.services.security.impl.DefaultCryptoService;

http://git-wip-us.apache.org/repos/asf/knox/blob/e766b3b7/gateway-server/src/main/java/org/apache/knox/gateway/services/topology/impl/DefaultClusterConfigurationMonitorService.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/main/java/org/apache/knox/gateway/services/topology/impl/DefaultClusterConfigurationMonitorService.java b/gateway-server/src/main/java/org/apache/knox/gateway/services/topology/impl/DefaultClusterConfigurationMonitorService.java
new file mode 100644
index 0000000..e7ef01d
--- /dev/null
+++ b/gateway-server/src/main/java/org/apache/knox/gateway/services/topology/impl/DefaultClusterConfigurationMonitorService.java
@@ -0,0 +1,81 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.knox.gateway.services.topology.impl;
+
+import org.apache.knox.gateway.config.GatewayConfig;
+import org.apache.knox.gateway.services.ServiceLifecycleException;
+import org.apache.knox.gateway.services.security.AliasService;
+import org.apache.knox.gateway.topology.ClusterConfigurationMonitorService;
+import org.apache.knox.gateway.topology.discovery.ClusterConfigurationMonitor;
+import org.apache.knox.gateway.topology.discovery.ClusterConfigurationMonitorProvider;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.ServiceLoader;
+
+
+public class DefaultClusterConfigurationMonitorService implements ClusterConfigurationMonitorService {
+
+    private AliasService aliasService = null;
+
+    private Map<String, ClusterConfigurationMonitor> monitors = new HashMap<>();
+
+    @Override
+    public void init(GatewayConfig config, Map<String, String> options) throws ServiceLifecycleException {
+        ServiceLoader<ClusterConfigurationMonitorProvider> providers =
+                                                        ServiceLoader.load(ClusterConfigurationMonitorProvider.class);
+        for (ClusterConfigurationMonitorProvider provider : providers) {
+            // Check the gateway configuration to determine if this type of monitor is enabled
+            if (config.isClusterMonitorEnabled(provider.getType())) {
+                ClusterConfigurationMonitor monitor = provider.newInstance(config, aliasService);
+                if (monitor != null) {
+                    monitors.put(provider.getType(), monitor);
+                }
+            }
+        }
+    }
+
+    @Override
+    public void start() {
+        for (ClusterConfigurationMonitor monitor : monitors.values()) {
+            monitor.start();
+        }
+    }
+
+    @Override
+    public void stop() {
+        for (ClusterConfigurationMonitor monitor : monitors.values()) {
+            monitor.stop();
+        }
+    }
+
+    @Override
+    public ClusterConfigurationMonitor getMonitor(String type) {
+        return monitors.get(type);
+    }
+
+    @Override
+    public void addListener(ClusterConfigurationMonitor.ConfigurationChangeListener listener) {
+        for (ClusterConfigurationMonitor monitor : monitors.values()) {
+            monitor.addListener(listener);
+        }
+    }
+
+    public void setAliasService(AliasService aliasService) {
+        this.aliasService = aliasService;
+    }
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/e766b3b7/gateway-server/src/main/java/org/apache/knox/gateway/topology/monitor/DefaultConfigurationMonitorProvider.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/main/java/org/apache/knox/gateway/topology/monitor/DefaultConfigurationMonitorProvider.java b/gateway-server/src/main/java/org/apache/knox/gateway/topology/monitor/DefaultConfigurationMonitorProvider.java
new file mode 100644
index 0000000..25bea08
--- /dev/null
+++ b/gateway-server/src/main/java/org/apache/knox/gateway/topology/monitor/DefaultConfigurationMonitorProvider.java
@@ -0,0 +1,31 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.knox.gateway.topology.monitor;
+
+import org.apache.knox.gateway.config.GatewayConfig;
+import org.apache.knox.gateway.services.config.client.RemoteConfigurationRegistryClientService;
+
+
+public class DefaultConfigurationMonitorProvider implements RemoteConfigurationMonitorProvider {
+
+    @Override
+    public RemoteConfigurationMonitor newInstance(final GatewayConfig                            config,
+                                                  final RemoteConfigurationRegistryClientService clientService) {
+        return new DefaultRemoteConfigurationMonitor(config, clientService);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/e766b3b7/gateway-server/src/main/java/org/apache/knox/gateway/topology/monitor/DefaultRemoteConfigurationMonitor.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/main/java/org/apache/knox/gateway/topology/monitor/DefaultRemoteConfigurationMonitor.java b/gateway-server/src/main/java/org/apache/knox/gateway/topology/monitor/DefaultRemoteConfigurationMonitor.java
new file mode 100644
index 0000000..efafee0
--- /dev/null
+++ b/gateway-server/src/main/java/org/apache/knox/gateway/topology/monitor/DefaultRemoteConfigurationMonitor.java
@@ -0,0 +1,228 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.knox.gateway.topology.monitor;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.knox.gateway.GatewayMessages;
+import org.apache.knox.gateway.config.GatewayConfig;
+import org.apache.knox.gateway.i18n.messages.MessagesFactory;
+import org.apache.knox.gateway.services.config.client.RemoteConfigurationRegistryClient.ChildEntryListener;
+import org.apache.knox.gateway.services.config.client.RemoteConfigurationRegistryClient.EntryListener;
+import org.apache.knox.gateway.services.config.client.RemoteConfigurationRegistryClient;
+import org.apache.knox.gateway.services.config.client.RemoteConfigurationRegistryClientService;
+import org.apache.zookeeper.ZooDefs;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+
+class DefaultRemoteConfigurationMonitor implements RemoteConfigurationMonitor {
+
+    private static final String NODE_KNOX = "/knox";
+    private static final String NODE_KNOX_CONFIG = NODE_KNOX + "/config";
+    private static final String NODE_KNOX_PROVIDERS = NODE_KNOX_CONFIG + "/shared-providers";
+    private static final String NODE_KNOX_DESCRIPTORS = NODE_KNOX_CONFIG + "/descriptors";
+
+    private static GatewayMessages log = MessagesFactory.get(GatewayMessages.class);
+
+    // N.B. This is ZooKeeper-specific, and should be abstracted when another registry is supported
+    private static final RemoteConfigurationRegistryClient.EntryACL AUTHENTICATED_USERS_ALL;
+    static {
+        AUTHENTICATED_USERS_ALL = new RemoteConfigurationRegistryClient.EntryACL() {
+            public String getId() {
+                return "";
+            }
+
+            public String getType() {
+                return "auth";
+            }
+
+            public Object getPermissions() {
+                return ZooDefs.Perms.ALL;
+            }
+
+            public boolean canRead() {
+                return true;
+            }
+
+            public boolean canWrite() {
+                return true;
+            }
+        };
+    }
+
+    private RemoteConfigurationRegistryClient client = null;
+
+    private File providersDir;
+    private File descriptorsDir;
+
+    /**
+     * @param config                The gateway configuration
+     * @param registryClientService The service from which the remote registry client should be acquired.
+     */
+    DefaultRemoteConfigurationMonitor(GatewayConfig                            config,
+                                      RemoteConfigurationRegistryClientService registryClientService) {
+        this.providersDir   = new File(config.getGatewayProvidersConfigDir());
+        this.descriptorsDir = new File(config.getGatewayDescriptorsDir());
+
+        if (registryClientService != null) {
+            String clientName = config.getRemoteConfigurationMonitorClientName();
+            if (clientName != null) {
+                this.client = registryClientService.get(clientName);
+                if (this.client == null) {
+                    log.unresolvedClientConfigurationForRemoteMonitoring(clientName);
+                }
+            } else {
+                log.missingClientConfigurationForRemoteMonitoring();
+            }
+        }
+    }
+
+    @Override
+    public void start() throws Exception {
+        if (client == null) {
+            throw new IllegalStateException("Failed to acquire a remote configuration registry client.");
+        }
+
+        final String monitorSource = client.getAddress();
+        log.startingRemoteConfigurationMonitor(monitorSource);
+
+        // Ensure the existence of the expected entries and their associated ACLs
+        ensureEntries();
+
+        // Confirm access to the remote provider configs directory znode
+        List<String> providerConfigs = client.listChildEntries(NODE_KNOX_PROVIDERS);
+        if (providerConfigs == null) {
+            // Either the ZNode does not exist, or there is an authentication problem
+            throw new IllegalStateException("Unable to access remote path: " + NODE_KNOX_PROVIDERS);
+        }
+
+        // Confirm access to the remote descriptors directory znode
+        List<String> descriptors = client.listChildEntries(NODE_KNOX_DESCRIPTORS);
+        if (descriptors == null) {
+            // Either the ZNode does not exist, or there is an authentication problem
+            throw new IllegalStateException("Unable to access remote path: " + NODE_KNOX_DESCRIPTORS);
+        }
+
+        // Register a listener for provider config znode additions/removals
+        client.addChildEntryListener(NODE_KNOX_PROVIDERS, new ConfigDirChildEntryListener(providersDir));
+
+        // Register a listener for descriptor znode additions/removals
+        client.addChildEntryListener(NODE_KNOX_DESCRIPTORS, new ConfigDirChildEntryListener(descriptorsDir));
+
+        log.monitoringRemoteConfigurationSource(monitorSource);
+    }
+
+
+    @Override
+    public void stop() throws Exception {
+        client.removeEntryListener(NODE_KNOX_PROVIDERS);
+        client.removeEntryListener(NODE_KNOX_DESCRIPTORS);
+    }
+
+    private void ensureEntries() {
+        ensureEntry(NODE_KNOX);
+        ensureEntry(NODE_KNOX_CONFIG);
+        ensureEntry(NODE_KNOX_PROVIDERS);
+        ensureEntry(NODE_KNOX_DESCRIPTORS);
+    }
+
+    private void ensureEntry(String name) {
+        if (!client.entryExists(name)) {
+            client.createEntry(name);
+        } else {
+            // Validate the ACL
+            List<RemoteConfigurationRegistryClient.EntryACL> entryACLs = client.getACL(name);
+            for (RemoteConfigurationRegistryClient.EntryACL entryACL : entryACLs) {
+                // N.B. This is ZooKeeper-specific, and should be abstracted when another registry is supported
+                // For now, check for ZooKeeper world:anyone with ANY permissions (even read-only)
+                if (entryACL.getType().equals("world") && entryACL.getId().equals("anyone")) {
+                    log.suspectWritableRemoteConfigurationEntry(name);
+
+                    // If the client is authenticated, but "anyone" can write the content, then the content may not
+                    // be trustworthy.
+                    if (client.isAuthenticationConfigured()) {
+                        log.correctingSuspectWritableRemoteConfigurationEntry(name);
+
+                        // Replace the existing ACL with one that permits only authenticated users
+                        client.setACL(name, Collections.singletonList(AUTHENTICATED_USERS_ALL));
+                  }
+                }
+            }
+        }
+    }
+
+    private static class ConfigDirChildEntryListener implements ChildEntryListener {
+        File localDir;
+
+        ConfigDirChildEntryListener(File localDir) {
+            this.localDir = localDir;
+        }
+
+        @Override
+        public void childEvent(RemoteConfigurationRegistryClient client, Type type, String path) {
+            File localFile = new File(localDir, path.substring(path.lastIndexOf("/") + 1));
+
+            switch (type) {
+                case REMOVED:
+                    FileUtils.deleteQuietly(localFile);
+                    log.deletedRemoteConfigFile(localDir.getName(), localFile.getName());
+                    try {
+                        client.removeEntryListener(path);
+                    } catch (Exception e) {
+                        log.errorRemovingRemoteConfigurationListenerForPath(path, e);
+                    }
+                    break;
+                case ADDED:
+                    try {
+                        client.addEntryListener(path, new ConfigEntryListener(localDir));
+                    } catch (Exception e) {
+                        log.errorAddingRemoteConfigurationListenerForPath(path, e);
+                    }
+                    break;
+            }
+        }
+    }
+
+    private static class ConfigEntryListener implements EntryListener {
+        private File localDir;
+
+        ConfigEntryListener(File localDir) {
+            this.localDir = localDir;
+        }
+
+        @Override
+        public void entryChanged(RemoteConfigurationRegistryClient client, String path, byte[] data) {
+            File localFile = new File(localDir, path.substring(path.lastIndexOf("/")));
+            if (data != null) {
+                try {
+                    FileUtils.writeByteArrayToFile(localFile, data);
+                    log.downloadedRemoteConfigFile(localDir.getName(), localFile.getName());
+                } catch (IOException e) {
+                    log.errorDownloadingRemoteConfiguration(path, e);
+                }
+            } else {
+                FileUtils.deleteQuietly(localFile);
+                log.deletedRemoteConfigFile(localDir.getName(), localFile.getName());
+            }
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/e766b3b7/gateway-server/src/main/java/org/apache/knox/gateway/topology/monitor/RemoteConfigurationMonitorFactory.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/main/java/org/apache/knox/gateway/topology/monitor/RemoteConfigurationMonitorFactory.java b/gateway-server/src/main/java/org/apache/knox/gateway/topology/monitor/RemoteConfigurationMonitorFactory.java
new file mode 100644
index 0000000..d020532
--- /dev/null
+++ b/gateway-server/src/main/java/org/apache/knox/gateway/topology/monitor/RemoteConfigurationMonitorFactory.java
@@ -0,0 +1,74 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.knox.gateway.topology.monitor;
+
+import org.apache.knox.gateway.GatewayMessages;
+import org.apache.knox.gateway.GatewayServer;
+import org.apache.knox.gateway.config.GatewayConfig;
+import org.apache.knox.gateway.i18n.messages.MessagesFactory;
+import org.apache.knox.gateway.services.GatewayServices;
+import org.apache.knox.gateway.services.config.client.RemoteConfigurationRegistryClientService;
+
+import java.util.ServiceLoader;
+
+public class RemoteConfigurationMonitorFactory {
+
+    private static final GatewayMessages log = MessagesFactory.get(GatewayMessages.class);
+
+    private static RemoteConfigurationRegistryClientService remoteConfigRegistryClientService = null;
+
+    public static void setClientService(RemoteConfigurationRegistryClientService clientService) {
+        remoteConfigRegistryClientService = clientService;
+    }
+
+    private static RemoteConfigurationRegistryClientService getClientService() {
+        if (remoteConfigRegistryClientService == null) {
+            GatewayServices services = GatewayServer.getGatewayServices();
+            if (services != null) {
+                remoteConfigRegistryClientService = services.getService(GatewayServices.REMOTE_REGISTRY_CLIENT_SERVICE);
+            }
+        }
+
+        return remoteConfigRegistryClientService;
+    }
+
+    /**
+     *
+     * @param config The GatewayConfig
+     *
+     * @return The first RemoteConfigurationMonitor extension that is found.
+     */
+    public static RemoteConfigurationMonitor get(GatewayConfig config) {
+        RemoteConfigurationMonitor rcm = null;
+
+        ServiceLoader<RemoteConfigurationMonitorProvider> providers =
+                                                 ServiceLoader.load(RemoteConfigurationMonitorProvider.class);
+        for (RemoteConfigurationMonitorProvider provider : providers) {
+            try {
+                rcm = provider.newInstance(config, getClientService());
+                if (rcm != null) {
+                    break;
+                }
+            } catch (Exception e) {
+                log.remoteConfigurationMonitorInitFailure(e.getLocalizedMessage(), e);
+            }
+        }
+
+        return rcm;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/e766b3b7/gateway-server/src/main/java/org/apache/knox/gateway/util/KnoxCLI.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/main/java/org/apache/knox/gateway/util/KnoxCLI.java b/gateway-server/src/main/java/org/apache/knox/gateway/util/KnoxCLI.java
index 9a87dd0..928c37e 100644
--- a/gateway-server/src/main/java/org/apache/knox/gateway/util/KnoxCLI.java
+++ b/gateway-server/src/main/java/org/apache/knox/gateway/util/KnoxCLI.java
@@ -1855,7 +1855,7 @@ public class KnoxCLI extends Configured implements Tool {
     static final String DESC = "Lists all of the remote configuration registry clients defined in gateway-site.xml.\n";
 
     /* (non-Javadoc)
-     * @see org.apache.hadoop.gateway.util.KnoxCLI.Command#execute()
+     * @see org.apache.knox.gateway.util.KnoxCLI.Command#execute()
      */
     @Override
     public void execute() throws Exception {
@@ -1870,7 +1870,7 @@ public class KnoxCLI extends Configured implements Tool {
     }
 
     /* (non-Javadoc)
-     * @see org.apache.hadoop.gateway.util.KnoxCLI.Command#getUsage()
+     * @see org.apache.knox.gateway.util.KnoxCLI.Command#getUsage()
      */
     @Override
     public String getUsage() {
@@ -1958,7 +1958,7 @@ public class KnoxCLI extends Configured implements Tool {
     }
 
     /* (non-Javadoc)
-     * @see org.apache.hadoop.gateway.util.KnoxCLI.Command#execute()
+     * @see org.apache.knox.gateway.util.KnoxCLI.Command#execute()
      */
     @Override
     public void execute() throws Exception {
@@ -1966,7 +1966,7 @@ public class KnoxCLI extends Configured implements Tool {
     }
 
     /* (non-Javadoc)
-     * @see org.apache.hadoop.gateway.util.KnoxCLI.Command#getUsage()
+     * @see org.apache.knox.gateway.util.KnoxCLI.Command#getUsage()
      */
     @Override
     public String getUsage() {
@@ -1987,7 +1987,7 @@ public class KnoxCLI extends Configured implements Tool {
     }
 
     /* (non-Javadoc)
-     * @see org.apache.hadoop.gateway.util.KnoxCLI.Command#execute()
+     * @see org.apache.knox.gateway.util.KnoxCLI.Command#execute()
      */
     @Override
     public void execute() throws Exception {
@@ -1995,7 +1995,7 @@ public class KnoxCLI extends Configured implements Tool {
     }
 
     /* (non-Javadoc)
-     * @see org.apache.hadoop.gateway.util.KnoxCLI.Command#getUsage()
+     * @see org.apache.knox.gateway.util.KnoxCLI.Command#getUsage()
      */
     @Override
     public String getUsage() {
@@ -2016,7 +2016,7 @@ public class KnoxCLI extends Configured implements Tool {
     }
 
     /* (non-Javadoc)
-     * @see org.apache.hadoop.gateway.util.KnoxCLI.Command#execute()
+     * @see org.apache.knox.gateway.util.KnoxCLI.Command#execute()
      */
     @Override
     public void execute() throws Exception {
@@ -2039,7 +2039,7 @@ public class KnoxCLI extends Configured implements Tool {
     }
 
     /* (non-Javadoc)
-     * @see org.apache.hadoop.gateway.util.KnoxCLI.Command#getUsage()
+     * @see org.apache.knox.gateway.util.KnoxCLI.Command#getUsage()
      */
     @Override
     public String getUsage() {

http://git-wip-us.apache.org/repos/asf/knox/blob/e766b3b7/gateway-server/src/main/resources/META-INF/services/org.apache.hadoop.gateway.topology.monitor.RemoteConfigurationMonitorProvider
----------------------------------------------------------------------
diff --git a/gateway-server/src/main/resources/META-INF/services/org.apache.hadoop.gateway.topology.monitor.RemoteConfigurationMonitorProvider b/gateway-server/src/main/resources/META-INF/services/org.apache.hadoop.gateway.topology.monitor.RemoteConfigurationMonitorProvider
deleted file mode 100644
index bd4023e..0000000
--- a/gateway-server/src/main/resources/META-INF/services/org.apache.hadoop.gateway.topology.monitor.RemoteConfigurationMonitorProvider
+++ /dev/null
@@ -1,19 +0,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.
-##########################################################################
-
-org.apache.hadoop.gateway.topology.monitor.DefaultConfigurationMonitorProvider

http://git-wip-us.apache.org/repos/asf/knox/blob/e766b3b7/gateway-server/src/main/resources/META-INF/services/org.apache.knox.gateway.topology.monitor.RemoteConfigurationMonitorProvider
----------------------------------------------------------------------
diff --git a/gateway-server/src/main/resources/META-INF/services/org.apache.knox.gateway.topology.monitor.RemoteConfigurationMonitorProvider b/gateway-server/src/main/resources/META-INF/services/org.apache.knox.gateway.topology.monitor.RemoteConfigurationMonitorProvider
new file mode 100644
index 0000000..63f438a
--- /dev/null
+++ b/gateway-server/src/main/resources/META-INF/services/org.apache.knox.gateway.topology.monitor.RemoteConfigurationMonitorProvider
@@ -0,0 +1,19 @@
+##########################################################################
+# 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.
+##########################################################################
+
+org.apache.knox.gateway.topology.monitor.DefaultConfigurationMonitorProvider