// Path: src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationFileBasedConfig.java
// public static String replaceName(String in, String name, boolean keyIsOptional) {
//   String key = "${name}";
//   int n = in.indexOf(key);
//   if (0 <= n) {
//     return in.substring(0, n) + name + in.substring(n + key.length());
//   }
//   if (keyIsOptional) {
//     return in;
//   }
//   return null;
// }
// 
// Path: src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationQueue.java
// static final NamedFluentLogger repLog = NamedFluentLogger.forName(REPLICATION_LOG_NAME);
// 
// Path: src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationConfig.java
// enum FilterType {
//   PROJECT_CREATION,
//   PROJECT_DELETION,
//   ALL
// }


import static com.googlesource.gerrit.plugins.replication.AdminApiFactory.isGerrit;
import static com.googlesource.gerrit.plugins.replication.AdminApiFactory.isGerritHttp;
import static com.googlesource.gerrit.plugins.replication.AdminApiFactory.isSSH;
import static com.googlesource.gerrit.plugins.replication.ReplicationFileBasedConfig.replaceName;
import static com.googlesource.gerrit.plugins.replication.ReplicationQueue.repLog;
import static java.util.stream.Collectors.toList;
import com.google.common.base.Strings;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.Multimap;
import com.google.common.collect.SetMultimap;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
import com.google.common.flogger.FluentLogger;
import com.google.gerrit.entities.Project;
import com.google.gerrit.server.git.WorkQueue;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
import com.googlesource.gerrit.plugins.replication.ReplicationConfig.FilterType;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Predicate;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.transport.URIish;
    while ((inFlight > 0 || pending > 0) && drainQueueAttempts > 0) {
      try {
        logger.atInfo().log(
            "Draining replication events, postpone shutdown. Events left: inFlight %d, pending %d",
            inFlight, pending);
        Thread.sleep(destination.getReplicationDelayMilliseconds());
      } catch (InterruptedException ie) {
        logger.atWarning().withCause(ie).log(
            "Wait for replication events to drain has been interrupted");
      }
      pending = destination.getQueueInfo().pending.size();
      inFlight = destination.getQueueInfo().inFlight.size();
      drainQueueAttempts--;
    }
    if (pending > 0 || inFlight > 0) {
      throw new EventQueueNotEmptyException(
          String.format("Pending: %d - InFlight: %d", pending, inFlight));
    }
  }

  @Subscribe
  public synchronized void onReload(List<RemoteConfiguration> remoteConfigurations) {
    if (shuttingDown) {
      logger.atWarning().log("Shutting down: configuration reload ignored");
      return;
    }

    try {
      replicationQueue.get().stop();
      destinations = allDestinations(destinationFactory, remoteConfigurations);
// Path: src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationFileBasedConfig.java
// public static String replaceName(String in, String name, boolean keyIsOptional) {
//   String key = "${name}";
//   int n = in.indexOf(key);
//   if (0 <= n) {
//     return in.substring(0, n) + name + in.substring(n + key.length());
//   }
//   if (keyIsOptional) {
//     return in;
//   }
//   return null;
// }
// 
// Path: src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationQueue.java
// static final NamedFluentLogger repLog = NamedFluentLogger.forName(REPLICATION_LOG_NAME);
// 
// Path: src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationConfig.java
// enum FilterType {
//   PROJECT_CREATION,
//   PROJECT_DELETION,
//   ALL
// }


// Path: src/main/java/com/googlesource/gerrit/plugins/replication/DestinationsCollection.java
import static com.googlesource.gerrit.plugins.replication.AdminApiFactory.isGerrit;
import static com.googlesource.gerrit.plugins.replication.AdminApiFactory.isGerritHttp;
import static com.googlesource.gerrit.plugins.replication.AdminApiFactory.isSSH;
import static com.googlesource.gerrit.plugins.replication.ReplicationFileBasedConfig.replaceName;
import static com.googlesource.gerrit.plugins.replication.ReplicationQueue.repLog;
import static java.util.stream.Collectors.toList;
import com.google.common.base.Strings;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.Multimap;
import com.google.common.collect.SetMultimap;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
import com.google.common.flogger.FluentLogger;
import com.google.gerrit.entities.Project;
import com.google.gerrit.server.git.WorkQueue;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
import com.googlesource.gerrit.plugins.replication.ReplicationConfig.FilterType;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Predicate;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.transport.URIish;

    while ((inFlight > 0 || pending > 0) && drainQueueAttempts > 0) {
      try {
        logger.atInfo().log(
            "Draining replication events, postpone shutdown. Events left: inFlight %d, pending %d",
            inFlight, pending);
        Thread.sleep(destination.getReplicationDelayMilliseconds());
      } catch (InterruptedException ie) {
        logger.atWarning().withCause(ie).log(
            "Wait for replication events to drain has been interrupted");
      }
      pending = destination.getQueueInfo().pending.size();
      inFlight = destination.getQueueInfo().inFlight.size();
      drainQueueAttempts--;
    }
    if (pending > 0 || inFlight > 0) {
      throw new EventQueueNotEmptyException(
          String.format("Pending: %d - InFlight: %d", pending, inFlight));
    }
  }

  @Subscribe
  public synchronized void onReload(List<RemoteConfiguration> remoteConfigurations) {
    if (shuttingDown) {
      logger.atWarning().log("Shutting down: configuration reload ignored");
      return;
    }

    try {
      replicationQueue.get().stop();
      destinations = allDestinations(destinationFactory, remoteConfigurations);
      logger.atInfo().log("Configuration reloaded: %d destinations", getAll(FilterType.ALL).size());