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:21 UTC

[syncope] 02/02: [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 2_1_X
in repository https://gitbox.apache.org/repos/asf/syncope.git

commit f18da0d71fda4892466ea707cf297dc0f789f7ef
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 +
 .../java/job/AutowiringSpringBeanJobFactory.java   | 85 ----------------------
 .../core/provisioning/java/job/JobManagerImpl.java | 78 +++++---------------
 .../java/job/SyncopeSpringBeanJobFactory.java      | 45 ++++++++++++
 .../src/main/resources/provisioningContext.xml     |  2 +-
 5 files changed, 67 insertions(+), 147 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 ddd641f..8b8ab9b 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";
 
     JobKey NOTIFICATION_JOB = new JobKey("notificationJob", Scheduler.DEFAULT_GROUP);
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/JobManagerImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/JobManagerImpl.java
index 274153e..13a5b21 100644
--- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/JobManagerImpl.java
+++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/job/JobManagerImpl.java
@@ -36,7 +36,6 @@ import org.apache.syncope.common.lib.SyncopeConstants;
 import org.apache.syncope.common.lib.types.ImplementationType;
 import org.apache.syncope.common.lib.types.TaskType;
 import org.apache.syncope.core.persistence.api.dao.ConfDAO;
-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.SyncopeLoader;
 import org.apache.syncope.core.persistence.api.DomainsHolder;
 import org.apache.syncope.core.persistence.api.dao.ImplementationDAO;
@@ -62,9 +60,7 @@ 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.annotation.Autowired;
-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;
@@ -77,6 +73,7 @@ import org.apache.syncope.core.provisioning.java.job.notification.NotificationJo
 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.quartz.Trigger;
 
 public class JobManagerImpl implements JobManager, SyncopeLoader {
 
@@ -144,7 +141,7 @@ public class JobManagerImpl implements JobManager, SyncopeLoader {
     }
 
     private 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 {
@@ -157,34 +154,28 @@ public class JobManagerImpl implements JobManager, SyncopeLoader {
         // 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);
                 }
             }
 
@@ -192,38 +183,10 @@ public class JobManagerImpl implements JobManager, SyncopeLoader {
         }
     }
 
-    @SuppressWarnings("unchecked")
-    private <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)
             throws SchedulerException {
 
-        TaskJob job = createSpringBean(TaskJob.class);
-        job.setTaskKey(task.getKey());
-
         Implementation jobDelegate = task.getJobDelegate() == null
                 ? task instanceof PullTask
                         ? implementationDAO.find(ImplementationType.TASKJOB_DELEGATE).stream().
@@ -241,12 +204,13 @@ public class JobManagerImpl implements JobManager, SyncopeLoader {
         }
 
         Map<String, Object> jobMap = new HashMap<>();
+        jobMap.put(JobManager.TASK_KEY, task.getKey());
         jobMap.put(JobManager.DOMAIN_KEY, AuthContextUtils.getDomain());
         jobMap.put(TaskJob.DELEGATE_IMPLEMENTATION, jobDelegate.getKey());
 
         registerJob(
                 JobNamer.getJobKey(task).getName(),
-                job,
+                TaskJob.class,
                 task.getCronExpression(),
                 startAt,
                 jobMap);
@@ -257,13 +221,11 @@ public class JobManagerImpl implements JobManager, SyncopeLoader {
     public void register(final Report report, final Date startAt, final long interruptMaxRetries)
             throws SchedulerException {
 
-        ReportJob job = createSpringBean(ReportJob.class);
-        job.setReportKey(report.getKey());
-
         Map<String, Object> jobMap = new HashMap<>();
+        jobMap.put(JobManager.REPORT_KEY, report.getKey());
         jobMap.put(JobManager.DOMAIN_KEY, AuthContextUtils.getDomain());
 
-        registerJob(JobNamer.getJobKey(report).getName(), job, report.getCronExpression(), startAt, jobMap);
+        registerJob(JobNamer.getJobKey(report).getName(), ReportJob.class, report.getCronExpression(), startAt, jobMap);
     }
 
     private void unregisterJob(final String jobName) {
@@ -273,10 +235,6 @@ public class JobManagerImpl implements JobManager, SyncopeLoader {
         } catch (SchedulerException e) {
             LOG.error("Could not remove job " + jobName, e);
         }
-
-        if (ApplicationContextProvider.getBeanFactory().containsSingleton(jobName)) {
-            ApplicationContextProvider.getBeanFactory().destroySingleton(jobName);
-        }
     }
 
     @Override
@@ -379,10 +337,9 @@ public class JobManagerImpl implements JobManager, SyncopeLoader {
                     NotificationJob.class.getSimpleName(), conf.getLeft());
 
             try {
-                NotificationJob job = createSpringBean(NotificationJob.class);
                 registerJob(
                         NOTIFICATION_JOB.getName(),
-                        job,
+                        NotificationJob.class,
                         conf.getLeft(),
                         null,
                         jobMap);
@@ -394,10 +351,9 @@ public class JobManagerImpl implements JobManager, SyncopeLoader {
         // 4. SystemLoadReporterJob (fixed schedule, every minute)
         LOG.debug("Registering {}", SystemLoadReporterJob.class);
         try {
-            SystemLoadReporterJob job = createSpringBean(SystemLoadReporterJob.class);
             registerJob(
                     "systemLoadReporterJob",
-                    job,
+                    SystemLoadReporterJob.class,
                     "0 * * * * ?",
                     null,
                     jobMap);
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;
+    }
+}
diff --git a/core/provisioning-java/src/main/resources/provisioningContext.xml b/core/provisioning-java/src/main/resources/provisioningContext.xml
index b905294..13f4d9f 100644
--- a/core/provisioning-java/src/main/resources/provisioningContext.xml
+++ b/core/provisioning-java/src/main/resources/provisioningContext.xml
@@ -77,7 +77,7 @@ under the License.
     <property name="dataSource" ref="MasterDataSource"/>
     <property name="transactionManager" ref="MasterTransactionManager"/>
     <property name="jobFactory">
-      <bean class="org.apache.syncope.core.provisioning.java.job.AutowiringSpringBeanJobFactory"/>
+      <bean class="org.apache.syncope.core.provisioning.java.job.SyncopeSpringBeanJobFactory"/>
     </property>
     <property name="quartzProperties">
       <props>