Keep positive status upon successful replication

It is quite useful to keep both positive and negative replication status
in order to keep track as well when the last replication happened.

Generally speaking using the replication status records we should be
able to classify each repo with:
- green status: replication successfully completed
- amber status: no replication status found
- red status: one or more refs have replication errors

Change-Id: I5c4375c66fd21c5806063c9315f3f2b2d9f0249a
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 6eed4ea..f6f4c71 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
@@ -18,6 +18,7 @@
 import com.google.gerrit.extensions.registration.DynamicSet;
 import com.google.gerrit.extensions.webui.TopMenu;
 import com.google.gerrit.server.account.GroupBackend;
+import com.google.gson.Gson;
 import com.google.inject.AbstractModule;
 import com.google.inject.Scopes;
 import com.google.inject.TypeLiteral;
@@ -29,7 +30,8 @@
 import com.googlesource.gerrit.plugins.github.oauth.GitHubLogin;
 import com.googlesource.gerrit.plugins.github.oauth.IdentifiedUserGitHubLoginProvider;
 import com.googlesource.gerrit.plugins.github.oauth.UserScopedProvider;
-import com.googlesource.gerrit.plugins.github.replication.ReplicationErrorListener;
+import com.googlesource.gerrit.plugins.github.replication.GerritGsonProvider;
+import com.googlesource.gerrit.plugins.github.replication.ReplicationStatusListener;
 import com.googlesource.gerrit.plugins.github.replication.ReplicationStatusFlatFile;
 import com.googlesource.gerrit.plugins.github.replication.ReplicationStatusStore;
 
@@ -43,8 +45,7 @@
 
     DynamicSet.bind(binder(), TopMenu.class).to(GitHubTopMenu.class);
     DynamicSet.bind(binder(), GroupBackend.class).to(GitHubGroupBackend.class);
-    DynamicSet.bind(binder(), EventListener.class).to(ReplicationErrorListener.class);
-
+    DynamicSet.bind(binder(), EventListener.class).to(ReplicationStatusListener.class);
 
     install(new FactoryModuleBuilder()
         .build(GitHubOrganisationGroup.Factory.class));
@@ -53,5 +54,6 @@
 
     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/GerritGsonProvider.java b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/replication/GerritGsonProvider.java
new file mode 100644
index 0000000..c4334be
--- /dev/null
+++ b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/replication/GerritGsonProvider.java
@@ -0,0 +1,30 @@
+// 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.server.OutputFormat;
+import com.google.gson.Gson;
+import com.google.inject.Provider;
+import com.google.inject.Singleton;
+
+@Singleton
+public class GerritGsonProvider implements Provider<Gson> {
+  private final Gson gerritStyleGson = OutputFormat.JSON_COMPACT.newGson();
+
+  @Override
+  public Gson get() {
+    return gerritStyleGson;
+  }
+}
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 ebba163..3bf0645 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
@@ -23,6 +23,7 @@
 import java.nio.file.Path;
 
 import com.google.gerrit.extensions.annotations.PluginData;
+import com.google.gerrit.reviewdb.client.Project;
 import com.google.gson.JsonObject;
 import com.google.inject.Inject;
 
@@ -35,24 +36,24 @@
   }
 
   @Override
-  public void set(String key, JsonObject event) throws IOException {
-    Path replicationStatusPath = getReplicationStatusPath(key);
-    Files.write(replicationStatusPath, event.toString().getBytes(),
+  public void set(Project.NameKey projectKey, String refKey,
+      JsonObject statusEvent) throws IOException {
+    Path replicationStatusPath =
+        getReplicationStatusPath(projectKey.get() + "/" + refKey);
+    Files.write(replicationStatusPath, statusEvent.toString().getBytes(),
         TRUNCATE_EXISTING, CREATE, WRITE);
   }
 
-  @Override
-  public void remove(String key) throws IOException {
-      Path replicationStatusPath = getReplicationStatusPath(key);
-      if (Files.exists(replicationStatusPath)) {
-        Files.delete(replicationStatusPath);
-      }
-  }
-
   private Path getReplicationStatusPath(String key) throws IOException {
-    String sanitizedKey = key.replace(".", "_").replace(" ","_");
-    Path projectPath = pluginData.resolve(sanitizedKey + ".replication-error.json");
+    Path projectPath =
+        pluginData.resolve(getSanitizedKey(key) + ".replication-error.json");
     Files.createDirectories(projectPath.getParent());
     return projectPath;
   }
+
+  private String getSanitizedKey(String key) {
+    String sanitizedKey = key.replace(".", "_").replace(" ", "_");
+    return sanitizedKey;
+  }
+
 }
diff --git a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/replication/ReplicationErrorListener.java b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/replication/ReplicationStatusListener.java
similarity index 74%
rename from github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/replication/ReplicationErrorListener.java
rename to github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/replication/ReplicationStatusListener.java
index 3eea388..49358a9 100644
--- a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/replication/ReplicationErrorListener.java
+++ b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/replication/ReplicationStatusListener.java
@@ -21,27 +21,28 @@
 
 import com.google.gerrit.common.EventListener;
 import com.google.gerrit.reviewdb.client.Project.NameKey;
-import com.google.gerrit.server.OutputFormat;
 import com.google.gerrit.server.events.Event;
 import com.google.gerrit.server.events.RefEvent;
 import com.google.gson.Gson;
 import com.google.gson.JsonObject;
 import com.google.inject.Inject;
+import com.google.inject.Provider;
 import com.google.inject.Singleton;
 
 @Singleton
-public class ReplicationErrorListener implements EventListener {
+public class ReplicationStatusListener implements EventListener {
   private static final String REF_REPLICATED_EVENT = "ref-replicated";
   private static Logger log = LoggerFactory
-      .getLogger(ReplicationErrorListener.class);
+      .getLogger(ReplicationStatusListener.class);
 
   private final ReplicationStatusStore statusStore;
   private final Gson gson;
 
   @Inject
-  public ReplicationErrorListener(ReplicationStatusStore statusStore) {
+  public ReplicationStatusListener(ReplicationStatusStore statusStore,
+      Provider<Gson> gsonProvider) {
     this.statusStore = statusStore;
-    this.gson = OutputFormat.JSON_COMPACT.newGson();
+    this.gson = gsonProvider.get();
   }
 
   @Override
@@ -51,18 +52,13 @@
       RefEvent refEvent = (RefEvent) event;
       NameKey projectNameKey = refEvent.getProjectNameKey();
       JsonObject eventJson = (JsonObject) gson.toJsonTree(event);
-      String projectKey =
-          projectNameKey.get() + "/" + eventJson.get("ref").getAsString();
+      String refKey = eventJson.get("ref").getAsString();
 
       try {
-        if (eventJson.get("status").getAsString().equals("succeeded")) {
-          statusStore.remove(projectKey);
-        } else {
-          statusStore.set(projectKey, eventJson);
-        }
+        statusStore.set(projectNameKey, refKey, eventJson);
       } catch (IOException e) {
         log.error("Unable to update replication status for event " + eventJson
-            + " on project " + projectKey, e);
+            + " on project " + projectNameKey, e);
       }
     }
   }
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 2eb8c24..701869b 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
@@ -16,11 +16,11 @@
 
 import java.io.IOException;
 
+import com.google.gerrit.reviewdb.client.Project;
 import com.google.gson.JsonObject;
 
 public interface ReplicationStatusStore {
 
-  public void set(String key, JsonObject event) throws IOException;
-
-  public void remove(String key) throws IOException;
+  public void set(Project.NameKey projectKey, String refKey,
+      JsonObject statusEvent) throws IOException;
 }