Load ProjectLevelConfig directly

Cache introduced in [1] (in 3.3.1) prevents using getAllProjects().getConfig(...)
from Gerrit Core to read serviceuser db file.

To overcome this, we need to read config directly, bypassing the cache.

[1] https://gerrit-review.googlesource.com/c/gerrit/+/275992

Change-Id: I9b4b1e66cf8e2b41059997bb53ebeeaba7ee3ea3
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 74b97b2..c0c245c 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/GetOwner.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/GetOwner.java
@@ -14,49 +14,62 @@
 
 package com.googlesource.gerrit.plugins.serviceuser;
 
+import static com.google.gerrit.server.api.ApiUtil.asRestApiException;
 import static com.googlesource.gerrit.plugins.serviceuser.CreateServiceUser.KEY_OWNER;
 import static com.googlesource.gerrit.plugins.serviceuser.CreateServiceUser.USER;
 
 import com.google.gerrit.entities.GroupDescription;
-import com.google.gerrit.extensions.annotations.PluginName;
 import com.google.gerrit.extensions.common.GroupInfo;
 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.extensions.restapi.TopLevelResource;
+import com.google.gerrit.server.config.AllProjectsName;
+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.group.GroupJson;
 import com.google.gerrit.server.restapi.group.GroupsCollection;
 import com.google.inject.Inject;
+import com.google.inject.Provider;
 import com.google.inject.Singleton;
