This is an automated email from the ASF dual-hosted git repository. mmoayyed pushed a commit to branch SYNCOPE-163-1 in repository https://gitbox.apache.org/repos/asf/syncope.git
commit 3532a2ea0991716cc55cb9098addcbee6c065c9c Author: Misagh Moayyed <[email protected]> AuthorDate: Wed Mar 25 21:46:14 2020 +0430 SYNCOPE-160: lazy-load syncope-client after application is ready --- fit/wa-reference/src/main/resources/wa.properties | 13 ++++ .../java/org/apache/syncope/wa/WARestClient.java | 30 +++++++--- .../syncope/wa/starter/SyncopeWAApplication.java | 70 ++++++++++++++++++++-- .../src/main/resources/application.properties | 6 +- wa/starter/src/main/resources/wa.properties | 5 ++ 5 files changed, 109 insertions(+), 15 deletions(-) diff --git a/fit/wa-reference/src/main/resources/wa.properties b/fit/wa-reference/src/main/resources/wa.properties index add54f2..b04cb13 100644 --- a/fit/wa-reference/src/main/resources/wa.properties +++ b/fit/wa-reference/src/main/resources/wa.properties @@ -39,3 +39,16 @@ cas.sso.allow-missing-service-parameter=true # Disable the acceptable usage policy # by default for now. cas.acceptableUsagePolicy.enabled=false + +management.endpoints.web.exposure.include=health,loggers,refresh +management.endpoint.health.show-details=always + +management.endpoint.health.enabled=true +management.endpoint.loggers.enabled=true +management.endpoint.refresh.enabled=true + +cas.monitor.endpoints.endpoint.defaults.access=AUTHENTICATED + +spring.security.user.name=${anonymousUser} +spring.security.user.password=${anonymousKey} + diff --git a/wa/bootstrap/src/main/java/org/apache/syncope/wa/WARestClient.java b/wa/bootstrap/src/main/java/org/apache/syncope/wa/WARestClient.java index 7f56761..c33a738 100644 --- a/wa/bootstrap/src/main/java/org/apache/syncope/wa/WARestClient.java +++ b/wa/bootstrap/src/main/java/org/apache/syncope/wa/WARestClient.java @@ -21,6 +21,7 @@ package org.apache.syncope.wa; import org.apache.syncope.client.lib.AnonymousAuthenticationHandler; import org.apache.syncope.client.lib.SyncopeClient; import org.apache.syncope.client.lib.SyncopeClientFactoryBean; +import org.apache.syncope.common.keymaster.client.api.KeymasterException; import org.apache.syncope.common.keymaster.client.api.ServiceOps; import org.apache.syncope.common.keymaster.client.api.model.NetworkService; import org.slf4j.Logger; @@ -41,10 +42,10 @@ public class WARestClient { private SyncopeClient client; public WARestClient( - final ServiceOps serviceOps, - final String anonymousUser, - final String anonymousKey, - final boolean useGZIPCompression) { + final ServiceOps serviceOps, + final String anonymousUser, + final String anonymousKey, + final boolean useGZIPCompression) { this.serviceOps = serviceOps; this.anonymousUser = anonymousUser; @@ -54,12 +55,12 @@ public class WARestClient { public SyncopeClient getSyncopeClient() { synchronized (this) { - if (client == null) { + if (client == null && isReady()) { try { client = new SyncopeClientFactoryBean(). - setAddress(serviceOps.get(NetworkService.Type.CORE).getAddress()). - setUseCompression(useGZIPCompression). - create(new AnonymousAuthenticationHandler(anonymousUser, anonymousKey)); + setAddress(getCore().getAddress()). + setUseCompression(useGZIPCompression). + create(new AnonymousAuthenticationHandler(anonymousUser, anonymousKey)); } catch (Exception e) { LOG.error("Could not init SyncopeClient", e); } @@ -68,4 +69,17 @@ public class WARestClient { return client; } + + private NetworkService getCore() { + return serviceOps.get(NetworkService.Type.CORE); + } + + public boolean isReady() { + try { + return getCore() != null; + } catch (KeymasterException e) { + LOG.trace(e.getMessage()); + } + return false; + } } diff --git a/wa/starter/src/main/java/org/apache/syncope/wa/starter/SyncopeWAApplication.java b/wa/starter/src/main/java/org/apache/syncope/wa/starter/SyncopeWAApplication.java index 4d5d43a..887ad97 100644 --- a/wa/starter/src/main/java/org/apache/syncope/wa/starter/SyncopeWAApplication.java +++ b/wa/starter/src/main/java/org/apache/syncope/wa/starter/SyncopeWAApplication.java @@ -24,8 +24,18 @@ import org.apereo.cas.util.AsciiArtUtils; import org.apereo.cas.util.DateTimeUtils; import org.apache.commons.lang.StringUtils; +import org.quartz.Job; +import org.quartz.JobBuilder; +import org.quartz.JobDetail; +import org.quartz.JobExecutionContext; +import org.quartz.JobKey; +import org.quartz.SchedulerException; +import org.quartz.Trigger; +import org.quartz.TriggerBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration; import org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration; @@ -43,13 +53,19 @@ import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; +import org.springframework.cloud.context.refresh.ContextRefresher; import org.springframework.context.annotation.EnableAspectJAutoProxy; import org.springframework.context.annotation.PropertySource; import org.springframework.context.event.EventListener; import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.scheduling.quartz.SchedulerFactoryBean; import org.springframework.transaction.annotation.EnableTransactionManagement; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.Date; + @PropertySource("classpath:wa.properties") @PropertySource(value = "file:${conf.directory}/wa.properties", ignoreResourceNotFound = true) @SpringBootApplication(exclude = { @@ -75,10 +91,32 @@ public class SyncopeWAApplication extends SpringBootServletInitializer { private static final Logger LOG = LoggerFactory.getLogger(SyncopeWAApplication.class); + @Autowired + private ContextRefresher contextRefresher; + + @Autowired + private SchedulerFactoryBean scheduler; + + @Value("${contextRefreshDelay:15}") + private long contextRefreshDelay; + public static void main(final String[] args) { new SpringApplicationBuilder(SyncopeWAApplication.class).run(args); } + private static void advertiseReady(final ApplicationReadyEvent event) { + AsciiArtUtils.printAsciiArtReady(LOG, StringUtils.EMPTY); + LOG.info("Ready to process requests @ [{}]", DateTimeUtils.zonedDateTimeOf(event.getTimestamp())); + } + + private static void validateConfiguration(final ApplicationReadyEvent event) { + if (!Boolean.getBoolean("SKIP_CONFIG_VALIDATION")) { + CasConfigurationPropertiesValidator validator = + new CasConfigurationPropertiesValidator(event.getApplicationContext()); + validator.validate(); + } + } + /** * Handle application ready event. * @@ -86,13 +124,33 @@ public class SyncopeWAApplication extends SpringBootServletInitializer { */ @EventListener public void handleApplicationReadyEvent(final ApplicationReadyEvent event) { - if (!Boolean.getBoolean("SKIP_CONFIG_VALIDATION")) { - CasConfigurationPropertiesValidator validator = - new CasConfigurationPropertiesValidator(event.getApplicationContext()); - validator.validate(); + validateConfiguration(event); + scheduleJobToRefreshContext(); + advertiseReady(event); + } + + private void scheduleJobToRefreshContext() { + try { + Date date = Date.from(LocalDateTime.now().plusSeconds(this.contextRefreshDelay). + atZone(ZoneId.systemDefault()).toInstant()); + Trigger trigger = TriggerBuilder.newTrigger().startAt(date).build(); + JobKey jobKey = new JobKey(getClass().getSimpleName()); + + JobDetail job = JobBuilder.newJob(RefreshApplicationContextJob.class).withIdentity(jobKey).build(); + scheduler.getScheduler().scheduleJob(job, trigger); + } catch (SchedulerException e) { + throw new RuntimeException("Could not schedule refresh job", e); } + } - AsciiArtUtils.printAsciiArtReady(LOG, StringUtils.EMPTY); - LOG.info("Ready to process requests @ [{}]", DateTimeUtils.zonedDateTimeOf(event.getTimestamp())); + private class RefreshApplicationContextJob implements Job { + @Override + public void execute(final JobExecutionContext jobExecutionContext) { + try { + LOG.debug("Refreshed context: {}", contextRefresher.refresh()); + } catch (final Exception e) { + LOG.error(e.getMessage(), e); + } + } } } diff --git a/wa/starter/src/main/resources/application.properties b/wa/starter/src/main/resources/application.properties index 5ad1d51..1104f29 100644 --- a/wa/starter/src/main/resources/application.properties +++ b/wa/starter/src/main/resources/application.properties @@ -28,9 +28,13 @@ server.servlet.contextPath=/syncope-wa spring.resources.static-locations=classpath:/thymeleaf/static,classpath:/static -management.endpoints.web.exposure.include=health,loggers +management.endpoints.web.exposure.include=health,loggers,refresh management.endpoint.health.show-details=always +management.endpoint.health.enabled=true +management.endpoint.loggers.enabled=true +management.endpoint.refresh.enabled=true + ## # Allow configuration classes to override bean definitions from Spring Boot # diff --git a/wa/starter/src/main/resources/wa.properties b/wa/starter/src/main/resources/wa.properties index add54f2..3f68633 100644 --- a/wa/starter/src/main/resources/wa.properties +++ b/wa/starter/src/main/resources/wa.properties @@ -39,3 +39,8 @@ cas.sso.allow-missing-service-parameter=true # Disable the acceptable usage policy # by default for now. cas.acceptableUsagePolicy.enabled=false + +spring.security.user.name=${anonymousUser} +spring.security.user.password=${anonymousKey} + +cas.monitor.endpoints.endpoint.defaults.access=AUTHENTICATED
