Merge branch 'stable-2.15' into stable-2.16

* stable-2.15:
  Extend ServletModule instead of HttpPluginModule

Change-Id: I418271fde7d6d8699e1a92578c57180831b44646
diff --git a/WORKSPACE b/WORKSPACE
index fd849e0..4599fec 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -3,7 +3,7 @@
 load("//:bazlets.bzl", "load_bazlets")
 
 load_bazlets(
-    commit = "f4fcc606a6afa8ce27a013bcf62e495a5ec2505c",
+    commit = "5c1e201c6835e56a69a980c72206431e2a9d7d80",
     #local_path = "/home/<user>/projects/bazlets",
 )
 
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/AddSshKey.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/AddSshKey.java
index f6a18e0..64a024d 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/AddSshKey.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/AddSshKey.java
@@ -14,12 +14,12 @@
 
 package com.googlesource.gerrit.plugins.serviceuser;
 
+import com.google.gerrit.extensions.api.accounts.SshKeyInput;
 import com.google.gerrit.extensions.common.SshKeyInfo;
 import com.google.gerrit.extensions.restapi.AuthException;
 import com.google.gerrit.extensions.restapi.BadRequestException;
 import com.google.gerrit.extensions.restapi.Response;
 import com.google.gerrit.extensions.restapi.RestModifyView;
-import com.google.gerrit.server.account.AddSshKey.Input;
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
@@ -28,16 +28,16 @@
 import org.eclipse.jgit.errors.ConfigInvalidException;
 
 @Singleton
