Generalize replication configuration type

Configuration is tightly coupled to destination configuration, however
this can be abstracted away so that different type of configurations can
be plugged in at runtime.

Introduce the concept of RemoteConfiguration, so that pull-replication
can leverage the existing configuration classes and auto-reload
mechanism.

Feature: Issue 11751
Change-Id: I4ca494feb11c02b6f75b665815d8a0f43dcff8bb
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/AutoReloadRunnable.java b/src/main/java/com/googlesource/gerrit/plugins/replication/AutoReloadRunnable.java
index 8ac0307..5b7c148 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/AutoReloadRunnable.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/AutoReloadRunnable.java
@@ -72,7 +72,7 @@
     String pendingConfigVersion = loadedConfig.getVersion();
     try {
       ReplicationFileBasedConfig newConfig = new ReplicationFileBasedConfig(site, pluginDataDir);
-      final List<DestinationConfiguration> newValidDestinations =
+      final List<RemoteConfiguration> newValidDestinations =
           configValidator.validateConfig(newConfig);
       loadedConfig = newConfig;
       loadedConfigVersion = newConfig.getVersion();
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/DestinationConfiguration.java b/src/main/java/com/googlesource/gerrit/plugins/replication/DestinationConfiguration.java
index 053739c..d12abc4 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/DestinationConfiguration.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/DestinationConfiguration.java
@@ -22,7 +22,7 @@
 import org.eclipse.jgit.lib.Config;
 import org.eclipse.jgit.transport.RemoteConfig;
 
-public class DestinationConfiguration {
+public class DestinationConfiguration implements RemoteConfiguration {
   static final int DEFAULT_REPLICATION_DELAY = 15;
   static final int DEFAULT_RESCHEDULE_DELAY = 3;
   static final int DEFAULT_DRAIN_QUEUE_ATTEMPTS = 0;
@@ -84,14 +84,17 @@
                 TimeUnit.SECONDS);
   }
 
+  @Override
   public int getDelay() {
     return delay;
   }
 
+  @Override
   public int getRescheduleDelay() {
     return rescheduleDelay;
   }
 
+  @Override
   public int getRetryDelay() {
     return retryDelay;
   }
@@ -108,26 +111,32 @@
     return lockErrorMaxRetries;
   }
 
+  @Override
   public ImmutableList<String> getUrls() {
     return urls;
   }
 
+  @Override
   public ImmutableList<String> getAdminUrls() {
     return adminUrls;
   }
 
+  @Override
   public ImmutableList<String> getProjects() {
     return projects;
   }
 
+  @Override
   public ImmutableList<String> getAuthGroupNames() {
     return authGroupNames;
   }
 
+  @Override
   public String getRemoteNameStyle() {
     return remoteNameStyle;
   }
 
+  @Override
   public boolean replicatePermissions() {
     return replicatePermissions;
   }
@@ -144,10 +153,12 @@
     return replicateHiddenProjects;
   }
 
+  @Override
   public RemoteConfig getRemoteConfig() {
     return remoteConfig;
   }
 
+  @Override
   public int getMaxRetries() {
     return maxRetries;
   }
@@ -174,6 +185,7 @@
     return ret;
   }
 
+  @Override
   public int getSlowLatencyThreshold() {
     return slowLatencyThreshold;
   }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/DestinationsCollection.java b/src/main/java/com/googlesource/gerrit/plugins/replication/DestinationsCollection.java
index 570dfb8..e040dd6 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/DestinationsCollection.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/DestinationsCollection.java
@@ -232,7 +232,7 @@
   }
 
   @Subscribe
