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

smolnar pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/knox.git


The following commit(s) were added to refs/heads/master by this push:
     new 2e2230f  KNOX-2286 Cleaner log messages about monitoring 
topologies/providers/descriptors (#287)
2e2230f is described below

commit 2e2230f27b5e35e4ebb4acdf8b48d0f12569acb7
Author: Sandor Molnar <[email protected]>
AuthorDate: Thu Mar 12 15:07:31 2020 +0100

    KNOX-2286 Cleaner log messages about monitoring 
topologies/providers/descriptors (#287)
---
 .../org/apache/knox/gateway/GatewayMessages.java   |  18 +-
 .../org/apache/knox/gateway/GatewayServer.java     |   1 -
 .../topology/impl/DefaultTopologyService.java      | 237 +++------------------
 .../topology/monitor/DescriptorsMonitor.java       | 141 ++++++++++++
 .../monitor/SharedProviderConfigMonitor.java       |  86 ++++++++
 .../topology/DefaultTopologyServiceTest.java       |   8 +-
 6 files changed, 268 insertions(+), 223 deletions(-)

diff --git 
a/gateway-server/src/main/java/org/apache/knox/gateway/GatewayMessages.java 
b/gateway-server/src/main/java/org/apache/knox/gateway/GatewayMessages.java
index adc3901..46f6ba8 100644
--- a/gateway-server/src/main/java/org/apache/knox/gateway/GatewayMessages.java
+++ b/gateway-server/src/main/java/org/apache/knox/gateway/GatewayMessages.java
@@ -72,8 +72,8 @@ public interface GatewayMessages {
   @Message( level = MessageLevel.DEBUG, text = "Loading topology file: {0}" )
   void loadingTopologyFile( String fileName );
 
-  @Message( level = MessageLevel.INFO, text = "Monitoring topologies in 
directory: {0}" )
-  void monitoringTopologyChangesInDirectory( String topologiesDir );
+  @Message( level = MessageLevel.INFO, text = "Configured monitoring 
topologies in directory: {0}" )
+  void configuredMonitoringTopologyChangesInDirectory( String topologiesDir );
 
   @Message( level = MessageLevel.INFO, text = "Deploying topology {0} to {1}" )
   void deployingTopology( String clusterName, String warDirName );
@@ -512,11 +512,17 @@ public interface GatewayMessages {
   @Message( level = MessageLevel.WARN, text = "Could not resolve a remote 
configuration registry client for {0}." )
   void unresolvedClientConfigurationForRemoteMonitoring(String clientName);
 
-  @Message( level = MessageLevel.INFO, text = "Monitoring simple descriptors 
in directory: {0}" )
-  void monitoringDescriptorChangesInDirectory(String descriptorsDir);
+  @Message( level = MessageLevel.INFO, text = "Configured monitoring simple 
descriptors in directory: {0}" )
+  void configuredMonitoringDescriptorChangesInDirectory(String descriptorsDir);
 
-  @Message( level = MessageLevel.INFO, text = "Monitoring shared provider 
configurations in directory: {0}" )
-  void monitoringProviderConfigChangesInDirectory(String sharedProviderDir);
+  @Message( level = MessageLevel.INFO, text = "Configured monitoring shared 
provider configurations in directory: {0}" )
+  void configuredMonitoringProviderConfigChangesInDirectory(String 
sharedProviderDir);
+
+  @Message(level = MessageLevel.INFO, text = "Started monitoring {0}")
+  void startedMonitor(String monitorName);
+
+  @Message(level = MessageLevel.INFO, text = "Stopped monitoring {0}")
+  void stoppedMonitor(String monitorName);
 
   @Message( level = MessageLevel.ERROR, text = "Error registering listener for 
remote configuration path {0} : {1}" )
   void errorAddingRemoteConfigurationListenerForPath(String path,
diff --git 
a/gateway-server/src/main/java/org/apache/knox/gateway/GatewayServer.java 
b/gateway-server/src/main/java/org/apache/knox/gateway/GatewayServer.java
index c7ed675..7a1c340 100644
--- a/gateway-server/src/main/java/org/apache/knox/gateway/GatewayServer.java
+++ b/gateway-server/src/main/java/org/apache/knox/gateway/GatewayServer.java
@@ -697,7 +697,6 @@ public class GatewayServer {
     cleanupTopologyDeployments();
 
     // Start the topology monitor.
-    log.monitoringTopologyChangesInDirectory(topologiesDir.getAbsolutePath());
     monitor.startMonitor();
 
     handleClouderaManagerDescriptors();
diff --git 
a/gateway-server/src/main/java/org/apache/knox/gateway/services/topology/impl/DefaultTopologyService.java
 
b/gateway-server/src/main/java/org/apache/knox/gateway/services/topology/impl/DefaultTopologyService.java
index 894d976..c616a31 100644
--- 
a/gateway-server/src/main/java/org/apache/knox/gateway/services/topology/impl/DefaultTopologyService.java
+++ 
b/gateway-server/src/main/java/org/apache/knox/gateway/services/topology/impl/DefaultTopologyService.java
@@ -21,6 +21,7 @@ import org.apache.commons.digester3.Digester;
 import org.apache.commons.digester3.binder.DigesterLoader;
 import org.apache.commons.io.FileUtils;
 import org.apache.commons.io.FilenameUtils;
+import org.apache.commons.io.filefilter.TrueFileFilter;
 import org.apache.commons.io.monitor.FileAlterationListener;
 import org.apache.commons.io.monitor.FileAlterationListenerAdaptor;
 import org.apache.commons.io.monitor.FileAlterationMonitor;
@@ -43,6 +44,8 @@ import 
org.apache.knox.gateway.services.ServiceLifecycleException;
 import 
org.apache.knox.gateway.services.config.client.RemoteConfigurationRegistryClient;
 import org.apache.knox.gateway.services.security.AliasService;
 import org.apache.knox.gateway.services.topology.TopologyService;
+import org.apache.knox.gateway.services.topology.monitor.DescriptorsMonitor;
+import 
org.apache.knox.gateway.services.topology.monitor.SharedProviderConfigMonitor;
 import org.apache.knox.gateway.topology.ClusterConfigurationMonitorService;
 import org.apache.knox.gateway.topology.Service;
 import org.apache.knox.gateway.topology.Topology;
@@ -56,10 +59,8 @@ import 
org.apache.knox.gateway.topology.discovery.ClusterConfigurationMonitor;
 import org.apache.knox.gateway.topology.discovery.ServiceDiscovery;
 import org.apache.knox.gateway.topology.monitor.RemoteConfigurationMonitor;
 import 
org.apache.knox.gateway.topology.monitor.RemoteConfigurationMonitorFactory;
-import org.apache.knox.gateway.topology.simple.ProviderConfigurationParser;
 import org.apache.knox.gateway.topology.simple.SimpleDescriptor;
 import org.apache.knox.gateway.topology.simple.SimpleDescriptorFactory;
-import org.apache.knox.gateway.topology.simple.SimpleDescriptorHandler;
 import org.apache.knox.gateway.topology.validation.TopologyValidator;
 import org.apache.knox.gateway.topology.xml.AmbariFormatXmlTopologyRules;
 import org.apache.knox.gateway.topology.xml.KnoxFormatXmlTopologyRules;
@@ -84,6 +85,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
 
 import static org.apache.commons.digester3.binder.DigesterLoader.newLoader;
 
@@ -96,12 +98,12 @@ public class DefaultTopologyService extends 
FileAlterationListenerAdaptor implem
     AuditConstants.DEFAULT_AUDITOR_NAME, AuditConstants.KNOX_SERVICE_NAME,
     AuditConstants.KNOX_COMPONENT_NAME);
 
-  private static final List<String> SUPPORTED_TOPOLOGY_FILE_EXTENSIONS = 
Arrays.asList("xml", "conf");
+  public static final List<String> SUPPORTED_TOPOLOGY_FILE_EXTENSIONS = 
Collections.unmodifiableList(Arrays.asList("xml", "conf"));
 
   private static GatewayMessages log = 
MessagesFactory.get(GatewayMessages.class);
   private static DigesterLoader digesterLoader = newLoader(new 
KnoxFormatXmlTopologyRules(),
       new AmbariFormatXmlTopologyRules());
-  private List<FileAlterationMonitor> monitors = new ArrayList<>();
+  private Map<String, FileAlterationMonitor> monitors = new 
ConcurrentHashMap<>();
   private File topologiesDirectory;
   private File sharedProvidersDirectory;
   private File descriptorsDirectory;
@@ -253,20 +255,17 @@ public class DefaultTopologyService extends 
FileAlterationListenerAdaptor implem
     return configDir.getAbsoluteFile();
   }
 
-  private void initListener(FileAlterationMonitor  monitor,
-                            File                   directory,
-                            FileFilter             filter,
-                            FileAlterationListener listener) {
-    monitors.add(monitor);
+  private void initListener(String monitorName, FileAlterationMonitor monitor, 
File directory, FileFilter filter, FileAlterationListener listener) {
+    monitors.put(monitorName, monitor);
     FileAlterationObserver observer = new FileAlterationObserver(directory, 
filter);
     observer.addListener(listener);
     monitor.addObserver(observer);
   }
 
-  private void initListener(File directory, FileFilter filter, 
FileAlterationListener listener) {
+  private void initListener(String monitorName, File directory, FileFilter 
filter, FileAlterationListener listener) {
     // Increasing the monitoring interval to 5 seconds as profiling has shown
     // this is rather expensive in terms of generated garbage objects.
-    initListener(new FileAlterationMonitor(5000L), directory, filter, 
listener);
+    initListener(monitorName, new FileAlterationMonitor(5000L), directory, 
filter, listener);
   }
 
   private Map<File, Topology> loadTopologies(File directory) {
@@ -544,8 +543,9 @@ public class DefaultTopologyService extends 
FileAlterationListenerAdaptor implem
   @Override
   public void startMonitor() throws Exception {
     // Start the local configuration monitors
-    for (FileAlterationMonitor monitor : monitors) {
-      monitor.start();
+    for (Entry<String, FileAlterationMonitor> monitor : monitors.entrySet()) {
+      monitor.getValue().start();
+      log.startedMonitor(monitor.getKey());
     }
 
     // Start the remote configuration monitor, if it has been initialized
@@ -561,8 +561,9 @@ public class DefaultTopologyService extends 
FileAlterationListenerAdaptor implem
   @Override
   public void stopMonitor() throws Exception {
     // Stop the local configuration monitors
-    for (FileAlterationMonitor monitor : monitors) {
-      monitor.stop();
+    for (Entry<String, FileAlterationMonitor> monitor : monitors.entrySet()) {
+      monitor.getValue().stop();
+      log.stoppedMonitor(monitor.getKey());
     }
 
     // Stop the remote configuration monitor, if it has been initialized
@@ -638,19 +639,18 @@ public class DefaultTopologyService extends 
FileAlterationListenerAdaptor implem
       sharedProvidersDirectory = new File(configDirectory, "shared-providers");
 
       // Add support for conf/topologies
-      initListener(topologiesDirectory, this, this);
+      initListener("topologies", topologiesDirectory, this, this);
+      
log.configuredMonitoringTopologyChangesInDirectory(topologiesDirectory.getAbsolutePath());
 
       // Add support for conf/descriptors
       descriptorsMonitor = new DescriptorsMonitor(config, topologiesDirectory, 
aliasService);
-      initListener(descriptorsDirectory,
-                   descriptorsMonitor,
-                   descriptorsMonitor);
-      
log.monitoringDescriptorChangesInDirectory(descriptorsDirectory.getAbsolutePath());
+      initListener("simple descriptors", descriptorsDirectory, 
descriptorsMonitor, descriptorsMonitor);
+      
log.configuredMonitoringDescriptorChangesInDirectory(descriptorsDirectory.getAbsolutePath());
 
       // Add support for conf/shared-providers
       SharedProviderConfigMonitor spm = new 
SharedProviderConfigMonitor(descriptorsMonitor, descriptorsDirectory);
-      initListener(sharedProvidersDirectory, spm, spm);
-      
log.monitoringProviderConfigChangesInDirectory(sharedProvidersDirectory.getAbsolutePath());
+      initListener("shared provider configurations", sharedProvidersDirectory, 
spm, spm);
+      
log.configuredMonitoringProviderConfigChangesInDirectory(sharedProvidersDirectory.getAbsolutePath());
 
       // For all the descriptors currently in the descriptors dir at start-up 
time, determine if topology regeneration
       // is required.
@@ -658,7 +658,7 @@ public class DefaultTopologyService extends 
FileAlterationListenerAdaptor implem
       String[] descriptorFilenames =  descriptorsDirectory.list();
       if (descriptorFilenames != null) {
         for (String descriptorFilename : descriptorFilenames) {
-          if (DescriptorsMonitor.isDescriptorFile(descriptorFilename)) {
+          if 
(DescriptorsMonitor.SUPPORTED_EXTENSIONS.contains(FilenameUtils.getExtension(descriptorFilename)))
 {
             String topologyName = 
FilenameUtils.getBaseName(descriptorFilename);
             File existingDescriptorFile = 
getExistingFile(descriptorsDirectory, topologyName);
             if (existingDescriptorFile != null) {
@@ -739,15 +739,8 @@ public class DefaultTopologyService extends 
FileAlterationListenerAdaptor implem
    *
    * @return A List of the Files on the directory.
    */
-  private static List<File> listFiles(File directory) {
-    List<File> result;
-    File[] files = directory.listFiles();
-    if (files != null) {
-      result = Arrays.asList(files);
-    } else {
-      result = Collections.emptyList();
-    }
-    return result;
+  private static Collection<File> listFiles(File directory) {
+    return FileUtils.listFiles(directory, TrueFileFilter.INSTANCE, 
TrueFileFilter.INSTANCE);
   }
 
   /**
@@ -798,186 +791,6 @@ public class DefaultTopologyService extends 
FileAlterationListenerAdaptor implem
   /**
    * Change handler for simple descriptors
    */
-  public static class DescriptorsMonitor extends FileAlterationListenerAdaptor
-                                          implements FileFilter {
-
-    static final List<String> SUPPORTED_EXTENSIONS = new ArrayList<>();
-    static {
-      SUPPORTED_EXTENSIONS.add("json");
-      SUPPORTED_EXTENSIONS.add("yml");
-      SUPPORTED_EXTENSIONS.add("yaml");
-    }
-
-    private GatewayConfig gatewayConfig;
-
-    private File topologiesDir;
-
-    private AliasService aliasService;
-
-    private Map<String, List<String>> providerConfigReferences = new 
HashMap<>();
-
-
-    static boolean isDescriptorFile(String filename) {
-      return 
SUPPORTED_EXTENSIONS.contains(FilenameUtils.getExtension(filename));
-    }
-
-    public DescriptorsMonitor(GatewayConfig config, File topologiesDir, 
AliasService aliasService) {
-      this.gatewayConfig  = config;
-      this.topologiesDir  = topologiesDir;
-      this.aliasService   = aliasService;
-    }
-
-    List<String> getReferencingDescriptors(String providerConfigPath) {
-      String normalizedPath = FilenameUtils.normalize(providerConfigPath);
-      return providerConfigReferences.computeIfAbsent(normalizedPath, p -> new 
ArrayList<>());
-    }
-
-    @Override
-    public void onFileCreate(File file) {
-      onFileChange(file);
-    }
-
-    @Override
-    public void onFileDelete(File file) {
-      // For simple descriptors, we need to make sure to delete any 
corresponding full topology descriptors to trigger undeployment
-      for (String ext : 
DefaultTopologyService.SUPPORTED_TOPOLOGY_FILE_EXTENSIONS) {
-        File topologyFile =
-                new File(topologiesDir, 
FilenameUtils.getBaseName(file.getName()) + "." + ext);
-        if (topologyFile.exists()) {
-          log.deletingTopologyForDescriptorDeletion(topologyFile.getName(), 
file.getName());
-          topologyFile.delete();
-        }
-      }
-
-      String normalizedFilePath = 
FilenameUtils.normalize(file.getAbsolutePath());
-      String reference = null;
-      for (Map.Entry<String, List<String>> entry : 
providerConfigReferences.entrySet()) {
-        if (entry.getValue().contains(normalizedFilePath)) {
-          reference = entry.getKey();
-          break;
-        }
-      }
-
-      if (reference != null) {
-        providerConfigReferences.get(reference).remove(normalizedFilePath);
-        log.removedProviderConfigurationReference(normalizedFilePath, 
reference);
-      }
-    }
-
-    @Override
-    public void onFileChange(File file) {
-      try {
-        // When a simple descriptor has been created or modified, generate the 
new topology descriptor
-        Map<String, File> result = 
SimpleDescriptorHandler.handle(gatewayConfig, file, topologiesDir, 
aliasService);
-        
log.generatedTopologyForDescriptorChange(result.get(SimpleDescriptorHandler.RESULT_TOPOLOGY).getName(),
-            file.getName());
-
-        // Add the provider config reference relationship for handling updates 
to the provider config
-        String providerConfig =
-            
FilenameUtils.normalize(result.get(SimpleDescriptorHandler.RESULT_REFERENCE).getAbsolutePath());
-        if (!providerConfigReferences.containsKey(providerConfig)) {
-          providerConfigReferences.put(providerConfig, new ArrayList<>());
-        }
-        List<String> refs = providerConfigReferences.get(providerConfig);
-        String descriptorName = 
FilenameUtils.normalize(file.getAbsolutePath());
-        if (!refs.contains(descriptorName)) {
-          // Need to check if descriptor had previously referenced another 
provider config, so it can be removed
-          for (List<String> descs : providerConfigReferences.values()) {
-            descs.remove(descriptorName);
-          }
-
-          // Add the current reference relationship
-          refs.add(descriptorName);
-          log.addedProviderConfigurationReference(descriptorName, 
providerConfig);
-        }
-      } catch (IllegalArgumentException e) {
-        log.simpleDescriptorHandlingError(file.getName(), e);
-
-        // If the referenced provider configuration is invalid, remove any 
existing reference relationships for the
-        // referencing descriptor.
-        String descriptorName = 
FilenameUtils.normalize(file.getAbsolutePath());
-        // Need to check if descriptor had previously referenced another 
provider config, so it can be removed
-        for (List<String> descs : providerConfigReferences.values()) {
-          descs.remove(descriptorName);
-        }
-      } catch (Exception e) {
-        log.simpleDescriptorHandlingError(file.getName(), e);
-      }
-    }
-
-    @Override
-    public boolean accept(File file) {
-      boolean accept = false;
-      if (!file.isDirectory() && file.canRead()) {
-        String extension = FilenameUtils.getExtension(file.getName());
-        if (SUPPORTED_EXTENSIONS.contains(extension)) {
-          accept = true;
-        }
-      }
-      return accept;
-    }
-  }
-
-  /**
-   * Change handler for shared provider configurations
-   */
-  public static class SharedProviderConfigMonitor extends 
FileAlterationListenerAdaptor implements FileFilter {
-
-    static final List<String> SUPPORTED_EXTENSIONS = 
ProviderConfigurationParser.SUPPORTED_EXTENSIONS;
-
-    private DescriptorsMonitor descriptorsMonitor;
-    private File descriptorsDir;
-
-
-    SharedProviderConfigMonitor(DescriptorsMonitor descMonitor, File 
descriptorsDir) {
-      this.descriptorsMonitor = descMonitor;
-      this.descriptorsDir     = descriptorsDir;
-    }
-
-    @Override
-    public void onFileCreate(File file) {
-      onFileChange(file);
-    }
-
-    @Override
-    public void onFileDelete(File file) {
-      onFileChange(file);
-    }
-
-    @Override
-    public void onFileChange(File file) {
-      // For shared provider configuration, we need to update any simple 
descriptors that reference it
-      for (File descriptor : getReferencingDescriptors(file)) {
-        descriptor.setLastModified(System.currentTimeMillis());
-      }
-    }
-
-    private List<File> getReferencingDescriptors(File sharedProviderConfig) {
-      List<File> references = new ArrayList<>();
-
-      for (File descriptor : listFiles(descriptorsDir)) {
-        if 
(DescriptorsMonitor.SUPPORTED_EXTENSIONS.contains(FilenameUtils.getExtension(descriptor.getName())))
 {
-          for (String reference : 
descriptorsMonitor.getReferencingDescriptors(FilenameUtils.normalize(sharedProviderConfig.getAbsolutePath())))
 {
-            references.add(new File(reference));
-          }
-        }
-      }
-
-      return references;
-    }
-
-    @Override
-    public boolean accept(File file) {
-      boolean accept = false;
-      if (!file.isDirectory() && file.canRead()) {
-        String extension = FilenameUtils.getExtension(file.getName());
-        if (SUPPORTED_EXTENSIONS.contains(extension)) {
-          accept = true;
-        }
-      }
-      return accept;
-    }
-  }
 
   /**
    * Listener for Ambari config change events, which will trigger 
re-generation (including re-discovery) of the
diff --git 
a/gateway-server/src/main/java/org/apache/knox/gateway/services/topology/monitor/DescriptorsMonitor.java
 
b/gateway-server/src/main/java/org/apache/knox/gateway/services/topology/monitor/DescriptorsMonitor.java
new file mode 100644
index 0000000..9c67e37
--- /dev/null
+++ 
b/gateway-server/src/main/java/org/apache/knox/gateway/services/topology/monitor/DescriptorsMonitor.java
@@ -0,0 +1,141 @@
+/*
+ * 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.knox.gateway.services.topology.monitor;
+
+import java.io.File;
+import java.io.FileFilter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.io.FilenameUtils;
+import org.apache.commons.io.monitor.FileAlterationListenerAdaptor;
+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.security.AliasService;
+import org.apache.knox.gateway.services.topology.impl.DefaultTopologyService;
+import org.apache.knox.gateway.topology.simple.SimpleDescriptorHandler;
+
+public class DescriptorsMonitor extends FileAlterationListenerAdaptor 
implements FileFilter {
+
+  public static final List<String> SUPPORTED_EXTENSIONS = 
Collections.unmodifiableList(Arrays.asList("json", "yml", "yaml"));
+
+  private static final GatewayMessages LOG = 
MessagesFactory.get(GatewayMessages.class);
+
+  private final GatewayConfig gatewayConfig;
+  private final File topologiesDir;
+  private final AliasService aliasService;
+  private final Map<String, List<String>> providerConfigReferences = new 
HashMap<>();
+
+  public DescriptorsMonitor(GatewayConfig config, File topologiesDir, 
AliasService aliasService) {
+    this.gatewayConfig = config;
+    this.topologiesDir = topologiesDir;
+    this.aliasService = aliasService;
+  }
+
+  public List<String> getReferencingDescriptors(String providerConfigPath) {
+    final String normalizedPath = FilenameUtils.normalize(providerConfigPath);
+    return providerConfigReferences.computeIfAbsent(normalizedPath, p -> new 
ArrayList<>());
+  }
+
+  @Override
+  public void onFileCreate(File file) {
+    onFileChange(file);
+  }
+
+  @Override
+  public void onFileDelete(File file) {
+    // For simple descriptors, we need to make sure to delete any 
corresponding full topology descriptors to trigger undeployment
+    for (String ext : 
DefaultTopologyService.SUPPORTED_TOPOLOGY_FILE_EXTENSIONS) {
+      File topologyFile = new File(topologiesDir, 
FilenameUtils.getBaseName(file.getName()) + "." + ext);
+      if (topologyFile.exists()) {
+        LOG.deletingTopologyForDescriptorDeletion(topologyFile.getName(), 
file.getName());
+        topologyFile.delete();
+      }
+    }
+
+    final String normalizedFilePath = 
FilenameUtils.normalize(file.getAbsolutePath());
+    String reference = null;
+    for (Map.Entry<String, List<String>> entry : 
providerConfigReferences.entrySet()) {
+      if (entry.getValue().contains(normalizedFilePath)) {
+        reference = entry.getKey();
+        break;
+      }
+    }
+
+    if (reference != null) {
+      providerConfigReferences.get(reference).remove(normalizedFilePath);
+      LOG.removedProviderConfigurationReference(normalizedFilePath, reference);
+    }
+  }
+
+  @Override
+  public void onFileChange(File file) {
+    try {
+      // When a simple descriptor has been created or modified, generate the 
new topology descriptor
+      Map<String, File> result = SimpleDescriptorHandler.handle(gatewayConfig, 
file, topologiesDir, aliasService);
+      
LOG.generatedTopologyForDescriptorChange(result.get(SimpleDescriptorHandler.RESULT_TOPOLOGY).getName(),
 file.getName());
+
+      // Add the provider config reference relationship for handling updates 
to the provider config
+      String providerConfig = 
FilenameUtils.normalize(result.get(SimpleDescriptorHandler.RESULT_REFERENCE).getAbsolutePath());
+      if (!providerConfigReferences.containsKey(providerConfig)) {
+        providerConfigReferences.put(providerConfig, new ArrayList<>());
+      }
+      List<String> refs = providerConfigReferences.get(providerConfig);
+      String descriptorName = FilenameUtils.normalize(file.getAbsolutePath());
+      if (!refs.contains(descriptorName)) {
+        // Need to check if descriptor had previously referenced another 
provider config, so it can be removed
+        for (List<String> descs : providerConfigReferences.values()) {
+          descs.remove(descriptorName);
+        }
+
+        // Add the current reference relationship
+        refs.add(descriptorName);
+        LOG.addedProviderConfigurationReference(descriptorName, 
providerConfig);
+      }
+    } catch (IllegalArgumentException e) {
+      LOG.simpleDescriptorHandlingError(file.getName(), e);
+
+      // If the referenced provider configuration is invalid, remove any 
existing reference relationships for the
+      // referencing descriptor.
+      String descriptorName = FilenameUtils.normalize(file.getAbsolutePath());
+      // Need to check if descriptor had previously referenced another 
provider config, so it can be removed
+      for (List<String> descs : providerConfigReferences.values()) {
+        descs.remove(descriptorName);
+      }
+    } catch (Exception e) {
+      LOG.simpleDescriptorHandlingError(file.getName(), e);
+    }
+  }
+
+  @Override
+  public boolean accept(File file) {
+    boolean accept = false;
+    if (!file.isDirectory() && file.canRead()) {
+      String extension = FilenameUtils.getExtension(file.getName());
+      if (SUPPORTED_EXTENSIONS.contains(extension)) {
+        accept = true;
+      }
+    }
+    return accept;
+  }
+}
diff --git 
a/gateway-server/src/main/java/org/apache/knox/gateway/services/topology/monitor/SharedProviderConfigMonitor.java
 
b/gateway-server/src/main/java/org/apache/knox/gateway/services/topology/monitor/SharedProviderConfigMonitor.java
new file mode 100644
index 0000000..3e7e7c9
--- /dev/null
+++ 
b/gateway-server/src/main/java/org/apache/knox/gateway/services/topology/monitor/SharedProviderConfigMonitor.java
@@ -0,0 +1,86 @@
+/*
+ * 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.knox.gateway.services.topology.monitor;
+
+import java.io.File;
+import java.io.FileFilter;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.FilenameUtils;
+import org.apache.commons.io.filefilter.TrueFileFilter;
+import org.apache.commons.io.monitor.FileAlterationListenerAdaptor;
+import org.apache.knox.gateway.topology.simple.ProviderConfigurationParser;
+
+public class SharedProviderConfigMonitor extends FileAlterationListenerAdaptor 
implements FileFilter {
+
+  public static final List<String> SUPPORTED_EXTENSIONS = 
ProviderConfigurationParser.SUPPORTED_EXTENSIONS;
+
+  private DescriptorsMonitor descriptorsMonitor;
+  private File descriptorsDir;
+
+  public SharedProviderConfigMonitor(DescriptorsMonitor descMonitor, File 
descriptorsDir) {
+    this.descriptorsMonitor = descMonitor;
+    this.descriptorsDir = descriptorsDir;
+  }
+
+  @Override
+  public void onFileCreate(File file) {
+    onFileChange(file);
+  }
+
+  @Override
+  public void onFileDelete(File file) {
+    onFileChange(file);
+  }
+
+  @Override
+  public void onFileChange(File file) {
+    // For shared provider configuration, we need to update any simple 
descriptors that reference it
+    for (File descriptor : getReferencingDescriptors(file)) {
+      descriptor.setLastModified(System.currentTimeMillis());
+    }
+  }
+
+  private List<File> getReferencingDescriptors(File sharedProviderConfig) {
+    final List<File> references = new ArrayList<>();
+
+    for (File descriptor : FileUtils.listFiles(descriptorsDir, 
TrueFileFilter.INSTANCE, TrueFileFilter.INSTANCE)) {
+      if 
(DescriptorsMonitor.SUPPORTED_EXTENSIONS.contains(FilenameUtils.getExtension(descriptor.getName())))
 {
+        for (String reference : 
descriptorsMonitor.getReferencingDescriptors(FilenameUtils.normalize(sharedProviderConfig.getAbsolutePath())))
 {
+          references.add(new File(reference));
+        }
+      }
+    }
+
+    return references;
+  }
+
+  @Override
+  public boolean accept(File file) {
+    boolean accept = false;
+    if (!file.isDirectory() && file.canRead()) {
+      String extension = FilenameUtils.getExtension(file.getName());
+      if (SUPPORTED_EXTENSIONS.contains(extension)) {
+        accept = true;
+      }
+    }
+    return accept;
+  }
+}
diff --git 
a/gateway-server/src/test/java/org/apache/knox/gateway/services/topology/DefaultTopologyServiceTest.java
 
b/gateway-server/src/test/java/org/apache/knox/gateway/services/topology/DefaultTopologyServiceTest.java
index 61bce5d..fb9be76 100644
--- 
a/gateway-server/src/test/java/org/apache/knox/gateway/services/topology/DefaultTopologyServiceTest.java
+++ 
b/gateway-server/src/test/java/org/apache/knox/gateway/services/topology/DefaultTopologyServiceTest.java
@@ -23,6 +23,7 @@ import org.apache.commons.io.IOUtils;
 import org.apache.commons.io.monitor.FileAlterationListener;
 import org.apache.knox.gateway.config.GatewayConfig;
 import org.apache.knox.gateway.services.topology.impl.DefaultTopologyService;
+import org.apache.knox.gateway.services.topology.monitor.DescriptorsMonitor;
 import org.apache.knox.gateway.services.security.AliasService;
 import org.apache.knox.test.TestUtils;
 import org.apache.knox.gateway.topology.Param;
@@ -216,8 +217,7 @@ public class DefaultTopologyServiceTest {
       AliasService aliasService = EasyMock.createNiceMock(AliasService.class);
       
EasyMock.expect(aliasService.getPasswordFromAliasForGateway(anyObject(String.class))).andReturn(null).anyTimes();
       EasyMock.replay(aliasService);
-      DefaultTopologyService.DescriptorsMonitor dm =
-              new DefaultTopologyService.DescriptorsMonitor(config, 
topologyDir, aliasService);
+      DescriptorsMonitor dm = new DescriptorsMonitor(config, topologyDir, 
aliasService);
 
       // Listener to simulate the topologies directory monitor, to notice when 
a topology has been deleted
       provider.addTopologyChangeListener(new 
TestTopologyDeleteListener(provider));
@@ -332,7 +332,7 @@ public class DefaultTopologyServiceTest {
 
       java.lang.reflect.Field dmField = 
ts.getClass().getDeclaredField("descriptorsMonitor");
       dmField.setAccessible(true);
-      DefaultTopologyService.DescriptorsMonitor dm = 
(DefaultTopologyService.DescriptorsMonitor) dmField.get(ts);
+      DescriptorsMonitor dm = (DescriptorsMonitor) dmField.get(ts);
 
       // Write out the referenced provider configs first
       createFile(sharedProvidersDir,
@@ -424,7 +424,7 @@ public class DefaultTopologyServiceTest {
 
       java.lang.reflect.Field dmField = 
ts.getClass().getDeclaredField("descriptorsMonitor");
       dmField.setAccessible(true);
-      DefaultTopologyService.DescriptorsMonitor dm = 
(DefaultTopologyService.DescriptorsMonitor) dmField.get(ts);
+      DescriptorsMonitor dm = (DescriptorsMonitor) dmField.get(ts);
 
       final String simpleDescName  = "six.json";
       final String provConfOne     = "provider-config-one.xml";

Reply via email to