+import java.io.IOException;
+import org.eclipse.jgit.errors.ConfigInvalidException;
 
 @Singleton
 class GetOwner implements RestReadView<ServiceUserResource> {
   private final GroupsCollection groups;
-  private final String pluginName;
-  private final ProjectCache projectCache;
   private final GroupJson json;
+  private final Provider<ProjectLevelConfig.Bare> configProvider;
+  private final MetaDataUpdate.User metaDataUpdateFactory;
+  private final AllProjectsName allProjectsName;
 
   @Inject
   GetOwner(
       GroupsCollection groups,
-      @PluginName String pluginName,
-      ProjectCache projectCache,
+      Provider<ProjectLevelConfig.Bare> configProvider,
+      AllProjectsName allProjectsName,
+      MetaDataUpdate.User metaDataUpdateFactory,
       GroupJson json) {
     this.groups = groups;
-    this.pluginName = pluginName;
-    this.projectCache = projectCache;
+    this.configProvider = configProvider;
+    this.allProjectsName = allProjectsName;
+    this.metaDataUpdateFactory = metaDataUpdateFactory;
     this.json = json;
   }
 
   @Override
   public Response<GroupInfo> apply(ServiceUserResource rsrc)
-      throws RestApiException, PermissionBackendException {
-    ProjectLevelConfig storage = projectCache.getAllProjects().getConfig(pluginName + ".db");
-    String owner = storage.get().getString(USER, rsrc.getUser().getUserName().get(), KEY_OWNER);
+      throws IOException, RestApiException, PermissionBackendException {
+    ProjectLevelConfig.Bare storage = configProvider.get();
+    try (MetaDataUpdate md = metaDataUpdateFactory.create(allProjectsName)) {
+      storage.load(md);
+    } catch (ConfigInvalidException e) {
+      throw asRestApiException("Invalid configuration", e);
+    }
+    String owner =
+        storage.getConfig().getString(USER, rsrc.getUser().getUserName().get(), KEY_OWNER);
     if (owner != null) {
       GroupDescription.Basic group =
           groups.parse(TopLevelResource.INSTANCE, IdString.fromDecoded(owner)).getGroup();
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 c700da8..6b08307 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/GetServiceUser.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/GetServiceUser.java
@@ -21,7 +21,6 @@
 import static javax.servlet.http.HttpServletResponse.SC_OK;
 
 import com.google.gerrit.entities.Account;
-import com.google.gerrit.extensions.annotations.PluginName;
 import com.google.gerrit.extensions.common.AccountInfo;
 import com.google.gerrit.extensions.common.GroupInfo;
 import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
@@ -29,43 +28,54 @@
 import com.google.gerrit.extensions.restapi.RestApiException;
 import com.google.gerrit.extensions.restapi.RestReadView;
 import com.google.gerrit.server.account.AccountLoader;
+import com.google.gerrit.server.config.AllProjectsName;
+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.GetAccount;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 import com.google.inject.Singleton;
+import java.io.IOException;
+import org.eclipse.jgit.errors.ConfigInvalidException;
 import org.eclipse.jgit.lib.Config;
 
 @Singleton
 class GetServiceUser implements RestReadView<ServiceUserResource> {
   private final Provider<GetAccount> getAccount;
-  private final String pluginName;
-  private final ProjectCache projectCache;
   private final GetOwner getOwner;
   private final AccountLoader.Factory accountLoader;
+  private final Provider<ProjectLevelConfig.Bare> configProvider;
+  private final MetaDataUpdate.User metaDataUpdateFactory;
+  private final AllProjectsName allProjectsName;
 
   @Inject
   GetServiceUser(
       Provider<GetAccount> getAccount,
-      @PluginName String pluginName,
-      ProjectCache projectCache,
+      Provider<ProjectLevelConfig.Bare> configProvider,
+      AllProjectsName allProjectsName,
+      MetaDataUpdate.User metaDataUpdateFactory,
       GetOwner getOwner,
       AccountLoader.Factory accountLoader) {
     this.getAccount = getAccount;
-    this.pluginName = pluginName;
-    this.projectCache = projectCache;
+    this.configProvider = configProvider;
+    this.allProjectsName = allProjectsName;
+    this.metaDataUpdateFactory = metaDataUpdateFactory;
     this.getOwner = getOwner;
     this.accountLoader = accountLoader;
   }
 
   @Override
   public Response<ServiceUserInfo> apply(ServiceUserResource rsrc)
-      throws RestApiException, PermissionBackendException {
-    ProjectLevelConfig storage = projectCache.getAllProjects().getConfig(pluginName + ".db");
+      throws IOException, RestApiException, PermissionBackendException {
+    ProjectLevelConfig.Bare storage = configProvider.get();
+    try (MetaDataUpdate md = metaDataUpdateFactory.create(allProjectsName)) {
+      storage.load(md);
+    } catch (ConfigInvalidException e) {
+      throw asRestApiException("Invalid configuration", e);
+    }
     String username = rsrc.getUser().getUserName().get();
-    Config db = storage.get();
+    Config db = storage.getConfig();
     if (!db.getSubsections(USER).contains(username)) {
       throw new ResourceNotFoundException(username);
     }
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 5e77ce2..f0f9a64 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/ListServiceUsers.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/ListServiceUsers.java
@@ -18,7 +18,6 @@
 import static com.googlesource.gerrit.plugins.serviceuser.CreateServiceUser.USER;
 
 import com.google.common.collect.Maps;
-import com.google.gerrit.extensions.annotations.PluginName;
 import com.google.gerrit.extensions.restapi.AuthException;
 import com.google.gerrit.extensions.restapi.IdString;
 import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
@@ -28,9 +27,10 @@
 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.AllProjectsName;
 import com.google.gerrit.server.config.ConfigResource;
+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.inject.Inject;
 import com.google.inject.Provider;
@@ -45,23 +45,26 @@
 @Singleton
 class ListServiceUsers implements RestReadView<ConfigResource> {
   private final Provider<CurrentUser> userProvider;
-  private final String pluginName;
-  private final ProjectCache projectCache;
   private final AccountCache accountCache;
   private final Provider<ServiceUserCollection> serviceUsers;
   private final Provider<GetServiceUser> getServiceUser;
+  private final Provider<ProjectLevelConfig.Bare> configProvider;
+  private final MetaDataUpdate.User metaDataUpdateFactory;
+  private final AllProjectsName allProjectsName;
 
   @Inject
   ListServiceUsers(
       Provider<CurrentUser> userProvider,
-      @PluginName String pluginName,
-      ProjectCache projectCache,
+      Provider<ProjectLevelConfig.Bare> configProvider,
+      AllProjectsName allProjectsName,
+      MetaDataUpdate.User metaDataUpdateFactory,
       AccountCache accountCache,
       Provider<ServiceUserCollection> serviceUsers,
       Provider<GetServiceUser> getServiceUser) {
     this.userProvider = userProvider;
-    this.pluginName = pluginName;
-    this.projectCache = projectCache;
+    this.configProvider = configProvider;
+    this.allProjectsName = allProjectsName;
+    this.metaDataUpdateFactory = metaDataUpdateFactory;
     this.accountCache = accountCache;
     this.serviceUsers = serviceUsers;
     this.getServiceUser = getServiceUser;
@@ -70,14 +73,19 @@
   @Override
   public Response<Map<String, ServiceUserInfo>> apply(ConfigResource rscr)
       throws IOException, RestApiException, PermissionBackendException, ConfigInvalidException {
-    ProjectLevelConfig storage = projectCache.getAllProjects().getConfig(pluginName + ".db");
+    ProjectLevelConfig.Bare storage = configProvider.get();
+    try (MetaDataUpdate md = metaDataUpdateFactory.create(allProjectsName)) {
+      storage.load(md);
+    } catch (ConfigInvalidException e) {
+      throw asRestApiException("Invalid configuration", e);
+    }
     CurrentUser user = userProvider.get();
     if (user == null || !user.isIdentifiedUser()) {
       throw new AuthException("Authentication required");
     }
 
     Map<String, ServiceUserInfo> accounts = Maps.newTreeMap();
-    Config db = storage.get();
+    Config db = storage.getConfig();
     for (String username : db.getSubsections(USER)) {
       Optional<AccountState> account = accountCache.getByUsername(username);
       if (account.isPresent()) {
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 c5e5d9a..5a83d41 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/serviceuser/ServiceUserCollection.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/serviceuser/ServiceUserCollection.java
@@ -14,6 +14,7 @@
 
 package com.googlesource.gerrit.plugins.serviceuser;
 
+import static com.google.gerrit.server.api.ApiUtil.asRestApiException;
 import static com.google.gerrit.server.permissions.GlobalPermission.ADMINISTRATE_SERVER;
 import static com.googlesource.gerrit.plugins.serviceuser.CreateServiceUser.KEY_CREATOR_ID;
 import static com.googlesource.gerrit.plugins.serviceuser.CreateServiceUser.KEY_OWNER;
@@ -21,20 +22,21 @@
 
 import com.google.gerrit.entities.Account;
 import com.google.gerrit.entities.GroupDescription;
-import com.google.gerrit.extensions.annotations.PluginName;
 import com.google.gerrit.extensions.registration.DynamicMap;
 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.RestApiException;
 import com.google.gerrit.extensions.restapi.RestView;
 import com.google.gerrit.extensions.restapi.TopLevelResource;
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.IdentifiedUser;
+import com.google.gerrit.server.config.AllProjectsName;
 import com.google.gerrit.server.config.ConfigResource;
+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.account.AccountsCollection;
 import com.google.gerrit.server.restapi.group.GroupsCollection;
@@ -50,27 +52,30 @@
   private final DynamicMap<RestView<ServiceUserResource>> views;
   private final Provider<ListServiceUsers> list;
   private final Provider<AccountsCollection> accounts;
-  private final String pluginName;
-  private final ProjectCache projectCache;
   private final Provider<CurrentUser> userProvider;
   private final GroupsCollection groups;
   private final PermissionBackend permissionBackend;
+  private final Provider<ProjectLevelConfig.Bare> configProvider;
+  private final MetaDataUpdate.User metaDataUpdateFactory;
+  private final AllProjectsName allProjectsName;
 
   @Inject
   ServiceUserCollection(
       DynamicMap<RestView<ServiceUserResource>> views,
       Provider<ListServiceUsers> list,
       Provider<AccountsCollection> accounts,
-      @PluginName String pluginName,
-      ProjectCache projectCache,
+      Provider<ProjectLevelConfig.Bare> configProvider,
+      AllProjectsName allProjectsName,
+      MetaDataUpdate.User metaDataUpdateFactory,
       Provider<CurrentUser> userProvider,
       GroupsCollection groups,
       PermissionBackend permissionBackend) {
     this.views = views;
     this.list = list;
     this.accounts = accounts;
-    this.pluginName = pluginName;
-    this.projectCache = projectCache;
+    this.configProvider = configProvider;
+    this.allProjectsName = allProjectsName;
+    this.metaDataUpdateFactory = metaDataUpdateFactory;
     this.userProvider = userProvider;
     this.groups = groups;
     this.permissionBackend = permissionBackend;
@@ -79,11 +84,16 @@
   @Override
   public ServiceUserResource parse(ConfigResource parent, IdString id)
       throws ResourceNotFoundException, AuthException, IOException, PermissionBackendException,
-          ConfigInvalidException {
-    ProjectLevelConfig storage = projectCache.getAllProjects().getConfig(pluginName + ".db");
+          ConfigInvalidException, RestApiException {
+    ProjectLevelConfig.Bare storage = configProvider.get();
+    try (MetaDataUpdate md = metaDataUpdateFactory.create(allProjectsName)) {
+      storage.load(md);
+    } catch (ConfigInvalidException e) {
+      throw asRestApiException("Invalid configuration", e);
+    }
     IdentifiedUser serviceUser = accounts.get().parse(TopLevelResource.INSTANCE, id).getUser();
     if (serviceUser == null
-        || !storage.get().getSubsections(USER).contains(serviceUser.getUserName().get())) {
+        || !storage.getConfig().getSubsections(USER).contains(serviceUser.getUserName().get())) {
       throw new ResourceNotFoundException(id);
     }
     CurrentUser user = userProvider.get();
@@ -92,7 +102,7 @@
     }
     if (!permissionBackend.user(user).testOrFalse(ADMINISTRATE_SERVER)) {
       String username = serviceUser.getUserName().get();
-      String owner = storage.get().getString(USER, username, KEY_OWNER);
+      String owner = storage.getConfig().getString(USER, username, KEY_OWNER);
       if (owner != null) {
         GroupDescription.Basic group =
             groups.parse(TopLevelResource.INSTANCE, IdString.fromDecoded(owner)).getGroup();
@@ -101,7 +111,7 @@
         }
       } else if (!((IdentifiedUser) user)
           .getAccountId()
-          .equals(Account.id(storage.get().getInt(USER, username, KEY_CREATOR_ID, -1)))) {
+          .equals(Account.id(storage.getConfig().getInt(USER, username, KEY_CREATOR_ID, -1)))) {
         throw new ResourceNotFoundException(id);
       }
     }