-  public synchronized void onReload(List<DestinationConfiguration> destinationConfigurations) {
+  public synchronized void onReload(List<RemoteConfiguration> remoteConfigurations) {
     if (shuttingDown) {
       logger.atWarning().log("Shutting down: configuration reload ignored");
       return;
@@ -240,7 +240,7 @@
 
     try {
       replicationQueue.get().stop();
-      destinations = allDestinations(destinationFactory, destinationConfigurations);
+      destinations = allDestinations(destinationFactory, remoteConfigurations);
       logger.atInfo().log("Configuration reloaded: %d destinations", getAll(FilterType.ALL).size());
     } finally {
       replicationQueue.get().start();
@@ -248,7 +248,7 @@
   }
 
   @Override
-  public List<DestinationConfiguration> validateConfig(ReplicationFileBasedConfig replicationConfig)
+  public List<RemoteConfiguration> validateConfig(ReplicationFileBasedConfig replicationConfig)
       throws ConfigInvalidException {
     if (!replicationConfig.getConfig().getFile().exists()) {
       logger.atWarning().log(
@@ -280,7 +280,7 @@
     boolean defaultForceUpdate =
         replicationConfig.getConfig().getBoolean("gerrit", "defaultForceUpdate", false);
 
-    ImmutableList.Builder<DestinationConfiguration> confs = ImmutableList.builder();
+    ImmutableList.Builder<RemoteConfiguration> confs = ImmutableList.builder();
     for (RemoteConfig c : allRemotes(replicationConfig.getConfig())) {
       if (c.getURIs().isEmpty()) {
         continue;
@@ -321,12 +321,13 @@
   }
 
   private List<Destination> allDestinations(
-      Destination.Factory destinationFactory,
-      List<DestinationConfiguration> destinationConfigurations) {
+      Destination.Factory destinationFactory, List<RemoteConfiguration> remoteConfigurations) {
 
     ImmutableList.Builder<Destination> dest = ImmutableList.builder();
-    for (DestinationConfiguration c : destinationConfigurations) {
-      dest.add(destinationFactory.create(c));
+    for (RemoteConfiguration c : remoteConfigurations) {
+      if (c instanceof DestinationConfiguration) {
+        dest.add(destinationFactory.create((DestinationConfiguration) c));
+      }
     }
     return dest.build();
   }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/RemoteConfiguration.java b/src/main/java/com/googlesource/gerrit/plugins/replication/RemoteConfiguration.java
new file mode 100644
index 0000000..aa683ff
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/RemoteConfiguration.java
@@ -0,0 +1,98 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed 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 com.googlesource.gerrit.plugins.replication;
+
+import com.google.common.collect.ImmutableList;
+import org.eclipse.jgit.transport.RemoteConfig;
+
+/** Remote configuration for a replication endpoint */
+public interface RemoteConfiguration {
+  /**
+   * Time to wait before scheduling a remote replication operation. Setting to 0 effectively
+   * disables the delay.
+   *
+   * @return the delay value in seconds
+   */
+  int getDelay();
+  /**
+   * Time to wait before rescheduling a remote replication operation, which might have failed the
+   * first time round. Setting to 0 effectively disables the delay.
+   *
+   * @return the delay value in seconds
+   */
+  int getRescheduleDelay();
+  /**
+   * Time to wait before retrying a failed remote replication operation, Setting to 0 effectively
+   * disables the delay.
+   *
+   * @return the delay value in seconds
+   */
+  int getRetryDelay();
+  /**
+   * List of the remote endpoint addresses used for replication.
+   *
+   * @return list of remote URL strings
+   */
+  ImmutableList<String> getUrls();
+  /**
+   * List of alternative remote endpoint addresses, used for admin operations, such as repository
+   * creation
+   *
+   * @return list of remote URL strings
+   */
+  ImmutableList<String> getAdminUrls();
+  /**
+   * List of repositories that should be replicated
+   *
+   * @return list of project strings
+   */
+  ImmutableList<String> getProjects();
+  /**
+   * List of groups that should be used to access the repositories.
+   *
+   * @return list of group strings
+   */
+  ImmutableList<String> getAuthGroupNames();
+  /**
+   * Influence how the name of the remote repository should be computed.
+   *
+   * @return a string representing a remote style name
+   */
+  String getRemoteNameStyle();
+  /**
+   * If true, permissions-only projects and the refs/meta/config branch will also be replicated
+   *
+   * @return a string representing a remote style name
+   */
+  boolean replicatePermissions();
+  /**
+   * the JGIT remote configuration representing the replication for this endpoint
+   *
+   * @return The remote config {@link RemoteConfig}
+   */
+  RemoteConfig getRemoteConfig();
+  /**
+   * Number of times to retry a replication operation
+   *
+   * @return the number of retries
+   */
+  int getMaxRetries();
+
+  /**
+   * the time duration after which the replication for a project should be considered “slow”
+   *
+   * @return the slow latency threshold
+   */
+  int getSlowLatencyThreshold();
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationConfigValidator.java b/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationConfigValidator.java
index 2a2ced1..7883114 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationConfigValidator.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationConfigValidator.java
@@ -23,9 +23,9 @@
    * validate the new replication.config
    *
    * @param newConfig new configuration detected
-   * @return List of validated {@link DestinationConfiguration}
+   * @return List of validated {@link RemoteConfiguration}
    * @throws ConfigInvalidException if the new configuration is not valid.
    */
-  List<DestinationConfiguration> validateConfig(ReplicationFileBasedConfig newConfig)
+  List<RemoteConfiguration> validateConfig(ReplicationFileBasedConfig newConfig)
       throws ConfigInvalidException;
 }
diff --git a/src/test/java/com/googlesource/gerrit/plugins/replication/AutoReloadRunnableTest.java b/src/test/java/com/googlesource/gerrit/plugins/replication/AutoReloadRunnableTest.java
index c302271..b1aa7c8 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/replication/AutoReloadRunnableTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/replication/AutoReloadRunnableTest.java
@@ -105,14 +105,14 @@
 
   private static class TestValidConfigurationListener implements ReplicationConfigValidator {
     @Override
-    public List<DestinationConfiguration> validateConfig(ReplicationFileBasedConfig newConfig) {
+    public List<RemoteConfiguration> validateConfig(ReplicationFileBasedConfig newConfig) {
       return Collections.emptyList();
     }
   }
 
   private static class TestInvalidConfigurationListener implements ReplicationConfigValidator {
     @Override
-    public List<DestinationConfiguration> validateConfig(
+    public List<RemoteConfiguration> validateConfig(
         ReplicationFileBasedConfig configurationChangeEvent) throws ConfigInvalidException {
       throw new ConfigInvalidException("expected test failure");
     }