Rename RefPair to RefUpdateSnapshot and clean it up

- the old name RefPair was a misnomer, it's not a pair of refs
- the new name RefUpdateSnapshot better describes the purpose of this
  class: it's an immutable snapshot of a JGit RefUpdate as the class
  javadoc already explained
- reduce visibility of this class to package-visibility since it's only
  used within its enclosing package
- add getters for all properties the callers need from a
  RefUpdateSnapshot

Change-Id: I78c9d35c685beffbd3bc3d4ab18bd006d98382a6
diff --git a/src/main/java/com/gerritforge/gerrit/globalrefdb/validation/BatchRefUpdateValidator.java b/src/main/java/com/gerritforge/gerrit/globalrefdb/validation/BatchRefUpdateValidator.java
index 1e45951..cbdb8cd 100644
--- a/src/main/java/com/gerritforge/gerrit/globalrefdb/validation/BatchRefUpdateValidator.java
+++ b/src/main/java/com/gerritforge/gerrit/globalrefdb/validation/BatchRefUpdateValidator.java
@@ -140,22 +140,24 @@
       return;
     }
 
-    List<RefPair> refsToUpdate = getRefPairs(commands).collect(Collectors.toList());
-    List<RefPair> refsFailures =
-        refsToUpdate.stream().filter(RefPair::hasFailed).collect(Collectors.toList());
+    List<RefUpdateSnapshot> refsToUpdate =
+        getRefUpdateSnapshots(commands).collect(Collectors.toList());
+    List<RefUpdateSnapshot> refsFailures =
+        refsToUpdate.stream().filter(RefUpdateSnapshot::hasFailed).collect(Collectors.toList());
     if (!refsFailures.isEmpty()) {
       String allFailuresMessage =
           refsFailures.stream()
-              .map(refPair -> String.format("Failed to fetch ref %s", refPair.compareRef.getName()))
+              .map(refSnapshot -> String.format("Failed to fetch ref %s", refSnapshot.getName()))
               .collect(Collectors.joining(", "));
-      Exception firstFailureException = refsFailures.get(0).exception;
+      Exception firstFailureException = refsFailures.get(0).getException();
 
       logger.atSevere().withCause(firstFailureException).log("%s", allFailuresMessage);
       throw new IOException(allFailuresMessage, firstFailureException);
     }
 
     try (CloseableSet<AutoCloseable> locks = new CloseableSet<>()) {
-      final List<RefPair> finalRefsToUpdate = compareAndGetLatestLocalRefs(refsToUpdate, locks);
+      final List<RefUpdateSnapshot> finalRefsToUpdate =
+          compareAndGetLatestLocalRefs(refsToUpdate, locks);
       delegateUpdate.invoke();
       boolean sharedDbUpdateSucceeded = false;
       try {
@@ -184,7 +186,7 @@
 
   private void rollback(
       OneParameterVoidFunction<List<ReceiveCommand>> delegateUpdateRollback,
-      List<RefPair> refsBeforeUpdate,
+      List<RefUpdateSnapshot> refsBeforeUpdate,
       List<ReceiveCommand> receiveCommands)
       throws IOException {
     List<ReceiveCommand> rollbackCommands =
@@ -192,61 +194,62 @@
             .map(
                 refBeforeUpdate ->
                     new ReceiveCommand(
-                        refBeforeUpdate.putValue,
-                        refBeforeUpdate.compareRef.getObjectId(),
+                        refBeforeUpdate.getNewValue(),
+                        refBeforeUpdate.getOldValue(),
                         refBeforeUpdate.getName()))
             .collect(Collectors.toList());
     delegateUpdateRollback.invoke(rollbackCommands);
     receiveCommands.forEach(command -> command.setResult(ReceiveCommand.Result.LOCK_FAILURE));
   }
 
-  private void updateSharedRefDb(Stream<ReceiveCommand> commandStream, List<RefPair> refsToUpdate)
+  private void updateSharedRefDb(
+      Stream<ReceiveCommand> commandStream, List<RefUpdateSnapshot> refsToUpdate)
       throws IOException {
     if (commandStream.anyMatch(cmd -> cmd.getResult() != ReceiveCommand.Result.OK)) {
       return;
     }
 
-    for (RefPair refPair : refsToUpdate) {
-      updateSharedDbOrThrowExceptionFor(refPair);
+    for (RefUpdateSnapshot refUpdateSnapshot : refsToUpdate) {
+      updateSharedDbOrThrowExceptionFor(refUpdateSnapshot);
     }
   }
 
-  private Stream<RefPair> getRefPairs(List<ReceiveCommand> receivedCommands) {
-    return receivedCommands.stream().map(this::getRefPairForCommand);
+  private Stream<RefUpdateSnapshot> getRefUpdateSnapshots(List<ReceiveCommand> receivedCommands) {
+    return receivedCommands.stream().map(this::getRefUpdateSnapshotForCommand);
   }
 
-  private RefPair getRefPairForCommand(ReceiveCommand command) {
+  private RefUpdateSnapshot getRefUpdateSnapshotForCommand(ReceiveCommand command) {
     try {
       switch (command.getType()) {
         case CREATE:
-          return new RefPair(nullRef(command.getRefName()), getNewRef(command));
+          return new RefUpdateSnapshot(nullRef(command.getRefName()), getNewValue(command));
 
         case UPDATE:
         case UPDATE_NONFASTFORWARD:
-          return new RefPair(getCurrentRef(command.getRefName()), getNewRef(command));
+          return new RefUpdateSnapshot(getCurrentRef(command.getRefName()), getNewValue(command));
 
         case DELETE:
-          return new RefPair(getCurrentRef(command.getRefName()), ObjectId.zeroId());
+          return new RefUpdateSnapshot(getCurrentRef(command.getRefName()), ObjectId.zeroId());
 
         default:
-          return new RefPair(
+          return new RefUpdateSnapshot(
               command.getRef(),
               new IllegalArgumentException("Unsupported command type " + command.getType()));
       }
     } catch (IOException e) {
-      return new RefPair(command.getRef(), e);
+      return new RefUpdateSnapshot(command.getRef(), e);
     }
   }
 
-  private ObjectId getNewRef(ReceiveCommand command) {
+  private ObjectId getNewValue(ReceiveCommand command) {
     return command.getNewId();
   }
 
-  private List<RefPair> compareAndGetLatestLocalRefs(
-      List<RefPair> refsToUpdate, CloseableSet<AutoCloseable> locks) throws IOException {
-    List<RefPair> latestRefsToUpdate = new ArrayList<>();
-    for (RefPair refPair : refsToUpdate) {
-      latestRefsToUpdate.add(compareAndGetLatestLocalRef(refPair, locks));
+  private List<RefUpdateSnapshot> compareAndGetLatestLocalRefs(
+      List<RefUpdateSnapshot> refsToUpdate, CloseableSet<AutoCloseable> locks) throws IOException {
+    List<RefUpdateSnapshot> latestRefsToUpdate = new ArrayList<>();
+    for (RefUpdateSnapshot refUpdateSnapshot : refsToUpdate) {
+      latestRefsToUpdate.add(compareAndGetLatestLocalRef(refUpdateSnapshot, locks));
     }
     return latestRefsToUpdate;
   }
diff --git a/src/main/java/com/gerritforge/gerrit/globalrefdb/validation/RefPair.java b/src/main/java/com/gerritforge/gerrit/globalrefdb/validation/RefPair.java
deleted file mode 100644
index 4211c0c..0000000
--- a/src/main/java/com/gerritforge/gerrit/globalrefdb/validation/RefPair.java
+++ /dev/null
@@ -1,76 +0,0 @@
-// Copyright (C) 2020 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.gerritforge.gerrit.globalrefdb.validation;
-
-import org.eclipse.jgit.lib.ObjectId;
-import org.eclipse.jgit.lib.Ref;
-
-/**
- * A convenience object encompassing the old (current) and the new (candidate) value of a {@link
- * Ref}. This is used to snapshot the current status of a ref update so that validations against the
- * global refdb are unaffected by changes on the {@link org.eclipse.jgit.lib.RefDatabase}.
- */
-public class RefPair {
-  public final Ref compareRef;
-  public final ObjectId putValue;
-  public final Exception exception;
-
-  /**
-   * Constructs a {@code RefPair} with the provided old and new ref values. The oldRef value is
-   * required not to be null, in which case an {@link IllegalArgumentException} is thrown.
-   *
-   * @param oldRef the old ref
-   * @param newRefValue the new (candidate) value for this ref.
-   */
-  RefPair(Ref oldRef, ObjectId newRefValue) {
-    if (oldRef == null) {
-      throw new IllegalArgumentException("Required not-null ref in RefPair");
-    }
-    this.compareRef = oldRef;
-    this.putValue = newRefValue;
-    this.exception = null;
-  }
-
-  /**
-   * Constructs a {@code RefPair} with the current ref and an Exception indicating why the new ref
-   * value failed being retrieved.
-   *
-   * @param newRef
-   * @param e
-   */
-  RefPair(Ref newRef, Exception e) {
-    this.compareRef = newRef;
-    this.exception = e;
-    this.putValue = ObjectId.zeroId();
-  }
-
-  /**
-   * Getter for the current ref
-   *
-   * @return the current ref value
-   */
-  public String getName() {
-    return compareRef.getName();
-  }
-
-  /**
-   * Whether the new value failed being retrieved
-   *
-   * @return true when this refPair has failed, false otherwise.
-   */
-  public boolean hasFailed() {
-    return exception != null;
-  }
-}
diff --git a/src/main/java/com/gerritforge/gerrit/globalrefdb/validation/RefUpdateSnapshot.java b/src/main/java/com/gerritforge/gerrit/globalrefdb/validation/RefUpdateSnapshot.java
new file mode 100644
index 0000000..2e83be3
--- /dev/null
+++ b/src/main/java/com/gerritforge/gerrit/globalrefdb/validation/RefUpdateSnapshot.java
@@ -0,0 +1,114 @@
+// Copyright (C) 2020 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.gerritforge.gerrit.globalrefdb.validation;
+
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.Ref;
+
+/**
+ * A convenience object encompassing the old (current) and the new (candidate) value of a {@link
+ * Ref}. This is used to snapshot the current status of a ref update so that validations against the
+ * global refdb are unaffected by changes on the underlying {@link
+ * org.eclipse.jgit.lib.RefDatabase}.
+ */
+class RefUpdateSnapshot {
+  private final Ref ref;
+  private final ObjectId newValue;
+  private final Exception exception;
+
+  /**
+   * Constructs a {@code RefUpdateSnapshot} with the provided old and new values. The old value of
+   * this Ref must not be null, otherwise an {@link IllegalArgumentException} is thrown.
+   *
+   * @param ref the ref with its old value
+   * @param newRefValue the new (candidate) value for this ref.
+   */
+  RefUpdateSnapshot(Ref ref, ObjectId newRefValue) {
+    if (ref == null) {
+      throw new IllegalArgumentException("RefUpdateSnapshot cannot be created for null Ref");
+    }
+    this.ref = ref;
+    this.newValue = newRefValue;
+    this.exception = null;
+  }
+
+  /**
+   * Constructs a {@code RefUpdateSnapshot} with the current ref and an Exception indicating why the
+   * ref's new value could not be retrieved.
+   *
+   * @param ref the ref with its old value
+   * @param e exception caught when trying to retrieve the ref's new value
+   */
+  RefUpdateSnapshot(Ref ref, Exception e) {
+    this.ref = ref;
+    this.newValue = ObjectId.zeroId();
+    this.exception = e;
+  }
+
+  /**
+   * Get the ref name
+   *
+   * @return the ref name
+   */
+  public String getName() {
+    return ref.getName();
+  }
+
+  /**
+   * Get the ref's old value
+   *
+   * @return the ref's old value
+   */
+  public ObjectId getOldValue() {
+    return ref.getObjectId();
+  }
+
+  /**
+   * Get the ref's new (candidate) value
+   *
+   * @return the ref's new (candidate) value
+   */
+  public ObjectId getNewValue() {
+    return newValue;
+  }
+
+  /**
+   * Get the snapshotted ref with its old value
+   *
+   * @return the snapshotted ref with its old value
+   */
+  public Ref getRef() {
+    return ref;
+  }
+
+  /**
+   * Get the exception which occurred when retrieving the ref's new value
+   *
+   * @return the exception which occurred when retrieving the ref's new value
+   */
+  public Exception getException() {
+    return exception;
+  }
+
+  /**
+   * Whether retrieving the new (candidate) value failed
+   *
+   * @return {@code true} when retrieving the ref's new (candidate) value failed, {@code false}
+   *     otherwise.
+   */
+  public boolean hasFailed() {
+    return exception != null;
+  }
+}
diff --git a/src/main/java/com/gerritforge/gerrit/globalrefdb/validation/RefUpdateValidator.java b/src/main/java/com/gerritforge/gerrit/globalrefdb/validation/RefUpdateValidator.java
index 8823f3d..31d3af1 100644
--- a/src/main/java/com/gerritforge/gerrit/globalrefdb/validation/RefUpdateValidator.java
+++ b/src/main/java/com/gerritforge/gerrit/globalrefdb/validation/RefUpdateValidator.java
@@ -186,16 +186,16 @@
       OneParameterFunction<ObjectId, Result> rollbackFunction)
       throws IOException {
     try (CloseableSet<AutoCloseable> locks = new CloseableSet<>()) {
-      RefPair refPairForUpdate = newRefPairFrom(refUpdate);
-      compareAndGetLatestLocalRef(refPairForUpdate, locks);
+      RefUpdateSnapshot refUpdateSnapshot = newSnapshot(refUpdate);
+      compareAndGetLatestLocalRef(refUpdateSnapshot, locks);
       RefUpdate.Result result = refUpdateFunction.invoke();
       if (!isSuccessful(result)) {
         return result;
       }
       try {
-        updateSharedDbOrThrowExceptionFor(refPairForUpdate);
+        updateSharedDbOrThrowExceptionFor(refUpdateSnapshot);
       } catch (Exception e) {
-        result = rollbackFunction.invoke(refPairForUpdate.compareRef.getObjectId());
+        result = rollbackFunction.invoke(refUpdateSnapshot.getOldValue());
         if (isSuccessful(result)) {
           result = RefUpdate.Result.LOCK_FAILURE;
         }
@@ -207,26 +207,26 @@
     } catch (OutOfSyncException e) {
       logger.atWarning().withCause(e).log(
           "Local node is out of sync with ref-db: %s", e.getMessage());
-
       return RefUpdate.Result.LOCK_FAILURE;
     }
   }
 
-  protected void updateSharedDbOrThrowExceptionFor(RefPair refPair) throws IOException {
+  protected void updateSharedDbOrThrowExceptionFor(RefUpdateSnapshot refSnapshot)
+      throws IOException {
     // We are not checking refs that should be ignored
     final EnforcePolicy refEnforcementPolicy =
-        refEnforcement.getPolicy(projectName, refPair.getName());
+        refEnforcement.getPolicy(projectName, refSnapshot.getName());
     if (refEnforcementPolicy == EnforcePolicy.IGNORED) return;
 
     boolean succeeded;
     try {
       succeeded =
           sharedRefDb.compareAndPut(
-              Project.nameKey(projectName), refPair.compareRef, refPair.putValue);
+              Project.nameKey(projectName), refSnapshot.getRef(), refSnapshot.getNewValue());
     } catch (GlobalRefDbSystemError e) {
       logger.atWarning().withCause(e).log(
           "Not able to persist the data in global-refdb for project '%s', ref '%s' and value %s, message: %s",
-          projectName, refPair.getName(), refPair.putValue, e.getMessage());
+          projectName, refSnapshot.getName(), refSnapshot.getNewValue(), e.getMessage());
       throw e;
     }
 
@@ -236,17 +236,18 @@
               "Not able to persist the data in SharedRef for project '%s' and ref '%s',"
                   + "the cluster is now in Split Brain since the commit has been "
                   + "persisted locally but not in global-refdb the value %s",
-              projectName, refPair.getName(), refPair.putValue);
+              projectName, refSnapshot.getName(), refSnapshot.getNewValue());
       throw new SharedDbSplitBrainException(errorMessage);
     }
   }
 
-  protected RefPair compareAndGetLatestLocalRef(RefPair refPair, CloseableSet<AutoCloseable> locks)
+  protected RefUpdateSnapshot compareAndGetLatestLocalRef(
+      RefUpdateSnapshot refUpdateSnapshot, CloseableSet<AutoCloseable> locks)
       throws GlobalRefDbLockException, OutOfSyncException, IOException {
-    String refName = refPair.getName();
+    String refName = refUpdateSnapshot.getName();
     EnforcePolicy refEnforcementPolicy = refEnforcement.getPolicy(projectName, refName);
     if (refEnforcementPolicy == EnforcePolicy.IGNORED) {
-      return refPair;
+      return refUpdateSnapshot;
     }
 
     locks.addResourceIfNotExist(
@@ -255,30 +256,33 @@
             lockWrapperFactory.create(
                 projectName, refName, sharedRefDb.lockRef(Project.nameKey(projectName), refName)));
 
-    RefPair latestRefPair = getLatestLocalRef(refPair);
-    if (sharedRefDb.isUpToDate(Project.nameKey(projectName), latestRefPair.compareRef)) {
-      return latestRefPair;
+    RefUpdateSnapshot latestRefUpdateSnapshot = getLatestLocalRef(refUpdateSnapshot);
+    if (sharedRefDb.isUpToDate(Project.nameKey(projectName), latestRefUpdateSnapshot.getRef())) {
+      return latestRefUpdateSnapshot;
     }
 
-    if (isNullRef(latestRefPair.compareRef)
+    if (isNullRef(latestRefUpdateSnapshot.getRef())
         || sharedRefDb.exists(Project.nameKey(projectName), refName)) {
       validationMetrics.incrementSplitBrainPrevention();
 
       softFailBasedOnEnforcement(
-          new OutOfSyncException(projectName, latestRefPair.compareRef), refEnforcementPolicy);
+          new OutOfSyncException(projectName, latestRefUpdateSnapshot.getRef()),
+          refEnforcementPolicy);
     }
 
-    return latestRefPair;
+    return latestRefUpdateSnapshot;
   }
 
   private boolean isNullRef(Ref ref) {
     return ref.getObjectId().equals(ObjectId.zeroId());
   }
 
-  private RefPair getLatestLocalRef(RefPair refPair) throws IOException {
-    Ref latestRef = refDb.exactRef(refPair.getName());
-    return new RefPair(
-        latestRef == null ? nullRef(refPair.getName()) : latestRef, refPair.putValue);
+  private RefUpdateSnapshot getLatestLocalRef(RefUpdateSnapshot refUpdateSnapshot)
+      throws IOException {
+    Ref latestRef = refDb.exactRef(refUpdateSnapshot.getName());
+    return new RefUpdateSnapshot(
+        latestRef == null ? nullRef(refUpdateSnapshot.getName()) : latestRef,
+        refUpdateSnapshot.getNewValue());
   }
 
   private Ref nullRef(String name) {
@@ -306,8 +310,8 @@
     }
   }
 
-  protected RefPair newRefPairFrom(RefUpdate refUpdate) throws IOException {
-    return new RefPair(getCurrentRef(refUpdate.getName()), refUpdate.getNewObjectId());
+  protected RefUpdateSnapshot newSnapshot(RefUpdate refUpdate) throws IOException {
+    return new RefUpdateSnapshot(getCurrentRef(refUpdate.getName()), refUpdate.getNewObjectId());
   }
 
   protected Ref getCurrentRef(String refName) throws IOException {