AccountsUpdate: replace Consumer<AccountDelta.Builder> with dedicated interface

As part of b/333350069, I'm about to add a 3rd `ConfigureDeltaFrom...`
option. This change makes the interface more consistent, and allows
case-specific documentation.

Callers that use the lambda call (`u -> u.update,,,`) are unaffected.

Release-Notes: skip
Google-Bug-Id: b/333350069
Change-Id: I86e1b30f65ad230dff8b4c8bb5b459b24003cbc4
diff --git a/java/com/google/gerrit/acceptance/testsuite/account/AccountOperationsImpl.java b/java/com/google/gerrit/acceptance/testsuite/account/AccountOperationsImpl.java
index 5b5895f..b2abac1 100644
--- a/java/com/google/gerrit/acceptance/testsuite/account/AccountOperationsImpl.java
+++ b/java/com/google/gerrit/acceptance/testsuite/account/AccountOperationsImpl.java
@@ -28,12 +28,12 @@
 import com.google.gerrit.server.account.Accounts;
 import com.google.gerrit.server.account.AccountsUpdate;
 import com.google.gerrit.server.account.AccountsUpdate.ConfigureDeltaFromState;
+import com.google.gerrit.server.account.AccountsUpdate.ConfigureStatelessDelta;
 import com.google.gerrit.server.account.externalids.ExternalId;
 import com.google.gerrit.server.account.externalids.ExternalIdFactory;
 import com.google.inject.Inject;
 import java.io.IOException;
 import java.util.Optional;
