REST API to retrieve Project’s replication status

Expose a new REST API to return the list of replication statuses
associated to a project.

GET /projects/myproject/replication

returns a JSON Array of replication events as they are returned
by Gerrit stream events.

Change-Id: I7d601191f0a66352e41c621e2ef2f869e249fb24
diff --git a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/GuiceModule.java b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/GuiceModule.java
index f6f4c71..0521cef 100644
--- a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/GuiceModule.java
+++ b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/GuiceModule.java
@@ -16,8 +16,10 @@
 
 import com.google.gerrit.common.EventListener;
 import com.google.gerrit.extensions.registration.DynamicSet;
+import com.google.gerrit.extensions.restapi.RestApiModule;
 import com.google.gerrit.extensions.webui.TopMenu;
 import com.google.gerrit.server.account.GroupBackend;
+import com.google.gerrit.server.project.ProjectResource;
 import com.google.gson.Gson;
 import com.google.inject.AbstractModule;
 import com.google.inject.Scopes;
@@ -31,8 +33,9 @@
 import com.googlesource.gerrit.plugins.github.oauth.IdentifiedUserGitHubLoginProvider;
 import com.googlesource.gerrit.plugins.github.oauth.UserScopedProvider;
 import com.googlesource.gerrit.plugins.github.replication.GerritGsonProvider;
-import com.googlesource.gerrit.plugins.github.replication.ReplicationStatusListener;
+import com.googlesource.gerrit.plugins.github.replication.ListProjectReplicationStatus;
 import com.googlesource.gerrit.plugins.github.replication.ReplicationStatusFlatFile;
+import com.googlesource.gerrit.plugins.github.replication.ReplicationStatusListener;
 import com.googlesource.gerrit.plugins.github.replication.ReplicationStatusStore;
 
 public class GuiceModule extends AbstractModule {
@@ -52,6 +55,14 @@
     install(new FactoryModuleBuilder()
         .build(GitHubGroupMembership.Factory.class));
 
+    install(new RestApiModule() {
+      @Override
+      protected void configure() {
+        get(ProjectResource.PROJECT_KIND, "replication").to(
+            ListProjectReplicationStatus.class);
+      }
+    });
+
     bind(ReplicationStatusStore.class).to(ReplicationStatusFlatFile.class)
         .in(Scopes.SINGLETON);
     bind(Gson.class).toProvider(GerritGsonProvider.class);
diff --git a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/replication/ListProjectReplicationStatus.java b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/replication/ListProjectReplicationStatus.java
new file mode 100644
index 0000000..868ac5b
--- /dev/null
+++ b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/replication/ListProjectReplicationStatus.java
@@ -0,0 +1,37 @@
+// Copyright (C) 2013 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.github.replication;
+
+import com.google.gerrit.extensions.restapi.AuthException;
+import com.google.gerrit.extensions.restapi.BadRequestException;
+import com.google.gerrit.extensions.restapi.ResourceConflictException;
+import com.google.gerrit.extensions.restapi.RestReadView;
+import com.google.gerrit.server.project.ProjectResource;
+import com.google.inject.Inject;
+
+public class ListProjectReplicationStatus implements RestReadView<ProjectResource> {
+  private final ReplicationStatusStore statusStore;
+
+  @Inject
+  public ListProjectReplicationStatus(ReplicationStatusStore statusStore) {
+    this.statusStore = statusStore;
+  }
+
+  @Override
+  public Object apply(ProjectResource resource) throws AuthException,
+      BadRequestException, ResourceConflictException, Exception {
+    return statusStore.list(resource.getNameKey());
+  }
+}
diff --git a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/replication/ReplicationStatusFlatFile.java b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/replication/ReplicationStatusFlatFile.java
index 3bf0645..4d5a033 100644
--- a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/replication/ReplicationStatusFlatFile.java
+++ b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/replication/ReplicationStatusFlatFile.java
@@ -19,20 +19,32 @@
 import static java.nio.file.StandardOpenOption.WRITE;
 
 import java.io.IOException;
+import java.io.Reader;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.FileVisitResult;
 import java.nio.file.Files;
 import java.nio.file.Path;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.ArrayList;
+import java.util.List;
 
 import com.google.gerrit.extensions.annotations.PluginData;
 import com.google.gerrit.reviewdb.client.Project;
+import com.google.gson.Gson;
 import com.google.gson.JsonObject;
 import com.google.inject.Inject;
+import com.google.inject.Provider;
 
 public class ReplicationStatusFlatFile implements ReplicationStatusStore {
   private final Path pluginData;
+  private final Gson gson;
 
   @Inject
-  public ReplicationStatusFlatFile(@PluginData Path pluginData) {
+  public ReplicationStatusFlatFile(@PluginData Path pluginData,
+      Provider<Gson> gsonProvider) {
     this.pluginData = pluginData;
+    this.gson = gsonProvider.get();
   }
 
   @Override
@@ -56,4 +68,24 @@
     return sanitizedKey;
   }
 
+  @Override
+  public List<JsonObject> list(Project.NameKey parentKey) throws IOException {
+    Path projectPath = pluginData.resolve(getSanitizedKey(parentKey.get()));
+    final List<JsonObject> entries = new ArrayList<>();
+    Files.walkFileTree(projectPath, new SimpleFileVisitor<Path>() {
+
+      @Override
+      public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
+          throws IOException {
+        try (Reader fileReader =
+            Files.newBufferedReader(file, StandardCharsets.UTF_8)) {
+          JsonObject json = gson.fromJson(fileReader, JsonObject.class);
+          entries.add(json);
+        }
+        return FileVisitResult.CONTINUE;
+      }
+    });
+    return entries;
+  }
+
 }
diff --git a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/replication/ReplicationStatusStore.java b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/replication/ReplicationStatusStore.java
index 701869b..75c1872 100644
--- a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/replication/ReplicationStatusStore.java
+++ b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/replication/ReplicationStatusStore.java
@@ -15,6 +15,7 @@
 package com.googlesource.gerrit.plugins.github.replication;
 
 import java.io.IOException;
+import java.util.List;
 
 import com.google.gerrit.reviewdb.client.Project;
 import com.google.gson.JsonObject;
@@ -23,4 +24,6 @@
 
   public void set(Project.NameKey projectKey, String refKey,
       JsonObject statusEvent) throws IOException;
+
+  public List<JsonObject> list(Project.NameKey projectKey) throws IOException;
 }