Merge "ChangeJson: add Javadoc"
diff --git a/Documentation/dev-bazel.txt b/Documentation/dev-bazel.txt
index 3e52f16..34e1fd8 100644
--- a/Documentation/dev-bazel.txt
+++ b/Documentation/dev-bazel.txt
@@ -390,6 +390,7 @@
 build --experimental_local_disk_cache_path=/home/<user>/.gerritcodereview/bazel-cache/cas
 build --experimental_local_disk_cache
 build --experimental_strict_action_env
+build --action_env=PATH
 ----
 
 [NOTE] `experimental_local_disk_cache_path` must be absolute path. Expansion of `~` is
diff --git a/WORKSPACE b/WORKSPACE
index 88d7f60..2041bc7 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -566,10 +566,10 @@
 
 maven_jar(
     name = "blame_cache",
-    artifact = "com/google/gitiles:blame-cache:0.2-5",
+    artifact = "com/google/gitiles:blame-cache:0.2-6",
     attach_source = False,
     repository = GERRIT,
-    sha1 = "50861b114350c598579ba66f99285e692e3c8d45",
+    sha1 = "64827f1bc2cbdbb6515f1d29ce115db94c03bb6a",
 )
 
 # Keep this version of Soy synchronized with the version used in Gitiles.
diff --git a/java/com/google/gerrit/httpd/init/WebAppInitializer.java b/java/com/google/gerrit/httpd/init/WebAppInitializer.java
index 759f240..04d08e5 100644
--- a/java/com/google/gerrit/httpd/init/WebAppInitializer.java
+++ b/java/com/google/gerrit/httpd/init/WebAppInitializer.java
@@ -57,13 +57,13 @@
 import com.google.gerrit.server.config.GerritServerConfig;
 import com.google.gerrit.server.config.GerritServerConfigModule;
 import com.google.gerrit.server.config.SitePath;
+import com.google.gerrit.server.config.SysExecutorModule;
 import com.google.gerrit.server.events.EventBroker;
 import com.google.gerrit.server.events.StreamEventsApiListener;
 import com.google.gerrit.server.git.GarbageCollectionModule;
 import com.google.gerrit.server.git.GitRepositoryManagerModule;
 import com.google.gerrit.server.git.SearchingChangeCacheImpl;
 import com.google.gerrit.server.git.WorkQueue;
-import com.google.gerrit.server.git.receive.ReceiveCommitsExecutorModule;
 import com.google.gerrit.server.index.IndexModule;
 import com.google.gerrit.server.index.IndexModule.IndexType;
 import com.google.gerrit.server.mail.SignedTokenEmailTokenVerifier;
@@ -328,7 +328,7 @@
     modules.add(new JdbcAccountPatchReviewStore.Module(config));
     modules.add(cfgInjector.getInstance(GitRepositoryManagerModule.class));
     modules.add(new StreamEventsApiListener.Module());
-    modules.add(new ReceiveCommitsExecutorModule());
+    modules.add(new SysExecutorModule());
     modules.add(new DiffExecutorModule());
     modules.add(new MimeUtil2Module());
     modules.add(cfgInjector.getInstance(GerritGlobalModule.class));
diff --git a/java/com/google/gerrit/launcher/GerritLauncher.java b/java/com/google/gerrit/launcher/GerritLauncher.java
index b7d232d..13dad0e 100644
--- a/java/com/google/gerrit/launcher/GerritLauncher.java
+++ b/java/com/google/gerrit/launcher/GerritLauncher.java
@@ -305,9 +305,9 @@
 
     ClassLoader parent = ClassLoader.getSystemClassLoader();
     if (!extapi.isEmpty()) {
-      parent = new URLClassLoader(extapi.toArray(new URL[extapi.size()]), parent);
+      parent = URLClassLoader.newInstance(extapi.toArray(new URL[extapi.size()]), parent);
     }
-    return new URLClassLoader(jars.values().toArray(new URL[jars.size()]), parent);
+    return URLClassLoader.newInstance(jars.values().toArray(new URL[jars.size()]), parent);
   }
 
   private static void extractJar(ZipFile zf, ZipEntry ze, SortedMap<String, URL> jars)
@@ -718,7 +718,7 @@
         dirs.add(u);
       }
     }
-    return new URLClassLoader(
+    return URLClassLoader.newInstance(
         dirs.toArray(new URL[dirs.size()]), ClassLoader.getSystemClassLoader().getParent());
   }
 
diff --git a/java/com/google/gerrit/pgm/Daemon.java b/java/com/google/gerrit/pgm/Daemon.java
index b4ca534..4cc7b52 100644
--- a/java/com/google/gerrit/pgm/Daemon.java
+++ b/java/com/google/gerrit/pgm/Daemon.java
@@ -65,12 +65,12 @@
 import com.google.gerrit.server.config.GerritInstanceNameModule;
 import com.google.gerrit.server.config.GerritOptions;
 import com.google.gerrit.server.config.GerritServerConfig;
+import com.google.gerrit.server.config.SysExecutorModule;
 import com.google.gerrit.server.events.EventBroker;
 import com.google.gerrit.server.events.StreamEventsApiListener;
 import com.google.gerrit.server.git.GarbageCollectionModule;
 import com.google.gerrit.server.git.SearchingChangeCacheImpl;
 import com.google.gerrit.server.git.WorkQueue;
-import com.google.gerrit.server.git.receive.ReceiveCommitsExecutorModule;
 import com.google.gerrit.server.group.PeriodicGroupIndexer;
 import com.google.gerrit.server.index.IndexModule;
 import com.google.gerrit.server.index.IndexModule.IndexType;
@@ -412,7 +412,7 @@
         inMemoryTest
             ? new InMemoryAccountPatchReviewStore.Module()
             : new JdbcAccountPatchReviewStore.Module(config));
-    modules.add(new ReceiveCommitsExecutorModule());
+    modules.add(new SysExecutorModule());
     modules.add(new DiffExecutorModule());
     modules.add(new MimeUtil2Module());
     modules.add(cfgInjector.getInstance(GerritGlobalModule.class));
diff --git a/java/com/google/gerrit/pgm/init/InitAdminUser.java b/java/com/google/gerrit/pgm/init/InitAdminUser.java
index 6e41a07..d0aed46 100644
--- a/java/com/google/gerrit/pgm/init/InitAdminUser.java
+++ b/java/com/google/gerrit/pgm/init/InitAdminUser.java
@@ -145,7 +145,7 @@
 
           if (sshKey != null) {
             VersionedAuthorizedKeysOnInit authorizedKeys = authorizedKeysFactory.create(id).load();
-            authorizedKeys.addKey(sshKey.getSshPublicKey());
+            authorizedKeys.addKey(sshKey.sshPublicKey());
             authorizedKeys.save("Add SSH key for initial admin user\n");
           }
 
@@ -165,8 +165,8 @@
 
   private String readEmail(AccountSshKey sshKey) {
     String defaultEmail = "admin@example.com";
-    if (sshKey != null && sshKey.getComment() != null) {
-      String c = sshKey.getComment().trim();
+    if (sshKey != null && sshKey.comment() != null) {
+      String c = sshKey.comment().trim();
       if (EmailValidator.getInstance().isValid(c)) {
         defaultEmail = c;
       }
@@ -199,6 +199,6 @@
       throw new IOException(String.format("Cannot add public SSH key: %s is not a file", keyFile));
     }
     String content = new String(Files.readAllBytes(p), UTF_8);
-    return new AccountSshKey(new AccountSshKey.Id(id, 1), content);
+    return AccountSshKey.create(id, 1, content);
   }
 }
