AccountCacheImpl#ByNameLoader: Use account index to lookup usernames

If available, use the account index to find accounts by username. This
is a preparation for moving the external ids from ReviewDb into git.

Change-Id: I8fe3adc0a65e90e3e7a21641cfca7352c46a458f
Signed-off-by: Edwin Kempin <ekempin@google.com>
diff --git a/gerrit-gpg/src/main/java/com/google/gerrit/gpg/server/PostGpgKeys.java b/gerrit-gpg/src/main/java/com/google/gerrit/gpg/server/PostGpgKeys.java
index cd172a7..2deae3f 100644
--- a/gerrit-gpg/src/main/java/com/google/gerrit/gpg/server/PostGpgKeys.java
+++ b/gerrit-gpg/src/main/java/com/google/gerrit/gpg/server/PostGpgKeys.java
@@ -294,12 +294,7 @@
       msg.append("GPG key ").append(externalId)
           .append(" associated with multiple accounts: ");
       Joiner.on(", ").appendTo(msg,
-          Lists.transform(accountStates, new Function<AccountState, String>() {
-            @Override
-            public String apply(AccountState accountState) {
-              return accountState.getAccount().getId().toString();
-            }
-          }));
+          Lists.transform(accountStates, AccountState.ACCOUNT_ID_FUNCTION));
       log.error(msg.toString());
       throw new IllegalStateException(msg.toString());
     }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountCacheImpl.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountCacheImpl.java
index af0ee4c..02e8698 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountCacheImpl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountCacheImpl.java
@@ -14,10 +14,12 @@
 
 package com.google.gerrit.server.account;
 
+import com.google.common.base.Joiner;
 import com.google.common.base.Optional;
 import com.google.common.cache.CacheLoader;
 import com.google.common.cache.LoadingCache;
 import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Lists;
 import com.google.gerrit.common.TimeUtil;
 import com.google.gerrit.extensions.client.GeneralPreferencesInfo;
 import com.google.gerrit.reviewdb.client.Account;
@@ -27,7 +29,9 @@
 import com.google.gerrit.reviewdb.client.AccountProjectWatch;
 import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.cache.CacheModule;
+import com.google.gerrit.server.index.account.AccountIndexCollection;
 import com.google.gerrit.server.index.account.AccountIndexer;
+import com.google.gerrit.server.query.account.InternalAccountQuery;
 import com.google.gwtorm.server.OrmException;
 import com.google.gwtorm.server.SchemaFactory;
 import com.google.inject.Inject;
@@ -45,6 +49,7 @@
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Set;
 import java.util.concurrent.ExecutionException;
 
@@ -209,19 +214,42 @@
 
   static class ByNameLoader extends CacheLoader<String, Optional<Account.Id>> {
     private final SchemaFactory<ReviewDb> schema;
+    private final AccountIndexCollection accountIndexes;
+    private final Provider<InternalAccountQuery> accountQueryProvider;
 
     @Inject
-    ByNameLoader(final SchemaFactory<ReviewDb> sf) {
+    ByNameLoader(SchemaFactory<ReviewDb> sf,
+        AccountIndexCollection accountIndexes,
+        Provider<InternalAccountQuery> accountQueryProvider) {
       this.schema = sf;
+      this.accountIndexes = accountIndexes;
+      this.accountQueryProvider = accountQueryProvider;
     }
 
     @Override
     public Optional<Account.Id> load(String username) throws Exception {
-      try (ReviewDb db = schema.open()) {
-        final AccountExternalId.Key key = new AccountExternalId.Key( //
+        AccountExternalId.Key key = new AccountExternalId.Key( //
             AccountExternalId.SCHEME_USERNAME, //
             username);
-        final AccountExternalId id = db.accountExternalIds().get(key);
+      if (accountIndexes.getSearchIndex() != null) {
+        List<AccountState> accountStates =
+            accountQueryProvider.get().byExternalId(key.get());
+        if (accountStates.size() == 1) {
+          return Optional.of(accountStates.get(0).getAccount().getId());
+        } else if (accountStates.size() > 0) {
+          StringBuilder msg = new StringBuilder();
+          msg.append("Ambiguous username ")
+              .append(username)
+              .append("for accounts: ");
+          Joiner.on(", ").appendTo(msg, Lists.transform(accountStates,
+              AccountState.ACCOUNT_ID_FUNCTION));
+          log.warn(msg.toString());
+        }
+        return Optional.absent();
+      }
+
+      try (ReviewDb db = schema.open()) {
+        AccountExternalId id = db.accountExternalIds().get(key);
         if (id != null) {
           return Optional.of(id.getAccountId());
         }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountState.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountState.java
index 145f34b..a9eab0a 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountState.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/AccountState.java
@@ -17,6 +17,7 @@
 import static com.google.gerrit.reviewdb.client.AccountExternalId.SCHEME_MAILTO;
 import static com.google.gerrit.reviewdb.client.AccountExternalId.SCHEME_USERNAME;
 
+import com.google.common.base.Function;
 import com.google.common.cache.Cache;
 import com.google.common.cache.CacheBuilder;
 import com.google.gerrit.common.Nullable;
@@ -32,6 +33,14 @@
 import java.util.Set;
 
 public class AccountState {
+  public static Function<AccountState, Account.Id> ACCOUNT_ID_FUNCTION =
+      new Function<AccountState, Account.Id>() {
+        @Override
+        public Account.Id apply(AccountState in) {
+          return in.getAccount().getId();
+        }
+      };
+
   private final Account account;
   private final Set<AccountGroup.UUID> internalGroups;
   private final Collection<AccountExternalId> externalIds;