Make GitRepoMetricsCache a Singleton

Refactor GitRepoMetricsCache to be a singleton and add
accessor methods to access the metrics.

Change-Id: I48ab46c56f86dd819b3ac9c2b60b306f93513d06
diff --git a/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/GitRepoMetricsCacheModule.java b/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/GitRepoMetricsCache.java
similarity index 79%
rename from src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/GitRepoMetricsCacheModule.java
rename to src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/GitRepoMetricsCache.java
index bd39eee..fa00623 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/GitRepoMetricsCacheModule.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/GitRepoMetricsCache.java
@@ -15,6 +15,7 @@
 package com.googlesource.gerrit.plugins.gitrepometrics;
 
 import com.google.common.base.Supplier;
+import com.google.common.collect.Maps;
 import com.google.gerrit.metrics.Description;
 import com.google.gerrit.metrics.MetricMaker;
 import com.google.inject.Inject;
@@ -22,27 +23,31 @@
 import com.googlesource.gerrit.plugins.gitrepometrics.collectors.GitRepoMetric;
 import com.googlesource.gerrit.plugins.gitrepometrics.collectors.GitStats;
 import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 
 @Singleton
-public class GitRepoMetricsCacheModule {
+public class GitRepoMetricsCache {
+  private Map<String, Long> metrics;
+  private final MetricMaker metricMaker;
+  private final List<String> projects;
+
   public static List<GitRepoMetric> metricsNames = new ArrayList<>(GitStats.availableMetrics());
-  public List<String> projects;
-
-  public static Map<String, Long> metrics = new HashMap<>(Collections.emptyMap());;
-
-  public final MetricMaker metricMaker;
-  public final GitRepoMetricsConfig config;
 
   @Inject
-  GitRepoMetricsCacheModule(MetricMaker metricMaker, GitRepoMetricsConfig config) {
+  GitRepoMetricsCache(MetricMaker metricMaker, GitRepoMetricsConfig config) {
     this.metricMaker = metricMaker;
-    this.config = config;
     this.projects = config.getRepositoryNames();
+    this.metrics = Maps.newHashMap();
+  }
+
+  public Map<String, Long> getMetrics() {
+    return metrics;
+  }
+
+  public void setMetrics(Map<String, Long> metrics) {
+    this.metrics = metrics;
   }
 
   public void initCache() {
@@ -51,7 +56,7 @@
           projects.forEach(
               projectName -> {
                 String name =
-                    GitRepoMetricsCacheModule.getMetricName(gitRepoMetric.getName(), projectName);
+                    GitRepoMetricsCache.getMetricName(gitRepoMetric.getName(), projectName);
                 Supplier<Long> supplier =
                     new Supplier<Long>() {
                       public Long get() {
@@ -59,7 +64,7 @@
                         // registering
                         //     dynamically the metrics
                         // TODO add grace period!!
-                        return GitRepoMetricsCacheModule.metrics.getOrDefault(name, 0L);
+                        return getMetrics().getOrDefault(name, 0L);
                       }
                     };
 
diff --git a/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/GitRepoMetricsConfig.java b/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/GitRepoMetricsConfig.java
index cabe96a..a9937cf 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/GitRepoMetricsConfig.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/GitRepoMetricsConfig.java
@@ -26,16 +26,16 @@
 
 @Singleton
 public class GitRepoMetricsConfig {
-
+  private final String pluginName;
   private final Config config;
 
   @Inject
   public GitRepoMetricsConfig(PluginConfigFactory configFactory, @PluginName String pluginName) {
     config = configFactory.getGlobalPluginConfig(pluginName);
+    this.pluginName = pluginName;
   }
 
   public List<String> getRepositoryNames() {
-    return Arrays.stream(config.getStringList("git-repo-metrics", null, "project"))
-        .collect(toList());
+    return Arrays.stream(config.getStringList(pluginName, null, "project")).collect(toList());
   }
 }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/GitRepoUpdateListener.java b/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/GitRepoUpdateListener.java
index fc4307c..97bc7cf 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/GitRepoUpdateListener.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/GitRepoUpdateListener.java
@@ -28,12 +28,16 @@
   private static final FluentLogger logger = FluentLogger.forEnclosingClass();
   private final GitRepositoryManager repoManager;
   private final ExecutorService executor;
+  private final UpdateGitMetricsTask.Factory updateGitMetricsTaskFactory;
 
   @Inject
   GitRepoUpdateListener(
-      GitRepositoryManager repoManager, @UpdateGitMetricsExecutor ExecutorService executor) {
+      GitRepositoryManager repoManager,
+      @UpdateGitMetricsExecutor ExecutorService executor,
+      UpdateGitMetricsTask.Factory updateGitMetricsTaskFactory) {
     this.repoManager = repoManager;
     this.executor = executor;
+    this.updateGitMetricsTaskFactory = updateGitMetricsTaskFactory;
   }
 
   @Override
@@ -43,7 +47,7 @@
     logger.atFine().log("Got an update for project %s", projectName);
     try (Repository repository = repoManager.openRepository(projectNameKey)) {
       UpdateGitMetricsTask updateGitMetricsTask =
-          new UpdateGitMetricsTask(repository, Project.builder(projectNameKey).build());
+          updateGitMetricsTaskFactory.create(repository, Project.builder(projectNameKey).build());
       executor.execute(updateGitMetricsTask);
     } catch (RepositoryNotFoundException e) {
       logger.atSevere().withCause(e).log("Cannot find repository for %s", projectName);
diff --git a/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/Module.java b/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/Module.java
index e9df0e2..f743ccb 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/Module.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/Module.java
@@ -17,17 +17,20 @@
 import com.google.gerrit.extensions.events.GitReferenceUpdatedListener;
 import com.google.gerrit.extensions.registration.DynamicSet;
 import com.google.gerrit.lifecycle.LifecycleModule;
+import com.google.inject.Scopes;
 import java.util.concurrent.ExecutorService;
 
 public class Module extends LifecycleModule {
 
   @Override
   protected void configure() {
+    bind(GitRepoMetricsCache.class).in(Scopes.SINGLETON);
     bind(ExecutorService.class)
         .annotatedWith(UpdateGitMetricsExecutor.class)
         .toProvider(UpdateGitMetricsExecutorProvider.class);
     bind(GitRepoUpdateListener.class);
     DynamicSet.bind(binder(), GitReferenceUpdatedListener.class).to(GitRepoUpdateListener.class);
     listener().to(PluginStartup.class);
+    install(new UpdateGitMetricsTaskModule());
   }
 }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/PluginStartup.java b/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/PluginStartup.java
index 8c1cc60..3d019fe 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/PluginStartup.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/PluginStartup.java
@@ -21,16 +21,21 @@
 public class PluginStartup implements LifecycleListener {
   public final MetricMaker metricMaker;
   public final GitRepoMetricsConfig config;
+  public final GitRepoMetricsCache gitRepoMetricsCache;
 
   @Inject
-  public PluginStartup(MetricMaker metricMaker, GitRepoMetricsConfig config) {
+  public PluginStartup(
+      MetricMaker metricMaker,
+      GitRepoMetricsConfig config,
+      GitRepoMetricsCache gitRepoMetricsCache) {
     this.metricMaker = metricMaker;
     this.config = config;
+    this.gitRepoMetricsCache = gitRepoMetricsCache;
   }
 
   @Override
   public void start() {
-    new GitRepoMetricsCacheModule(metricMaker, config).initCache();
+    gitRepoMetricsCache.initCache();
   }
 
   @Override
diff --git a/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/UpdateGitMetricsTask.java b/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/UpdateGitMetricsTask.java
index f2b9fd3..bee852e 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/UpdateGitMetricsTask.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/UpdateGitMetricsTask.java
@@ -14,10 +14,10 @@
 
 package com.googlesource.gerrit.plugins.gitrepometrics;
 
-import static com.googlesource.gerrit.plugins.gitrepometrics.GitRepoMetricsCacheModule.metrics;
-
 import com.google.common.flogger.FluentLogger;
 import com.google.gerrit.entities.Project;
+import com.google.inject.Inject;
+import com.google.inject.assistedinject.Assisted;
 import com.googlesource.gerrit.plugins.gitrepometrics.collectors.GitStats;
 import java.util.Map;
 import java.util.stream.Collectors;
@@ -27,12 +27,22 @@
 public class UpdateGitMetricsTask implements Runnable {
   private static final FluentLogger logger = FluentLogger.forEnclosingClass();
 
+  public interface Factory {
+    UpdateGitMetricsTask create(Repository repository, Project project);
+  }
+
   private final Repository repository;
   private final Project project;
+  private GitRepoMetricsCache gitRepoMetricsCache;
 
-  UpdateGitMetricsTask(Repository repository, Project project) {
+  @Inject
+  UpdateGitMetricsTask(
+      GitRepoMetricsCache gitRepoMetricsCache,
+      @Assisted Repository repository,
+      @Assisted Project project) {
     this.repository = repository;
     this.project = project;
+    this.gitRepoMetricsCache = gitRepoMetricsCache;
   }
 
   @Override
@@ -46,7 +56,7 @@
     Map<String, Long> newMetrics = gitStats.get();
     logger.atInfo().log(
         "Here all the metrics for %s - %s", project.getName(), getStringFromMap(newMetrics));
-    metrics.putAll(newMetrics);
+    gitRepoMetricsCache.setMetrics(newMetrics);
   }
 
   String getStringFromMap(Map<String, Long> m) {
diff --git a/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/UpdateGitMetricsTaskModule.java b/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/UpdateGitMetricsTaskModule.java
new file mode 100644
index 0000000..30a37de
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/UpdateGitMetricsTaskModule.java
@@ -0,0 +1,24 @@
+// Copyright (C) 2022 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.gitrepometrics;
+
+import com.google.gerrit.extensions.config.FactoryModule;
+
+public class UpdateGitMetricsTaskModule extends FactoryModule {
+  @Override
+  protected void configure() {
+    factory(UpdateGitMetricsTask.Factory.class);
+  }
+}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/collectors/GitStats.java b/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/collectors/GitStats.java
index 9e2150d..8b8c2d7 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/collectors/GitStats.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/gitrepometrics/collectors/GitStats.java
@@ -16,7 +16,7 @@
 
 import com.google.common.flogger.FluentLogger;
 import com.google.gerrit.entities.Project;
-import com.googlesource.gerrit.plugins.gitrepometrics.GitRepoMetricsCacheModule;
+import com.googlesource.gerrit.plugins.gitrepometrics.GitRepoMetricsCache;
 import java.io.IOException;
 import java.util.Arrays;
 import java.util.Collections;
@@ -84,7 +84,6 @@
       String metricName,
       Function<GC.RepoStatistics, Long> fn,
       GC.RepoStatistics statistics) {
-    metrics.put(
-        GitRepoMetricsCacheModule.getMetricName(metricName, p.getName()), fn.apply(statistics));
+    metrics.put(GitRepoMetricsCache.getMetricName(metricName, p.getName()), fn.apply(statistics));
   }
 }
diff --git a/src/test/java/com/googlesource/gerrit/plugins/gitrepometrics/GitRepoMetricsCacheModuleTest.java b/src/test/java/com/googlesource/gerrit/plugins/gitrepometrics/GitRepoMetricsCacheTest.java
similarity index 86%
rename from src/test/java/com/googlesource/gerrit/plugins/gitrepometrics/GitRepoMetricsCacheModuleTest.java
rename to src/test/java/com/googlesource/gerrit/plugins/gitrepometrics/GitRepoMetricsCacheTest.java
index ee6e5f1..3f202fb 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/gitrepometrics/GitRepoMetricsCacheModuleTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/gitrepometrics/GitRepoMetricsCacheTest.java
@@ -28,23 +28,22 @@
 import org.eclipse.jgit.lib.Config;
 import org.junit.Test;
 
-public class GitRepoMetricsCacheModuleTest {
-
+public class GitRepoMetricsCacheTest {
+  private final String pluginName = "git-repo-metrics";
   PluginConfigFactory pluginConfigFactory = mock(PluginConfigFactory.class);
 
-  GitRepoMetricsCacheModule gitRepoMetricsCacheModule;
+  GitRepoMetricsCache gitRepoMetricsCacheModule;
   GitRepoMetricsConfig gitRepoMetricsConfig;
   FakeMetricMaker fakeMetricMaker;
 
   @Test
   public void shouldRegisterMetrics() {
     Config c = new Config();
-    c.setStringList("git-repo-metrics", null, "project", Collections.singletonList("repo1"));
+    c.setStringList(pluginName, null, "project", Collections.singletonList("repo1"));
     doReturn(c).when(pluginConfigFactory).getGlobalPluginConfig(any());
-    gitRepoMetricsConfig = new GitRepoMetricsConfig(pluginConfigFactory, "git-repo-metrics");
+    gitRepoMetricsConfig = new GitRepoMetricsConfig(pluginConfigFactory, pluginName);
     fakeMetricMaker = new FakeMetricMaker();
-    gitRepoMetricsCacheModule =
-        new GitRepoMetricsCacheModule(fakeMetricMaker, gitRepoMetricsConfig);
+    gitRepoMetricsCacheModule = new GitRepoMetricsCache(fakeMetricMaker, gitRepoMetricsConfig);
     gitRepoMetricsCacheModule.initCache();
     assertThat(fakeMetricMaker.callsCounter).isEqualTo(GitStats.availableMetrics().size());
   }
diff --git a/src/test/java/com/googlesource/gerrit/plugins/gitrepometrics/GitUpdateListenerTest.java b/src/test/java/com/googlesource/gerrit/plugins/gitrepometrics/GitUpdateListenerTest.java
index 8e7f2e3..b47a42c 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/gitrepometrics/GitUpdateListenerTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/gitrepometrics/GitUpdateListenerTest.java
@@ -21,11 +21,18 @@
 import static org.mockito.Mockito.verifyNoInteractions;
 
 import com.google.gerrit.entities.Project;
+import com.google.gerrit.extensions.annotations.PluginName;
 import com.google.gerrit.extensions.api.changes.NotifyHandling;
 import com.google.gerrit.extensions.common.AccountInfo;
 import com.google.gerrit.extensions.events.GitReferenceUpdatedListener;
 import com.google.gerrit.server.git.GitRepositoryManager;
+import com.google.gerrit.testing.InMemoryModule;
 import com.google.gerrit.testing.InMemoryRepositoryManager;
+import com.google.inject.AbstractModule;
+import com.google.inject.Guice;
+import com.google.inject.Inject;
+import com.google.inject.Injector;
+import com.google.inject.TypeLiteral;
 import java.io.IOException;
 import java.util.concurrent.ExecutorService;
 import org.eclipse.jgit.lib.Repository;
@@ -34,7 +41,7 @@
 import org.mockito.ArgumentCaptor;
 
 public class GitUpdateListenerTest {
-
+  private final String pluginName = "git-repo-metrics";
   private final GitRepositoryManager repoManager = new InMemoryRepositoryManager();
   private final ExecutorService mockedExecutorService = mock(ExecutorService.class);
   private GitRepoUpdateListener gitRepoUpdateListener;
@@ -44,10 +51,28 @@
   ArgumentCaptor<UpdateGitMetricsTask> valueCapture =
       ArgumentCaptor.forClass(UpdateGitMetricsTask.class);
 
+  @Inject private UpdateGitMetricsTask.Factory updateGitMetricsTaskFactory;
+
   @Before
   public void setupRepo() throws IOException {
+
+    AbstractModule m =
+        new AbstractModule() {
+          @Override
+          protected void configure() {
+            install(new InMemoryModule());
+            install(new UpdateGitMetricsTaskModule());
+            bind(new TypeLiteral<String>() {})
+                .annotatedWith(PluginName.class)
+                .toInstance(pluginName);
+          }
+        };
+    Injector injector = Guice.createInjector(m);
+    injector.injectMembers(this);
+
     reset(mockedExecutorService);
-    gitRepoUpdateListener = new GitRepoUpdateListener(repoManager, mockedExecutorService);
+    gitRepoUpdateListener =
+        new GitRepoUpdateListener(repoManager, mockedExecutorService, updateGitMetricsTaskFactory);
     repository = repoManager.createRepository(testProjectNameKey);
   }
 
@@ -56,7 +81,7 @@
     doNothing().when(mockedExecutorService).execute(valueCapture.capture());
     gitRepoUpdateListener.onGitReferenceUpdated(new TestEvent(testProject));
     UpdateGitMetricsTask expectedUpdateGitMetricsTask =
-        new UpdateGitMetricsTask(repository, Project.builder(testProjectNameKey).build());
+        updateGitMetricsTaskFactory.create(repository, Project.builder(testProjectNameKey).build());
     assertThat(valueCapture.getValue().toString())
         .isEqualTo(expectedUpdateGitMetricsTask.toString());
   }
diff --git a/src/test/java/com/googlesource/gerrit/plugins/gitrepometrics/UpdateGitMetricsTaskTest.java b/src/test/java/com/googlesource/gerrit/plugins/gitrepometrics/UpdateGitMetricsTaskTest.java
index 2a8aeb9..2cb70c3 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/gitrepometrics/UpdateGitMetricsTaskTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/gitrepometrics/UpdateGitMetricsTaskTest.java
@@ -15,26 +15,59 @@
 package com.googlesource.gerrit.plugins.gitrepometrics;
 
 import static com.google.common.truth.Truth.assertThat;
-import static com.googlesource.gerrit.plugins.gitrepometrics.GitRepoMetricsCacheModule.metrics;
 import static java.nio.file.Files.delete;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
 
 import com.google.gerrit.entities.Project;
+import com.google.gerrit.metrics.DisabledMetricMaker;
+import com.google.gerrit.server.config.PluginConfigFactory;
+import com.google.inject.AbstractModule;
+import com.google.inject.Guice;
+import com.google.inject.Inject;
+import com.google.inject.Injector;
 import java.nio.file.Files;
 import java.nio.file.Path;
+import java.util.Collections;
 import org.eclipse.jgit.internal.storage.file.FileRepository;
+import org.eclipse.jgit.lib.Config;
 import org.eclipse.jgit.lib.Repository;
 import org.junit.Before;
 import org.junit.Test;
 
 public class UpdateGitMetricsTaskTest {
-
+  private final String pluginName = "git-repo-metrics";
   private final String projectName = "testProject";
   private final Project.NameKey projectNameKey = Project.nameKey(projectName);
   private Repository testRepository;
   private Project testProject;
+  private static PluginConfigFactory pluginConfigFactory = mock(PluginConfigFactory.class);
+  private GitRepoMetricsCache gitRepoMetricsCache;
+
+  @Inject private UpdateGitMetricsTask.Factory updateGitMetricsTaskFactory;
 
   @Before
   public void setupRepository() throws Exception {
+    Config c = new Config();
+    c.setStringList(pluginName, null, "project", Collections.singletonList("repo1"));
+    doReturn(c).when(pluginConfigFactory).getGlobalPluginConfig(any());
+
+    gitRepoMetricsCache =
+        new GitRepoMetricsCache(
+            new DisabledMetricMaker(), new GitRepoMetricsConfig(pluginConfigFactory, pluginName));
+
+    AbstractModule m =
+        new AbstractModule() {
+          @Override
+          protected void configure() {
+            install(new UpdateGitMetricsTaskModule());
+            bind(GitRepoMetricsCache.class).toInstance(gitRepoMetricsCache);
+          }
+        };
+    Injector injector = Guice.createInjector(m);
+    injector.injectMembers(this);
+
     Path p = Files.createTempDirectory("git_repo_metrics_");
     try {
       testRepository = new FileRepository(p.toFile());
@@ -49,8 +82,8 @@
   @Test
   public void shouldUpdateMetrics() {
     UpdateGitMetricsTask updateGitMetricsTask =
-        new UpdateGitMetricsTask(testRepository, testProject);
+        updateGitMetricsTaskFactory.create(testRepository, testProject);
     updateGitMetricsTask.run();
-    assertThat(metrics.keySet()).isNotEmpty();
+    assertThat(gitRepoMetricsCache.getMetrics().keySet()).isNotEmpty();
   }
 }