Merge branch stable-2.14

* stable-2.14:
  Adapt to the JGit v4.5.x

Change-Id: I7d88bebded4f0155262f268f918ce49639ee306f
diff --git a/src/main/java/com/googlesource/gerrit/plugins/reviewnotes/CreateReviewNotes.java b/src/main/java/com/googlesource/gerrit/plugins/reviewnotes/CreateReviewNotes.java
index 504bfba..300baa4 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/reviewnotes/CreateReviewNotes.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/reviewnotes/CreateReviewNotes.java
@@ -28,9 +28,9 @@
 import com.google.gerrit.server.account.AccountCache;
 import com.google.gerrit.server.config.AnonymousCowardName;
 import com.google.gerrit.server.config.CanonicalWebUrl;
+import com.google.gerrit.server.git.LockFailureException;
 import com.google.gerrit.server.git.NotesBranchUtil;
 import com.google.gerrit.server.notedb.ChangeNotes;
-import com.google.gerrit.server.project.ChangeControl;
 import com.google.gerrit.server.project.NoSuchChangeException;
 import com.google.gerrit.server.project.ProjectCache;
 import com.google.gerrit.server.project.ProjectState;
@@ -43,7 +43,6 @@
 import java.io.IOException;
 import java.util.Collections;
 import java.util.List;
-import org.eclipse.jgit.api.errors.ConcurrentRefUpdateException;
 import org.eclipse.jgit.errors.IncorrectObjectTypeException;
 import org.eclipse.jgit.errors.MissingObjectException;
 import org.eclipse.jgit.lib.Constants;
@@ -75,7 +74,6 @@
   private final String anonymousCowardName;
   private final LabelTypes labelTypes;
   private final ApprovalsUtil approvalsUtil;
-  private final ChangeControl.GenericFactory changeControlFactory;
   private final ChangeNotes.Factory notesFactory;
   private final IdentifiedUser.GenericFactory userFactory;
   private final NotesBranchUtil.Factory notesBranchUtilFactory;
@@ -96,7 +94,6 @@
       @AnonymousCowardName String anonymousCowardName,
       ProjectCache projectCache,
       ApprovalsUtil approvalsUtil,
-      ChangeControl.GenericFactory changeControlFactory,
       ChangeNotes.Factory notesFactory,
       IdentifiedUser.GenericFactory userFactory,
       NotesBranchUtil.Factory notesBranchUtilFactory,
@@ -119,7 +116,6 @@
       this.labelTypes = projectState.getLabelTypes();
     }
     this.approvalsUtil = approvalsUtil;
-    this.changeControlFactory = changeControlFactory;
     this.notesFactory = notesFactory;
     this.userFactory = userFactory;
     this.notesBranchUtilFactory = notesBranchUtilFactory;
@@ -194,7 +190,7 @@
     }
   }
 
