You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by il...@apache.org on 2021/09/28 10:59:26 UTC

[syncope] 03/03: [SYNCOPE-1644] Now relying on SpringBeanJobFactory which creates the bean and immediately executes it

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

commit e06159e1a6323a63d337741826860fc3a7a85f0c
Author: Francesco Chicchiriccò <il...@apache.org>
AuthorDate: Tue Sep 28 12:21:46 2021 +0200

    [SYNCOPE-1644] Now relying on SpringBeanJobFactory which creates the bean and immediately executes it
---
 .../core/provisioning/api/job/JobManager.java      |  4 +
 .../provisioning/java/ProvisioningContext.java     |  4 +-
 .../java/job/AutowiringSpringBeanJobFactory.java   | 85 ----------------------
 .../provisioning/java/job/DefaultJobManager.java   | 78 +++++---------------
 .../java/job/SyncopeSpringBeanJobFactory.java      | 45 ++++++++++++
 5 files changed, 68 insertions(+), 148 deletions(-)

diff --git a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/job/JobManager.java b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/job/JobManager.java
index 6d8fa28..1402142 100644
--- a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/job/JobManager.java
+++ b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/job/JobManager.java
@@ -30,6 +30,10 @@ import org.quartz.SchedulerException;
 @SuppressWarnings("squid:S1214")
 public interface JobManager {
 
+    String TASK_KEY = "task";
+
+    String REPORT_KEY = "report";
+
     String DOMAIN_KEY = "domain";
     String EXECUTOR_KEY = "executor";
 
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/ProvisioningContext.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/ProvisioningContext.java
index 5030ce0..96ab095 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/ProvisioningContext.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/ProvisioningContext.java
@@ -155,10 +155,10 @@ import org.apache.syncope.core.provisioning.java.data.TaskDataBinderImpl;
 import org.apache.syncope.core.provisioning.java.data.UserDataBinderImpl;
 import org.apache.syncope.core.provisioning.java.data.WAConfigDataBinderImpl;
 import org.apache.syncope.core.provisioning.java.data.wa.WAClientAppDataBinderImpl;
-import org.apache.syncope.core.provisioning.java.job.AutowiringSpringBeanJobFactory;
 import org.apache.syncope.core.provisioning.java.job.DefaultJobManager;
 import org.apache.syncope.core.provisioning.java.job.SchedulerDBInit;
 import org.apache.syncope.core.provisioning.java.job.SchedulerShutdown;
+import org.apache.syncope.core.provisioning.java.job.SyncopeSpringBeanJobFactory;
 import org.apache.syncope.core.provisioning.java.job.SystemLoadReporterJob;
 import org.apache.syncope.core.provisioning.java.job.notification.DefaultNotificationJobDelegate;
 import org.apache.syncope.core.provisioning.java.job.notification.NotificationJob;
@@ -311,7 +311,7 @@ public class ProvisioningContext implements AsyncConfigurer {
         scheduler.setOverwriteExistingJobs(true);
         scheduler.setDataSource(masterDataSource);
         scheduler.setTransactionManager(masterTransactionManager);
-        scheduler.setJobFactory(new AutowiringSpringBeanJobFactory());
+        scheduler.setJobFactory(new SyncopeSpringBeanJobFactory());
 
         Properties quartzProperties = new Properties();
         quartzProperties.setProperty(
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/AutowiringSpringBeanJobFactory.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/AutowiringSpringBeanJobFactory.java
deleted file mode 100644
index 109c9c2..0000000
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/AutowiringSpringBeanJobFactory.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.syncope.core.provisioning.java.job;
-
-import org.quartz.SchedulerContext;
-import org.quartz.spi.TriggerFiredBundle;
-import org.springframework.beans.BeanWrapper;
-import org.springframework.beans.MutablePropertyValues;
-import org.springframework.beans.PropertyAccessorFactory;
-import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
-import org.springframework.context.ApplicationContext;
-import org.springframework.context.ApplicationContextAware;
-import org.springframework.scheduling.quartz.SpringBeanJobFactory;
-
-/**
- * An implementation of SpringBeanJobFactory that retrieves the bean from the Spring context so that autowiring and
- * transactions work.
- */
-public class AutowiringSpringBeanJobFactory extends SpringBeanJobFactory implements ApplicationContextAware {
-
-    private transient AutowireCapableBeanFactory beanFactory;
-
-    private String[] ignoredUnknownProperties;
-
-    private SchedulerContext schedulerContext;
-
-    @Override
-    public void setApplicationContext(final ApplicationContext context) {
-        beanFactory = context.getAutowireCapableBeanFactory();
-    }
-
-    @Override
-    public void setIgnoredUnknownProperties(final String... ignoredUnknownProperties) {
-        String[] defensiveCopy = ignoredUnknownProperties.clone();
-        super.setIgnoredUnknownProperties(defensiveCopy);
-        this.ignoredUnknownProperties = defensiveCopy;
-    }
-
-    @Override
-    public void setSchedulerContext(final SchedulerContext schedulerContext) {
-        super.setSchedulerContext(schedulerContext);
-        this.schedulerContext = schedulerContext;
-    }
-
-    @Override
-    protected Object createJobInstance(final TriggerFiredBundle bundle) throws Exception {
-        Object job = beanFactory.getBean(bundle.getJobDetail().getKey().getName());
-        if (isEligibleForPropertyPopulation(job)) {
-            BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(job);
-            MutablePropertyValues pvs = new MutablePropertyValues();
-            if (this.schedulerContext != null) {
-                pvs.addPropertyValues(this.schedulerContext);
-            }
-            pvs.addPropertyValues(bundle.getJobDetail().getJobDataMap());
-            pvs.addPropertyValues(bundle.getTrigger().getJobDataMap());
-            if (this.ignoredUnknownProperties != null) {
-                for (String propName : this.ignoredUnknownProperties) {
-                    if (pvs.contains(propName) && !bw.isWritableProperty(propName)) {
-                        pvs.removePropertyValue(propName);
-                    }
-                }
-                bw.setPropertyValues(pvs);
-            } else {
-                bw.setPropertyValues(pvs, true);
-            }
-        }
-        return job;
-    }
-}
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/DefaultJobManager.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/DefaultJobManager.java
index eb0d230..63c48a5 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/DefaultJobManager.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/DefaultJobManager.java
@@ -37,7 +37,6 @@ import org.apache.syncope.common.lib.SyncopeConstants;
 import org.apache.syncope.common.lib.types.IdRepoImplementationType;
 import org.apache.syncope.common.lib.types.TaskType;
 import org.apache.syncope.core.persistence.api.DomainHolder;
-import org.apache.syncope.core.persistence.api.dao.NotFoundException;
 import org.apache.syncope.core.persistence.api.dao.ReportDAO;
 import org.apache.syncope.core.persistence.api.dao.TaskDAO;
 import org.apache.syncope.core.persistence.api.entity.Report;
@@ -46,7 +45,6 @@ import org.apache.syncope.core.persistence.api.entity.task.SchedTask;
 import org.apache.syncope.core.persistence.api.entity.task.Task;
 import org.apache.syncope.core.provisioning.api.job.JobNamer;
 import org.apache.syncope.core.spring.security.AuthContextUtils;
-import org.apache.syncope.core.spring.ApplicationContextProvider;
 import org.apache.syncope.core.persistence.api.SyncopeCoreLoader;
 import org.apache.syncope.core.persistence.api.dao.ImplementationDAO;
 import org.apache.syncope.core.persistence.api.entity.Implementation;
@@ -61,8 +59,6 @@ import org.quartz.TriggerBuilder;
 import org.quartz.TriggerKey;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.BeanCreationException;
-import org.springframework.beans.factory.support.AbstractBeanDefinition;
 import org.springframework.scheduling.quartz.SchedulerFactoryBean;
 import org.springframework.transaction.annotation.Transactional;
 import org.apache.syncope.core.provisioning.api.job.JobManager;
@@ -76,6 +72,7 @@ import org.apache.syncope.core.provisioning.java.job.report.ReportJob;
 import org.apache.syncope.core.provisioning.java.pushpull.PullJobDelegate;
 import org.apache.syncope.core.provisioning.java.pushpull.PushJobDelegate;
 import org.apache.syncope.core.spring.security.SecurityProperties;
+import org.quartz.Trigger;
 
 public class DefaultJobManager implements JobManager, SyncopeCoreLoader {
 
@@ -157,7 +154,7 @@ public class DefaultJobManager implements JobManager, SyncopeCoreLoader {
     }
 
     protected void registerJob(
-            final String jobName, final Job jobInstance,
+            final String jobName, final Class<? extends Job> jobClass,
             final String cronExpression, final Date startAt,
             final Map<String, Object> jobMap)
             throws SchedulerException {
@@ -170,34 +167,28 @@ public class DefaultJobManager implements JobManager, SyncopeCoreLoader {
         // 0. unregister job
         unregisterJob(jobName);
 
-        // 1. Job bean
-        ApplicationContextProvider.getBeanFactory().registerSingleton(jobName, jobInstance);
-
-        // 2. JobDetail bean
-        JobBuilder jobDetailBuilder = JobBuilder.newJob(jobInstance.getClass()).
+        // 1. JobDetail
+        JobBuilder jobDetailBuilder = JobBuilder.newJob(jobClass).
                 withIdentity(jobName).
                 usingJobData(new JobDataMap(jobMap));
 
-        // 3. Trigger
+        // 2. Trigger
         if (cronExpression == null && startAt == null) {
             // Jobs added with no trigger must be durable
             scheduler.getScheduler().addJob(jobDetailBuilder.storeDurably().build(), true);
         } else {
-            TriggerBuilder<?> triggerBuilder;
+            TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger().
+                    withIdentity(JobNamer.getTriggerName(jobName));
 
             if (cronExpression == null) {
-                triggerBuilder = TriggerBuilder.newTrigger().
-                        withIdentity(JobNamer.getTriggerName(jobName)).
-                        startAt(startAt);
+                triggerBuilder.startAt(startAt);
             } else {
-                triggerBuilder = TriggerBuilder.newTrigger().
-                        withIdentity(JobNamer.getTriggerName(jobName)).
-                        withSchedule(CronScheduleBuilder.cronSchedule(cronExpression));
+                triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(cronExpression));
 
                 if (startAt == null) {
-                    triggerBuilder = triggerBuilder.startNow();
+                    triggerBuilder.startNow();
                 } else {
-                    triggerBuilder = triggerBuilder.startAt(startAt);
+                    triggerBuilder.startAt(startAt);
                 }
             }
 
@@ -205,39 +196,11 @@ public class DefaultJobManager implements JobManager, SyncopeCoreLoader {
         }
     }
 
-    @SuppressWarnings("unchecked")
-    protected static <T> T createSpringBean(final Class<T> jobClass) {
-        T jobInstance = null;
-        for (int i = 0; i < 5 && jobInstance == null; i++) {
-            LOG.debug("{} attempt to create Spring bean for {}", i, jobClass);
-            try {
-                jobInstance = (T) ApplicationContextProvider.getBeanFactory().
-                        createBean(jobClass, AbstractBeanDefinition.AUTOWIRE_BY_TYPE, false);
-                LOG.debug("{} attempt to create Spring bean for {} succeeded", i, jobClass);
-            } catch (BeanCreationException e) {
-                LOG.error("Could not create Spring bean for {}", jobClass, e);
-                try {
-                    Thread.sleep(1000);
-                } catch (final InterruptedException ex) {
-                    // ignore
-                }
-            }
-        }
-        if (jobInstance == null) {
-            throw new NotFoundException("Spring bean for " + jobClass);
-        }
-
-        return jobInstance;
-    }
-
     @Override
     public Map<String, Object> register(final SchedTask task, final Date startAt, final long interruptMaxRetries,
             final String executor)
             throws SchedulerException {
 
-        TaskJob job = createSpringBean(TaskJob.class);
-        job.setTaskKey(task.getKey());
-
         Implementation jobDelegate = task.getJobDelegate() == null
                 ? task instanceof PullTask
                         ? implementationDAO.findByType(IdRepoImplementationType.TASKJOB_DELEGATE).stream().
@@ -255,11 +218,12 @@ public class DefaultJobManager implements JobManager, SyncopeCoreLoader {
         }
 
         Map<String, Object> jobMap = createJobMapForExecutionContext(executor);
+        jobMap.put(JobManager.TASK_KEY, task.getKey());
         jobMap.put(TaskJob.DELEGATE_IMPLEMENTATION, jobDelegate.getKey());
 
         registerJob(
                 JobNamer.getJobKey(task).getName(),
-                job,
+                TaskJob.class,
                 task.getCronExpression(),
                 startAt,
                 jobMap);
@@ -270,12 +234,10 @@ public class DefaultJobManager implements JobManager, SyncopeCoreLoader {
     public void register(final Report report, final Date startAt, final long interruptMaxRetries,
             final String executor) throws SchedulerException {
 
-        ReportJob job = createSpringBean(ReportJob.class);
-        job.setReportKey(report.getKey());
-
         Map<String, Object> jobMap = createJobMapForExecutionContext(executor);
+        jobMap.put(JobManager.REPORT_KEY, report.getKey());
 
-        registerJob(JobNamer.getJobKey(report).getName(), job, report.getCronExpression(), startAt, jobMap);
+        registerJob(JobNamer.getJobKey(report).getName(), ReportJob.class, report.getCronExpression(), startAt, jobMap);
     }
 
     protected static Map<String, Object> createJobMapForExecutionContext(final String executor) {
@@ -292,10 +254,6 @@ public class DefaultJobManager implements JobManager, SyncopeCoreLoader {
         } catch (SchedulerException e) {
             LOG.error("Could not remove job " + jobName, e);
         }
-
-        if (ApplicationContextProvider.getBeanFactory().containsSingleton(jobName)) {
-            ApplicationContextProvider.getBeanFactory().destroySingleton(jobName);
-        }
     }
 
     @Override
@@ -396,11 +354,10 @@ public class DefaultJobManager implements JobManager, SyncopeCoreLoader {
                         NotificationJob.class.getSimpleName(), conf.getLeft());
 
                 try {
-                    NotificationJob job = createSpringBean(NotificationJob.class);
                     Map<String, Object> jobData = createJobMapForExecutionContext(securityProperties.getAdminUser());
                     registerJob(
                             NOTIFICATION_JOB.getName(),
-                            job,
+                            NotificationJob.class,
                             conf.getLeft(),
                             null,
                             jobData);
@@ -412,11 +369,10 @@ public class DefaultJobManager implements JobManager, SyncopeCoreLoader {
             // 4. SystemLoadReporterJob (fixed schedule, every minute)
             LOG.debug("Registering {}", SystemLoadReporterJob.class);
             try {
-                SystemLoadReporterJob job = createSpringBean(SystemLoadReporterJob.class);
                 Map<String, Object> jobData = createJobMapForExecutionContext(securityProperties.getAdminUser());
                 registerJob(
                         StringUtils.uncapitalize(SystemLoadReporterJob.class.getSimpleName()),
-                        job,
+                        SystemLoadReporterJob.class,
                         "0 * * * * ?",
                         null,
                         jobData);
diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/SyncopeSpringBeanJobFactory.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/SyncopeSpringBeanJobFactory.java
new file mode 100644
index 0000000..c690f39
--- /dev/null
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/SyncopeSpringBeanJobFactory.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.provisioning.java.job;
+
+import java.util.Optional;
+import org.apache.syncope.core.provisioning.api.job.JobManager;
+import org.apache.syncope.core.provisioning.java.job.report.ReportJob;
+import org.quartz.spi.TriggerFiredBundle;
+import org.springframework.scheduling.quartz.SpringBeanJobFactory;
+
+public class SyncopeSpringBeanJobFactory extends SpringBeanJobFactory {
+
+    @Override
+    protected Object createJobInstance(final TriggerFiredBundle bundle) throws Exception {
+        Object job = super.createJobInstance(bundle);
+
+        if (bundle.getJobDetail().getJobDataMap() != null) {
+            if (job instanceof ReportJob) {
+                Optional.ofNullable(bundle.getJobDetail().getJobDataMap().getString(JobManager.REPORT_KEY)).
+                        ifPresent(((ReportJob) job)::setReportKey);
+            } else if (job instanceof TaskJob) {
+                Optional.ofNullable(bundle.getJobDetail().getJobDataMap().getString(JobManager.TASK_KEY)).
+                        ifPresent(((TaskJob) job)::setTaskKey);
+            }
+        }
+
+        return job;
+    }
+}