-class AddSshKey implements RestModifyView<ServiceUserResource, Input> {
-  private final Provider<com.google.gerrit.server.account.AddSshKey> addSshKey;
+class AddSshKey implements RestModifyView<ServiceUserResource, SshKeyInput> {
+  private final Provider<com.google.gerrit.server.restapi.account.AddSshKey> addSshKey;
 
   @Inject
-  AddSshKey(Provider<com.google.gerrit.server.account.AddSshKey> addSshKey) {
+  AddSshKey(Provider<com.google.gerrit.server.restapi.account.AddSshKey> addSshKey) {
     this.addSshKey = addSshKey;
   }
 
   @Override
-  public Response<SshKeyInfo> apply(ServiceUserResource rsrc, Input input)
+  public Response<SshKeyInfo> apply(ServiceUserResource rsrc, SshKeyInput input)
       throws AuthException, BadRequestException, OrmException, IOException, ConfigInvalidException {
     return addSshKey.get().apply(rsrc.getUser(), input);
   }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/CreateServiceUser.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/CreateServiceUser.java
index cadde7b..5b3ae51 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/CreateServiceUser.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/CreateServiceUser.java
@@ -17,42 +17,35 @@
 import com.google.common.base.Function;
 import com.google.common.base.Strings;
 import com.google.common.collect.Lists;
-import com.google.gerrit.common.TimeUtil;
 import com.google.gerrit.extensions.annotations.PluginName;
 import com.google.gerrit.extensions.annotations.RequiresCapability;
 import com.google.gerrit.extensions.api.accounts.AccountInput;
 import com.google.gerrit.extensions.common.AccountInfo;
 import com.google.gerrit.extensions.restapi.AuthException;
 import com.google.gerrit.extensions.restapi.BadRequestException;
+import com.google.gerrit.extensions.restapi.IdString;
 import com.google.gerrit.extensions.restapi.ResourceConflictException;
 import com.google.gerrit.extensions.restapi.Response;
-import com.google.gerrit.extensions.restapi.RestModifyView;
-import com.google.gerrit.extensions.restapi.TopLevelResource;
-import com.google.gerrit.extensions.restapi.UnprocessableEntityException;
+import com.google.gerrit.extensions.restapi.RestApiException;
+import com.google.gerrit.extensions.restapi.RestCollectionCreateView;
 import com.google.gerrit.reviewdb.client.Account;
-import com.google.gerrit.reviewdb.client.AccountGroup;
-import com.google.gerrit.reviewdb.client.AccountGroupMember;
-import com.google.gerrit.reviewdb.client.AccountGroupMemberAudit;
 import com.google.gerrit.reviewdb.client.Project;
-import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.CurrentUser;
 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.AccountLoader;
-import com.google.gerrit.server.account.CreateAccount;
-import com.google.gerrit.server.account.GroupCache;
 import com.google.gerrit.server.config.ConfigResource;
 import com.google.gerrit.server.config.PluginConfig;
 import com.google.gerrit.server.config.PluginConfigFactory;
-import com.google.gerrit.server.git.MetaDataUpdate;
-import com.google.gerrit.server.git.ProjectLevelConfig;
-import com.google.gerrit.server.group.InternalGroup;
+import com.google.gerrit.server.git.meta.MetaDataUpdate;
+import com.google.gerrit.server.permissions.PermissionBackendException;
 import com.google.gerrit.server.project.ProjectCache;
+import com.google.gerrit.server.project.ProjectLevelConfig;
+import com.google.gerrit.server.restapi.account.CreateAccount;
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
-import com.google.inject.assistedinject.Assisted;
+import com.google.inject.Singleton;
 import com.googlesource.gerrit.plugins.serviceuser.CreateServiceUser.Input;
 import com.googlesource.gerrit.plugins.serviceuser.GetServiceUser.ServiceUserInfo;
 import java.io.IOException;
@@ -60,21 +53,17 @@
 import java.text.SimpleDateFormat;
 import java.util.Arrays;
 import java.util.Calendar;
-import java.util.Collections;
 import java.util.Date;
 import java.util.List;
 import java.util.Locale;
-import java.util.Optional;
 import org.eclipse.jgit.errors.ConfigInvalidException;
 import org.eclipse.jgit.lib.Config;
 import org.eclipse.jgit.lib.PersonIdent;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 @RequiresCapability(CreateServiceUserCapability.ID)
-class CreateServiceUser implements RestModifyView<ConfigResource, Input> {
-  private static final Logger log = LoggerFactory.getLogger(CreateServiceUser.class);
-
+@Singleton
+class CreateServiceUser
+    implements RestCollectionCreateView<ConfigResource, ServiceUserResource, Input> {
   public static final String USER = "user";
   public static final String KEY_CREATED_BY = "createdBy";
   public static final String KEY_CREATED_AT = "createdAt";
@@ -87,17 +76,8 @@
     String email;
   }
 
-  interface Factory {
-    CreateServiceUser create(String username);
-  }
-
   private final PluginConfig cfg;
-  private final CreateAccount.Factory createAccountFactory;
-  private final GroupCache groupCache;
-  private final AccountCache accountCache;
-  private final Provider<IdentifiedUser> currentUser;
-  private final Provider<ReviewDb> db;
-  private final String username;
+  private final CreateAccount createAccount;
   private final List<String> blockedNames;
   private final Provider<CurrentUser> userProvider;
   private final MetaDataUpdate.User metaDataUpdateFactory;
@@ -111,25 +91,15 @@
   CreateServiceUser(
       PluginConfigFactory cfgFactory,
       @PluginName String pluginName,
-      CreateAccount.Factory createAccountFactory,
-      GroupCache groupCache,
-      AccountCache accountCache,
-      Provider<IdentifiedUser> currentUser,
-      Provider<ReviewDb> db,
+      CreateAccount createAccount,
       Provider<CurrentUser> userProvider,
       @GerritPersonIdent PersonIdent gerritIdent,
       MetaDataUpdate.User metaDataUpdateFactory,
       ProjectCache projectCache,
-      @Assisted String username,
       Provider<GetConfig> getConfig,
       AccountLoader.Factory accountLoader) {
     this.cfg = cfgFactory.getFromGerritConfig(pluginName);
-    this.createAccountFactory = createAccountFactory;
-    this.groupCache = groupCache;
-    this.accountCache = accountCache;
-    this.currentUser = currentUser;
-    this.db = db;
-    this.username = username;
+    this.createAccount = createAccount;
     this.blockedNames =
         Lists.transform(
             Arrays.asList(cfg.getStringList("block")),
@@ -151,9 +121,10 @@
   }
 
   @Override
-  public Response<ServiceUserInfo> apply(ConfigResource resource, Input input)
-      throws AuthException, BadRequestException, ResourceConflictException,
-          UnprocessableEntityException, OrmException, IOException, ConfigInvalidException {
+  public Response<ServiceUserInfo> apply(
+      ConfigResource parentResource, IdString id, CreateServiceUser.Input input)
+      throws RestApiException, OrmException, IOException, ConfigInvalidException,
+          PermissionBackendException {
     CurrentUser user = userProvider.get();
     if (user == null || !user.isIdentifiedUser()) {
       throw new AuthException("authentication required");
@@ -162,6 +133,7 @@
     if (input == null) {
       input = new Input();
     }
+    String username = id.get();
     if (input.username != null && !username.equals(input.username)) {
       throw new BadRequestException("username must match URL");
     }
@@ -183,12 +155,10 @@
     }
 
     AccountInput in = new ServiceUserInput(username, input.email, input.sshKey);
-    Response<AccountInfo> response =
-        createAccountFactory.create(username).apply(TopLevelResource.INSTANCE, in);
+    in.groups = Arrays.asList(cfg.getStringList("group"));
+    Response<AccountInfo> response = createAccount.apply(IdString.fromDecoded(username), in);
 
-    addToGroups(new Account.Id(response.value()._accountId), cfg.getStringList("group"));
-
-    String creator = user.getUserName();
+    String creator = user.getUserName().get();
     Account.Id creatorId = ((IdentifiedUser) user).getAccountId();
     String creationDate = rfc2822DateFormatter.format(new Date());
 
@@ -210,30 +180,4 @@
     info.createdAt = creationDate;
     return Response.created(info);
   }
-
-  private void addToGroups(Account.Id accountId, String[] groupNames)
-      throws OrmException, IOException {
-    for (String groupName : groupNames) {
-      Optional<InternalGroup> group = groupCache.get(new AccountGroup.NameKey(groupName));
-      if (group.isPresent()) {
-        AccountGroupMember m =
-            new AccountGroupMember(new AccountGroupMember.Key(accountId, group.get().getId()));
-        db.get()
-            .accountGroupMembersAudit()
-            .insert(
-                Collections.singleton(
-                    new AccountGroupMemberAudit(
-                        m, currentUser.get().getAccountId(), TimeUtil.nowTs())));
-        db.get().accountGroupMembers().insert(Collections.singleton(m));
-      } else {
-        log.error(
-            String.format(
-                "Could not add new service user %s to group %s: group not found",
-                username, groupName));
-      }
-    }
-    if (groupNames.length > 0) {
-      accountCache.evict(accountId);
-    }
-  }
 }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/CreateServiceUserCommand.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/CreateServiceUserCommand.java
index 1b6d925..bebd520 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/CreateServiceUserCommand.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/CreateServiceUserCommand.java
@@ -17,8 +17,10 @@
 import static java.nio.charset.StandardCharsets.UTF_8;
 
 import com.google.gerrit.extensions.annotations.RequiresCapability;
+import com.google.gerrit.extensions.restapi.IdString;
 import com.google.gerrit.extensions.restapi.RestApiException;
 import com.google.gerrit.server.config.ConfigResource;
+import com.google.gerrit.server.permissions.PermissionBackendException;
 import com.google.gerrit.sshd.CommandMetaData;
 import com.google.gerrit.sshd.SshCommand;
 import com.google.gwtorm.server.OrmException;
@@ -44,15 +46,18 @@
       usage = "public key for SSH authentication")
   private String sshKey;
 
-  @Inject private CreateServiceUser.Factory createServiceUser;
+  @Inject private CreateServiceUser createServiceUser;
 
   @Override
-  protected void run() throws OrmException, IOException, UnloggedFailure, ConfigInvalidException {
+  protected void run()
+      throws OrmException, IOException, UnloggedFailure, ConfigInvalidException,
+          PermissionBackendException {
     CreateServiceUser.Input input = new CreateServiceUser.Input();
     input.sshKey = readSshKey();
+    input.username = username;
 
     try {
-      createServiceUser.create(username).apply(new ConfigResource(), input);
+      createServiceUser.apply(new ConfigResource(), IdString.fromDecoded(username), input);
     } catch (RestApiException e) {
       throw die(e.getMessage());
     }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/CreateServiceUserNotes.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/CreateServiceUserNotes.java
index 31333fd..c0e4c20 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/CreateServiceUserNotes.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/CreateServiceUserNotes.java
@@ -20,10 +20,13 @@
 import static org.eclipse.jgit.lib.Constants.OBJ_COMMIT;
 
 import com.google.gerrit.extensions.common.AccountInfo;
+import com.google.gerrit.extensions.restapi.MethodNotAllowedException;
+import com.google.gerrit.extensions.restapi.RestApiException;
 import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.server.GerritPersonIdent;
 import com.google.gerrit.server.config.AnonymousCowardName;
 import com.google.gerrit.server.git.NotesBranchUtil;
+import com.google.gerrit.server.permissions.PermissionBackendException;
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.assistedinject.Assisted;
@@ -80,7 +83,8 @@
   }
 
   void createNotes(String branch, ObjectId oldObjectId, ObjectId newObjectId)
-      throws IOException, OrmException, ConfigInvalidException {
+      throws IOException, OrmException, ConfigInvalidException, PermissionBackendException,
+          RestApiException {
     if (ObjectId.zeroId().equals(newObjectId)) {
       return;
     }
@@ -152,13 +156,13 @@
   }
 
   private ObjectId createNoteContent(String branch, ServiceUserInfo serviceUser)
-      throws IOException, OrmException {
+      throws IOException, OrmException, MethodNotAllowedException, PermissionBackendException {
     return getInserter()
         .insert(Constants.OBJ_BLOB, createServiceUserNote(branch, serviceUser).getBytes(UTF_8));
   }
 
   private String createServiceUserNote(String branch, ServiceUserInfo serviceUser)
-      throws OrmException {
+      throws OrmException, MethodNotAllowedException, PermissionBackendException {
     HeaderFormatter fmt = new HeaderFormatter(gerritServerIdent.getTimeZone(), anonymousCowardName);
     fmt.appendDate();
     fmt.append("Project", project.get());
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/DeleteActive.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/DeleteActive.java
index 58532fd..5393e03 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/DeleteActive.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/DeleteActive.java
@@ -14,10 +14,10 @@
 
 package com.googlesource.gerrit.plugins.serviceuser;
 
+import com.google.gerrit.extensions.common.Input;
 import com.google.gerrit.extensions.restapi.Response;
 import com.google.gerrit.extensions.restapi.RestApiException;
 import com.google.gerrit.extensions.restapi.RestModifyView;
-import com.google.gerrit.server.account.DeleteActive.Input;
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
@@ -27,10 +27,10 @@
 
 @Singleton
 class DeleteActive implements RestModifyView<ServiceUserResource, Input> {
-  private final Provider<com.google.gerrit.server.account.DeleteActive> deleteActive;
+  private final Provider<com.google.gerrit.server.restapi.account.DeleteActive> deleteActive;
 
   @Inject
-  DeleteActive(Provider<com.google.gerrit.server.account.DeleteActive> deleteActive) {
+  DeleteActive(Provider<com.google.gerrit.server.restapi.account.DeleteActive> deleteActive) {
     this.deleteActive = deleteActive;
   }
 
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/DeleteSshKey.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/DeleteSshKey.java
index 09031bc..9092e74 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/DeleteSshKey.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/DeleteSshKey.java
@@ -14,11 +14,11 @@
 
 package com.googlesource.gerrit.plugins.serviceuser;
 
+import com.google.gerrit.extensions.common.Input;
 import com.google.gerrit.extensions.restapi.AuthException;
 import com.google.gerrit.extensions.restapi.Response;
 import com.google.gerrit.extensions.restapi.RestModifyView;
 import com.google.gerrit.server.account.AccountResource;
-import com.google.gerrit.server.account.DeleteSshKey.Input;
 import com.google.gerrit.server.permissions.PermissionBackendException;
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
@@ -30,10 +30,10 @@
 
 @Singleton
 class DeleteSshKey implements RestModifyView<ServiceUserResource.SshKey, Input> {
-  private final Provider<com.google.gerrit.server.account.DeleteSshKey> deleteSshKey;
+  private final Provider<com.google.gerrit.server.restapi.account.DeleteSshKey> deleteSshKey;
 
   @Inject
-  DeleteSshKey(Provider<com.google.gerrit.server.account.DeleteSshKey> deleteSshKey) {
+  DeleteSshKey(Provider<com.google.gerrit.server.restapi.account.DeleteSshKey> deleteSshKey) {
     this.deleteSshKey = deleteSshKey;
   }
 
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/GetActive.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/GetActive.java
index d279cc7..3939119 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/GetActive.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/GetActive.java
@@ -21,10 +21,10 @@
 
 @Singleton
 class GetActive implements RestReadView<ServiceUserResource> {
-  private final Provider<com.google.gerrit.server.account.GetActive> getActive;
+  private final Provider<com.google.gerrit.server.restapi.account.GetActive> getActive;
 
   @Inject
-  GetActive(Provider<com.google.gerrit.server.account.GetActive> getActive) {
+  GetActive(Provider<com.google.gerrit.server.restapi.account.GetActive> getActive) {
     this.getActive = getActive;
   }
 
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/GetConfig.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/GetConfig.java
index cd30b45..28d7be3 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/GetConfig.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/GetConfig.java
@@ -23,9 +23,10 @@
 import com.google.gerrit.server.config.ConfigResource;
 import com.google.gerrit.server.config.PluginConfig;
 import com.google.gerrit.server.config.PluginConfigFactory;
-import com.google.gerrit.server.group.GroupJson;
 import com.google.gerrit.server.group.InternalGroup;
 import com.google.gerrit.server.group.InternalGroupDescription;
+import com.google.gerrit.server.permissions.PermissionBackendException;
+import com.google.gerrit.server.restapi.group.GroupJson;
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
@@ -59,7 +60,7 @@
   }
 
   @Override
-  public ConfigInfo apply(ConfigResource rsrc) throws OrmException {
+  public ConfigInfo apply(ConfigResource rsrc) throws OrmException, PermissionBackendException {
     PluginConfig cfg = cfgFactory.getFromGerritConfig(pluginName);
     ConfigInfo info = new ConfigInfo();
     info.info = Strings.emptyToNull(cfg.getString("infoMessage"));
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/GetName.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/GetName.java
index a1a1db4..6ed1af6 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/GetName.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/GetName.java
@@ -21,10 +21,10 @@
 
 @Singleton
 class GetName implements RestReadView<ServiceUserResource> {
-  private final Provider<com.google.gerrit.server.account.GetName> getName;
+  private final Provider<com.google.gerrit.server.restapi.account.GetName> getName;
 
   @Inject
-  GetName(Provider<com.google.gerrit.server.account.GetName> getName) {
+  GetName(Provider<com.google.gerrit.server.restapi.account.GetName> getName) {
     this.getName = getName;
   }
 
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/GetOwner.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/GetOwner.java
index 8eb5031..47783f5 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/GetOwner.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/GetOwner.java
@@ -20,13 +20,16 @@
 import com.google.gerrit.common.data.GroupDescription;
 import com.google.gerrit.extensions.annotations.PluginName;
 import com.google.gerrit.extensions.common.GroupInfo;
-import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
+import com.google.gerrit.extensions.restapi.IdString;
 import com.google.gerrit.extensions.restapi.Response;
+import com.google.gerrit.extensions.restapi.RestApiException;
 import com.google.gerrit.extensions.restapi.RestReadView;
-import com.google.gerrit.server.git.ProjectLevelConfig;
-import com.google.gerrit.server.group.GroupJson;
-import com.google.gerrit.server.group.GroupsCollection;
+import com.google.gerrit.extensions.restapi.TopLevelResource;
+import com.google.gerrit.server.permissions.PermissionBackendException;
 import com.google.gerrit.server.project.ProjectCache;
+import com.google.gerrit.server.project.ProjectLevelConfig;
+import com.google.gerrit.server.restapi.group.GroupJson;
+import com.google.gerrit.server.restapi.group.GroupsCollection;
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
@@ -52,11 +55,12 @@
 
   @Override
   public Response<GroupInfo> apply(ServiceUserResource rsrc)
-      throws ResourceNotFoundException, OrmException {
+      throws RestApiException, OrmException, PermissionBackendException {
     ProjectLevelConfig storage = projectCache.getAllProjects().getConfig(pluginName + ".db");
-    String owner = storage.get().getString(USER, rsrc.getUser().getUserName(), KEY_OWNER);
+    String owner = storage.get().getString(USER, rsrc.getUser().getUserName().get(), KEY_OWNER);
     if (owner != null) {
-      GroupDescription.Basic group = groups.parseId(owner);
+      GroupDescription.Basic group =
+          groups.parse(TopLevelResource.INSTANCE, IdString.fromDecoded(owner)).getGroup();
       return Response.<GroupInfo>ok(json.format(group));
     }
     return Response.none();
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/GetServiceUser.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/GetServiceUser.java
index 5ce479e..a4ad837 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/GetServiceUser.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/GetServiceUser.java
@@ -24,12 +24,14 @@
 import com.google.gerrit.extensions.common.GroupInfo;
 import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
 import com.google.gerrit.extensions.restapi.Response;
+import com.google.gerrit.extensions.restapi.RestApiException;
 import com.google.gerrit.extensions.restapi.RestReadView;
 import com.google.gerrit.reviewdb.client.Account;
 import com.google.gerrit.server.account.AccountLoader;
-import com.google.gerrit.server.account.GetAccount;
-import com.google.gerrit.server.git.ProjectLevelConfig;
+import com.google.gerrit.server.permissions.PermissionBackendException;
 import com.google.gerrit.server.project.ProjectCache;
+import com.google.gerrit.server.project.ProjectLevelConfig;
+import com.google.gerrit.server.restapi.account.GetAccount;
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
@@ -60,9 +62,9 @@
 
   @Override
   public ServiceUserInfo apply(ServiceUserResource rsrc)
-      throws ResourceNotFoundException, OrmException {
+      throws RestApiException, OrmException, PermissionBackendException {
     ProjectLevelConfig storage = projectCache.getAllProjects().getConfig(pluginName + ".db");
-    String username = rsrc.getUser().getUserName();
+    String username = rsrc.getUser().getUserName().get();
     Config db = storage.get();
     if (!db.getSubsections(USER).contains(username)) {
       throw new ResourceNotFoundException(username);
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/GetSshKey.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/GetSshKey.java
index baab715..00a0968 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/GetSshKey.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/GetSshKey.java
@@ -23,10 +23,10 @@
 
 @Singleton
 class GetSshKey implements RestReadView<ServiceUserResource.SshKey> {
-  private final Provider<com.google.gerrit.server.account.GetSshKey> getSshKey;
+  private final Provider<com.google.gerrit.server.restapi.account.GetSshKey> getSshKey;
 
   @Inject
-  GetSshKey(Provider<com.google.gerrit.server.account.GetSshKey> getSshKey) {
+  GetSshKey(Provider<com.google.gerrit.server.restapi.account.GetSshKey> getSshKey) {
     this.getSshKey = getSshKey;
   }
 
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/GetSshKeys.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/GetSshKeys.java
index be08a69..92a9430 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/GetSshKeys.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/GetSshKeys.java
@@ -28,10 +28,10 @@
 
 @Singleton
 class GetSshKeys implements RestReadView<ServiceUserResource> {
-  private final Provider<com.google.gerrit.server.account.GetSshKeys> getSshKeys;
+  private final Provider<com.google.gerrit.server.restapi.account.GetSshKeys> getSshKeys;
 
   @Inject
-  GetSshKeys(Provider<com.google.gerrit.server.account.GetSshKeys> getSshKeys) {
+  GetSshKeys(Provider<com.google.gerrit.server.restapi.account.GetSshKeys> getSshKeys) {
     this.getSshKeys = getSshKeys;
   }
 
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/ListServiceUsers.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/ListServiceUsers.java
index 3b696bc..cf6ea40 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/ListServiceUsers.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/ListServiceUsers.java
@@ -21,14 +21,15 @@
 import com.google.gerrit.extensions.restapi.AuthException;
 import com.google.gerrit.extensions.restapi.IdString;
 import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
+import com.google.gerrit.extensions.restapi.RestApiException;
 import com.google.gerrit.extensions.restapi.RestReadView;
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.account.AccountCache;
 import com.google.gerrit.server.account.AccountState;
 import com.google.gerrit.server.config.ConfigResource;
-import com.google.gerrit.server.git.ProjectLevelConfig;
 import com.google.gerrit.server.permissions.PermissionBackendException;
 import com.google.gerrit.server.project.ProjectCache;
+import com.google.gerrit.server.project.ProjectLevelConfig;
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
@@ -36,6 +37,7 @@
 import com.googlesource.gerrit.plugins.serviceuser.GetServiceUser.ServiceUserInfo;
 import java.io.IOException;
 import java.util.Map;
+import java.util.Optional;
 import org.eclipse.jgit.errors.ConfigInvalidException;
 import org.eclipse.jgit.lib.Config;
 
@@ -66,7 +68,7 @@
 
   @Override
   public Map<String, ServiceUserInfo> apply(ConfigResource rscr)
-      throws OrmException, IOException, AuthException, PermissionBackendException,
+      throws OrmException, IOException, RestApiException, PermissionBackendException,
           ConfigInvalidException {
     ProjectLevelConfig storage = projectCache.getAllProjects().getConfig(pluginName + ".db");
     CurrentUser user = userProvider.get();
@@ -77,8 +79,8 @@
     Map<String, ServiceUserInfo> accounts = Maps.newTreeMap();
     Config db = storage.get();
     for (String username : db.getSubsections(USER)) {
-      AccountState account = accountCache.getByUsername(username);
-      if (account != null) {
+      Optional<AccountState> account = accountCache.getByUsername(username);
+      if (account.isPresent()) {
         ServiceUserInfo info;
         try {
           ServiceUserResource serviceUserResource =
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/Module.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/Module.java
index 97cda35..9ceba80 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/Module.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/Module.java
@@ -48,8 +48,8 @@
             DynamicMap.mapOf(binder(), SERVICE_USER_SSH_KEY_KIND);
             bind(ServiceUserCollection.class);
             child(CONFIG_KIND, "serviceusers").to(ServiceUserCollection.class);
+            create(SERVICE_USER_KIND).to(CreateServiceUser.class);
             get(SERVICE_USER_KIND).to(GetServiceUser.class);
-            install(new FactoryModuleBuilder().build(CreateServiceUser.Factory.class));
             get(CONFIG_KIND, "config").to(GetConfig.class);
             put(CONFIG_KIND, "config").to(PutConfig.class);
             child(SERVICE_USER_KIND, "sshkeys").to(SshKeys.class);
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/PutActive.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/PutActive.java
index 517ccbc..1282935 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/PutActive.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/PutActive.java
@@ -14,10 +14,10 @@
 
 package com.googlesource.gerrit.plugins.serviceuser;
 
-import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
+import com.google.gerrit.extensions.common.Input;
 import com.google.gerrit.extensions.restapi.Response;
+import com.google.gerrit.extensions.restapi.RestApiException;
 import com.google.gerrit.extensions.restapi.RestModifyView;
-import com.google.gerrit.server.account.PutActive.Input;
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
@@ -27,16 +27,16 @@
 
 @Singleton
 class PutActive implements RestModifyView<ServiceUserResource, Input> {
-  private final Provider<com.google.gerrit.server.account.PutActive> putActive;
+  private final Provider<com.google.gerrit.server.restapi.account.PutActive> putActive;
 
   @Inject
-  PutActive(Provider<com.google.gerrit.server.account.PutActive> putActive) {
+  PutActive(Provider<com.google.gerrit.server.restapi.account.PutActive> putActive) {
     this.putActive = putActive;
   }
 
   @Override
   public Response<String> apply(ServiceUserResource rsrc, Input input)
-      throws ResourceNotFoundException, OrmException, IOException, ConfigInvalidException {
+      throws OrmException, IOException, ConfigInvalidException, RestApiException {
     return putActive.get().apply(rsrc, input);
   }
 }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/PutEmail.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/PutEmail.java
index 8ea158c..135e34f 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/PutEmail.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/PutEmail.java
@@ -19,21 +19,18 @@
 import com.google.common.base.Strings;
 import com.google.gerrit.common.errors.EmailException;
 import com.google.gerrit.extensions.api.accounts.EmailInput;
-import com.google.gerrit.extensions.restapi.AuthException;
-import com.google.gerrit.extensions.restapi.BadRequestException;
 import com.google.gerrit.extensions.restapi.DefaultInput;
-import com.google.gerrit.extensions.restapi.MethodNotAllowedException;
-import com.google.gerrit.extensions.restapi.ResourceConflictException;
-import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
+import com.google.gerrit.extensions.restapi.IdString;
 import com.google.gerrit.extensions.restapi.Response;
+import com.google.gerrit.extensions.restapi.RestApiException;
 import com.google.gerrit.extensions.restapi.RestModifyView;
 import com.google.gerrit.server.CurrentUser;
-import com.google.gerrit.server.account.CreateEmail;
-import com.google.gerrit.server.account.DeleteEmail;
-import com.google.gerrit.server.account.PutPreferred;
 import com.google.gerrit.server.config.ConfigResource;
 import com.google.gerrit.server.permissions.PermissionBackend;
 import com.google.gerrit.server.permissions.PermissionBackendException;
+import com.google.gerrit.server.restapi.account.CreateEmail;
+import com.google.gerrit.server.restapi.account.DeleteEmail;
+import com.google.gerrit.server.restapi.account.PutPreferred;
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
@@ -50,7 +47,7 @@
 
   private final Provider<GetConfig> getConfig;
   private final Provider<GetEmail> getEmail;
-  private final Provider<CreateEmail.Factory> createEmailFactory;
+  private final Provider<CreateEmail> createEmail;
   private final Provider<DeleteEmail> deleteEmail;
   private final Provider<PutPreferred> putPreferred;
   private final Provider<CurrentUser> self;
@@ -60,14 +57,14 @@
   PutEmail(
       Provider<GetConfig> getConfig,
       Provider<GetEmail> getEmail,
-      Provider<CreateEmail.Factory> createEmailFactory,
+      Provider<CreateEmail> createEmail,
       Provider<DeleteEmail> deleteEmail,
       Provider<PutPreferred> putPreferred,
       Provider<CurrentUser> self,
       PermissionBackend permissionBackend) {
     this.getConfig = getConfig;
     this.getEmail = getEmail;
-    this.createEmailFactory = createEmailFactory;
+    this.createEmail = createEmail;
     this.deleteEmail = deleteEmail;
     this.putPreferred = putPreferred;
     this.self = self;
@@ -76,12 +73,11 @@
 
   @Override
   public Response<?> apply(ServiceUserResource rsrc, Input input)
-      throws AuthException, ResourceNotFoundException, ResourceConflictException,
-          MethodNotAllowedException, OrmException, BadRequestException, ConfigInvalidException,
-          EmailException, IOException, PermissionBackendException {
+      throws OrmException, ConfigInvalidException, EmailException, IOException,
+          PermissionBackendException, RestApiException {
     Boolean emailAllowed = getConfig.get().apply(new ConfigResource()).allowEmail;
     if ((emailAllowed == null || !emailAllowed)) {
-      permissionBackend.user(self).check(ADMINISTRATE_SERVER);
+      permissionBackend.user(self.get()).check(ADMINISTRATE_SERVER);
     }
 
     String email = getEmail.get().apply(rsrc);
@@ -99,7 +95,7 @@
       EmailInput in = new EmailInput();
       in.email = input.email;
       in.noConfirmation = true;
-      createEmailFactory.get().create(input.email).apply(rsrc.getUser(), in);
+      createEmail.get().apply(rsrc.getUser(), IdString.fromDecoded(email), in);
       putPreferred.get().apply(rsrc.getUser(), input.email);
       return Response.ok(input.email);
     }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/PutHttpPassword.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/PutHttpPassword.java
index a920f62..1a6be4e 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/PutHttpPassword.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/PutHttpPassword.java
@@ -55,14 +55,14 @@
   }
 
   private final Provider<GetConfig> getConfig;
-  private final com.google.gerrit.server.account.PutHttpPassword putHttpPassword;
+  private final com.google.gerrit.server.restapi.account.PutHttpPassword putHttpPassword;
   private final Provider<CurrentUser> self;
   private final PermissionBackend permissionBackend;
 
   @Inject
   PutHttpPassword(
       Provider<GetConfig> getConfig,
-      com.google.gerrit.server.account.PutHttpPassword putHttpPassword,
+      com.google.gerrit.server.restapi.account.PutHttpPassword putHttpPassword,
       Provider<CurrentUser> self,
       PermissionBackend permissionBackend) {
     this.getConfig = getConfig;
@@ -83,10 +83,10 @@
     Boolean httpPasswordAllowed = getConfig.get().apply(new ConfigResource()).allowHttpPassword;
     if (input.generate || input.httpPassword == null) {
       if ((httpPasswordAllowed == null || !httpPasswordAllowed)) {
-        permissionBackend.user(self).check(ADMINISTRATE_SERVER);
+        permissionBackend.user(self.get()).check(ADMINISTRATE_SERVER);
       }
     } else {
-      permissionBackend.user(self).check(ADMINISTRATE_SERVER);
+      permissionBackend.user(self.get()).check(ADMINISTRATE_SERVER);
     }
 
     String newPassword = input.generate ? generate() : input.httpPassword;
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/PutName.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/PutName.java
index 4cfca2c..4bcdd6a 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/PutName.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/PutName.java
@@ -14,11 +14,11 @@
 
 package com.googlesource.gerrit.plugins.serviceuser;
 
+import com.google.gerrit.extensions.common.NameInput;
 import com.google.gerrit.extensions.restapi.MethodNotAllowedException;
 import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
 import com.google.gerrit.extensions.restapi.Response;
 import com.google.gerrit.extensions.restapi.RestModifyView;
-import com.google.gerrit.server.account.PutName.Input;
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
@@ -27,16 +27,16 @@
 import org.eclipse.jgit.errors.ConfigInvalidException;
 
 @Singleton
-class PutName implements RestModifyView<ServiceUserResource, Input> {
-  private Provider<com.google.gerrit.server.account.PutName> putName;
+class PutName implements RestModifyView<ServiceUserResource, NameInput> {
+  private Provider<com.google.gerrit.server.restapi.account.PutName> putName;
 
   @Inject
-  PutName(Provider<com.google.gerrit.server.account.PutName> putName) {
+  PutName(Provider<com.google.gerrit.server.restapi.account.PutName> putName) {
     this.putName = putName;
   }
 
   @Override
-  public Response<String> apply(ServiceUserResource rsrc, Input input)
+  public Response<String> apply(ServiceUserResource rsrc, NameInput input)
       throws MethodNotAllowedException, ResourceNotFoundException, OrmException, IOException,
           ConfigInvalidException {
     return putName.get().apply(rsrc.getUser(), input);
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/PutOwner.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/PutOwner.java
index 67be740..37bbf17 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/PutOwner.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/PutOwner.java
@@ -22,31 +22,30 @@
 import com.google.gerrit.common.data.GroupDescription;
 import com.google.gerrit.extensions.annotations.PluginName;
 import com.google.gerrit.extensions.common.GroupInfo;
-import com.google.gerrit.extensions.restapi.AuthException;
 import com.google.gerrit.extensions.restapi.DefaultInput;
+import com.google.gerrit.extensions.restapi.IdString;
 import com.google.gerrit.extensions.restapi.MethodNotAllowedException;
-import com.google.gerrit.extensions.restapi.ResourceConflictException;
 import com.google.gerrit.extensions.restapi.Response;
+import com.google.gerrit.extensions.restapi.RestApiException;
 import com.google.gerrit.extensions.restapi.RestModifyView;
-import com.google.gerrit.extensions.restapi.UnprocessableEntityException;
+import com.google.gerrit.extensions.restapi.TopLevelResource;
 import com.google.gerrit.reviewdb.client.AccountGroup;
 import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.config.ConfigResource;
-import com.google.gerrit.server.git.MetaDataUpdate;
-import com.google.gerrit.server.git.ProjectLevelConfig;
-import com.google.gerrit.server.group.GroupJson;
-import com.google.gerrit.server.group.GroupsCollection;
+import com.google.gerrit.server.git.meta.MetaDataUpdate;
 import com.google.gerrit.server.permissions.PermissionBackend;
 import com.google.gerrit.server.permissions.PermissionBackendException;
 import com.google.gerrit.server.project.ProjectCache;
+import com.google.gerrit.server.project.ProjectLevelConfig;
+import com.google.gerrit.server.restapi.group.GroupJson;
+import com.google.gerrit.server.restapi.group.GroupsCollection;
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 import com.google.inject.Singleton;
 import com.googlesource.gerrit.plugins.serviceuser.PutOwner.Input;
 import java.io.IOException;
-import org.eclipse.jgit.errors.RepositoryNotFoundException;
 import org.eclipse.jgit.lib.Config;
 
 @Singleton
@@ -88,29 +87,27 @@
 
   @Override
   public Response<GroupInfo> apply(ServiceUserResource rsrc, Input input)
-      throws UnprocessableEntityException, RepositoryNotFoundException, MethodNotAllowedException,
-          IOException, OrmException, ResourceConflictException, AuthException,
-          PermissionBackendException {
+      throws RestApiException, IOException, OrmException, PermissionBackendException {
     ProjectLevelConfig storage = projectCache.getAllProjects().getConfig(pluginName + ".db");
     Boolean ownerAllowed = getConfig.get().apply(new ConfigResource()).allowOwner;
     if ((ownerAllowed == null || !ownerAllowed)) {
-      permissionBackend.user(self).check(ADMINISTRATE_SERVER);
+      permissionBackend.user(self.get()).check(ADMINISTRATE_SERVER);
     }
 
     if (input == null) {
       input = new Input();
     }
     Config db = storage.get();
-    String oldGroup = db.getString(USER, rsrc.getUser().getUserName(), KEY_OWNER);
+    String oldGroup = db.getString(USER, rsrc.getUser().getUserName().get(), KEY_OWNER);
     GroupDescription.Basic group = null;
     if (Strings.isNullOrEmpty(input.group)) {
-      db.unset(USER, rsrc.getUser().getUserName(), KEY_OWNER);
+      db.unset(USER, rsrc.getUser().getUserName().get(), KEY_OWNER);
     } else {
-      group = groups.parse(input.group);
+      group = groups.parse(TopLevelResource.INSTANCE, IdString.fromDecoded(input.group)).getGroup();
       if (!AccountGroup.isInternalGroup(group.getGroupUUID())) {
         throw new MethodNotAllowedException();
       }
-      db.setString(USER, rsrc.getUser().getUserName(), KEY_OWNER, group.getGroupUUID().get());
+      db.setString(USER, rsrc.getUser().getUserName().get(), KEY_OWNER, group.getGroupUUID().get());
     }
     MetaDataUpdate md = metaDataUpdateFactory.create(allProjects);
     md.setMessage("Set owner for service user '" + rsrc.getUser().getUserName() + "'\n");
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/RefUpdateListener.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/RefUpdateListener.java
index bcf4c6b..69512c5 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/RefUpdateListener.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/RefUpdateListener.java
@@ -16,12 +16,14 @@
 
 import com.google.gerrit.extensions.annotations.PluginName;
 import com.google.gerrit.extensions.events.GitReferenceUpdatedListener;
+import com.google.gerrit.extensions.restapi.RestApiException;
 import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.server.config.PluginConfig;
 import com.google.gerrit.server.config.PluginConfigFactory;
 import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.gerrit.server.git.ProjectRunnable;
 import com.google.gerrit.server.git.WorkQueue;
+import com.google.gerrit.server.permissions.PermissionBackendException;
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
@@ -106,7 +108,11 @@
           ObjectId.fromString(e.getOldObjectId()),
           ObjectId.fromString(e.getNewObjectId()));
       crn.commitNotes();
-    } catch (IOException | OrmException | ConfigInvalidException x) {
+    } catch (IOException
+        | OrmException
+        | ConfigInvalidException
+        | PermissionBackendException
+        | RestApiException x) {
       log.error(x.getMessage(), x);
     }
   }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/ServiceUserCollection.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/ServiceUserCollection.java
index f449391..729282c 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/ServiceUserCollection.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/ServiceUserCollection.java
@@ -22,23 +22,22 @@
 import com.google.gerrit.common.data.GroupDescription;
 import com.google.gerrit.extensions.annotations.PluginName;
 import com.google.gerrit.extensions.registration.DynamicMap;
-import com.google.gerrit.extensions.restapi.AcceptsCreate;
 import com.google.gerrit.extensions.restapi.AuthException;
 import com.google.gerrit.extensions.restapi.ChildCollection;
 import com.google.gerrit.extensions.restapi.IdString;
 import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
 import com.google.gerrit.extensions.restapi.RestView;
-import com.google.gerrit.extensions.restapi.UnprocessableEntityException;
+import com.google.gerrit.extensions.restapi.TopLevelResource;
 import com.google.gerrit.reviewdb.client.Account;
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.IdentifiedUser;
-import com.google.gerrit.server.account.AccountsCollection;
 import com.google.gerrit.server.config.ConfigResource;
-import com.google.gerrit.server.git.ProjectLevelConfig;
-import com.google.gerrit.server.group.GroupsCollection;
 import com.google.gerrit.server.permissions.PermissionBackend;
 import com.google.gerrit.server.permissions.PermissionBackendException;
 import com.google.gerrit.server.project.ProjectCache;
+import com.google.gerrit.server.project.ProjectLevelConfig;
+import com.google.gerrit.server.restapi.account.AccountsCollection;
+import com.google.gerrit.server.restapi.group.GroupsCollection;
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
@@ -47,11 +46,9 @@
 import org.eclipse.jgit.errors.ConfigInvalidException;
 
 @Singleton
-class ServiceUserCollection
-    implements ChildCollection<ConfigResource, ServiceUserResource>, AcceptsCreate<ConfigResource> {
+class ServiceUserCollection implements ChildCollection<ConfigResource, ServiceUserResource> {
 
   private final DynamicMap<RestView<ServiceUserResource>> views;
-  private final CreateServiceUser.Factory createServiceUserFactory;
   private final Provider<ListServiceUsers> list;
   private final Provider<AccountsCollection> accounts;
   private final String pluginName;
@@ -63,7 +60,6 @@
   @Inject
   ServiceUserCollection(
       DynamicMap<RestView<ServiceUserResource>> views,
-      CreateServiceUser.Factory createServiceUserFactory,
       Provider<ListServiceUsers> list,
       Provider<AccountsCollection> accounts,
       @PluginName String pluginName,
@@ -72,7 +68,6 @@
       GroupsCollection groups,
       PermissionBackend permissionBackend) {
     this.views = views;
-    this.createServiceUserFactory = createServiceUserFactory;
     this.list = list;
     this.accounts = accounts;
     this.pluginName = pluginName;
@@ -87,24 +82,21 @@
       throws ResourceNotFoundException, AuthException, IOException, OrmException,
           PermissionBackendException, ConfigInvalidException {
     ProjectLevelConfig storage = projectCache.getAllProjects().getConfig(pluginName + ".db");
-    IdentifiedUser serviceUser = accounts.get().parseId(id.get());
+    IdentifiedUser serviceUser = accounts.get().parse(TopLevelResource.INSTANCE, id).getUser();
     if (serviceUser == null
-        || !storage.get().getSubsections(USER).contains(serviceUser.getUserName())) {
+        || !storage.get().getSubsections(USER).contains(serviceUser.getUserName().get())) {
       throw new ResourceNotFoundException(id);
     }
     CurrentUser user = userProvider.get();
     if (user == null || !user.isIdentifiedUser()) {
       throw new AuthException("Authentication required");
     }
-    if (!permissionBackend.user(userProvider).testOrFalse(ADMINISTRATE_SERVER)) {
+    if (!permissionBackend.user(user).testOrFalse(ADMINISTRATE_SERVER)) {
       String owner = storage.get().getString(USER, id.get(), KEY_OWNER);
       if (owner != null) {
-        try {
-          GroupDescription.Basic group = groups.parse(owner);
-          if (!user.getEffectiveGroups().contains(group.getGroupUUID())) {
-            throw new ResourceNotFoundException(id);
-          }
-        } catch (UnprocessableEntityException e) {
+        GroupDescription.Basic group =
+            groups.parse(TopLevelResource.INSTANCE, IdString.fromDecoded(owner)).getGroup();
+        if (!user.getEffectiveGroups().contains(group.getGroupUUID())) {
           throw new ResourceNotFoundException(id);
         }
       } else if (!((IdentifiedUser) user)
@@ -125,9 +117,4 @@
   public DynamicMap<RestView<ServiceUserResource>> views() {
     return views;
   }
-
-  @Override
-  public CreateServiceUser create(ConfigResource parent, IdString username) {
-    return createServiceUserFactory.create(username.get());
-  }
 }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/ServiceUserMenu.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/ServiceUserMenu.java
index 2756143..df2cf8c 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/ServiceUserMenu.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/ServiceUserMenu.java
@@ -21,8 +21,10 @@
 import com.google.gerrit.extensions.api.access.PluginPermission;
 import com.google.gerrit.extensions.client.MenuItem;
 import com.google.gerrit.extensions.restapi.AuthException;
+import com.google.gerrit.extensions.restapi.RestApiException;
 import com.google.gerrit.extensions.webui.TopMenu;
 import com.google.gerrit.server.CurrentUser;
+import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.config.ConfigResource;
 import com.google.gerrit.server.permissions.PermissionBackend;
 import com.google.gerrit.server.permissions.PermissionBackendException;
@@ -46,7 +48,7 @@
       Provider<CurrentUser> userProvider,
       Provider<ListServiceUsers> listServiceUsers,
       PermissionBackend permissionBackend)
-      throws IOException, PermissionBackendException, ConfigInvalidException {
+      throws IOException, PermissionBackendException, ConfigInvalidException, RestApiException {
     this.pluginName = pluginName;
     this.userProvider = userProvider;
     this.listServiceUsers = listServiceUsers;
@@ -67,16 +69,17 @@
 
   private boolean canCreateServiceUser() {
     if (userProvider.get().isIdentifiedUser()) {
+      IdentifiedUser user = userProvider.get().asIdentifiedUser();
       return permissionBackend
-              .user(userProvider)
+              .user(user)
               .testOrFalse(new PluginPermission(pluginName, CreateServiceUserCapability.ID))
-          || permissionBackend.user(userProvider).testOrFalse(ADMINISTRATE_SERVER);
+          || permissionBackend.user(user).testOrFalse(ADMINISTRATE_SERVER);
     }
     return false;
   }
 
   private boolean hasServiceUser()
-      throws PermissionBackendException, IOException, ConfigInvalidException {
+      throws PermissionBackendException, IOException, ConfigInvalidException, RestApiException {
     try {
       return !listServiceUsers.get().apply(new ConfigResource()).isEmpty();
     } catch (AuthException | OrmException e) {
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/ServiceUserResolver.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/ServiceUserResolver.java
index 734f47e..686b6ba 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/ServiceUserResolver.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/ServiceUserResolver.java
@@ -14,8 +14,11 @@
 
 package com.googlesource.gerrit.plugins.serviceuser;
 
+import com.google.gerrit.common.data.GroupDescription;
 import com.google.gerrit.extensions.common.AccountInfo;
+import com.google.gerrit.extensions.restapi.MethodNotAllowedException;
 import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
+import com.google.gerrit.extensions.restapi.RestApiException;
 import com.google.gerrit.reviewdb.client.Account;
 import com.google.gerrit.reviewdb.client.AccountGroup;
 import com.google.gerrit.reviewdb.server.ReviewDb;
@@ -24,8 +27,12 @@
 import com.google.gerrit.server.account.AccountCache;
 import com.google.gerrit.server.account.AccountResolver;
 import com.google.gerrit.server.account.AccountState;
+import com.google.gerrit.server.account.GroupControl;
 import com.google.gerrit.server.account.GroupMembership;
-import com.google.gerrit.server.group.ListMembers;
+import com.google.gerrit.server.group.GroupResolver;
+import com.google.gerrit.server.group.GroupResource;
+import com.google.gerrit.server.permissions.PermissionBackendException;
+import com.google.gerrit.server.restapi.group.ListMembers;
 import com.google.gerrit.server.util.RequestContext;
 import com.google.gerrit.server.util.ThreadLocalRequestContext;
 import com.google.gwtorm.server.OrmException;
@@ -38,6 +45,7 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.Optional;
 import java.util.Set;
 import org.eclipse.jgit.errors.ConfigInvalidException;
 import org.eclipse.jgit.lib.PersonIdent;
@@ -51,6 +59,8 @@
   private final SchemaFactory<ReviewDb> schema;
   private final ThreadLocalRequestContext tl;
   private final AccountCache accountCache;
+  private final GroupControl.Factory groupControlFactory;
+  private final GroupResolver groupResolver;
 
   @Inject
   ServiceUserResolver(
@@ -60,7 +70,9 @@
       Provider<ListMembers> listMembers,
       SchemaFactory<ReviewDb> schema,
       ThreadLocalRequestContext tl,
-      AccountCache accountCache) {
+      AccountCache accountCache,
+      GroupControl.Factory groupControlFactory,
+      GroupResolver groupResolver) {
     this.resolver = resolver;
     this.genericUserFactory = genericUserFactory;
     this.getServiceUser = getServiceUser;
@@ -68,10 +80,13 @@
     this.schema = schema;
     this.tl = tl;
     this.accountCache = accountCache;
+    this.groupControlFactory = groupControlFactory;
+    this.groupResolver = groupResolver;
   }
 
   ServiceUserInfo getAsServiceUser(PersonIdent committerIdent)
-      throws ConfigInvalidException, IOException, OrmException {
+      throws ConfigInvalidException, IOException, OrmException, PermissionBackendException,
+          RestApiException {
     StringBuilder committer = new StringBuilder();
     committer.append(committerIdent.getName());
     committer.append(" <");
@@ -91,7 +106,8 @@
     }
   }
 
-  List<AccountInfo> listOwners(ServiceUserInfo serviceUser) throws OrmException {
+  List<AccountInfo> listOwners(ServiceUserInfo serviceUser)
+      throws OrmException, MethodNotAllowedException, PermissionBackendException {
     if (serviceUser.owner == null) {
       return Collections.emptyList();
     }
@@ -128,6 +144,11 @@
                     }
                   };
                 }
+
+                @Override
+                public Object getCacheKey() {
+                  return null;
+                }
               };
             }
 
@@ -143,10 +164,13 @@
           };
       RequestContext old = tl.setContext(context);
       try {
+        GroupDescription.Basic group = groupResolver.parseId(serviceUser.owner.id);
+        GroupControl ctl = groupControlFactory.controlFor(group);
         ListMembers lm = listMembers.get();
+        GroupResource rsrc = new GroupResource(ctl);
         lm.setRecursive(true);
         List<AccountInfo> owners = new ArrayList<>();
-        for (AccountInfo a : lm.apply(new AccountGroup.UUID(serviceUser.owner.id))) {
+        for (AccountInfo a : lm.apply(rsrc)) {
           owners.add(a);
         }
         return owners;
@@ -156,11 +180,12 @@
     }
   }
 
-  List<AccountInfo> listActiveOwners(ServiceUserInfo serviceUser) throws OrmException {
+  List<AccountInfo> listActiveOwners(ServiceUserInfo serviceUser)
+      throws OrmException, MethodNotAllowedException, PermissionBackendException {
     List<AccountInfo> activeOwners = new ArrayList<>();
     for (AccountInfo owner : listOwners(serviceUser)) {
-      AccountState accountState = accountCache.get(new Account.Id(owner._accountId));
-      if (accountState != null && accountState.getAccount().isActive()) {
+      Optional<AccountState> accountState = accountCache.get(new Account.Id(owner._accountId));
+      if (accountState.isPresent() && accountState.get().getAccount().isActive()) {
         activeOwners.add(owner);
       }
     }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/ServiceUserResource.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/ServiceUserResource.java
index 2a37815..ffcc9f6 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/ServiceUserResource.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/ServiceUserResource.java
@@ -15,9 +15,9 @@
 package com.googlesource.gerrit.plugins.serviceuser;
 
 import com.google.gerrit.extensions.restapi.RestView;
-import com.google.gerrit.reviewdb.client.AccountSshKey;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.account.AccountResource;
+import com.google.gerrit.server.account.AccountSshKey;
 import com.google.inject.TypeLiteral;
 
 class ServiceUserResource extends AccountResource {
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/SshKeys.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/SshKeys.java
index ac64ebb..7858b12 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/SshKeys.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/SshKeys.java
@@ -30,13 +30,13 @@
 class SshKeys implements ChildCollection<ServiceUserResource, ServiceUserResource.SshKey> {
   private final DynamicMap<RestView<ServiceUserResource.SshKey>> views;
   private final Provider<GetSshKeys> list;
-  private final Provider<com.google.gerrit.server.account.SshKeys> sshKeys;
+  private final Provider<com.google.gerrit.server.restapi.account.SshKeys> sshKeys;
 
   @Inject
   SshKeys(
       DynamicMap<RestView<ServiceUserResource.SshKey>> views,
       Provider<GetSshKeys> list,
-      Provider<com.google.gerrit.server.account.SshKeys> sshKeys) {
+      Provider<com.google.gerrit.server.restapi.account.SshKeys> sshKeys) {
     this.views = views;
     this.list = list;
     this.sshKeys = sshKeys;
diff --git a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/ValidateServiceUserCommits.java b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/ValidateServiceUserCommits.java
index f7b1179..ebf072b 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/ValidateServiceUserCommits.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/ValidateServiceUserCommits.java
@@ -14,6 +14,7 @@
 
 package com.googlesource.gerrit.plugins.serviceuser;
 
+import com.google.gerrit.extensions.restapi.RestApiException;
 import com.google.gerrit.reviewdb.client.Account;
 import com.google.gerrit.server.account.AccountCache;
 import com.google.gerrit.server.account.AccountState;
@@ -21,6 +22,7 @@
 import com.google.gerrit.server.git.validators.CommitValidationException;
 import com.google.gerrit.server.git.validators.CommitValidationListener;
 import com.google.gerrit.server.git.validators.CommitValidationMessage;
+import com.google.gerrit.server.permissions.PermissionBackendException;
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
@@ -28,6 +30,7 @@
 import java.io.IOException;
 import java.util.Collections;
 import java.util.List;
+import java.util.Optional;
 import org.eclipse.jgit.errors.ConfigInvalidException;
 import org.eclipse.jgit.lib.PersonIdent;
 
@@ -59,8 +62,9 @@
                   committer.getName(),
                   committer.getEmailAddress()));
         }
-        AccountState creator = accountCache.get(new Account.Id(serviceUser.createdBy._accountId));
-        if (creator == null || !creator.getAccount().isActive()) {
+        Optional<AccountState> creator =
+            accountCache.get(new Account.Id(serviceUser.createdBy._accountId));
+        if (!creator.isPresent() || !creator.get().getAccount().isActive()) {
           throw new CommitValidationException(
               String.format(
                   "Commit %s of service user %s (%s) is rejected because "
@@ -70,7 +74,11 @@
                   committer.getEmailAddress()));
         }
       }
-    } catch (IOException | OrmException | ConfigInvalidException e) {
+    } catch (IOException
+        | OrmException
+        | ConfigInvalidException
+        | PermissionBackendException
+        | RestApiException e) {
       throw new CommitValidationException(
           "Internal error while checking for service user commits.", e);
     }