-  void commitNotes() throws IOException, ConcurrentRefUpdateException {
+  void commitNotes() throws LockFailureException, IOException {
     try {
       if (reviewNotes == null) {
         return;
@@ -212,7 +208,7 @@
   }
 
   private void markUninteresting(Repository git, String branch, RevWalk rw, ObjectId oldObjectId) {
-    for (final Ref r : git.getAllRefs().values()) {
+    for (Ref r : git.getAllRefs().values()) {
       try {
         if (r.getName().equals(branch)) {
           if (!ObjectId.zeroId().equals(oldObjectId)) {
@@ -268,10 +264,10 @@
     // TODO(dborowitz): These will eventually be stamped in the ChangeNotes at
     // commit time so we will be able to skip this normalization step.
     Change change = notes.getChange();
-    ChangeControl ctl =
-        changeControlFactory.controlFor(notes, userFactory.create(change.getOwner()));
     PatchSetApproval submit = null;
-    for (PatchSetApproval a : approvalsUtil.byPatchSet(reviewDb, ctl, ps.getId())) {
+    for (PatchSetApproval a :
+        approvalsUtil.byPatchSet(
+            reviewDb, notes, userFactory.create(change.getOwner()), ps.getId(), null, null)) {
       if (a.getValue() == 0) {
         // Ignore 0 values.
       } else if (a.isLegacySubmit()) {
diff --git a/src/main/java/com/googlesource/gerrit/plugins/reviewnotes/ExportReviewNotes.java b/src/main/java/com/googlesource/gerrit/plugins/reviewnotes/ExportReviewNotes.java
index 520ae0a..4144381 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/reviewnotes/ExportReviewNotes.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/reviewnotes/ExportReviewNotes.java
@@ -14,15 +14,20 @@
 
 package com.googlesource.gerrit.plugins.reviewnotes;
 
+import com.github.rholder.retry.Attempt;
+import com.github.rholder.retry.RetryListener;
 import com.google.common.collect.ImmutableListMultimap;
 import com.google.common.collect.ListMultimap;
 import com.google.common.collect.Maps;
 import com.google.common.collect.MultimapBuilder;
+import com.google.gerrit.extensions.restapi.RestApiException;
 import com.google.gerrit.reviewdb.client.Change;
 import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.gerrit.server.notedb.ChangeNotes;
+import com.google.gerrit.server.update.RetryHelper;
+import com.google.gerrit.server.update.UpdateException;
 import com.google.gerrit.sshd.SshCommand;
 import com.google.gwtorm.server.OrmException;
 import com.google.gwtorm.server.SchemaFactory;
@@ -30,7 +35,6 @@
 import java.io.IOException;
 import java.util.List;
 import java.util.Map;
-import org.eclipse.jgit.api.errors.ConcurrentRefUpdateException;
 import org.eclipse.jgit.errors.RepositoryNotFoundException;
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.lib.TextProgressMonitor;
@@ -50,6 +54,8 @@
 
   @Inject private ChangeNotes.Factory notesFactory;
 
+  @Inject private RetryHelper retryHelper;
+
   private ListMultimap<Project.NameKey, ChangeNotes> changes;
   private ThreadSafeProgressMonitor monitor;
 
@@ -85,16 +91,27 @@
   }
 
   private void export(ReviewDb db, Project.NameKey project, List<ChangeNotes> notes)
-      throws IOException, OrmException {
-    try (Repository git = gitManager.openRepository(project)) {
-      CreateReviewNotes crn = reviewNotesFactory.create(db, project, git);
-      crn.createNotes(notes, monitor);
-      crn.commitNotes();
-    } catch (RepositoryNotFoundException e) {
-      stderr.println("Unable to open project: " + project.get());
-    } catch (ConcurrentRefUpdateException e) {
-      stderr.println(e.getMessage());
-    }
+      throws RestApiException, UpdateException {
+    retryHelper.execute(
+        updateFactory -> {
+          try (Repository git = gitManager.openRepository(project)) {
+            CreateReviewNotes crn = reviewNotesFactory.create(db, project, git);
+            crn.createNotes(notes, monitor);
+            crn.commitNotes();
+          } catch (RepositoryNotFoundException e) {
+            stderr.println("Unable to open project: " + project.get());
+          }
+          return null;
+        },
+        RetryHelper.options()
+            .listener(
+                new RetryListener() {
+                  @Override
+                  public <V> void onRetry(Attempt<V> attempt) {
+                    monitor.update(-notes.size());
+                  }
+                })
+            .build());
   }
 
   private Map.Entry<Project.NameKey, List<ChangeNotes>> next() {
@@ -117,7 +134,7 @@
           if (next != null) {
             try {
               export(db, next.getKey(), next.getValue());
-            } catch (OrmException | IOException e) {
+            } catch (RestApiException | UpdateException e) {
               stderr.println(e.getMessage());
             }
           } else {
diff --git a/src/main/java/com/googlesource/gerrit/plugins/reviewnotes/RefUpdateListener.java b/src/main/java/com/googlesource/gerrit/plugins/reviewnotes/RefUpdateListener.java
index 46331ca..17b7f81 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/reviewnotes/RefUpdateListener.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/reviewnotes/RefUpdateListener.java
@@ -15,18 +15,19 @@
 package com.googlesource.gerrit.plugins.reviewnotes;
 
 import com.google.gerrit.extensions.events.GitReferenceUpdatedListener;
+import com.google.gerrit.extensions.restapi.RestApiException;
 import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.client.RefNames;
 import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.config.GerritServerConfig;
 import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.gerrit.server.git.ProjectRunnable;
 import com.google.gerrit.server.git.WorkQueue;
-import com.google.gwtorm.server.OrmException;
+import com.google.gerrit.server.update.RetryHelper;
+import com.google.gerrit.server.update.UpdateException;
 import com.google.gwtorm.server.SchemaFactory;
 import com.google.inject.Inject;
-import java.io.IOException;
 import java.util.concurrent.Future;
-import org.eclipse.jgit.api.errors.ConcurrentRefUpdateException;
 import org.eclipse.jgit.lib.Config;
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.Repository;
@@ -41,24 +42,27 @@
   private final SchemaFactory<ReviewDb> schema;
   private final GitRepositoryManager repoManager;
   private final WorkQueue workQueue;
+  private final RetryHelper retryHelper;
   private final boolean async;
 
   @Inject
   RefUpdateListener(
-      final CreateReviewNotes.Factory reviewNotesFactory,
-      final SchemaFactory<ReviewDb> schema,
-      final GitRepositoryManager repoManager,
-      final WorkQueue workQueue,
-      @GerritServerConfig final Config config) {
+      CreateReviewNotes.Factory reviewNotesFactory,
+      SchemaFactory<ReviewDb> schema,
+      GitRepositoryManager repoManager,
+      WorkQueue workQueue,
+      RetryHelper retryHelper,
+      @GerritServerConfig Config config) {
     this.reviewNotesFactory = reviewNotesFactory;
     this.schema = schema;
     this.repoManager = repoManager;
     this.workQueue = workQueue;
+    this.retryHelper = retryHelper;
     this.async = config.getBoolean("reviewnotes", null, "async", false);
   }
 
   @Override
-  public void onGitReferenceUpdated(final Event e) {
+  public void onGitReferenceUpdated(Event e) {
     Runnable task =
         new ProjectRunnable() {
           @Override
@@ -95,19 +99,26 @@
   }
 
   private void createReviewNotes(Event e) {
-    Project.NameKey projectName = new Project.NameKey(e.getProjectName());
-    try (Repository git = repoManager.openRepository(projectName);
-        ReviewDb reviewDb = schema.open()) {
-      CreateReviewNotes crn = reviewNotesFactory.create(reviewDb, projectName, git);
-      if (e.getRefName().startsWith("refs/heads/")) {
-        crn.createNotes(
-            e.getRefName(),
-            ObjectId.fromString(e.getOldObjectId()),
-            ObjectId.fromString(e.getNewObjectId()),
-            null);
-        crn.commitNotes();
-      }
-    } catch (OrmException | IOException | ConcurrentRefUpdateException x) {
+    if (!e.getRefName().startsWith(RefNames.REFS_HEADS)) {
+      return;
+    }
+    try {
+      retryHelper.execute(
+          updateFactory -> {
+            Project.NameKey projectName = new Project.NameKey(e.getProjectName());
+            try (Repository git = repoManager.openRepository(projectName);
+                ReviewDb reviewDb = schema.open()) {
+              CreateReviewNotes crn = reviewNotesFactory.create(reviewDb, projectName, git);
+              crn.createNotes(
+                  e.getRefName(),
+                  ObjectId.fromString(e.getOldObjectId()),
+                  ObjectId.fromString(e.getNewObjectId()),
+                  null);
+              crn.commitNotes();
+            }
+            return null;
+          });
+    } catch (RestApiException | UpdateException x) {
       log.error(x.getMessage(), x);
     }
   }