Support multiple plugins repositories bindings

Change-Id: I023b0b339f4999f4d62f68e2f4070f7af72d92a6
diff --git a/src/main/java/com/googlesource/gerrit/plugins/manager/Module.java b/src/main/java/com/googlesource/gerrit/plugins/manager/Module.java
index c29f2c9..0a96bfb 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/manager/Module.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/manager/Module.java
@@ -29,7 +29,8 @@
   protected void configure() {
     DynamicSet.bind(binder(), TopMenu.class).to(PluginManagerTopMenu.class);
 
-    bind(PluginsRepository.class).to(JenkinsCiPluginsRepository.class);
+    DynamicSet.setOf(binder(), PluginsRepository.class);
+    DynamicSet.bind(binder(), PluginsRepository.class).to(JenkinsCiPluginsRepository.class);
 
     install(PluginsCentralCache.module());
 
diff --git a/src/main/java/com/googlesource/gerrit/plugins/manager/OnStartStop.java b/src/main/java/com/googlesource/gerrit/plugins/manager/OnStartStop.java
index 8156016..1032613 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/manager/OnStartStop.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/manager/OnStartStop.java
@@ -14,33 +14,31 @@
 
 package com.googlesource.gerrit.plugins.manager;
 
-import com.google.gerrit.common.Version;
 import com.google.gerrit.extensions.annotations.PluginName;
 import com.google.gerrit.extensions.events.LifecycleListener;
 import com.google.inject.Inject;
 
 import com.googlesource.gerrit.plugins.manager.repository.PluginInfo;
-import com.googlesource.gerrit.plugins.manager.repository.PluginsRepository;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.io.IOException;
 import java.util.Collection;
+import java.util.concurrent.ExecutionException;
 
 public class OnStartStop implements LifecycleListener {
   private static final Logger log = LoggerFactory.getLogger(OnStartStop.class);
 
-  private final PluginsRepository pluginsRepo;
+  private final PluginsCentralCache pluginsCache;
 
   private final String pluginName;
 
   private final PluginManagerConfig config;
 
   @Inject
-  public OnStartStop(PluginsRepository pluginsRepo,
+  public OnStartStop(PluginsCentralCache pluginsCache,
       @PluginName String pluginName, PluginManagerConfig config) {
-    this.pluginsRepo = pluginsRepo;
+    this.pluginsCache = pluginsCache;
     this.pluginName = pluginName;
     this.config = config;
   }
@@ -54,10 +52,9 @@
         public void run() {
           log.info("Start-up: pre-loading list of plugins from registry");
           try {
-            Collection<PluginInfo> plugins =
-                pluginsRepo.list(Version.getVersion());
+            Collection<PluginInfo> plugins = pluginsCache.availablePlugins();
             log.info("{} plugins successfully pre-loaded", plugins.size());
-          } catch (IOException e) {
+          } catch (ExecutionException e) {
             log.error("Cannot access plugins list at this time", e);
           }
         }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/manager/PluginsCentralLoader.java b/src/main/java/com/googlesource/gerrit/plugins/manager/PluginsCentralLoader.java
index d7bf1b9..ccc8a70 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/manager/PluginsCentralLoader.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/manager/PluginsCentralLoader.java
@@ -16,6 +16,7 @@
 
 import com.google.common.cache.CacheLoader;
 import com.google.gerrit.common.Version;
+import com.google.gerrit.extensions.registration.DynamicSet;
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
 
@@ -24,6 +25,8 @@
 import com.googlesource.gerrit.plugins.manager.repository.PluginsRepository;
 
 import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
 
 @Singleton
 public class PluginsCentralLoader extends
@@ -37,15 +40,55 @@
 
   private static final String GERRIT_VERSION = Version.getVersion();
 
-  private final PluginsRepository repository;
+  private final DynamicSet<PluginsRepository> repositories;
 
   @Inject
-  public PluginsCentralLoader(PluginsRepository repository) {
-    this.repository = repository;
+  public PluginsCentralLoader(DynamicSet<PluginsRepository> repositories) {
+    this.repositories = repositories;
   }
 
   @Override
   public Collection<PluginInfo> load(ListKey all) throws Exception {
-    return repository.list(GERRIT_VERSION);
+    Map<String, PluginInfo> pluginsMap = new HashMap<>();
+    Collection<PluginInfo> plugins;
+    for (PluginsRepository pluginsRepository : repositories) {
+      plugins = pluginsRepository.list(GERRIT_VERSION);
+      addAll(pluginsMap, plugins);
+    }
+    return pluginsMap.values();
+  }
+
+  private void addAll(Map<String, PluginInfo> pluginsMap,
+      Collection<PluginInfo> plugins) {
+    for (PluginInfo pluginInfo : plugins) {
+      PluginInfo currPlugin = pluginsMap.get(pluginInfo.name);
+      if (currPlugin == null
+          || isLaterVersion(pluginInfo.version, currPlugin.version)) {
+        pluginsMap.put(pluginInfo.name, pluginInfo);
+      }
+    }
+  }
+
+  private boolean isLaterVersion(String newVersion, String currVersion) {
+    String[] vals1 = newVersion.replaceAll("-", ".").split("\\.");
+    String[] vals2 = currVersion.replaceAll("-", ".").split("\\.");
+    int i = 0;
+
+    while (i < vals1.length && i < vals2.length && vals1[i].equals(vals2[i])) {
+      i++;
+    }
+
+    if (i < vals1.length && i < vals2.length) {
+      return compareNumOrStrings(vals1[i], vals2[i]) > 0;
+    }
+    return vals1.length - vals2.length > 0;
+  }
+
+  private int compareNumOrStrings(String v1, String v2) {
+    try {
+      return Integer.parseInt(v1) - Integer.parseInt(v2);
+    } catch (NumberFormatException e) {
+      return v1.compareTo(v2);
+    }
   }
 }