-import java.util.function.Consumer;
 import org.eclipse.jgit.errors.ConfigInvalidException;
 
 /**
@@ -73,7 +73,7 @@
 
   protected Account.Id createAccount(TestAccountCreation testAccountCreation) throws Exception {
     Account.Id accountId = Account.id(seq.nextAccountId());
-    Consumer<AccountDelta.Builder> accountCreation =
+    ConfigureStatelessDelta accountCreation =
         deltaBuilder -> initAccountDelta(deltaBuilder, testAccountCreation, accountId);
     AccountState createdAccount =
         accountsUpdate.insert("Create Test Account", accountId, accountCreation);
diff --git a/java/com/google/gerrit/server/account/AccountManager.java b/java/com/google/gerrit/server/account/AccountManager.java
index 61012d7..51948f9 100644
--- a/java/com/google/gerrit/server/account/AccountManager.java
+++ b/java/com/google/gerrit/server/account/AccountManager.java
@@ -38,6 +38,7 @@
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.Sequences;
 import com.google.gerrit.server.ServerInitiated;
+import com.google.gerrit.server.account.AccountsUpdate.ConfigureStatelessDelta;
 import com.google.gerrit.server.account.externalids.DuplicateExternalIdKeyException;
 import com.google.gerrit.server.account.externalids.ExternalId;
 import com.google.gerrit.server.account.externalids.ExternalIdFactory;
@@ -60,7 +61,6 @@
 import java.util.Objects;
 import java.util.Optional;
 import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.function.Consumer;
 import org.eclipse.jgit.errors.ConfigInvalidException;
 import org.eclipse.jgit.lib.Config;
 
@@ -269,7 +269,7 @@
   private void update(AuthRequest who, ExternalId extId)
       throws IOException, ConfigInvalidException, AccountException {
     IdentifiedUser user = userFactory.create(extId.accountId());
-    List<Consumer<AccountDelta.Builder>> accountUpdates = new ArrayList<>();
+    List<ConfigureStatelessDelta> accountUpdates = new ArrayList<>();
 
     // If the email address was modified by the authentication provider,
     // update our records to match the changed email.
@@ -311,7 +311,7 @@
               .update(
                   "Update Account on Login",
                   user.getAccountId(),
-                  AccountsUpdate.joinConsumers(accountUpdates));
+                  AccountsUpdate.joinDeltaConfigures(accountUpdates));
       if (!updatedAccount.isPresent()) {
         throw new StorageException("Account " + user.getAccountId() + " has been deleted");
       }
diff --git a/java/com/google/gerrit/server/account/AccountsUpdate.java b/java/com/google/gerrit/server/account/AccountsUpdate.java
index 45ff128..c84c204 100644
--- a/java/com/google/gerrit/server/account/AccountsUpdate.java
+++ b/java/com/google/gerrit/server/account/AccountsUpdate.java
@@ -35,7 +35,6 @@
 import java.lang.annotation.Target;
 import java.util.List;
 import java.util.Optional;
-import java.util.function.Consumer;
 import org.eclipse.jgit.errors.ConfigInvalidException;
 import org.eclipse.jgit.lib.PersonIdent;
 
@@ -51,6 +50,7 @@
  * <p>See the implementing classes for more information.
  */
 public abstract class AccountsUpdate {
+  /** Loader for {@link AccountsUpdate}s. */
   public interface AccountsUpdateLoader {
     /**
      * Creates an {@code AccountsUpdate} which uses the identity of the specified user as author for
@@ -89,15 +89,18 @@
   public static class UpdateArguments {
     public final String message;
     public final Account.Id accountId;
-    public final AccountsUpdate.ConfigureDeltaFromState configureDeltaFromState;
+    public final ConfigureDeltaFromState configureDelta;
 
     public UpdateArguments(
-        String message,
-        Account.Id accountId,
-        AccountsUpdate.ConfigureDeltaFromState configureDeltaFromState) {
+        String message, Account.Id accountId, ConfigureStatelessDelta configureDelta) {
+      this(message, accountId, (a, u) -> configureDelta.configure(u));
+    }
+
+    public UpdateArguments(
+        String message, Account.Id accountId, ConfigureDeltaFromState configureDelta) {
       this.message = message;
       this.accountId = accountId;
-      this.configureDeltaFromState = configureDeltaFromState;
+      this.configureDelta = configureDelta;
     }
 
     @Override
@@ -110,11 +113,31 @@
   }
 
   /**
-   * Account updates are commonly performed by evaluating the current account state and creating a
-   * delta to be applied to it in a later step. This is done by implementing this interface.
+   * The most basic interface for updating the account delta, providing no state.
    *
-   * <p>If the current account state is not needed, use a {@link Consumer} of {@link
-   * com.google.gerrit.server.account.AccountDelta.Builder} instead.
+   * <p>Account updates that do not need to know the current account state should use this
+   * interface.
+   *
+   * <p>If the current {@link AccountState} is needed, use {@link ConfigureDeltaFromState} instead.
+   */
+  @FunctionalInterface
+  public interface ConfigureStatelessDelta {
+    /**
+     * Configures an {@link com.google.gerrit.server.account.AccountDelta.Builder} with changes to
+     * the account.
+     *
+     * @param delta the changes to be applied
+     */
+    void configure(AccountDelta.Builder delta);
+  }
+
+  /**
+   * Interface for updating the account delta, providing the current state.
+   *
+   * <p>Account updates are commonly performed by evaluating the current account state and creating
+   * a delta to be applied to it in a later step. This is done by implementing this interface.
+   *
+   * <p>If the current account state is not needed, use {@link ConfigureStatelessDelta} instead.
    */
   @FunctionalInterface
   public interface ConfigureDeltaFromState {
@@ -129,13 +152,9 @@
   }
 
   /** Returns an instance that runs all specified consumers. */
-  public static ConfigureDeltaFromState joinConsumers(
-      List<Consumer<AccountDelta.Builder>> consumers) {
-    return (accountStateIgnored, update) -> consumers.forEach(c -> c.accept(update));
-  }
-
-  static ConfigureDeltaFromState fromConsumer(Consumer<AccountDelta.Builder> consumer) {
-    return (a, u) -> consumer.accept(u);
+  public static ConfigureStatelessDelta joinDeltaConfigures(
+      List<ConfigureStatelessDelta> deltaConfigures) {
+    return (update) -> deltaConfigures.forEach(c -> c.configure(update));
   }
 
   protected final PersonIdent committerIdent;
@@ -150,20 +169,11 @@
   }
 
   /**
-   * Like {@link #insert(String, Account.Id, ConfigureDeltaFromState)}, but using a {@link Consumer}
-   * instead, i.e. the update does not depend on the current account state (which, for insertion,
-   * would only contain the account ID).
-   */
-  @CanIgnoreReturnValue
-  public final AccountState insert(
-      String message, Account.Id accountId, Consumer<AccountDelta.Builder> init)
-      throws IOException, ConfigInvalidException {
-    return insert(message, accountId, AccountsUpdate.fromConsumer(init));
-  }
-
-  /**
    * Inserts a new account.
    *
+   * <p>If the current account state is not needed, use {@link #insert(String, Account.Id,
+   * ConfigureStatelessDelta)} instead.
+   *
    * @param message commit message for the account creation, must not be {@code null or empty}
    * @param accountId ID of the new account
    * @param init to populate the new account
@@ -172,19 +182,20 @@
    * @throws IOException if creating the user branch fails due to an IO error
    * @throws ConfigInvalidException if any of the account fields has an invalid value
    */
+  @CanIgnoreReturnValue
   public abstract AccountState insert(
       String message, Account.Id accountId, ConfigureDeltaFromState init)
       throws IOException, ConfigInvalidException;
 
   /**
-   * Like {@link #update(String, Account.Id, ConfigureDeltaFromState)}, but using a {@link Consumer}
-   * instead, i.e. the update does not depend on the current account state.
+   * Like {@link #insert(String, Account.Id, ConfigureDeltaFromState)}, but using {@link
+   * ConfigureStatelessDelta} instead. I.e. the update does not depend on the current account state.
    */
   @CanIgnoreReturnValue
-  public final Optional<AccountState> update(
-      String message, Account.Id accountId, Consumer<AccountDelta.Builder> update)
+  public final AccountState insert(
+      String message, Account.Id accountId, ConfigureStatelessDelta init)
       throws IOException, ConfigInvalidException {
-    return update(message, accountId, AccountsUpdate.fromConsumer(update));
+    return insert(message, accountId, (a, u) -> init.configure(u));
   }
 
   /**
@@ -192,10 +203,12 @@
    *
    * <p>Changing the registration date of an account is not supported.
    *
+   * <p>If the current account state is not needed, use {@link #update(String, Account.Id,
+   * ConfigureStatelessDelta)} instead.
+   *
    * @param message commit message for the account update, must not be {@code null or empty}
    * @param accountId ID of the account
-   * @param configureDeltaFromState deltaBuilder to update the account, only invoked if the account
-   *     exists
+   * @param configureDelta deltaBuilder to update the account, only invoked if the account exists
    * @return the updated account, {@link Optional#empty} if the account doesn't exist
    * @throws IOException if updating the user branch fails due to an IO error
    * @throws LockFailureException if updating the user branch still fails due to concurrent updates
@@ -204,14 +217,25 @@
    */
   @CanIgnoreReturnValue
   public final Optional<AccountState> update(
-      String message, Account.Id accountId, ConfigureDeltaFromState configureDeltaFromState)
+      String message, Account.Id accountId, ConfigureDeltaFromState configureDelta)
       throws IOException, ConfigInvalidException {
-    return updateBatch(
-            ImmutableList.of(new UpdateArguments(message, accountId, configureDeltaFromState)))
+    return updateBatch(ImmutableList.of(new UpdateArguments(message, accountId, configureDelta)))
         .get(0);
   }
 
   /**
+   * Like {@link #update(String, Account.Id, ConfigureDeltaFromState)} , but using {@link
+   * ConfigureStatelessDelta} instead. I.e. the update does not depend on the current account state,
+   * nor requires any extra storage reads/writes.
+   */
+  @CanIgnoreReturnValue
+  public final Optional<AccountState> update(
+      String message, Account.Id accountId, ConfigureStatelessDelta configureDelta)
+      throws IOException, ConfigInvalidException {
+    return update(message, accountId, (a, u) -> configureDelta.configure(u));
+  }
+
+  /**
    * Updates multiple different accounts atomically. This will only store a single new value (aka
    * set of all external IDs of the host) in the external ID cache, which is important for storage
    * economy. All {@code updates} must be for different accounts.
diff --git a/java/com/google/gerrit/server/account/storage/notedb/AccountsUpdateNoteDbImpl.java b/java/com/google/gerrit/server/account/storage/notedb/AccountsUpdateNoteDbImpl.java
index 27a43ba..08b2fa5 100644
--- a/java/com/google/gerrit/server/account/storage/notedb/AccountsUpdateNoteDbImpl.java
+++ b/java/com/google/gerrit/server/account/storage/notedb/AccountsUpdateNoteDbImpl.java
@@ -61,7 +61,6 @@
 import java.util.Objects;
 import java.util.Optional;
 import java.util.Set;
-import java.util.function.Consumer;
 import javax.inject.Inject;
 import javax.inject.Singleton;
 import org.eclipse.jgit.errors.ConfigInvalidException;
@@ -83,8 +82,8 @@
  * com.google.gerrit.server.account.AccountsUpdate.ConfigureDeltaFromState}. The account updater
  * reads the current {@link AccountState} and prepares updates to the account by calling setters on
  * the provided {@link com.google.gerrit.server.account.AccountDelta.Builder}. If the current
- * account state is of no interest the caller may also provide a {@link Consumer} for {@link
- * com.google.gerrit.server.account.AccountDelta.Builder} instead of the account updater.
+ * account state is of no interest the caller may also provide a {@link ConfigureStatelessDelta}
+ * instead of the account updater.
  *
  * <p>The provided commit message is used for the update of the user branch. Using a precise and
  * unique commit message allows to identify the code from which an update was made when looking at a
@@ -315,8 +314,7 @@
   public void delete(String message, Account.Id accountId)
       throws IOException, ConfigInvalidException {
     ImmutableSet<ExternalId> accountExternalIds = externalIds.byAccount(accountId);
-    Consumer<AccountDelta.Builder> delta =
-        deltaBuilder -> deltaBuilder.deleteAccount(accountExternalIds);
+    ConfigureStatelessDelta delta = deltaBuilder -> deltaBuilder.deleteAccount(accountExternalIds);
     update(message, accountId, delta);
   }
 
@@ -332,7 +330,7 @@
       }
 
       AccountDelta.Builder deltaBuilder = AccountDelta.builder();
-      updateArguments.configureDeltaFromState.configure(accountState.get(), deltaBuilder);
+      updateArguments.configureDelta.configure(accountState.get(), deltaBuilder);
 
       AccountDelta delta = deltaBuilder.build();
       updateExternalIdNotes(