Merge branch 'stable-2.15'

* stable-2.15:
  CreateReviewNotes: Use Logger's built-in string formatting

Change-Id: Ib1b4ff88c7cb573a6df6f493e755b14b8393bdd8
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 300baa4..4f6866b 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/reviewnotes/CreateReviewNotes.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/reviewnotes/CreateReviewNotes.java
@@ -26,6 +26,7 @@
 import com.google.gerrit.server.GerritPersonIdent;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.account.AccountCache;
+import com.google.gerrit.server.account.AccountState;
 import com.google.gerrit.server.config.AnonymousCowardName;
 import com.google.gerrit.server.config.CanonicalWebUrl;
 import com.google.gerrit.server.git.LockFailureException;
@@ -275,12 +276,18 @@
       } else {
         LabelType type = labelTypes.byLabel(a.getLabelId());
         if (type != null) {
-          fmt.appendApproval(type, a.getValue(), accountCache.get(a.getAccountId()).getAccount());
+          fmt.appendApproval(
+              type,
+              a.getValue(),
+              a.getAccountId(),
+              accountCache.get(a.getAccountId()).map(AccountState::getAccount));
         }
       }
     }
     if (submit != null) {
-      fmt.appendSubmittedBy(accountCache.get(submit.getAccountId()).getAccount());
+      fmt.appendSubmittedBy(
+          submit.getAccountId(),
+          accountCache.get(submit.getAccountId()).map(AccountState::getAccount));
       fmt.appendSubmittedAt(submit.getGranted());
     }
     if (canonicalWebUrl != null) {
diff --git a/src/main/java/com/googlesource/gerrit/plugins/reviewnotes/HeaderFormatter.java b/src/main/java/com/googlesource/gerrit/plugins/reviewnotes/HeaderFormatter.java
index 8633d5c..2572309 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/reviewnotes/HeaderFormatter.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/reviewnotes/HeaderFormatter.java
@@ -14,6 +14,9 @@
 
 package com.googlesource.gerrit.plugins.reviewnotes;
 
+import static com.google.common.base.Preconditions.checkState;
+
+import com.google.common.base.Strings;
 import com.google.gerrit.common.data.LabelType;
 import com.google.gerrit.common.data.LabelValue;
 import com.google.gerrit.reviewdb.client.Account;
@@ -23,6 +26,7 @@
 import java.util.Calendar;
 import java.util.Date;
 import java.util.Locale;
+import java.util.Optional;
 import java.util.TimeZone;
 
 /**
@@ -44,38 +48,57 @@
     this.anonymousCowardName = anonymousCowardName;
   }
 
-  void appendChangeId(Change.Key changeKey) {
-    sb.append("Change-Id: ").append(changeKey.get()).append("\n");
-  }
-
-  void appendApproval(LabelType label, short value, Account user) {
+  /**
+   * Appends a header for an approval.
+   *
+   * @param label the label on which the approval was done
+   * @param value the voting value
+   * @param accountId the account ID of the approver
+   * @param account the account of the approver, can be {@link Optional#empty} if the account is
+   *     missing
+   */
+  void appendApproval(
+      LabelType label, short value, Account.Id accountId, Optional<Account> account) {
     sb.append(label.getName());
     sb.append(LabelValue.formatValue(value));
     sb.append(": ");
-    appendUserData(user);
+    appendUserData(accountId, account);
     sb.append("\n");
   }
 
-  private void appendUserData(Account user) {
+  /**
+   * Appends user data.
+   *
+   * @param accountId the ID of the account
+   * @param account the account, can be {link Optional#empty} if the account is missing
+   */
+  private void appendUserData(Account.Id accountId, Optional<Account> account) {
+    checkState(
+        !account.isPresent() || accountId.equals(account.get().getId()), "mismatching account IDs");
+
     boolean needSpace = false;
     boolean wroteData = false;
 
-    if (user.getFullName() != null && !user.getFullName().isEmpty()) {
-      sb.append(user.getFullName());
-      needSpace = true;
-      wroteData = true;
-    }
-
-    if (user.getPreferredEmail() != null && !user.getPreferredEmail().isEmpty()) {
-      if (needSpace) {
-        sb.append(" ");
+    if (account.isPresent()) {
+      String fullName = account.get().getFullName();
+      if (!Strings.isNullOrEmpty(fullName)) {
+        sb.append(fullName);
+        needSpace = true;
+        wroteData = true;
       }
-      sb.append("<").append(user.getPreferredEmail()).append(">");
-      wroteData = true;
+
+      String preferredEmail = account.get().getPreferredEmail();
+      if (!Strings.isNullOrEmpty(preferredEmail)) {
+        if (needSpace) {
+          sb.append(" ");
+        }
+        sb.append("<").append(preferredEmail).append(">");
+        wroteData = true;
+      }
     }
 
     if (!wroteData) {
-      sb.append(anonymousCowardName).append(" #").append(user.getId());
+      sb.append(anonymousCowardName).append(" #").append(accountId);
     }
   }
 
@@ -87,9 +110,16 @@
     sb.append("Branch: ").append(branch).append("\n");
   }
 
-  void appendSubmittedBy(Account user) {
+  /**
+   * Appends a header with the submitter information.
+   *
+   * @param accountId the account ID of the submitter
+   * @param account the account of the submitter, can be {@link Optional#empty()} if the account is
+   *     missing
+   */
+  void appendSubmittedBy(Account.Id accountId, Optional<Account> account) {
     sb.append("Submitted-by: ");
-    appendUserData(user);
+    appendUserData(accountId, account);
     sb.append("\n");
   }