This is an automated email from the ASF dual-hosted git repository.

ilgrosso pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/syncope.git


The following commit(s) were added to refs/heads/master by this push:
     new cbcae20f2d [SYNCOPE-1770] Fixing various quirks with Domains (#490)
cbcae20f2d is described below

commit cbcae20f2db14192fdbc8b8afe303ccea6c6a8ec
Author: Francesco Chicchiriccò <[email protected]>
AuthorDate: Tue Jul 11 15:53:29 2023 +0200

    [SYNCOPE-1770] Fixing various quirks with Domains (#490)
---
 .../client/console/SyncopeConsoleSession.java      |  42 ++++----
 .../client/console/SyncopeWebApplication.java      |   6 +-
 .../client/enduser/SyncopeEnduserSession.java      |  55 +++++-----
 .../client/enduser/SyncopeWebApplication.java      |   6 +-
 .../src/main/resources/defaultContent.xml          |  10 +-
 .../core/rest/cxf/IdRepoRESTCXFContext.java        |   9 +-
 .../core/persistence/jpa/DomainConfFactory.java    |  59 +++++-----
 .../syncope/core/persistence/jpa/MasterDomain.java |  10 ++
 .../core/persistence/jpa/PersistenceContext.java   |   5 +-
 .../syncope/core/starter/SelfKeymasterContext.java |   5 +-
 .../actuate/DefaultSyncopeCoreInfoContributor.java | 119 ++++++++++++---------
 11 files changed, 178 insertions(+), 148 deletions(-)

diff --git 
a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/SyncopeConsoleSession.java
 
b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/SyncopeConsoleSession.java
index 40360206eb..6fd73ba815 100644
--- 
a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/SyncopeConsoleSession.java
+++ 
b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/SyncopeConsoleSession.java
@@ -95,15 +95,11 @@ public class SyncopeConsoleSession extends 
AuthenticatedWebSession implements Ba
 
     protected static final Logger LOG = 
LoggerFactory.getLogger(SyncopeConsoleSession.class);
 
-    protected final SyncopeClientFactoryBean clientFactory;
-
-    protected final SyncopeAnonymousClient anonymousClient;
-
-    protected final Pair<String, String> gitAndBuildInfo;
-
-    protected final PlatformInfo platformInfo;
+    public static SyncopeConsoleSession get() {
+        return (SyncopeConsoleSession) Session.get();
+    }
 
-    protected final SystemInfo systemInfo;
+    protected final SyncopeClientFactoryBean clientFactory;
 
     protected final Map<Class<?>, Object> services = 
Collections.synchronizedMap(new HashMap<>());
 
@@ -113,6 +109,14 @@ public class SyncopeConsoleSession extends 
AuthenticatedWebSession implements Ba
 
     protected SyncopeClient client;
 
+    protected SyncopeAnonymousClient anonymousClient;
+
+    protected Pair<String, String> gitAndBuildInfo;
+
+    protected PlatformInfo platformInfo;
+
+    protected SystemInfo systemInfo;
+
     protected UserTO selfTO;
 
     protected Map<String, Set<String>> auth;
@@ -123,19 +127,10 @@ public class SyncopeConsoleSession extends 
AuthenticatedWebSession implements Ba
 
     protected Roles roles;
 
-    public static SyncopeConsoleSession get() {
-        return (SyncopeConsoleSession) Session.get();
-    }
-
     public SyncopeConsoleSession(final Request request) {
         super(request);
 
         clientFactory = SyncopeWebApplication.get().newClientFactory();
-        anonymousClient = SyncopeWebApplication.get().newAnonymousClient();
-
-        gitAndBuildInfo = anonymousClient.gitAndBuildInfo();
-        platformInfo = anonymousClient.platform();
-        systemInfo = anonymousClient.system();
 
         executor = SyncopeWebApplication.get().newThreadPoolTaskExecutor();
     }
@@ -258,6 +253,11 @@ public class SyncopeConsoleSession extends 
AuthenticatedWebSession implements Ba
     }
 
     public void cleanup() {
+        anonymousClient = null;
+        gitAndBuildInfo = null;
+        platformInfo = null;
+        systemInfo = null;
+
         client = null;
         auth = null;
         delegations = null;
@@ -368,6 +368,11 @@ public class SyncopeConsoleSession extends 
AuthenticatedWebSession implements Ba
 
     public void refreshAuth(final String username) {
         try {
+            anonymousClient = 
SyncopeWebApplication.get().newAnonymousClient(getDomain());
+            gitAndBuildInfo = anonymousClient.gitAndBuildInfo();
+            platformInfo = anonymousClient.platform();
+            systemInfo = anonymousClient.system();
+
             Triple<Map<String, Set<String>>, List<String>, UserTO> self = 
client.self();
             auth = self.getLeft();
             delegations = self.getMiddle();
@@ -384,7 +389,8 @@ public class SyncopeConsoleSession extends 
AuthenticatedWebSession implements Ba
 
     @Override
     public SyncopeAnonymousClient getAnonymousClient() {
-        return anonymousClient;
+        return Optional.ofNullable(anonymousClient).
+                orElseGet(() -> 
SyncopeWebApplication.get().newAnonymousClient(getDomain()));
     }
 
     @Override
diff --git 
a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/SyncopeWebApplication.java
 
b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/SyncopeWebApplication.java
index 5cd84a74dd..747bb0ff40 100644
--- 
a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/SyncopeWebApplication.java
+++ 
b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/SyncopeWebApplication.java
@@ -286,8 +286,10 @@ public class SyncopeWebApplication extends 
WicketBootSecuredWebApplication {
         return executor;
     }
 
-    public SyncopeAnonymousClient newAnonymousClient() {
-        return newClientFactory().createAnonymous(props.getAnonymousUser(), 
props.getAnonymousKey());
+    public SyncopeAnonymousClient newAnonymousClient(final String domain) {
+        return newClientFactory().
+                setDomain(domain).
+                createAnonymous(props.getAnonymousUser(), 
props.getAnonymousKey());
     }
 
     public SyncopeClientFactoryBean newClientFactory() {
diff --git 
a/client/idrepo/enduser/src/main/java/org/apache/syncope/client/enduser/SyncopeEnduserSession.java
 
b/client/idrepo/enduser/src/main/java/org/apache/syncope/client/enduser/SyncopeEnduserSession.java
index 3056eb701d..b50bf89f82 100644
--- 
a/client/idrepo/enduser/src/main/java/org/apache/syncope/client/enduser/SyncopeEnduserSession.java
+++ 
b/client/idrepo/enduser/src/main/java/org/apache/syncope/client/enduser/SyncopeEnduserSession.java
@@ -28,6 +28,7 @@ import java.text.DateFormat;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Optional;
 import java.util.concurrent.Callable;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.Future;
@@ -44,7 +45,6 @@ import org.apache.syncope.client.ui.commons.DateOps;
 import org.apache.syncope.common.lib.SyncopeClientException;
 import org.apache.syncope.common.lib.SyncopeConstants;
 import org.apache.syncope.common.lib.info.PlatformInfo;
-import org.apache.syncope.common.lib.info.SystemInfo;
 import org.apache.syncope.common.lib.to.UserTO;
 import org.apache.syncope.common.lib.types.ClientExceptionType;
 import org.apache.syncope.common.lib.types.IdRepoEntitlement;
@@ -84,36 +84,28 @@ public class SyncopeEnduserSession extends 
AuthenticatedWebSession implements Ba
         }
     }
 
-    private static final Logger LOG = 
LoggerFactory.getLogger(SyncopeEnduserSession.class);
+    protected static final Logger LOG = 
LoggerFactory.getLogger(SyncopeEnduserSession.class);
 
-    private final SyncopeClientFactoryBean clientFactory;
-
-    private final SyncopeAnonymousClient anonymousClient;
+    public static SyncopeEnduserSession get() {
+        return (SyncopeEnduserSession) Session.get();
+    }
 
-    private final PlatformInfo platformInfo;
+    protected final SyncopeClientFactoryBean clientFactory;
 
-    private final SystemInfo systemInfo;
+    protected final Map<Class<?>, Object> services = 
Collections.synchronizedMap(new HashMap<>());
 
-    private final Map<Class<?>, Object> services = 
Collections.synchronizedMap(new HashMap<>());
+    protected String domain;
 
-    private String domain;
+    protected SyncopeClient client;
 
-    private SyncopeClient client;
+    protected SyncopeAnonymousClient anonymousClient;
 
-    private UserTO selfTO;
-
-    public static SyncopeEnduserSession get() {
-        return (SyncopeEnduserSession) Session.get();
-    }
+    protected UserTO selfTO;
 
     public SyncopeEnduserSession(final Request request) {
         super(request);
 
         clientFactory = SyncopeWebApplication.get().newClientFactory();
-        anonymousClient = SyncopeWebApplication.get().newAnonymousClient();
-
-        platformInfo = anonymousClient.platform();
-        systemInfo = anonymousClient.system();
     }
 
     protected String message(final SyncopeClientException sce) {
@@ -197,11 +189,7 @@ public class SyncopeEnduserSession extends 
AuthenticatedWebSession implements Ba
     }
 
     public PlatformInfo getPlatformInfo() {
-        return platformInfo;
-    }
-
-    public SystemInfo getSystemInfo() {
-        return systemInfo;
+        return getAnonymousClient().platform();
     }
 
     @Override
@@ -214,7 +202,7 @@ public class SyncopeEnduserSession extends 
AuthenticatedWebSession implements Ba
         try {
             client = clientFactory.setDomain(getDomain()).create(username, 
password);
 
-            afterAuthentication(username);
+            refreshAuth(username);
 
             authenticated = true;
         } catch (Exception e) {
@@ -230,7 +218,7 @@ public class SyncopeEnduserSession extends 
AuthenticatedWebSession implements Ba
         try {
             client = clientFactory.setDomain(getDomain()).create(jwt);
 
-            afterAuthentication(null);
+            refreshAuth(null);
 
             authenticated = true;
         } catch (Exception e) {
@@ -240,8 +228,10 @@ public class SyncopeEnduserSession extends 
AuthenticatedWebSession implements Ba
         return authenticated;
     }
 
-    private void afterAuthentication(final String username) {
+    protected void refreshAuth(final String username) {
         try {
+            anonymousClient = 
SyncopeWebApplication.get().newAnonymousClient(getDomain());
+
             selfTO = client.self().getRight();
         } catch (ForbiddenException e) {
             LOG.warn("Could not read self(), probably in a {} scenario", 
IdRepoEntitlement.MUST_CHANGE_PASSWORD, e);
@@ -265,6 +255,8 @@ public class SyncopeEnduserSession extends 
AuthenticatedWebSession implements Ba
     }
 
     public void cleanup() {
+        anonymousClient = null;
+
         client = null;
         selfTO = null;
         services.clear();
@@ -291,19 +283,20 @@ public class SyncopeEnduserSession extends 
AuthenticatedWebSession implements Ba
 
     public UserTO getSelfTO(final boolean reload) {
         if (reload) {
-            afterAuthentication(selfTO.getUsername());
+            refreshAuth(selfTO.getUsername());
         }
         return selfTO;
     }
 
     @Override
     public SyncopeAnonymousClient getAnonymousClient() {
-        return anonymousClient;
+        return Optional.ofNullable(anonymousClient).
+                orElseGet(() -> 
SyncopeWebApplication.get().newAnonymousClient(getDomain()));
     }
 
     @Override
     public <T> T getAnonymousService(final Class<T> serviceClass) {
-        return getService(serviceClass);
+        return getAnonymousClient().getService(serviceClass);
     }
 
     @SuppressWarnings("unchecked")
@@ -324,7 +317,7 @@ public class SyncopeEnduserSession extends 
AuthenticatedWebSession implements Ba
     @Override
     public <T> T getService(final Class<T> serviceClass) {
         T service = (client == null || !isAuthenticated())
-                ? anonymousClient.getService(serviceClass)
+                ? getAnonymousClient().getService(serviceClass)
                 : client.getService(serviceClass);
         WebClient.client(service).header(RESTHeaders.DOMAIN, getDomain());
         return service;
diff --git 
a/client/idrepo/enduser/src/main/java/org/apache/syncope/client/enduser/SyncopeWebApplication.java
 
b/client/idrepo/enduser/src/main/java/org/apache/syncope/client/enduser/SyncopeWebApplication.java
index 8d660dba0d..63d3c0272c 100644
--- 
a/client/idrepo/enduser/src/main/java/org/apache/syncope/client/enduser/SyncopeWebApplication.java
+++ 
b/client/idrepo/enduser/src/main/java/org/apache/syncope/client/enduser/SyncopeWebApplication.java
@@ -259,8 +259,10 @@ public class SyncopeWebApplication extends 
WicketBootSecuredWebApplication {
         return new SyncopeEnduserSession(request);
     }
 
-    public SyncopeAnonymousClient newAnonymousClient() {
-        return newClientFactory().createAnonymous(props.getAnonymousUser(), 
props.getAnonymousKey());
+    public SyncopeAnonymousClient newAnonymousClient(final String domain) {
+        return newClientFactory().
+                setDomain(domain).
+                createAnonymous(props.getAnonymousUser(), 
props.getAnonymousKey());
     }
 
     public SyncopeClientFactoryBean newClientFactory() {
diff --git a/common/keymaster/client-api/src/main/resources/defaultContent.xml 
b/common/keymaster/client-api/src/main/resources/defaultContent.xml
index 69372e8095..6c16e24f57 100644
--- a/common/keymaster/client-api/src/main/resources/defaultContent.xml
+++ b/common/keymaster/client-api/src/main/resources/defaultContent.xml
@@ -41,8 +41,8 @@ under the License.
 
   <Implementation id="ExpiredAccessTokenCleanup" type="TASKJOB_DELEGATE" 
engine="JAVA"
                   
body="org.apache.syncope.core.provisioning.java.job.ExpiredAccessTokenCleanup"/>
-  <Task DTYPE="SchedTask" id="89de5014-e3f5-4462-84d8-d97575740baf" 
name="Access Token Cleanup Task"  active="1"
-        jobDelegate_id="ExpiredAccessTokenCleanup" cronExpression="0 0/5 * * * 
?"/>
+  <SchedTask id="89de5014-e3f5-4462-84d8-d97575740baf" name="Access Token 
Cleanup Task"  active="1"
+             jobDelegate_id="ExpiredAccessTokenCleanup" cronExpression="0 0/5 
* * * ?"/>
   
   <!-- Password reset notifications -->
   <MailTemplate id="requestPasswordReset"
@@ -85,12 +85,10 @@ we are happy to inform you that the password request was 
successfully executed f
 
   <Notification id="c74b4616-9c63-4350-b4bf-ae0077b1ae6a" active="1" 
recipientAttrName="email" selfAsRecipient="1" 
                 sender="[email protected]" subject="Password Reset 
request" template_id="requestPasswordReset" 
-                traceLevel="FAILURES"/> 
+                traceLevel="FAILURES" 
events='["[CUSTOM]:[]:[]:[requestPasswordReset]:[SUCCESS]"]'/> 
   <AnyAbout id="0d4e37a1-a4f4-4865-afcb-4be01da3da53" anyType_id="USER" 
notification_id="c74b4616-9c63-4350-b4bf-ae0077b1ae6a" 
anyType_filter="token!=$null"/>
-  <Notification_events notification_id="c74b4616-9c63-4350-b4bf-ae0077b1ae6a" 
event="[CUSTOM]:[]:[]:[requestPasswordReset]:[SUCCESS]"/>
   
   <Notification id="71769807-7f74-4dc3-ba61-e4a7a00eb8ad" active="1" 
recipientAttrName="email" selfAsRecipient="1" 
                 sender="[email protected]" subject="Password Reset 
successful" template_id="confirmPasswordReset" 
-                traceLevel="FAILURES"/> 
-  <Notification_events notification_id="71769807-7f74-4dc3-ba61-e4a7a00eb8ad" 
event="[CUSTOM]:[]:[]:[confirmPasswordReset]:[SUCCESS]"/>
+                traceLevel="FAILURES" 
events='["[CUSTOM]:[]:[]:[confirmPasswordReset]:[SUCCESS]"]'/> 
 </dataset>
diff --git 
a/core/idrepo/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/IdRepoRESTCXFContext.java
 
b/core/idrepo/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/IdRepoRESTCXFContext.java
index 90e9e1fb6a..b5bac8d48a 100644
--- 
a/core/idrepo/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/IdRepoRESTCXFContext.java
+++ 
b/core/idrepo/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/IdRepoRESTCXFContext.java
@@ -136,7 +136,6 @@ import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Qualifier;
 import 
org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
 import 
org.springframework.boot.context.properties.EnableConfigurationProperties;
-import org.springframework.context.ApplicationContext;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.context.annotation.PropertySource;
@@ -272,8 +271,8 @@ public class IdRepoRESTCXFContext {
 
     @ConditionalOnMissingBean
     @Bean
-    public OpenApiFeature openapiFeature(final OpenApiCustomizer 
openApiCustomizer, final ApplicationContext ctx) {
-        String version = ctx.getEnvironment().getProperty("version");
+    public OpenApiFeature openapiFeature(final OpenApiCustomizer 
openApiCustomizer, final Environment env) {
+        String version = env.getProperty("version");
         OpenApiFeature openapiFeature = new OpenApiFeature();
         openapiFeature.setUseContextBasedConfig(true);
         openapiFeature.setTitle("Apache Syncope");
@@ -319,8 +318,7 @@ public class IdRepoRESTCXFContext {
             final ThreadLocalCleanupOutInterceptor 
threadLocalCleanupOutInterceptor,
             final OpenApiFeature openapiFeature,
             final RestServiceExceptionMapper restServiceExceptionMapper,
-            final Bus bus,
-            final ApplicationContext ctx) {
+            final Bus bus) {
 
         SpringJAXRSServerFactoryBean restContainer = new 
SpringJAXRSServerFactoryBean();
         restContainer.setBus(bus);
@@ -351,7 +349,6 @@ public class IdRepoRESTCXFContext {
 
         restContainer.setFeatures(List.of(openapiFeature));
 
-        restContainer.setApplicationContext(ctx);
         return restContainer.create();
     }
 
diff --git 
a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/DomainConfFactory.java
 
b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/DomainConfFactory.java
index 80d6ea8ed6..b5069b798a 100644
--- 
a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/DomainConfFactory.java
+++ 
b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/DomainConfFactory.java
@@ -29,7 +29,6 @@ import javax.sql.DataSource;
 import org.apache.syncope.common.keymaster.client.api.model.Domain;
 import org.apache.syncope.core.persistence.api.DomainRegistry;
 import 
org.apache.syncope.core.persistence.jpa.spring.DomainEntityManagerFactoryBean;
-import org.apache.syncope.core.spring.ApplicationContextProvider;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Qualifier;
@@ -37,44 +36,50 @@ import 
org.springframework.beans.factory.config.BeanDefinition;
 import org.springframework.beans.factory.support.AbstractBeanDefinition;
 import org.springframework.beans.factory.support.AutowireCandidateQualifier;
 import org.springframework.beans.factory.support.BeanDefinitionBuilder;
-import org.springframework.core.env.Environment;
+import org.springframework.beans.factory.support.DefaultListableBeanFactory;
+import org.springframework.context.ConfigurableApplicationContext;
 import org.springframework.core.io.ClassPathResource;
 import org.springframework.jdbc.datasource.init.DataSourceInitializer;
 import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
 import org.springframework.jndi.JndiObjectFactoryBean;
 import org.springframework.orm.jpa.JpaTransactionManager;
 import org.springframework.orm.jpa.vendor.OpenJpaVendorAdapter;
+import org.springframework.transaction.support.TransactionTemplate;
 
 public class DomainConfFactory implements DomainRegistry {
 
     protected static final Logger LOG = 
LoggerFactory.getLogger(DomainConfFactory.class);
 
-    protected static void unregisterSingleton(final String name) {
-        if 
(ApplicationContextProvider.getBeanFactory().containsSingleton(name)) {
-            ApplicationContextProvider.getBeanFactory().destroySingleton(name);
-        }
+    protected final ConfigurableApplicationContext ctx;
+
+    public DomainConfFactory(final ConfigurableApplicationContext ctx) {
+        this.ctx = ctx;
     }
 
-    protected static void registerSingleton(final String name, final Object 
bean) {
-        unregisterSingleton(name);
-        ApplicationContextProvider.getBeanFactory().registerSingleton(name, 
bean);
+    protected DefaultListableBeanFactory beanFactory() {
+        return (DefaultListableBeanFactory) ctx.getBeanFactory();
     }
 
-    protected static void unregisterBeanDefinition(final String name) {
-        if 
(ApplicationContextProvider.getBeanFactory().containsBeanDefinition(name)) {
-            
ApplicationContextProvider.getBeanFactory().removeBeanDefinition(name);
+    protected void unregisterSingleton(final String name) {
+        if (beanFactory().containsSingleton(name)) {
+            beanFactory().destroySingleton(name);
         }
     }
 
-    protected static void registerBeanDefinition(final String name, final 
BeanDefinition beanDefinition) {
-        unregisterBeanDefinition(name);
-        
ApplicationContextProvider.getBeanFactory().registerBeanDefinition(name, 
beanDefinition);
+    protected void registerSingleton(final String name, final Object bean) {
+        unregisterSingleton(name);
+        beanFactory().registerSingleton(name, bean);
     }
 
-    protected final Environment env;
+    protected void unregisterBeanDefinition(final String name) {
+        if (beanFactory().containsBeanDefinition(name)) {
+            beanFactory().removeBeanDefinition(name);
+        }
+    }
 
-    public DomainConfFactory(final Environment env) {
-        this.env = env;
+    protected void registerBeanDefinition(final String name, final 
BeanDefinition beanDefinition) {
+        unregisterBeanDefinition(name);
+        beanFactory().registerBeanDefinition(name, beanDefinition);
     }
 
     @Override
@@ -96,8 +101,7 @@ public class DomainConfFactory implements DomainRegistry {
                         addPropertyValue("jndiName", 
"java:comp/env/jdbc/syncope" + domain.getKey() + "DataSource").
                         addPropertyValue("defaultObject", new 
HikariDataSource(hikariConfig)).
                         getBeanDefinition());
-        DataSource initedDataSource = 
ApplicationContextProvider.getBeanFactory().
-                getBean(domain.getKey() + "DataSource", DataSource.class);
+        DataSource initedDataSource = beanFactory().getBean(domain.getKey() + 
"DataSource", DataSource.class);
 
         // domainResourceDatabasePopulator
         ResourceDatabasePopulator databasePopulator = new 
ResourceDatabasePopulator();
@@ -126,14 +130,14 @@ public class DomainConfFactory implements DomainRegistry {
                 addPropertyReference("dataSource", domain.getKey() + 
"DataSource").
                 addPropertyValue("jpaVendorAdapter", vendorAdapter).
                 addPropertyReference("commonEntityManagerFactoryConf", 
"commonEMFConf");
-        if (env.containsProperty("openjpaMetaDataFactory")) {
+        if (ctx.getEnvironment().containsProperty("openjpaMetaDataFactory")) {
             emf.addPropertyValue("jpaPropertyMap", Map.of(
                     "openjpa.MetaDataFactory",
-                    
Objects.requireNonNull(env.getProperty("openjpaMetaDataFactory")).
+                    
Objects.requireNonNull(ctx.getEnvironment().getProperty("openjpaMetaDataFactory")).
                             replace("##orm##", domain.getOrm())));
         }
         registerBeanDefinition(domain.getKey() + "EntityManagerFactory", 
emf.getBeanDefinition());
-        ApplicationContextProvider.getBeanFactory().getBean(domain.getKey() + 
"EntityManagerFactory");
+        beanFactory().getBean(domain.getKey() + "EntityManagerFactory");
 
         // domainTransactionManager
         AbstractBeanDefinition domainTransactionManager =
@@ -143,6 +147,13 @@ public class DomainConfFactory implements DomainRegistry {
         domainTransactionManager.addQualifier(new 
AutowireCandidateQualifier(Qualifier.class, domain.getKey()));
         registerBeanDefinition(domain.getKey() + "TransactionManager", 
domainTransactionManager);
 
+        // domainTransactionTemplate
+        AbstractBeanDefinition domainTransactionTemplate =
+                
BeanDefinitionBuilder.rootBeanDefinition(TransactionTemplate.class).
+                        addPropertyReference("transactionManager", 
domain.getKey() + "TransactionManager").
+                        getBeanDefinition();
+        registerBeanDefinition(domain.getKey() + "TransactionTemplate", 
domainTransactionTemplate);
+
         // domainContentXML
         registerBeanDefinition(domain.getKey() + "ContentXML",
                 
BeanDefinitionBuilder.rootBeanDefinition(ByteArrayInputStream.class).
@@ -168,7 +179,7 @@ public class DomainConfFactory implements DomainRegistry {
 
         // domainEntityManagerFactory
         try {
-            EntityManagerFactory emf = 
ApplicationContextProvider.getBeanFactory().
+            EntityManagerFactory emf = beanFactory().
                     getBean(domain + "EntityManagerFactory", 
EntityManagerFactory.class);
             emf.close();
         } catch (Exception e) {
diff --git 
a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/MasterDomain.java
 
b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/MasterDomain.java
index e701849537..5b05547240 100644
--- 
a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/MasterDomain.java
+++ 
b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/MasterDomain.java
@@ -42,6 +42,7 @@ import org.springframework.jndi.JndiObjectFactoryBean;
 import org.springframework.orm.jpa.JpaTransactionManager;
 import org.springframework.orm.jpa.vendor.OpenJpaVendorAdapter;
 import org.springframework.transaction.PlatformTransactionManager;
+import org.springframework.transaction.support.TransactionTemplate;
 
 @EnableConfigurationProperties(PersistenceProperties.class)
 @Configuration(proxyBeanMethods = false)
@@ -124,6 +125,15 @@ public class MasterDomain {
         return new 
JpaTransactionManager(Objects.requireNonNull(masterEntityManagerFactory.getObject()));
     }
 
+    @ConditionalOnMissingBean(name = "MasterTransactionTemplate")
+    @Bean(name = "MasterTransactionTemplate")
+    public TransactionTemplate transactionTemplate(
+            @Qualifier("MasterTransactionManager")
+            final PlatformTransactionManager masterTransactionManager) {
+
+        return new TransactionTemplate(masterTransactionManager);
+    }
+
     @Bean(name = "MasterContentXML")
     public InputStream masterContentXML(
             final ResourceLoader resourceLoader,
diff --git 
a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/PersistenceContext.java
 
b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/PersistenceContext.java
index 738915747b..57078645f5 100644
--- 
a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/PersistenceContext.java
+++ 
b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/PersistenceContext.java
@@ -148,6 +148,7 @@ import 
org.springframework.beans.factory.config.BeanFactoryPostProcessor;
 import 
org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
 import 
org.springframework.boot.context.properties.EnableConfigurationProperties;
 import org.springframework.context.ApplicationEventPublisher;
+import org.springframework.context.ConfigurableApplicationContext;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.context.annotation.Lazy;
@@ -243,8 +244,8 @@ public class PersistenceContext {
 
     @ConditionalOnMissingBean
     @Bean
-    public DomainRegistry domainRegistry(final Environment env) {
-        return new DomainConfFactory(env);
+    public DomainRegistry domainRegistry(final ConfigurableApplicationContext 
ctx) {
+        return new DomainConfFactory(ctx);
     }
 
     @ConditionalOnMissingBean
diff --git 
a/core/self-keymaster-starter/src/main/java/org/apache/syncope/core/starter/SelfKeymasterContext.java
 
b/core/self-keymaster-starter/src/main/java/org/apache/syncope/core/starter/SelfKeymasterContext.java
index 06fc6fd0cb..02398a5fd5 100644
--- 
a/core/self-keymaster-starter/src/main/java/org/apache/syncope/core/starter/SelfKeymasterContext.java
+++ 
b/core/self-keymaster-starter/src/main/java/org/apache/syncope/core/starter/SelfKeymasterContext.java
@@ -66,7 +66,6 @@ import 
org.springframework.boot.autoconfigure.condition.ConditionOutcome;
 import 
org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
 import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
 import 
org.springframework.boot.context.properties.EnableConfigurationProperties;
-import org.springframework.context.ApplicationContext;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.ConditionContext;
 import org.springframework.context.annotation.Conditional;
@@ -102,8 +101,7 @@ public class SelfKeymasterContext {
             final GZIPOutInterceptor gzipOutInterceptor,
             final JAXRSBeanValidationInInterceptor validationInInterceptor,
             final RestServiceExceptionMapper restServiceExceptionMapper,
-            final Bus bus,
-            final ApplicationContext ctx) {
+            final Bus bus) {
 
         SpringJAXRSServerFactoryBean selfKeymasterContainer = new 
SpringJAXRSServerFactoryBean();
         selfKeymasterContainer.setBus(bus);
@@ -120,7 +118,6 @@ public class SelfKeymasterContext {
 
         
selfKeymasterContainer.setProviders(List.of(restServiceExceptionMapper, 
jsonProvider));
 
-        selfKeymasterContainer.setApplicationContext(ctx);
         return selfKeymasterContainer.create();
     }
 
diff --git 
a/core/starter/src/main/java/org/apache/syncope/core/starter/actuate/DefaultSyncopeCoreInfoContributor.java
 
b/core/starter/src/main/java/org/apache/syncope/core/starter/actuate/DefaultSyncopeCoreInfoContributor.java
index bbcdd31c38..a5752ca5fd 100644
--- 
a/core/starter/src/main/java/org/apache/syncope/core/starter/actuate/DefaultSyncopeCoreInfoContributor.java
+++ 
b/core/starter/src/main/java/org/apache/syncope/core/starter/actuate/DefaultSyncopeCoreInfoContributor.java
@@ -18,6 +18,7 @@
  */
 package org.apache.syncope.core.starter.actuate;
 
+import jakarta.servlet.http.HttpServletRequest;
 import java.lang.management.ManagementFactory;
 import java.lang.management.OperatingSystemMXBean;
 import java.lang.management.RuntimeMXBean;
@@ -26,11 +27,13 @@ import java.net.URI;
 import java.net.UnknownHostException;
 import java.util.Iterator;
 import java.util.Map;
+import java.util.Optional;
 import java.util.Set;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 import org.apache.syncope.common.keymaster.client.api.ConfParamOps;
+import org.apache.syncope.common.lib.SyncopeConstants;
 import org.apache.syncope.common.lib.info.JavaImplInfo;
 import org.apache.syncope.common.lib.info.NumbersInfo;
 import org.apache.syncope.common.lib.info.PlatformInfo;
@@ -38,6 +41,7 @@ import org.apache.syncope.common.lib.info.SystemInfo;
 import org.apache.syncope.common.lib.types.EntitlementsHolder;
 import org.apache.syncope.common.lib.types.ImplementationTypesHolder;
 import org.apache.syncope.common.lib.types.TaskType;
+import org.apache.syncope.common.rest.api.RESTHeaders;
 import org.apache.syncope.core.persistence.api.dao.AnyObjectDAO;
 import org.apache.syncope.core.persistence.api.dao.AnyTypeClassDAO;
 import org.apache.syncope.core.persistence.api.dao.AnyTypeDAO;
@@ -61,6 +65,7 @@ import 
org.apache.syncope.core.provisioning.api.ImplementationLookup;
 import org.apache.syncope.core.spring.security.AuthContextUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.actuate.info.Info;
 import org.springframework.boot.actuate.info.InfoContributor;
 import org.springframework.context.PayloadApplicationEvent;
@@ -137,6 +142,9 @@ public class DefaultSyncopeCoreInfoContributor implements 
SyncopeCoreInfoContrib
         }
     }
 
+    @Autowired
+    protected HttpServletRequest request;
+
     protected final AnyTypeDAO anyTypeDAO;
 
     protected final AnyTypeClassDAO anyTypeClassDAO;
@@ -272,60 +280,62 @@ public class DefaultSyncopeCoreInfoContributor implements 
SyncopeCoreInfoContrib
         }
     }
 
-    protected NumbersInfo buildNumbers() {
-        NumbersInfo numbersInfo = new NumbersInfo();
-
-        numbersInfo.setTotalUsers(userDAO.count());
-        numbersInfo.getUsersByRealm().putAll(userDAO.countByRealm());
-        numbersInfo.getUsersByStatus().putAll(userDAO.countByStatus());
-
-        numbersInfo.setTotalGroups(groupDAO.count());
-        numbersInfo.getGroupsByRealm().putAll(groupDAO.countByRealm());
-
-        Map<AnyType, Integer> anyObjectNumbers = anyObjectDAO.countByType();
-        int i = 0;
-        for (Iterator<Map.Entry<AnyType, Integer>> itor = 
anyObjectNumbers.entrySet().iterator();
-                i < 2 && itor.hasNext(); i++) {
-
-            Map.Entry<AnyType, Integer> entry = itor.next();
-            if (i == 0) {
-                numbersInfo.setAnyType1(entry.getKey().getKey());
-                numbersInfo.setTotalAny1(entry.getValue());
-                
numbersInfo.getAny1ByRealm().putAll(anyObjectDAO.countByRealm(entry.getKey()));
-            } else {
-                numbersInfo.setAnyType2(entry.getKey().getKey());
-                numbersInfo.setTotalAny2(entry.getValue());
-                
numbersInfo.getAny2ByRealm().putAll(anyObjectDAO.countByRealm(entry.getKey()));
+    protected NumbersInfo buildNumbers(final String domain) {
+        return AuthContextUtils.callAsAdmin(domain, () -> {
+            NumbersInfo numbersInfo = new NumbersInfo();
+
+            numbersInfo.setTotalUsers(userDAO.count());
+            numbersInfo.getUsersByRealm().putAll(userDAO.countByRealm());
+            numbersInfo.getUsersByStatus().putAll(userDAO.countByStatus());
+
+            numbersInfo.setTotalGroups(groupDAO.count());
+            numbersInfo.getGroupsByRealm().putAll(groupDAO.countByRealm());
+
+            Map<AnyType, Integer> anyObjectNumbers = 
anyObjectDAO.countByType();
+            int i = 0;
+            for (Iterator<Map.Entry<AnyType, Integer>> itor = 
anyObjectNumbers.entrySet().iterator();
+                    i < 2 && itor.hasNext(); i++) {
+
+                Map.Entry<AnyType, Integer> entry = itor.next();
+                if (i == 0) {
+                    numbersInfo.setAnyType1(entry.getKey().getKey());
+                    numbersInfo.setTotalAny1(entry.getValue());
+                    
numbersInfo.getAny1ByRealm().putAll(anyObjectDAO.countByRealm(entry.getKey()));
+                } else {
+                    numbersInfo.setAnyType2(entry.getKey().getKey());
+                    numbersInfo.setTotalAny2(entry.getValue());
+                    
numbersInfo.getAny2ByRealm().putAll(anyObjectDAO.countByRealm(entry.getKey()));
+                }
             }
-        }
 
-        numbersInfo.setTotalResources(resourceDAO.count());
-
-        numbersInfo.setTotalRoles(roleDAO.count());
-
-        numbersInfo.getConfCompleteness().put(
-                NumbersInfo.ConfItem.RESOURCE.name(), 
numbersInfo.getTotalResources() > 0);
-        numbersInfo.getConfCompleteness().put(
-                NumbersInfo.ConfItem.ACCOUNT_POLICY.name(), 
!policyDAO.find(AccountPolicy.class).isEmpty());
-        numbersInfo.getConfCompleteness().put(
-                NumbersInfo.ConfItem.PASSWORD_POLICY.name(), 
!policyDAO.find(PasswordPolicy.class).isEmpty());
-        numbersInfo.getConfCompleteness().put(
-                NumbersInfo.ConfItem.NOTIFICATION.name(), 
!notificationDAO.findAll().isEmpty());
-        numbersInfo.getConfCompleteness().put(
-                NumbersInfo.ConfItem.PULL_TASK.name(), 
!taskDAO.findAll(TaskType.PULL).isEmpty());
-        numbersInfo.getConfCompleteness().put(
-                NumbersInfo.ConfItem.VIR_SCHEMA.name(), 
!virSchemaDAO.findAll().isEmpty());
-        numbersInfo.getConfCompleteness().put(
-                NumbersInfo.ConfItem.ANY_TYPE.name(), 
!anyObjectNumbers.isEmpty());
-        numbersInfo.getConfCompleteness().put(
-                NumbersInfo.ConfItem.SECURITY_QUESTION.name(), 
!securityQuestionDAO.findAll().isEmpty());
-        numbersInfo.getConfCompleteness().put(
-                NumbersInfo.ConfItem.ROLE.name(), numbersInfo.getTotalRoles() 
> 0);
-
-        taskExecutors.forEach((name, bean) -> 
numbersInfo.getTaskExecutorInfos().
-                put(name, 
getTaskExecutorInfo(bean.getThreadPoolExecutor().toString())));
-
-        return numbersInfo;
+            numbersInfo.setTotalResources(resourceDAO.count());
+
+            numbersInfo.setTotalRoles(roleDAO.count());
+
+            numbersInfo.getConfCompleteness().put(
+                    NumbersInfo.ConfItem.RESOURCE.name(), 
numbersInfo.getTotalResources() > 0);
+            numbersInfo.getConfCompleteness().put(
+                    NumbersInfo.ConfItem.ACCOUNT_POLICY.name(), 
!policyDAO.find(AccountPolicy.class).isEmpty());
+            numbersInfo.getConfCompleteness().put(
+                    NumbersInfo.ConfItem.PASSWORD_POLICY.name(), 
!policyDAO.find(PasswordPolicy.class).isEmpty());
+            numbersInfo.getConfCompleteness().put(
+                    NumbersInfo.ConfItem.NOTIFICATION.name(), 
!notificationDAO.findAll().isEmpty());
+            numbersInfo.getConfCompleteness().put(
+                    NumbersInfo.ConfItem.PULL_TASK.name(), 
!taskDAO.findAll(TaskType.PULL).isEmpty());
+            numbersInfo.getConfCompleteness().put(
+                    NumbersInfo.ConfItem.VIR_SCHEMA.name(), 
!virSchemaDAO.findAll().isEmpty());
+            numbersInfo.getConfCompleteness().put(
+                    NumbersInfo.ConfItem.ANY_TYPE.name(), 
!anyObjectNumbers.isEmpty());
+            numbersInfo.getConfCompleteness().put(
+                    NumbersInfo.ConfItem.SECURITY_QUESTION.name(), 
!securityQuestionDAO.findAll().isEmpty());
+            numbersInfo.getConfCompleteness().put(
+                    NumbersInfo.ConfItem.ROLE.name(), 
numbersInfo.getTotalRoles() > 0);
+
+            taskExecutors.forEach((name, bean) -> 
numbersInfo.getTaskExecutorInfos().
+                    put(name, 
getTaskExecutorInfo(bean.getThreadPoolExecutor().toString())));
+
+            return numbersInfo;
+        });
     }
 
     protected void buildSystem() {
@@ -342,7 +352,10 @@ public class DefaultSyncopeCoreInfoContributor implements 
SyncopeCoreInfoContrib
 
         builder.withDetail("persistence", persistenceInfoDAO.info());
 
-        builder.withDetail("numbers", buildNumbers());
+        builder.withDetail(
+                "numbers",
+                
buildNumbers(Optional.ofNullable(request.getHeader(RESTHeaders.DOMAIN)).
+                        orElse(SyncopeConstants.MASTER_DOMAIN)));
 
         buildSystem();
         builder.withDetail("system", SYSTEM_INFO);


Reply via email to