diff --git a/java/com/google/gerrit/pgm/init/InitPluginStepsLoader.java b/java/com/google/gerrit/pgm/init/InitPluginStepsLoader.java
index c1d142b..0fd9eba 100644
--- a/java/com/google/gerrit/pgm/init/InitPluginStepsLoader.java
+++ b/java/com/google/gerrit/pgm/init/InitPluginStepsLoader.java
@@ -66,7 +66,7 @@
   private InitStep loadInitStep(Path jar) {
     try {
       URLClassLoader pluginLoader =
-          new URLClassLoader(
+          URLClassLoader.newInstance(
               new URL[] {jar.toUri().toURL()}, InitPluginStepsLoader.class.getClassLoader());
       try (JarFile jarFile = new JarFile(jar.toFile())) {
         Attributes jarFileAttributes = jarFile.getManifest().getMainAttributes();
diff --git a/java/com/google/gerrit/pgm/init/VersionedAuthorizedKeysOnInit.java b/java/com/google/gerrit/pgm/init/VersionedAuthorizedKeysOnInit.java
index 757c9a4..a9c6cc8 100644
--- a/java/com/google/gerrit/pgm/init/VersionedAuthorizedKeysOnInit.java
+++ b/java/com/google/gerrit/pgm/init/VersionedAuthorizedKeysOnInit.java
@@ -66,8 +66,8 @@
   public AccountSshKey addKey(String pub) {
     checkState(keys != null, "SSH keys not loaded yet");
     int seq = keys.isEmpty() ? 1 : keys.size() + 1;
-    AccountSshKey.Id keyId = new AccountSshKey.Id(accountId, seq);
-    AccountSshKey key = new VersionedAuthorizedKeys.SimpleSshKeyCreator().create(keyId, pub);
+    AccountSshKey key =
+        new VersionedAuthorizedKeys.SimpleSshKeyCreator().create(accountId, seq, pub);
     keys.add(Optional.of(key));
     return key;
   }
diff --git a/java/com/google/gerrit/pgm/util/BatchProgramModule.java b/java/com/google/gerrit/pgm/util/BatchProgramModule.java
index ffec375..efd1bf4 100644
--- a/java/com/google/gerrit/pgm/util/BatchProgramModule.java
+++ b/java/com/google/gerrit/pgm/util/BatchProgramModule.java
@@ -51,13 +51,13 @@
 import com.google.gerrit.server.config.GerritServerConfig;
 import com.google.gerrit.server.config.GitReceivePackGroups;
 import com.google.gerrit.server.config.GitUploadPackGroups;
+import com.google.gerrit.server.config.SysExecutorModule;
 import com.google.gerrit.server.extensions.events.EventUtil;
 import com.google.gerrit.server.extensions.events.GitReferenceUpdated;
 import com.google.gerrit.server.extensions.events.RevisionCreated;
 import com.google.gerrit.server.git.MergeUtil;
 import com.google.gerrit.server.git.SearchingChangeCacheImpl;
 import com.google.gerrit.server.git.TagCache;
-import com.google.gerrit.server.git.receive.ReceiveCommitsExecutorModule;
 import com.google.gerrit.server.mail.send.ReplacePatchSetSender;
 import com.google.gerrit.server.notedb.NoteDbModule;
 import com.google.gerrit.server.patch.DiffExecutorModule;
@@ -105,7 +105,7 @@
   protected void configure() {
     install(reviewDbModule);
     install(new DiffExecutorModule());
-    install(new ReceiveCommitsExecutorModule());
+    install(new SysExecutorModule());
     install(BatchUpdate.module());
     install(PatchListCacheImpl.module());
 
diff --git a/java/com/google/gerrit/server/account/AccountSshKey.java b/java/com/google/gerrit/server/account/AccountSshKey.java
index aeccc0a..f132585 100644
--- a/java/com/google/gerrit/server/account/AccountSshKey.java
+++ b/java/com/google/gerrit/server/account/AccountSshKey.java
@@ -14,76 +14,50 @@
 
 package com.google.gerrit.server.account;
 
+import com.google.auto.value.AutoValue;
 import com.google.common.base.Splitter;
 import com.google.gerrit.reviewdb.client.Account;
-import java.io.Serializable;
 import java.util.List;
-import java.util.Objects;
 
 /** An SSH key approved for use by an {@link Account}. */
-public final class AccountSshKey {
-  public static class Id implements Serializable {
-    private static final long serialVersionUID = 2L;
-
-    private Account.Id accountId;
-    private int seq;
-
-    public Id(Account.Id a, int s) {
-      accountId = a;
-      seq = s;
-    }
-
-    public Account.Id getParentKey() {
-      return accountId;
-    }
-
-    public int get() {
-      return seq;
-    }
-
-    public boolean isValid() {
-      return seq > 0;
-    }
-
-    @Override
-    public int hashCode() {
-      return Objects.hash(accountId, seq);
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-      if (!(obj instanceof Id)) {
-        return false;
-      }
-      Id otherId = (Id) obj;
-      return Objects.equals(accountId, otherId.accountId) && Objects.equals(seq, otherId.seq);
-    }
+@AutoValue
+public abstract class AccountSshKey {
+  public static AccountSshKey create(Account.Id accountId, int seq, String sshPublicKey) {
+    return create(accountId, seq, sshPublicKey, true);
   }
 
-  private AccountSshKey.Id id;
-  private String sshPublicKey;
-  private boolean valid;
-
-  public AccountSshKey(AccountSshKey.Id i, String pub) {
-    id = i;
-    sshPublicKey = pub.replace("\n", "").replace("\r", "");
-    valid = id.isValid();
+  public static AccountSshKey createInvalid(Account.Id accountId, int seq, String sshPublicKey) {
+    return create(accountId, seq, sshPublicKey, false);
   }
 
-  public Account.Id getAccount() {
-    return id.accountId;
+  public static AccountSshKey createInvalid(AccountSshKey key) {
+    return create(key.accountId(), key.seq(), key.sshPublicKey(), false);
   }
 
-  public AccountSshKey.Id getKey() {
-    return id;
+  public static AccountSshKey create(
+      Account.Id accountId, int seq, String sshPublicKey, boolean valid) {
+    return new AutoValue_AccountSshKey.Builder()
+        .setAccountId(accountId)
+        .setSeq(seq)
+        .setSshPublicKey(stripOffNewLines(sshPublicKey))
+        .setValid(valid && seq > 0)
+        .build();
   }
 
-  public String getSshPublicKey() {
-    return sshPublicKey;
+  private static String stripOffNewLines(String s) {
+    return s.replace("\n", "").replace("\r", "");
   }
 
-  private String getPublicKeyPart(int index, String defaultValue) {
-    String s = getSshPublicKey();
+  public abstract Account.Id accountId();
+
+  public abstract int seq();
+
+  public abstract String sshPublicKey();
+
+  public abstract boolean valid();
+
+  private String publicKeyPart(int index, String defaultValue) {
+    String s = sshPublicKey();
     if (s != null && s.length() > 0) {
       List<String> parts = Splitter.on(' ').splitToList(s);
       if (parts.size() > index) {
@@ -93,39 +67,28 @@
     return defaultValue;
   }
 
-  public String getAlgorithm() {
-    return getPublicKeyPart(0, "none");
+  public String algorithm() {
+    return publicKeyPart(0, "none");
   }
 
-  public String getEncodedKey() {
-    return getPublicKeyPart(1, null);
+  public String encodedKey() {
+    return publicKeyPart(1, null);
   }
 
-  public String getComment() {
-    return getPublicKeyPart(2, "");
+  public String comment() {
+    return publicKeyPart(2, "");
   }
 
-  public boolean isValid() {
-    return valid && id.isValid();
-  }
+  @AutoValue.Builder
+  abstract static class Builder {
+    public abstract Builder setAccountId(Account.Id accountId);
 
-  public void setInvalid() {
-    valid = false;
-  }
+    public abstract Builder setSeq(int seq);
 
-  @Override
-  public boolean equals(Object o) {
-    if (o instanceof AccountSshKey) {
-      AccountSshKey other = (AccountSshKey) o;
-      return Objects.equals(id, other.id)
-          && Objects.equals(sshPublicKey, other.sshPublicKey)
-          && Objects.equals(valid, other.valid);
-    }
-    return false;
-  }
+    public abstract Builder setSshPublicKey(String sshPublicKey);
 
-  @Override
-  public int hashCode() {
-    return Objects.hash(id, sshPublicKey, valid);
+    public abstract Builder setValid(boolean valid);
+
+    public abstract AccountSshKey build();
   }
 }
diff --git a/java/com/google/gerrit/server/account/AuthorizedKeys.java b/java/com/google/gerrit/server/account/AuthorizedKeys.java
index 3a6c032..b392c18 100644
--- a/java/com/google/gerrit/server/account/AuthorizedKeys.java
+++ b/java/com/google/gerrit/server/account/AuthorizedKeys.java
@@ -41,8 +41,7 @@
         continue;
       } else if (line.startsWith(INVALID_KEY_COMMENT_PREFIX)) {
         String pub = line.substring(INVALID_KEY_COMMENT_PREFIX.length());
-        AccountSshKey key = new AccountSshKey(new AccountSshKey.Id(accountId, seq++), pub);
-        key.setInvalid();
+        AccountSshKey key = AccountSshKey.createInvalid(accountId, seq++, pub);
         keys.add(Optional.of(key));
       } else if (line.startsWith(DELETED_KEY_COMMENT)) {
         keys.add(Optional.empty());
@@ -50,7 +49,7 @@
       } else if (line.startsWith("#")) {
         continue;
       } else {
-        AccountSshKey key = new AccountSshKey(new AccountSshKey.Id(accountId, seq++), line);
+        AccountSshKey key = AccountSshKey.create(accountId, seq++, line);
         keys.add(Optional.of(key));
       }
     }
@@ -61,10 +60,10 @@
     StringBuilder b = new StringBuilder();
     for (Optional<AccountSshKey> key : keys) {
       if (key.isPresent()) {
-        if (!key.get().isValid()) {
+        if (!key.get().valid()) {
           b.append(INVALID_KEY_COMMENT_PREFIX);
         }
-        b.append(key.get().getSshPublicKey().trim());
+        b.append(key.get().sshPublicKey().trim());
       } else {
         b.append(DELETED_KEY_COMMENT);
       }
diff --git a/java/com/google/gerrit/server/account/VersionedAuthorizedKeys.java b/java/com/google/gerrit/server/account/VersionedAuthorizedKeys.java
index 6a32f57..c7ffa55 100644
--- a/java/com/google/gerrit/server/account/VersionedAuthorizedKeys.java
+++ b/java/com/google/gerrit/server/account/VersionedAuthorizedKeys.java
@@ -24,7 +24,6 @@
 import com.google.gerrit.reviewdb.client.Account;
 import com.google.gerrit.reviewdb.client.RefNames;
 import com.google.gerrit.server.IdentifiedUser;
-import com.google.gerrit.server.account.AccountSshKey.Id;
 import com.google.gerrit.server.config.AllUsersName;
 import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.gerrit.server.git.meta.MetaDataUpdate;
@@ -139,8 +138,8 @@
 
   public static class SimpleSshKeyCreator implements SshKeyCreator {
     @Override
-    public AccountSshKey create(Id id, String encoded) {
-      return new AccountSshKey(id, encoded);
+    public AccountSshKey create(Account.Id accountId, int seq, String encoded) {
+      return AccountSshKey.create(accountId, seq, encoded);
     }
   }
 
@@ -211,14 +210,13 @@
     checkLoaded();
 
     for (Optional<AccountSshKey> key : keys) {
-      if (key.isPresent() && key.get().getSshPublicKey().trim().equals(pub.trim())) {
+      if (key.isPresent() && key.get().sshPublicKey().trim().equals(pub.trim())) {
         return key.get();
       }
     }
 
     int seq = keys.size() + 1;
-    AccountSshKey.Id keyId = new AccountSshKey.Id(accountId, seq);
-    AccountSshKey key = sshKeyCreator.create(keyId, pub);
+    AccountSshKey key = sshKeyCreator.create(accountId, seq, pub);
     keys.add(Optional.of(key));
     return key;
   }
@@ -249,9 +247,10 @@
    */
   private boolean markKeyInvalid(int seq) {
     checkLoaded();
-    AccountSshKey key = getKey(seq);
-    if (key != null && key.isValid()) {
-      key.setInvalid();
+
+    Optional<AccountSshKey> key = keys.get(seq - 1);
+    if (key.isPresent() && key.get().valid()) {
+      keys.set(seq - 1, Optional.of(AccountSshKey.createInvalid(key.get())));
       return true;
     }
     return false;
@@ -265,10 +264,10 @@
    * @param newKeys the new public SSH keys
    */
   public void setKeys(Collection<AccountSshKey> newKeys) {
-    Ordering<AccountSshKey> o = Ordering.from(comparing(k -> k.getKey().get()));
-    keys = new ArrayList<>(Collections.nCopies(o.max(newKeys).getKey().get(), Optional.empty()));
+    Ordering<AccountSshKey> o = Ordering.from(comparing(k -> k.seq()));
+    keys = new ArrayList<>(Collections.nCopies(o.max(newKeys).seq(), Optional.empty()));
     for (AccountSshKey key : newKeys) {
-      keys.set(key.getKey().get() - 1, Optional.of(key));
+      keys.set(key.seq() - 1, Optional.of(key));
     }
   }
 
diff --git a/java/com/google/gerrit/server/change/ChangeInserter.java b/java/com/google/gerrit/server/change/ChangeInserter.java
index 4748911..a08203e 100644
--- a/java/com/google/gerrit/server/change/ChangeInserter.java
+++ b/java/com/google/gerrit/server/change/ChangeInserter.java
@@ -41,13 +41,13 @@
 import com.google.gerrit.server.ChangeMessagesUtil;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.PatchSetUtil;
+import com.google.gerrit.server.config.SendEmailExecutor;
 import com.google.gerrit.server.events.CommitReceivedEvent;
 import com.google.gerrit.server.extensions.events.CommentAdded;
 import com.google.gerrit.server.extensions.events.RevisionCreated;
 import com.google.gerrit.server.git.GroupCollector;
 import com.google.gerrit.server.git.validators.CommitValidationException;
 import com.google.gerrit.server.git.validators.CommitValidators;
-import com.google.gerrit.server.mail.SendEmailExecutor;
 import com.google.gerrit.server.mail.send.CreateChangeSender;
 import com.google.gerrit.server.notedb.ChangeNotes;
 import com.google.gerrit.server.notedb.ChangeUpdate;
diff --git a/java/com/google/gerrit/server/change/EmailReviewComments.java b/java/com/google/gerrit/server/change/EmailReviewComments.java
index 05f8fc0..6286a2f 100644
--- a/java/com/google/gerrit/server/change/EmailReviewComments.java
+++ b/java/com/google/gerrit/server/change/EmailReviewComments.java
@@ -27,7 +27,7 @@
 import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.IdentifiedUser;
-import com.google.gerrit.server.mail.SendEmailExecutor;
+import com.google.gerrit.server.config.SendEmailExecutor;
 import com.google.gerrit.server.mail.send.CommentSender;
 import com.google.gerrit.server.notedb.ChangeNotes;
 import com.google.gerrit.server.patch.PatchSetInfoFactory;
diff --git a/java/com/google/gerrit/server/update/ChangeUpdateExecutor.java b/java/com/google/gerrit/server/config/ChangeUpdateExecutor.java
similarity index 91%
rename from java/com/google/gerrit/server/update/ChangeUpdateExecutor.java
rename to java/com/google/gerrit/server/config/ChangeUpdateExecutor.java
index 1d957cf..4c9e5f0 100644
--- a/java/com/google/gerrit/server/update/ChangeUpdateExecutor.java
+++ b/java/com/google/gerrit/server/config/ChangeUpdateExecutor.java
@@ -12,11 +12,12 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.server.update;
+package com.google.gerrit.server.config;
 
 import static java.lang.annotation.RetentionPolicy.RUNTIME;
 
 import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.gerrit.server.update.BatchUpdate;
 import com.google.inject.BindingAnnotation;
 import java.lang.annotation.Retention;
 
diff --git a/java/com/google/gerrit/server/git/receive/ReceiveCommitsExecutor.java b/java/com/google/gerrit/server/config/ReceiveCommitsExecutor.java
similarity index 88%
rename from java/com/google/gerrit/server/git/receive/ReceiveCommitsExecutor.java
rename to java/com/google/gerrit/server/config/ReceiveCommitsExecutor.java
index ee83a2c..16d389c 100644
--- a/java/com/google/gerrit/server/git/receive/ReceiveCommitsExecutor.java
+++ b/java/com/google/gerrit/server/config/ReceiveCommitsExecutor.java
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.server.git.receive;
+package com.google.gerrit.server.config;
 
 import static java.lang.annotation.RetentionPolicy.RUNTIME;
 
@@ -20,7 +20,7 @@
 import java.lang.annotation.Retention;
 import java.util.concurrent.ExecutorService;
 
-/** Marker on the global {@link ExecutorService} used by {@link ReceiveCommits}. */
+/** Marker on the global {@link ExecutorService} used by {@code ReceiveCommits}. */
 @Retention(RUNTIME)
 @BindingAnnotation
 public @interface ReceiveCommitsExecutor {}
diff --git a/java/com/google/gerrit/server/mail/SendEmailExecutor.java b/java/com/google/gerrit/server/config/SendEmailExecutor.java
similarity index 95%
rename from java/com/google/gerrit/server/mail/SendEmailExecutor.java
rename to java/com/google/gerrit/server/config/SendEmailExecutor.java
index bfd5c17..cf90cbf 100644
--- a/java/com/google/gerrit/server/mail/SendEmailExecutor.java
+++ b/java/com/google/gerrit/server/config/SendEmailExecutor.java
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.server.mail;
+package com.google.gerrit.server.config;
 
 import static java.lang.annotation.RetentionPolicy.RUNTIME;
 
diff --git a/java/com/google/gerrit/server/git/receive/ReceiveCommitsExecutorModule.java b/java/com/google/gerrit/server/config/SysExecutorModule.java
similarity index 85%
rename from java/com/google/gerrit/server/git/receive/ReceiveCommitsExecutorModule.java
rename to java/com/google/gerrit/server/config/SysExecutorModule.java
index 40c0aa5..99edb65 100644
--- a/java/com/google/gerrit/server/git/receive/ReceiveCommitsExecutorModule.java
+++ b/java/com/google/gerrit/server/config/SysExecutorModule.java
@@ -12,15 +12,12 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.server.git.receive;
+package com.google.gerrit.server.config;
 
 import com.google.common.util.concurrent.ListeningExecutorService;
 import com.google.common.util.concurrent.MoreExecutors;
 import com.google.common.util.concurrent.ThreadFactoryBuilder;
-import com.google.gerrit.server.config.GerritServerConfig;
 import com.google.gerrit.server.git.WorkQueue;
-import com.google.gerrit.server.mail.SendEmailExecutor;
-import com.google.gerrit.server.update.ChangeUpdateExecutor;
 import com.google.inject.AbstractModule;
 import com.google.inject.Provides;
 import com.google.inject.Singleton;
@@ -33,10 +30,11 @@
 /**
  * Module providing the {@link ReceiveCommitsExecutor}.
  *
- * <p>Unlike {@link ReceiveCommitsModule}, this module is intended to be installed only in top-level
- * injectors like in {@code Daemon}, not in the {@code sysInjector}.
+ * <p>This module is intended to be installed at the top level when creating a {@code sysInjector}
+ * in {@code Daemon} or similar, not nested in another module. This ensures the module can be
+ * swapped out for the googlesource.com implementation.
  */
-public class ReceiveCommitsExecutorModule extends AbstractModule {
+public class SysExecutorModule extends AbstractModule {
   @Override
   protected void configure() {}
 
diff --git a/java/com/google/gerrit/server/git/MergedByPushOp.java b/java/com/google/gerrit/server/git/MergedByPushOp.java
index 2439bb7..bb50218 100644
--- a/java/com/google/gerrit/server/git/MergedByPushOp.java
+++ b/java/com/google/gerrit/server/git/MergedByPushOp.java
@@ -25,8 +25,8 @@
 import com.google.gerrit.server.ApprovalsUtil;
 import com.google.gerrit.server.ChangeMessagesUtil;
 import com.google.gerrit.server.PatchSetUtil;
+import com.google.gerrit.server.config.SendEmailExecutor;
 import com.google.gerrit.server.extensions.events.ChangeMerged;
-import com.google.gerrit.server.mail.SendEmailExecutor;
 import com.google.gerrit.server.mail.send.MergedSender;
 import com.google.gerrit.server.notedb.ChangeUpdate;
 import com.google.gerrit.server.patch.PatchSetInfoFactory;
diff --git a/java/com/google/gerrit/server/git/receive/AsyncReceiveCommits.java b/java/com/google/gerrit/server/git/receive/AsyncReceiveCommits.java
index 23e771d..b7297fa 100644
--- a/java/com/google/gerrit/server/git/receive/AsyncReceiveCommits.java
+++ b/java/com/google/gerrit/server/git/receive/AsyncReceiveCommits.java
@@ -24,6 +24,7 @@
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.config.ConfigUtil;
 import com.google.gerrit.server.config.GerritServerConfig;
+import com.google.gerrit.server.config.ReceiveCommitsExecutor;
 import com.google.gerrit.server.git.DefaultAdvertiseRefsHook;
 import com.google.gerrit.server.git.MultiProgressMonitor;
 import com.google.gerrit.server.git.ProjectRunnable;
diff --git a/java/com/google/gerrit/server/git/receive/ReplaceOp.java b/java/com/google/gerrit/server/git/receive/ReplaceOp.java
index d842790..3b8091c 100644
--- a/java/com/google/gerrit/server/git/receive/ReplaceOp.java
+++ b/java/com/google/gerrit/server/git/receive/ReplaceOp.java
@@ -43,12 +43,12 @@
 import com.google.gerrit.server.account.AccountResolver;
 import com.google.gerrit.server.change.ChangeKindCache;
 import com.google.gerrit.server.change.EmailReviewComments;
+import com.google.gerrit.server.config.SendEmailExecutor;
 import com.google.gerrit.server.extensions.events.CommentAdded;
 import com.google.gerrit.server.extensions.events.RevisionCreated;
 import com.google.gerrit.server.git.MergedByPushOp;
 import com.google.gerrit.server.git.receive.ReceiveCommits.MagicBranchInput;
 import com.google.gerrit.server.mail.MailUtil.MailRecipients;
-import com.google.gerrit.server.mail.SendEmailExecutor;
 import com.google.gerrit.server.mail.send.ReplacePatchSetSender;
 import com.google.gerrit.server.notedb.ChangeNotes;
 import com.google.gerrit.server.notedb.ChangeUpdate;
diff --git a/java/com/google/gerrit/server/mail/send/AddKeySender.java b/java/com/google/gerrit/server/mail/send/AddKeySender.java
index 3622cf9..ae8ac31 100644
--- a/java/com/google/gerrit/server/mail/send/AddKeySender.java
+++ b/java/com/google/gerrit/server/mail/send/AddKeySender.java
@@ -127,7 +127,7 @@
   }
 
   public String getSshKey() {
-    return (sshKey != null) ? sshKey.getSshPublicKey() + "\n" : null;
+    return (sshKey != null) ? sshKey.sshPublicKey() + "\n" : null;
   }
 
   public String getGpgKeys() {
diff --git a/java/com/google/gerrit/server/plugins/DelegatingClassLoader.java b/java/com/google/gerrit/server/plugins/DelegatingClassLoader.java
index daee9c7..32adb9c 100644
--- a/java/com/google/gerrit/server/plugins/DelegatingClassLoader.java
+++ b/java/com/google/gerrit/server/plugins/DelegatingClassLoader.java
@@ -31,13 +31,17 @@
   @Override
   public Class<?> findClass(String name) throws ClassNotFoundException {
     String path = name.replace('.', '/') + ".class";
-    InputStream resource = target.getResourceAsStream(path);
-    if (resource != null) {
-      try {
-        byte[] bytes = ByteStreams.toByteArray(resource);
-        return defineClass(name, bytes, 0, bytes.length);
-      } catch (IOException e) {
+    try (InputStream resource = target.getResourceAsStream(path)) {
+      if (resource != null) {
+        try {
+          byte[] bytes = ByteStreams.toByteArray(resource);
+          return defineClass(name, bytes, 0, bytes.length);
+        } catch (IOException e) {
+          // throws ClassNotFoundException later
+        }
       }
+    } catch (IOException e) {
+      // throws ClassNotFoundException later
     }
     throw new ClassNotFoundException(name);
   }
diff --git a/java/com/google/gerrit/server/plugins/JarPluginProvider.java b/java/com/google/gerrit/server/plugins/JarPluginProvider.java
index de82370..87c3df7 100644
--- a/java/com/google/gerrit/server/plugins/JarPluginProvider.java
+++ b/java/com/google/gerrit/server/plugins/JarPluginProvider.java
@@ -136,7 +136,8 @@
       urls.add(tmp.toUri().toURL());
 
       ClassLoader pluginLoader =
-          new URLClassLoader(urls.toArray(new URL[urls.size()]), PluginUtil.parentFor(type));
+          URLClassLoader.newInstance(
+              urls.toArray(new URL[urls.size()]), PluginUtil.parentFor(type));
 
       JarScanner jarScanner = createJarScanner(tmp);
       PluginConfig pluginConfig = configFactory.getFromGerritConfig(name);
diff --git a/java/com/google/gerrit/server/restapi/account/DeleteSshKey.java b/java/com/google/gerrit/server/restapi/account/DeleteSshKey.java
index f278df2..998c6f0 100644
--- a/java/com/google/gerrit/server/restapi/account/DeleteSshKey.java
+++ b/java/com/google/gerrit/server/restapi/account/DeleteSshKey.java
@@ -61,7 +61,7 @@
       permissionBackend.currentUser().check(GlobalPermission.ADMINISTRATE_SERVER);
     }
 
-    authorizedKeys.deleteKey(rsrc.getUser().getAccountId(), rsrc.getSshKey().getKey().get());
+    authorizedKeys.deleteKey(rsrc.getUser().getAccountId(), rsrc.getSshKey().seq());
     rsrc.getUser().getUserName().ifPresent(sshKeyCache::evict);
 
     return Response.none();
diff --git a/java/com/google/gerrit/server/restapi/account/GetSshKeys.java b/java/com/google/gerrit/server/restapi/account/GetSshKeys.java
index cd8dc09..15ad75f 100644
--- a/java/com/google/gerrit/server/restapi/account/GetSshKeys.java
+++ b/java/com/google/gerrit/server/restapi/account/GetSshKeys.java
@@ -70,12 +70,12 @@
 
   public static SshKeyInfo newSshKeyInfo(AccountSshKey sshKey) {
     SshKeyInfo info = new SshKeyInfo();
-    info.seq = sshKey.getKey().get();
-    info.sshPublicKey = sshKey.getSshPublicKey();
-    info.encodedKey = sshKey.getEncodedKey();
-    info.algorithm = sshKey.getAlgorithm();
-    info.comment = Strings.emptyToNull(sshKey.getComment());
-    info.valid = sshKey.isValid();
+    info.seq = sshKey.seq();
+    info.sshPublicKey = sshKey.sshPublicKey();
+    info.encodedKey = sshKey.encodedKey();
+    info.algorithm = sshKey.algorithm();
+    info.comment = Strings.emptyToNull(sshKey.comment());
+    info.valid = sshKey.valid();
     return info;
   }
 }
diff --git a/java/com/google/gerrit/server/rules/RulesCache.java b/java/com/google/gerrit/server/rules/RulesCache.java
index d7a614d..6ef11fa 100644
--- a/java/com/google/gerrit/server/rules/RulesCache.java
+++ b/java/com/google/gerrit/server/rules/RulesCache.java
@@ -175,7 +175,7 @@
       Path jarPath = rulesDir.resolve("rules-" + rulesId.getName() + ".jar");
       if (Files.isRegularFile(jarPath)) {
         URL[] cp = new URL[] {toURL(jarPath)};
-        return save(newEmptyMachine(new URLClassLoader(cp, systemLoader)));
+        return save(newEmptyMachine(URLClassLoader.newInstance(cp, systemLoader)));
       }
     }
 
diff --git a/java/com/google/gerrit/server/schema/Schema_124.java b/java/com/google/gerrit/server/schema/Schema_124.java
index 497d5f2..8746427 100644
--- a/java/com/google/gerrit/server/schema/Schema_124.java
+++ b/java/com/google/gerrit/server/schema/Schema_124.java
@@ -84,11 +84,8 @@
         Account.Id accountId = new Account.Id(rs.getInt(1));
         int seq = rs.getInt(2);
         String sshPublicKey = rs.getString(3);
-        AccountSshKey key = new AccountSshKey(new AccountSshKey.Id(accountId, seq), sshPublicKey);
         boolean valid = toBoolean(rs.getString(4));
-        if (!valid) {
-          key.setInvalid();
-        }
+        AccountSshKey key = AccountSshKey.create(accountId, seq, sshPublicKey, valid);
         imports.put(accountId, key);
       }
     }
@@ -122,15 +119,13 @@
   }
 
   private Collection<AccountSshKey> fixInvalidSequenceNumbers(Collection<AccountSshKey> keys) {
-    Ordering<AccountSshKey> o = Ordering.from(comparing(k -> k.getKey().get()));
+    Ordering<AccountSshKey> o = Ordering.from(comparing(k -> k.seq()));
     List<AccountSshKey> fixedKeys = new ArrayList<>(keys);
     AccountSshKey minKey = o.min(keys);
-    while (minKey.getKey().get() <= 0) {
+    while (minKey.seq() <= 0) {
       AccountSshKey fixedKey =
-          new AccountSshKey(
-              new AccountSshKey.Id(
-                  minKey.getKey().getParentKey(), Math.max(o.max(keys).getKey().get() + 1, 1)),
-              minKey.getSshPublicKey());
+          AccountSshKey.create(
+              minKey.accountId(), Math.max(o.max(keys).seq() + 1, 1), minKey.sshPublicKey());
       Collections.replaceAll(fixedKeys, minKey, fixedKey);
       minKey = o.min(fixedKeys);
     }
diff --git a/java/com/google/gerrit/server/ssh/NoSshKeyCache.java b/java/com/google/gerrit/server/ssh/NoSshKeyCache.java
index 308d0cc..387242c 100644
--- a/java/com/google/gerrit/server/ssh/NoSshKeyCache.java
+++ b/java/com/google/gerrit/server/ssh/NoSshKeyCache.java
@@ -15,6 +15,7 @@
 package com.google.gerrit.server.ssh;
 
 import com.google.gerrit.common.errors.InvalidSshKeyException;
+import com.google.gerrit.reviewdb.client.Account;
 import com.google.gerrit.server.account.AccountSshKey;
 import com.google.inject.AbstractModule;
 import com.google.inject.Module;
@@ -37,7 +38,8 @@
   public void evict(String username) {}
 
   @Override
-  public AccountSshKey create(AccountSshKey.Id id, String encoded) throws InvalidSshKeyException {
+  public AccountSshKey create(Account.Id accountId, int seq, String encoded)
+      throws InvalidSshKeyException {
     throw new InvalidSshKeyException();
   }
 }
diff --git a/java/com/google/gerrit/server/ssh/SshKeyCreator.java b/java/com/google/gerrit/server/ssh/SshKeyCreator.java
index d078c43..55ba5ed 100644
--- a/java/com/google/gerrit/server/ssh/SshKeyCreator.java
+++ b/java/com/google/gerrit/server/ssh/SshKeyCreator.java
@@ -15,8 +15,9 @@
 package com.google.gerrit.server.ssh;
 
 import com.google.gerrit.common.errors.InvalidSshKeyException;
+import com.google.gerrit.reviewdb.client.Account;
 import com.google.gerrit.server.account.AccountSshKey;
 
 public interface SshKeyCreator {
-  AccountSshKey create(AccountSshKey.Id id, String encoded) throws InvalidSshKeyException;
+  AccountSshKey create(Account.Id accountId, int seq, String encoded) throws InvalidSshKeyException;
 }
diff --git a/java/com/google/gerrit/server/submit/EmailMerge.java b/java/com/google/gerrit/server/submit/EmailMerge.java
index c8e4e1d..aceb824 100644
--- a/java/com/google/gerrit/server/submit/EmailMerge.java
+++ b/java/com/google/gerrit/server/submit/EmailMerge.java
@@ -24,7 +24,7 @@
 import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.IdentifiedUser;
-import com.google.gerrit.server.mail.SendEmailExecutor;
+import com.google.gerrit.server.config.SendEmailExecutor;
 import com.google.gerrit.server.mail.send.MergedSender;
 import com.google.gerrit.server.util.RequestContext;
 import com.google.gerrit.server.util.ThreadLocalRequestContext;
diff --git a/java/com/google/gerrit/server/update/ReviewDbBatchUpdate.java b/java/com/google/gerrit/server/update/ReviewDbBatchUpdate.java
index 07ae04d..9cdb006 100644
--- a/java/com/google/gerrit/server/update/ReviewDbBatchUpdate.java
+++ b/java/com/google/gerrit/server/update/ReviewDbBatchUpdate.java
@@ -43,6 +43,7 @@
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.GerritPersonIdent;
 import com.google.gerrit.server.config.AllUsersName;
+import com.google.gerrit.server.config.ChangeUpdateExecutor;
 import com.google.gerrit.server.config.GerritServerConfig;
 import com.google.gerrit.server.extensions.events.GitReferenceUpdated;
 import com.google.gerrit.server.git.GitRepositoryManager;
diff --git a/java/com/google/gerrit/sshd/SshKeyCacheEntry.java b/java/com/google/gerrit/sshd/SshKeyCacheEntry.java
index 206b279..8e962e3 100644
--- a/java/com/google/gerrit/sshd/SshKeyCacheEntry.java
+++ b/java/com/google/gerrit/sshd/SshKeyCacheEntry.java
@@ -15,20 +15,19 @@
 package com.google.gerrit.sshd;
 
 import com.google.gerrit.reviewdb.client.Account;
-import com.google.gerrit.server.account.AccountSshKey;
 import java.security.PublicKey;
 
 class SshKeyCacheEntry {
-  private final AccountSshKey.Id id;
+  private final Account.Id accountId;
   private final PublicKey publicKey;
 
-  SshKeyCacheEntry(AccountSshKey.Id i, PublicKey k) {
-    id = i;
-    publicKey = k;
+  SshKeyCacheEntry(Account.Id accountId, PublicKey publicKey) {
+    this.accountId = accountId;
+    this.publicKey = publicKey;
   }
 
   Account.Id getAccount() {
-    return id.getParentKey();
+    return accountId;
   }
 
   boolean match(PublicKey inkey) {
diff --git a/java/com/google/gerrit/sshd/SshKeyCacheImpl.java b/java/com/google/gerrit/sshd/SshKeyCacheImpl.java
index fd226f3..3ab7a58 100644
--- a/java/com/google/gerrit/sshd/SshKeyCacheImpl.java
+++ b/java/com/google/gerrit/sshd/SshKeyCacheImpl.java
@@ -109,7 +109,7 @@
 
       List<SshKeyCacheEntry> kl = new ArrayList<>(4);
       for (AccountSshKey k : authorizedKeys.getKeys(user.get().accountId())) {
-        if (k.isValid()) {
+        if (k.valid()) {
           add(kl, k);
         }
       }
@@ -122,7 +122,7 @@
 
     private void add(List<SshKeyCacheEntry> kl, AccountSshKey k) {
       try {
-        kl.add(new SshKeyCacheEntry(k.getKey(), SshUtil.parse(k)));
+        kl.add(new SshKeyCacheEntry(k.accountId(), SshUtil.parse(k)));
       } catch (OutOfMemoryError e) {
         // This is the only case where we assume the problem has nothing
         // to do with the key object, and instead we must abort this load.
@@ -135,11 +135,11 @@
 
     private void markInvalid(AccountSshKey k) {
       try {
-        log.info("Flagging SSH key " + k.getKey() + " invalid");
-        authorizedKeys.markKeyInvalid(k.getAccount(), k.getKey().get());
-        k.setInvalid();
+        log.info("Flagging SSH key " + k.seq() + " of account " + k.accountId() + " invalid");
+        authorizedKeys.markKeyInvalid(k.accountId(), k.seq());
       } catch (IOException | ConfigInvalidException e) {
-        log.error("Failed to mark SSH key" + k.getKey() + " invalid", e);
+        log.error(
+            "Failed to mark SSH key " + k.seq() + " of account " + k.accountId() + " invalid", e);
       }
     }
   }
diff --git a/java/com/google/gerrit/sshd/SshKeyCreatorImpl.java b/java/com/google/gerrit/sshd/SshKeyCreatorImpl.java
index b838e07..bb47e3f 100644
--- a/java/com/google/gerrit/sshd/SshKeyCreatorImpl.java
+++ b/java/com/google/gerrit/sshd/SshKeyCreatorImpl.java
@@ -15,6 +15,7 @@
 package com.google.gerrit.sshd;
 
 import com.google.gerrit.common.errors.InvalidSshKeyException;
+import com.google.gerrit.reviewdb.client.Account;
 import com.google.gerrit.server.account.AccountSshKey;
 import com.google.gerrit.server.ssh.SshKeyCreator;
 import java.security.NoSuchAlgorithmException;
@@ -27,9 +28,10 @@
   private static final Logger log = LoggerFactory.getLogger(SshKeyCreatorImpl.class);
 
   @Override
-  public AccountSshKey create(AccountSshKey.Id id, String encoded) throws InvalidSshKeyException {
+  public AccountSshKey create(Account.Id accountId, int seq, String encoded)
+      throws InvalidSshKeyException {
     try {
-      AccountSshKey key = new AccountSshKey(id, SshUtil.toOpenSshPublicKey(encoded));
+      AccountSshKey key = AccountSshKey.create(accountId, seq, SshUtil.toOpenSshPublicKey(encoded));
       SshUtil.parse(key);
       return key;
     } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
diff --git a/java/com/google/gerrit/sshd/SshUtil.java b/java/com/google/gerrit/sshd/SshUtil.java
index 6fb83f0..b37ca8b 100644
--- a/java/com/google/gerrit/sshd/SshUtil.java
+++ b/java/com/google/gerrit/sshd/SshUtil.java
@@ -51,7 +51,7 @@
   public static PublicKey parse(AccountSshKey key)
       throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchProviderException {
     try {
-      final String s = key.getEncodedKey();
+      final String s = key.encodedKey();
       if (s == null) {
         throw new InvalidKeySpecException("No key string");
       }
diff --git a/java/com/google/gerrit/sshd/commands/SetAccountCommand.java b/java/com/google/gerrit/sshd/commands/SetAccountCommand.java
index 04f7d3c..bc1e084 100644
--- a/java/com/google/gerrit/sshd/commands/SetAccountCommand.java
+++ b/java/com/google/gerrit/sshd/commands/SetAccountCommand.java
@@ -263,8 +263,7 @@
   private void deleteSshKey(SshKeyInfo i)
       throws AuthException, OrmException, RepositoryNotFoundException, IOException,
           ConfigInvalidException, PermissionBackendException {
-    AccountSshKey sshKey =
-        new AccountSshKey(new AccountSshKey.Id(user.getAccountId(), i.seq), i.sshPublicKey);
+    AccountSshKey sshKey = AccountSshKey.create(user.getAccountId(), i.seq, i.sshPublicKey);
     deleteSshKey.apply(new AccountResource.SshKey(user.asIdentifiedUser(), sshKey), null);
   }
 
diff --git a/java/com/google/gerrit/testing/InMemoryModule.java b/java/com/google/gerrit/testing/InMemoryModule.java
index 471f4fa..0a9165f1 100644
--- a/java/com/google/gerrit/testing/InMemoryModule.java
+++ b/java/com/google/gerrit/testing/InMemoryModule.java
@@ -42,12 +42,14 @@
 import com.google.gerrit.server.config.AnonymousCowardNameProvider;
 import com.google.gerrit.server.config.CanonicalWebUrlModule;
 import com.google.gerrit.server.config.CanonicalWebUrlProvider;
+import com.google.gerrit.server.config.ChangeUpdateExecutor;
 import com.google.gerrit.server.config.GerritGlobalModule;
 import com.google.gerrit.server.config.GerritInstanceNameModule;
 import com.google.gerrit.server.config.GerritOptions;
 import com.google.gerrit.server.config.GerritServerConfig;
 import com.google.gerrit.server.config.GerritServerId;
 import com.google.gerrit.server.config.GerritServerIdProvider;
+import com.google.gerrit.server.config.SendEmailExecutor;
 import com.google.gerrit.server.config.SitePath;
 import com.google.gerrit.server.config.TrackingFooters;
 import com.google.gerrit.server.config.TrackingFootersProvider;
@@ -62,7 +64,6 @@
 import com.google.gerrit.server.index.change.ChangeSchemaDefinitions;
 import com.google.gerrit.server.index.group.AllGroupsIndexer;
 import com.google.gerrit.server.index.group.GroupSchemaDefinitions;
-import com.google.gerrit.server.mail.SendEmailExecutor;
 import com.google.gerrit.server.mail.SignedTokenEmailTokenVerifier;
 import com.google.gerrit.server.notedb.ChangeBundleReader;
 import com.google.gerrit.server.notedb.GwtormChangeBundleReader;
@@ -82,7 +83,6 @@
 import com.google.gerrit.server.securestore.SecureStore;
 import com.google.gerrit.server.ssh.NoSshKeyCache;
 import com.google.gerrit.server.submit.LocalMergeSuperSetComputation;
-import com.google.gerrit.server.update.ChangeUpdateExecutor;
 import com.google.gwtorm.server.OrmException;
 import com.google.gwtorm.server.SchemaFactory;
 import com.google.inject.AbstractModule;
diff --git a/javatests/com/google/gerrit/server/query/IndexConfig.java b/java/com/google/gerrit/testing/IndexConfig.java
similarity index 87%
rename from javatests/com/google/gerrit/server/query/IndexConfig.java
rename to java/com/google/gerrit/testing/IndexConfig.java
index 4edf0b2..9cace88 100644
--- a/javatests/com/google/gerrit/server/query/IndexConfig.java
+++ b/java/com/google/gerrit/testing/IndexConfig.java
@@ -1,4 +1,4 @@
-// Copyright (C) 2017 The Android Open Source Project
+// Copyright (C) 2018 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.
@@ -12,11 +12,25 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.server.query;
+package com.google.gerrit.testing;
 
 import org.eclipse.jgit.lib.Config;
 
 public class IndexConfig {
+  public static Config create() {
+    return createFromExistingConfig(new Config());
+  }
+
+  public static Config createFromExistingConfig(Config cfg) {
+    cfg.setInt("index", null, "maxPages", 10);
+    cfg.setString("trackingid", "query-bug", "footer", "Bug:");
+    cfg.setString("trackingid", "query-bug", "match", "QUERY\\d{2,8}");
+    cfg.setString("trackingid", "query-bug", "system", "querytests");
+    cfg.setString("trackingid", "query-feature", "footer", "Feature");
+    cfg.setString("trackingid", "query-feature", "match", "QUERY\\d{2,8}");
+    cfg.setString("trackingid", "query-feature", "system", "querytests");
+    return cfg;
+  }
 
   public static Config createForLucene() {
     return create();
@@ -31,16 +45,4 @@
 
     return cfg;
   }
-
-  public static Config create() {
-    Config cfg = new Config();
-    cfg.setInt("index", null, "maxPages", 10);
-    cfg.setString("trackingid", "query-bug", "footer", "Bug:");
-    cfg.setString("trackingid", "query-bug", "match", "QUERY\\d{2,8}");
-    cfg.setString("trackingid", "query-bug", "system", "querytests");
-    cfg.setString("trackingid", "query-feature", "footer", "Feature");
-    cfg.setString("trackingid", "query-feature", "match", "QUERY\\d{2,8}");
-    cfg.setString("trackingid", "query-feature", "system", "querytests");
-    return cfg;
-  }
 }
diff --git a/javatests/com/google/gerrit/elasticsearch/BUILD b/javatests/com/google/gerrit/elasticsearch/BUILD
index 567595b..70d7089 100644
--- a/javatests/com/google/gerrit/elasticsearch/BUILD
+++ b/javatests/com/google/gerrit/elasticsearch/BUILD
@@ -41,7 +41,6 @@
         "//java/com/google/gerrit/server",
         "//java/com/google/gerrit/server/project/testing:project-test-util",
         "//java/com/google/gerrit/testing:gerrit-test-util",
-        "//javatests/com/google/gerrit/server/query:index-config",
         "//javatests/com/google/gerrit/server/query/%s:abstract_query_tests" % name,
         "//lib/guice",
         "//lib/jgit/org.eclipse.jgit:jgit",
diff --git a/javatests/com/google/gerrit/elasticsearch/ElasticQueryAccountsTest.java b/javatests/com/google/gerrit/elasticsearch/ElasticQueryAccountsTest.java
index 794956f..bf5494f 100644
--- a/javatests/com/google/gerrit/elasticsearch/ElasticQueryAccountsTest.java
+++ b/javatests/com/google/gerrit/elasticsearch/ElasticQueryAccountsTest.java
@@ -15,10 +15,10 @@
 package com.google.gerrit.elasticsearch;
 
 import com.google.gerrit.elasticsearch.ElasticTestUtils.ElasticNodeInfo;
-import com.google.gerrit.server.query.IndexConfig;
 import com.google.gerrit.server.query.account.AbstractQueryAccountsTest;
 import com.google.gerrit.testing.ConfigSuite;
 import com.google.gerrit.testing.InMemoryModule;
+import com.google.gerrit.testing.IndexConfig;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 import java.util.concurrent.ExecutionException;
diff --git a/javatests/com/google/gerrit/elasticsearch/ElasticQueryChangesTest.java b/javatests/com/google/gerrit/elasticsearch/ElasticQueryChangesTest.java
index bc6c853..62321b7 100644
--- a/javatests/com/google/gerrit/elasticsearch/ElasticQueryChangesTest.java
+++ b/javatests/com/google/gerrit/elasticsearch/ElasticQueryChangesTest.java
@@ -15,11 +15,11 @@
 package com.google.gerrit.elasticsearch;
 
 import com.google.gerrit.elasticsearch.ElasticTestUtils.ElasticNodeInfo;
-import com.google.gerrit.server.query.IndexConfig;
 import com.google.gerrit.server.query.change.AbstractQueryChangesTest;
 import com.google.gerrit.testing.ConfigSuite;
 import com.google.gerrit.testing.InMemoryModule;
 import com.google.gerrit.testing.InMemoryRepositoryManager.Repo;
+import com.google.gerrit.testing.IndexConfig;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 import java.util.concurrent.ExecutionException;
diff --git a/javatests/com/google/gerrit/elasticsearch/ElasticQueryGroupsTest.java b/javatests/com/google/gerrit/elasticsearch/ElasticQueryGroupsTest.java
index 9659c9e..80b8eb3 100644
--- a/javatests/com/google/gerrit/elasticsearch/ElasticQueryGroupsTest.java
+++ b/javatests/com/google/gerrit/elasticsearch/ElasticQueryGroupsTest.java
@@ -15,10 +15,10 @@
 package com.google.gerrit.elasticsearch;
 
 import com.google.gerrit.elasticsearch.ElasticTestUtils.ElasticNodeInfo;
-import com.google.gerrit.server.query.IndexConfig;
 import com.google.gerrit.server.query.group.AbstractQueryGroupsTest;
 import com.google.gerrit.testing.ConfigSuite;
 import com.google.gerrit.testing.InMemoryModule;
+import com.google.gerrit.testing.IndexConfig;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 import java.util.concurrent.ExecutionException;
diff --git a/javatests/com/google/gerrit/elasticsearch/ElasticQueryProjectsTest.java b/javatests/com/google/gerrit/elasticsearch/ElasticQueryProjectsTest.java
index 66a6aab..9126670 100644
--- a/javatests/com/google/gerrit/elasticsearch/ElasticQueryProjectsTest.java
+++ b/javatests/com/google/gerrit/elasticsearch/ElasticQueryProjectsTest.java
@@ -15,10 +15,10 @@
 package com.google.gerrit.elasticsearch;
 
 import com.google.gerrit.elasticsearch.ElasticTestUtils.ElasticNodeInfo;
-import com.google.gerrit.server.query.IndexConfig;
 import com.google.gerrit.server.query.project.AbstractQueryProjectsTest;
 import com.google.gerrit.testing.ConfigSuite;
 import com.google.gerrit.testing.InMemoryModule;
+import com.google.gerrit.testing.IndexConfig;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 import java.util.concurrent.ExecutionException;
diff --git a/javatests/com/google/gerrit/server/account/AuthorizedKeysTest.java b/javatests/com/google/gerrit/server/account/AuthorizedKeysTest.java
index 87e2e67..80a15a3 100644
--- a/javatests/com/google/gerrit/server/account/AuthorizedKeysTest.java
+++ b/javatests/com/google/gerrit/server/account/AuthorizedKeysTest.java
@@ -113,30 +113,30 @@
 
   @Test
   public void validity() throws Exception {
-    AccountSshKey key = new AccountSshKey(new AccountSshKey.Id(accountId, -1), KEY1);
-    assertThat(key.isValid()).isFalse();
-    key = new AccountSshKey(new AccountSshKey.Id(accountId, 0), KEY1);
-    assertThat(key.isValid()).isFalse();
-    key = new AccountSshKey(new AccountSshKey.Id(accountId, 1), KEY1);
-    assertThat(key.isValid()).isTrue();
+    AccountSshKey key = AccountSshKey.create(accountId, -1, KEY1);
+    assertThat(key.valid()).isFalse();
+    key = AccountSshKey.create(accountId, 0, KEY1);
+    assertThat(key.valid()).isFalse();
+    key = AccountSshKey.create(accountId, 1, KEY1);
+    assertThat(key.valid()).isTrue();
   }
 
   @Test
   public void getters() throws Exception {
-    AccountSshKey key = new AccountSshKey(new AccountSshKey.Id(accountId, 1), KEY1);
-    assertThat(key.getSshPublicKey()).isEqualTo(KEY1);
-    assertThat(key.getAlgorithm()).isEqualTo(KEY1.split(" ")[0]);
-    assertThat(key.getEncodedKey()).isEqualTo(KEY1.split(" ")[1]);
-    assertThat(key.getComment()).isEqualTo(KEY1.split(" ")[2]);
+    AccountSshKey key = AccountSshKey.create(accountId, 1, KEY1);
+    assertThat(key.sshPublicKey()).isEqualTo(KEY1);
+    assertThat(key.algorithm()).isEqualTo(KEY1.split(" ")[0]);
+    assertThat(key.encodedKey()).isEqualTo(KEY1.split(" ")[1]);
+    assertThat(key.comment()).isEqualTo(KEY1.split(" ")[2]);
   }
 
   @Test
   public void keyWithNewLines() throws Exception {
-    AccountSshKey key = new AccountSshKey(new AccountSshKey.Id(accountId, 1), KEY1_WITH_NEWLINES);
-    assertThat(key.getSshPublicKey()).isEqualTo(KEY1);
-    assertThat(key.getAlgorithm()).isEqualTo(KEY1.split(" ")[0]);
-    assertThat(key.getEncodedKey()).isEqualTo(KEY1.split(" ")[1]);
-    assertThat(key.getComment()).isEqualTo(KEY1.split(" ")[2]);
+    AccountSshKey key = AccountSshKey.create(accountId, 1, KEY1_WITH_NEWLINES);
+    assertThat(key.sshPublicKey()).isEqualTo(KEY1);
+    assertThat(key.algorithm()).isEqualTo(KEY1.split(" ")[0]);
+    assertThat(key.encodedKey()).isEqualTo(KEY1.split(" ")[1]);
+    assertThat(key.comment()).isEqualTo(KEY1.split(" ")[2]);
   }
 
   private static String toWindowsLineEndings(String s) {
@@ -157,8 +157,8 @@
     int seq = 1;
     for (Optional<AccountSshKey> sshKey : parsedKeys) {
       if (sshKey.isPresent()) {
-        assertThat(sshKey.get().getAccount()).isEqualTo(accountId);
-        assertThat(sshKey.get().getKey().get()).isEqualTo(seq);
+        assertThat(sshKey.get().accountId()).isEqualTo(accountId);
+        assertThat(sshKey.get().seq()).isEqualTo(seq);
       }
       seq++;
     }
@@ -170,10 +170,9 @@
    * @return the expected line for this key in the authorized_keys file
    */
   private static String addKey(List<Optional<AccountSshKey>> keys, String pub) {
-    AccountSshKey.Id keyId = new AccountSshKey.Id(new Account.Id(1), keys.size() + 1);
-    AccountSshKey key = new AccountSshKey(keyId, pub);
+    AccountSshKey key = AccountSshKey.create(new Account.Id(1), keys.size() + 1, pub);
     keys.add(Optional.of(key));
-    return key.getSshPublicKey() + "\n";
+    return key.sshPublicKey() + "\n";
   }
 
   /**
@@ -182,11 +181,9 @@
    * @return the expected line for this key in the authorized_keys file
    */
   private static String addInvalidKey(List<Optional<AccountSshKey>> keys, String pub) {
-    AccountSshKey.Id keyId = new AccountSshKey.Id(new Account.Id(1), keys.size() + 1);
-    AccountSshKey key = new AccountSshKey(keyId, pub);
-    key.setInvalid();
+    AccountSshKey key = AccountSshKey.createInvalid(new Account.Id(1), keys.size() + 1, pub);
     keys.add(Optional.of(key));
-    return AuthorizedKeys.INVALID_KEY_COMMENT_PREFIX + key.getSshPublicKey() + "\n";
+    return AuthorizedKeys.INVALID_KEY_COMMENT_PREFIX + key.sshPublicKey() + "\n";
   }
 
   /**
diff --git a/javatests/com/google/gerrit/server/query/BUILD b/javatests/com/google/gerrit/server/query/BUILD
deleted file mode 100644
index 96201d2..0000000
--- a/javatests/com/google/gerrit/server/query/BUILD
+++ /dev/null
@@ -1,10 +0,0 @@
-load("//tools/bzl:junit.bzl", "junit_tests")
-
-java_library(
-    name = "index-config",
-    srcs = glob(["*.java"]),
-    visibility = ["//visibility:public"],
-    deps = [
-        "//lib/jgit/org.eclipse.jgit:jgit",
-    ],
-)
diff --git a/javatests/com/google/gerrit/server/query/account/BUILD b/javatests/com/google/gerrit/server/query/account/BUILD
index 497fc22..c352f43 100644
--- a/javatests/com/google/gerrit/server/query/account/BUILD
+++ b/javatests/com/google/gerrit/server/query/account/BUILD
@@ -35,7 +35,6 @@
         ":abstract_query_tests",
         "//java/com/google/gerrit/server",
         "//java/com/google/gerrit/testing:gerrit-test-util",
-        "//javatests/com/google/gerrit/server/query:index-config",
         "//lib/guice",
         "//lib/jgit/org.eclipse.jgit:jgit",
     ],
diff --git a/javatests/com/google/gerrit/server/query/account/LuceneQueryAccountsTest.java b/javatests/com/google/gerrit/server/query/account/LuceneQueryAccountsTest.java
index da4b0d5..660c1d8 100644
--- a/javatests/com/google/gerrit/server/query/account/LuceneQueryAccountsTest.java
+++ b/javatests/com/google/gerrit/server/query/account/LuceneQueryAccountsTest.java
@@ -15,9 +15,9 @@
 package com.google.gerrit.server.query.account;
 
 import com.google.gerrit.server.index.account.AccountSchemaDefinitions;
-import com.google.gerrit.server.query.IndexConfig;
 import com.google.gerrit.testing.ConfigSuite;
 import com.google.gerrit.testing.InMemoryModule;
+import com.google.gerrit.testing.IndexConfig;
 import com.google.gerrit.testing.IndexVersions;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
diff --git a/javatests/com/google/gerrit/server/query/change/BUILD b/javatests/com/google/gerrit/server/query/change/BUILD
index 7df5062..66c825c 100644
--- a/javatests/com/google/gerrit/server/query/change/BUILD
+++ b/javatests/com/google/gerrit/server/query/change/BUILD
@@ -41,7 +41,6 @@
         "//java/com/google/gerrit/reviewdb:server",
         "//java/com/google/gerrit/server",
         "//java/com/google/gerrit/testing:gerrit-test-util",
-        "//javatests/com/google/gerrit/server/query:index-config",
         "//lib:gwtorm",
         "//lib:truth",
         "//lib/guice",
diff --git a/javatests/com/google/gerrit/server/query/change/LuceneQueryChangesTest.java b/javatests/com/google/gerrit/server/query/change/LuceneQueryChangesTest.java
index e0ddc4c..5ee3aa4 100644
--- a/javatests/com/google/gerrit/server/query/change/LuceneQueryChangesTest.java
+++ b/javatests/com/google/gerrit/server/query/change/LuceneQueryChangesTest.java
@@ -17,10 +17,10 @@
 import com.google.gerrit.extensions.restapi.BadRequestException;
 import com.google.gerrit.reviewdb.client.Change;
 import com.google.gerrit.server.index.change.ChangeSchemaDefinitions;
-import com.google.gerrit.server.query.IndexConfig;
 import com.google.gerrit.testing.ConfigSuite;
 import com.google.gerrit.testing.InMemoryModule;
 import com.google.gerrit.testing.InMemoryRepositoryManager.Repo;
+import com.google.gerrit.testing.IndexConfig;
 import com.google.gerrit.testing.IndexVersions;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
diff --git a/javatests/com/google/gerrit/server/query/group/BUILD b/javatests/com/google/gerrit/server/query/group/BUILD
index 7f14fe3..01a54a3 100644
--- a/javatests/com/google/gerrit/server/query/group/BUILD
+++ b/javatests/com/google/gerrit/server/query/group/BUILD
@@ -34,7 +34,6 @@
         ":abstract_query_tests",
         "//java/com/google/gerrit/server",
         "//java/com/google/gerrit/testing:gerrit-test-util",
-        "//javatests/com/google/gerrit/server/query:index-config",
         "//lib/guice",
         "//lib/jgit/org.eclipse.jgit:jgit",
     ],
diff --git a/javatests/com/google/gerrit/server/query/group/LuceneQueryGroupsTest.java b/javatests/com/google/gerrit/server/query/group/LuceneQueryGroupsTest.java
index be231a3..83835c1 100644
--- a/javatests/com/google/gerrit/server/query/group/LuceneQueryGroupsTest.java
+++ b/javatests/com/google/gerrit/server/query/group/LuceneQueryGroupsTest.java
@@ -15,9 +15,9 @@
 package com.google.gerrit.server.query.group;
 
 import com.google.gerrit.server.index.group.GroupSchemaDefinitions;
-import com.google.gerrit.server.query.IndexConfig;
 import com.google.gerrit.testing.ConfigSuite;
 import com.google.gerrit.testing.InMemoryModule;
+import com.google.gerrit.testing.IndexConfig;
 import com.google.gerrit.testing.IndexVersions;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
diff --git a/javatests/com/google/gerrit/server/query/project/BUILD b/javatests/com/google/gerrit/server/query/project/BUILD
index 4ad9e73..ac2692b 100644
--- a/javatests/com/google/gerrit/server/query/project/BUILD
+++ b/javatests/com/google/gerrit/server/query/project/BUILD
@@ -33,7 +33,6 @@
         "//java/com/google/gerrit/index/project",
         "//java/com/google/gerrit/server",
         "//java/com/google/gerrit/testing:gerrit-test-util",
-        "//javatests/com/google/gerrit/server/query:index-config",
         "//lib/guice",
         "//lib/jgit/org.eclipse.jgit:jgit",
     ],
diff --git a/javatests/com/google/gerrit/server/query/project/LuceneQueryProjectsTest.java b/javatests/com/google/gerrit/server/query/project/LuceneQueryProjectsTest.java
index 1cf09d8..42964fa 100644
--- a/javatests/com/google/gerrit/server/query/project/LuceneQueryProjectsTest.java
+++ b/javatests/com/google/gerrit/server/query/project/LuceneQueryProjectsTest.java
@@ -15,9 +15,9 @@
 package com.google.gerrit.server.query.project;
 
 import com.google.gerrit.index.project.ProjectSchemaDefinitions;
-import com.google.gerrit.server.query.IndexConfig;
 import com.google.gerrit.testing.ConfigSuite;
 import com.google.gerrit.testing.InMemoryModule;
+import com.google.gerrit.testing.IndexConfig;
 import com.google.gerrit.testing.IndexVersions;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
diff --git a/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members.html b/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members.html
index 23d617f..e019e05 100644
--- a/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members.html
+++ b/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members.html
@@ -57,7 +57,7 @@
         }
       }
       a {
-        color: var(--default-text-color);
+        color: var(--primary-text-color);
         text-decoration: none;
       }
       a:hover {
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item.html b/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item.html
index 9ec1f2d..d7eac85 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item.html
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list-item/gr-change-list-item.html
@@ -86,7 +86,7 @@
         padding: .4rem .6rem;
       }
       a {
-        color: var(--default-text-color);
+        color: var(--primary-text-color);
         cursor: pointer;
         display: inline-block;
         text-decoration: none;
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list-view/gr-change-list-view.js b/polygerrit-ui/app/elements/change-list/gr-change-list-view/gr-change-list-view.js
index ceb4b4d..2a05a2f 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list-view/gr-change-list-view.js
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list-view/gr-change-list-view.js
@@ -147,7 +147,9 @@
         this.set('viewState.offset', this._offset);
       }
 
-      this.fire('title-change', {title: this._query});
+      // NOTE: This method may be called before attachment. Fire title-change
+      // in an async so that attachment to the DOM can take place first.
+      this.async(() => this.fire('title-change', {title: this._query}));
 
       this._getPreferences().then(prefs => {
         this._changesPerPage = prefs.changes_per_page;
diff --git a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.html b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.html
index 96b0628..cb854b2 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.html
+++ b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.html
@@ -250,7 +250,7 @@
           display: block;
         }
         .row.selected {
-          background-color: #fff;
+          background-color: var(--view-background-color);
         }
         .stats {
           display: none;
diff --git a/polygerrit-ui/app/elements/change/gr-included-in-dialog/gr-included-in-dialog.html b/polygerrit-ui/app/elements/change/gr-included-in-dialog/gr-included-in-dialog.html
index 77f95ec..8514061 100644
--- a/polygerrit-ui/app/elements/change/gr-included-in-dialog/gr-included-in-dialog.html
+++ b/polygerrit-ui/app/elements/change/gr-included-in-dialog/gr-included-in-dialog.html
@@ -29,7 +29,7 @@
         padding: 4.5em 1em 1em 1em;
       }
       header {
-        background: #fff;
+        background: var(--view-background-color);
         border-bottom: 1px solid var(--border-color);
         left: 0;
         padding: 1em;
diff --git a/polygerrit-ui/app/elements/change/gr-message/gr-message.html b/polygerrit-ui/app/elements/change/gr-message/gr-message.html
index fea01ca..8acf96f 100644
--- a/polygerrit-ui/app/elements/change/gr-message/gr-message.html
+++ b/polygerrit-ui/app/elements/change/gr-message/gr-message.html
@@ -119,7 +119,7 @@
         position: static;
       }
       .collapsed .author {
-        color: var(--default-text-color);
+        color: var(--primary-text-color);
         margin-right: .4em;
       }
       .expanded .author {
diff --git a/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list.html b/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list.html
index 761e8ee..ec91715 100644
--- a/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list.html
+++ b/polygerrit-ui/app/elements/change/gr-messages-list/gr-messages-list.html
@@ -48,7 +48,7 @@
       }
       @keyframes fadeOut {
         0% { background-color: #fff9c4; }
-        100% { background-color: #fff; }
+        100% { background-color: var(--view-background-color); }
       }
       #messageControlsContainer {
         align-items: center;
diff --git a/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.html b/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.html
index bdf5d3b..595ad33 100644
--- a/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.html
+++ b/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.html
@@ -121,7 +121,7 @@
         text-decoration: none;
       }
       .dropdown-content {
-        background-color: #fff;
+        background-color: var(--view-background-color);
         box-shadow: 0 1px 5px rgba(0, 0, 0, .3);
       }
       @media screen and (max-width: 50em) {
diff --git a/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar.html b/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar.html
index 1117bac..39b2f7e 100644
--- a/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar.html
+++ b/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar.html
@@ -28,7 +28,7 @@
         display: flex;
       }
       gr-autocomplete {
-        background-color: white;
+        background-color: var(--view-background-color);
         border: 1px solid var(--border-color);
         border-radius: 2px 0 0 2px;
         flex: 1;
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.html b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.html
index 839d3f6..e20a765 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.html
@@ -57,7 +57,7 @@
         }
       }
       gr-fixed-panel {
-        background-color: #fff;
+        background-color: var(--view-background-color);
         border-bottom: 1px solid var(--border-color);
         z-index: 1;
       }
diff --git a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.html b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.html
index 008a85b..f45b2d3 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.html
@@ -87,7 +87,7 @@
       }
       .blank,
       .content {
-        background-color: #fff;
+        background-color: var(--view-background-color);
       }
       .full-width {
         width: 100%;
diff --git a/polygerrit-ui/app/elements/gr-app.html b/polygerrit-ui/app/elements/gr-app.html
index 62f802b..7cfb3b0 100644
--- a/polygerrit-ui/app/elements/gr-app.html
+++ b/polygerrit-ui/app/elements/gr-app.html
@@ -64,9 +64,10 @@
   <template>
     <style include="shared-styles">
       :host {
+        background-color: var(--view-background-color);
         display: flex;
-        min-height: 100%;
         flex-direction: column;
+        min-height: 100%;
       }
       gr-fixed-panel {
         /**
diff --git a/polygerrit-ui/app/elements/shared/gr-account-link/gr-account-link.html b/polygerrit-ui/app/elements/shared/gr-account-link/gr-account-link.html
index bea8d27..34b0de6 100644
--- a/polygerrit-ui/app/elements/shared/gr-account-link/gr-account-link.html
+++ b/polygerrit-ui/app/elements/shared/gr-account-link/gr-account-link.html
@@ -28,7 +28,7 @@
         display: inline-block;
       }
       a {
-        color: var(--default-text-color);
+        color: var(--primary-text-color);
         text-decoration: none;
       }
       gr-account-label {
diff --git a/polygerrit-ui/app/elements/shared/gr-alert/gr-alert.html b/polygerrit-ui/app/elements/shared/gr-alert/gr-alert.html
index 0e6a000..b47d5a4 100644
--- a/polygerrit-ui/app/elements/shared/gr-alert/gr-alert.html
+++ b/polygerrit-ui/app/elements/shared/gr-alert/gr-alert.html
@@ -33,7 +33,7 @@
         bottom: 1.25rem;
         border-radius: 3px;
         box-shadow: 0 1px 3px rgba(0, 0, 0, .3);
-        color: #fff;
+        color: var(--view-background-color);
         left: 1.25rem;
         padding: 1em 1.5em;
         position: fixed;
diff --git a/polygerrit-ui/app/elements/shared/gr-autocomplete-dropdown/gr-autocomplete-dropdown.html b/polygerrit-ui/app/elements/shared/gr-autocomplete-dropdown/gr-autocomplete-dropdown.html
index ef9ed4e..5179783 100644
--- a/polygerrit-ui/app/elements/shared/gr-autocomplete-dropdown/gr-autocomplete-dropdown.html
+++ b/polygerrit-ui/app/elements/shared/gr-autocomplete-dropdown/gr-autocomplete-dropdown.html
@@ -46,7 +46,7 @@
         background-color: #eee;
       }
       .dropdown-content {
-        background: #fff;
+        background: var(--view-background-color);
         box-shadow: rgba(0, 0, 0, 0.3) 0 1px 3px;
       }
     </style>
diff --git a/polygerrit-ui/app/elements/shared/gr-button/gr-button.html b/polygerrit-ui/app/elements/shared/gr-button/gr-button.html
index 6dd197d..1e190dd 100644
--- a/polygerrit-ui/app/elements/shared/gr-button/gr-button.html
+++ b/polygerrit-ui/app/elements/shared/gr-button/gr-button.html
@@ -27,7 +27,7 @@
     <style include="shared-styles">
       /* general styles for all buttons */
       :host {
-        --background-color: var(--gr-button-background, #fff);
+        --background-color: var(--gr-button-background, var(--view-background-color));
         --button-color: var(--gr-button-color, var(--color-link));
         display: inline-block;
         font-family: var(--font-family-bold);
@@ -66,13 +66,13 @@
       :host([primary][raised]),
       :host([secondary][raised]) {
         --background-color: var(--color-link);
-        --button-color: #fff;
+        --button-color: var(--view-background-color);
       }
 
       /* Keep below color definition for primary/secondary so that this takes
        precedence when disabled. */
       :host([disabled]) {
-        --background-color: #eaeaea;
+        --background-color: var(--table-subheader-background-color);
         --button-color: #a8a8a8;
         cursor: default;
       }
diff --git a/polygerrit-ui/app/elements/shared/gr-dropdown-list/gr-dropdown-list.html b/polygerrit-ui/app/elements/shared/gr-dropdown-list/gr-dropdown-list.html
index b855045..7f79196 100644
--- a/polygerrit-ui/app/elements/shared/gr-dropdown-list/gr-dropdown-list.html
+++ b/polygerrit-ui/app/elements/shared/gr-dropdown-list/gr-dropdown-list.html
@@ -43,7 +43,7 @@
         padding: 0;
       }
       .dropdown-content {
-        background-color: #fff;
+        background-color: var(--view-background-color);
         box-shadow: 0 1px 5px rgba(0, 0, 0, .3);
         max-height: 70vh;
         margin-top: 2em;
diff --git a/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown.html b/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown.html
index 3f8d93e..46fe046 100644
--- a/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown.html
+++ b/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown.html
@@ -36,7 +36,7 @@
         width: 100%;
       }
       .dropdown-content {
-        background-color: #fff;
+        background-color: var(--view-background-color);
         box-shadow: 0 1px 5px rgba(0, 0, 0, .3);
       }
       gr-button {
@@ -75,7 +75,7 @@
       }
       li .itemAction:not(.disabled):hover {
         background-color: #6B82D6;
-        color: #fff;
+        color: var(--view-background-color);
       }
       li:focus,
       li.selected {
diff --git a/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label.html b/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label.html
index 8addfb6..6d3c864 100644
--- a/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label.html
+++ b/polygerrit-ui/app/elements/shared/gr-editable-label/gr-editable-label.html
@@ -55,7 +55,7 @@
         box-shadow: rgba(0, 0, 0, 0.3) 0 1px 3px;
       }
       .inputContainer {
-        background-color: #fff;
+        background-color: var(--view-background-color);
         padding: .8em;
         @apply --input-style;
       }
diff --git a/polygerrit-ui/app/elements/shared/gr-list-view/gr-list-view.html b/polygerrit-ui/app/elements/shared/gr-list-view/gr-list-view.html
index d295770..71999acaf 100644
--- a/polygerrit-ui/app/elements/shared/gr-list-view/gr-list-view.html
+++ b/polygerrit-ui/app/elements/shared/gr-list-view/gr-list-view.html
@@ -37,7 +37,7 @@
         display: none;
       }
       a {
-        color: var(--default-text-color);
+        color: var(--primary-text-color);
         text-decoration: none;
       }
       a:hover {
diff --git a/polygerrit-ui/app/elements/shared/gr-overlay/gr-overlay.html b/polygerrit-ui/app/elements/shared/gr-overlay/gr-overlay.html
index e9bfb6d..ea94086 100644
--- a/polygerrit-ui/app/elements/shared/gr-overlay/gr-overlay.html
+++ b/polygerrit-ui/app/elements/shared/gr-overlay/gr-overlay.html
@@ -23,7 +23,7 @@
   <template>
     <style include="shared-styles">
       :host {
-        background: #fff;
+        background: var(--view-background-color);
         box-shadow: rgba(0, 0, 0, 0.3) 0 1px 3px;
       }
 
diff --git a/polygerrit-ui/app/elements/shared/gr-page-nav/gr-page-nav.html b/polygerrit-ui/app/elements/shared/gr-page-nav/gr-page-nav.html
index 916f08d..3885497 100644
--- a/polygerrit-ui/app/elements/shared/gr-page-nav/gr-page-nav.html
+++ b/polygerrit-ui/app/elements/shared/gr-page-nav/gr-page-nav.html
@@ -22,7 +22,7 @@
   <template>
     <style include="shared-styles">
       #nav {
-        background-color: #f5f5f5;
+        background-color: var(--table-header-background-color);
         border: 1px solid var(--border-color);
         border-top: none;
         height: 100%;
diff --git a/polygerrit-ui/app/elements/shared/gr-tooltip/gr-tooltip.html b/polygerrit-ui/app/elements/shared/gr-tooltip/gr-tooltip.html
index 12a8f1c..ac9226c 100644
--- a/polygerrit-ui/app/elements/shared/gr-tooltip/gr-tooltip.html
+++ b/polygerrit-ui/app/elements/shared/gr-tooltip/gr-tooltip.html
@@ -27,7 +27,7 @@
 
         background-color: var(--tooltip-background-color, #333);
         box-shadow: 0 1px 3px rgba(0, 0, 0, .3);
-        color: #fff;
+        color: var(--view-background-color);
         font-size: var(--font-size-small);
         position: absolute;
         z-index: 1000;
diff --git a/polygerrit-ui/app/styles/app-theme.html b/polygerrit-ui/app/styles/app-theme.html
index ce9f8a1..a9c449e 100644
--- a/polygerrit-ui/app/styles/app-theme.html
+++ b/polygerrit-ui/app/styles/app-theme.html
@@ -27,8 +27,6 @@
 
   /* Following are not part of plugin API. */
   --selection-background-color: #f1f5fb;
-  --selection-border-color: #cadcfa;
-  --default-text-color: #000;
   --view-background-color: #fff;
   --default-horizontal-margin: 1rem;
   --font-family: 'Roboto', -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';
@@ -38,6 +36,7 @@
     transition: none;
   }
   --table-header-background-color: #fafafa;
+  --table-subheader-background-color: #eaeaea;
 
   /* Font sizes */
   --font-size-normal: 1rem;
diff --git a/polygerrit-ui/app/styles/gr-change-list-styles.html b/polygerrit-ui/app/styles/gr-change-list-styles.html
index 3daca76..3f6399f 100644
--- a/polygerrit-ui/app/styles/gr-change-list-styles.html
+++ b/polygerrit-ui/app/styles/gr-change-list-styles.html
@@ -27,7 +27,6 @@
       gr-change-list-item[selected],
       gr-change-list-item:focus {
         background-color: var(--selection-background-color);
-        border: 1px solid var(--selection-border-color);
       }
       .topHeader ~ gr-change-list-item:first-of-type,
       .topHeader + .groupHeader {
@@ -81,7 +80,7 @@
         top: 0;
       }
       .groupHeader {
-        background-color: #eaeaea;
+        background-color: var(--table-subheader-background-color);
       }
       .groupHeader a {
         color: var(--primary-text-color);
@@ -131,7 +130,7 @@
       .truncatedProject {
         display: none;
       }
-      @media only screen and (max-width: 90em) {
+      @media only screen and (max-width: 100em) {
         .assignee,
         .branch,
         .owner {
diff --git a/polygerrit-ui/app/styles/gr-page-nav-styles.html b/polygerrit-ui/app/styles/gr-page-nav-styles.html
index 8d8659e..b1b5149 100644
--- a/polygerrit-ui/app/styles/gr-page-nav-styles.html
+++ b/polygerrit-ui/app/styles/gr-page-nav-styles.html
@@ -49,7 +49,7 @@
         margin: .4em 0;
       }
       .navStyles .selected {
-        background-color: #fff;
+        background-color: var(--view-background-color);
         border-bottom: 1px dotted #808080;
         border-top: 1px dotted #808080;
         font-family: var(--font-family-bold);
diff --git a/polygerrit-ui/app/styles/gr-table-styles.html b/polygerrit-ui/app/styles/gr-table-styles.html
index 9964d02..b187c3b 100644
--- a/polygerrit-ui/app/styles/gr-table-styles.html
+++ b/polygerrit-ui/app/styles/gr-table-styles.html
@@ -43,7 +43,7 @@
         background-color: #eee;
       }
       .genericList a {
-        color: var(--default-text-color);
+        color: var(--primary-text-color);
         text-decoration: none;
       }
       .genericList a:hover {