Announcement Announcement Module
Collapse
No announcement yet.
Quartz Method Invocation on Beans Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Quartz Method Invocation on Beans

    I've hunted the forums briefly and hadn't found if someone else went down the same path as I am.

    I'm looking to use Quartz to schedule a future callback on a bean using a persistent job store.

    The MethodInvokingJobDetailFactoryBean works fine for calling back a bean for a memory-only data store.

    It looks like there needs to be some form of callback handler that is bean factory aware that can delegate the persisted callback (since the bean it's calling back is not serializable).

    I was about to rig this up using JMS with the Quartz job dropping the callback into a JMS queue and letting my JMS message handler (which has a reference to the factory) delegate to the bean by name. Is there a better mechanism I'm about to overlook?

    TIA!

  • #2
    As always I think I answered my own question.

    A more convenient method of handling is implementing a Job class that uses the Scheduler context on the JobExecutionContext to get a reference to the bean factory.

    using the SchedulerFactoryBean, you can call setSchedulerContextAsMap() to stick this in there...

    Comment


    • #3
      Originally posted by fallofrome
      As always I think I answered my own question.

      A more convenient method of handling is implementing a Job class that uses the Scheduler context on the JobExecutionContext to get a reference to the bean factory.

      using the SchedulerFactoryBean, you can call setSchedulerContextAsMap() to stick this in there...
      Note that if the bean that does the scheduling is the same that the method will have to be called on you will end with a circular reference that I don't know how to solve without recurring to a locator that uses the name of the bean at runtime. If this is your case and you find a nicer IOC solution, drop me a line!

      Comment


      • #4
        Here's a class and some paraphernalia I use to schedule a method call on a named bean.

        Michael

        Code:
        import java.util.Date;
        
        import org.quartz.Job;
        import org.quartz.JobDataMap;
        import org.quartz.JobDetail;
        import org.quartz.JobExecutionContext;
        import org.quartz.JobExecutionException;
        import org.quartz.Scheduler;
        import org.quartz.SchedulerException;
        import org.quartz.SimpleTrigger;
        import org.quartz.Trigger;
        import org.springframework.beans.factory.InitializingBean;
        import org.springframework.beans.support.ArgumentConvertingMethodInvoker;
        import org.springframework.context.ApplicationContext;
        import org.springframework.util.Assert;
        import org.springframework.util.MethodInvoker;
        
        
        /**
         * Bean that uses a 
         * <a href="http&#58;//quartz.sourceforge.net/">Quartz</a>
         * scheduler to invoke a method on a named bean in a 
         * <a href="http&#58;//www.springframework.org/">Spring</a>
         * &#123;@link org.springframework.context.ApplicationContext&#125;.
         */
        public class MethodInvocationSchedulerBean implements InitializingBean &#123;
            private static final String APPLICATION_CONTEXT_KEY = "applicationContext";
            private static final String TARGET_BEAN_NAME_KEY = "target";
            private static final String METHOD_NAME_KEY = "method";
            private static final String ARGUMENTS_KEY = "arguments";
        
            private Scheduler _scheduler;
            private String _group;
            
            
            public void setScheduler&#40; Scheduler scheduler &#41; &#123;
                _scheduler = scheduler;
            &#125;
        
            
            public void setGroup&#40; String group &#41; &#123;
                _group = group;
            &#125;
            
        
            public void afterPropertiesSet&#40;&#41; throws Exception &#123;
                Assert.notNull&#40;_scheduler, "scheduler property must be set"&#41;;
                Assert.hasText&#40;_group, "group property must not be empty"&#41;;
            &#125;
        
            
            public void scheduleInvocation&#40;
                    Date when,
                    String beanName,
                    String methodName,
                    Object&#91;&#93; args&#41; throws SchedulerException &#123;
                Assert.notNull&#40;when, "Date must not be null"&#41;;
                Assert.hasText&#40;beanName, "beanName must not be blank"&#41;;
                Assert.hasText&#40;methodName, "methodName must not be blank"&#41;;
                
                String name = beanName + '#' + methodName;
                
                _scheduler.scheduleJob&#40;
                        createJobDetail&#40;beanName, methodName, args, name&#41;,
                        createTrigger&#40;name, when&#41;&#41;;
            &#125;
            
            
            private Trigger createTrigger&#40; String name, Date when&#41; &#123;
                return new SimpleTrigger&#40;name, _group, when&#41;;
            &#125;
        
            
            private JobDetail createJobDetail&#40;
                    String beanName,
                    String methodName,
                    Object&#91;&#93; args,
                    String name&#41; &#123;
                JobDetail detail = new JobDetail&#40;
                        name, _group,
                        ScheduledInvocationJob.class,
                        true, false, false&#41;;
                
                detail.getJobDataMap&#40;&#41;.put&#40;TARGET_BEAN_NAME_KEY, beanName&#41;;
                detail.getJobDataMap&#40;&#41;.put&#40;METHOD_NAME_KEY, methodName&#41;;
                detail.getJobDataMap&#40;&#41;.put&#40;ARGUMENTS_KEY, args&#41;;
                
                return detail;
            &#125;
        
            
            
            public static class ScheduledInvocationJob implements Job &#123;
        
                public void execute&#40; JobExecutionContext context &#41;
                    throws JobExecutionException &#123;
                    
                    try &#123;
                        ApplicationContext appCtx = getApplicationContext&#40;context&#41;;
        
                        JobDataMap data = context.getJobDetail&#40;&#41;.getJobDataMap&#40;&#41;;
                        String beanName = data.getString&#40;TARGET_BEAN_NAME_KEY&#41;;
                        Object target = appCtx.getBean&#40;beanName&#41;;
                        String methodName = data.getString&#40;METHOD_NAME_KEY&#41;;
                        Object&#91;&#93; args = &#40;Object&#91;&#93;&#41;data.get&#40;ARGUMENTS_KEY&#41;;
                        
                        invokeMethod&#40;target, methodName, args&#41;;
                    &#125; catch &#40;JobExecutionException e&#41; &#123;
                        throw e;
                    &#125; catch &#40;Exception e&#41; &#123;
                        throw new JobExecutionException&#40;e&#41;;
                    &#125;
                &#125;
        
                private void invokeMethod&#40;Object target, String methodName, Object&#91;&#93; args&#41; 
                        throws Exception &#123;
                    MethodInvoker inv = new ArgumentConvertingMethodInvoker&#40;&#41;;
                    inv.setTargetObject&#40;target&#41;;
                    inv.setTargetMethod&#40;methodName&#41;;
                    inv.setArguments&#40;args&#41;;
                    inv.prepare&#40;&#41;;
                    inv.invoke&#40;&#41;;
                &#125;
        
                private ApplicationContext getApplicationContext&#40; JobExecutionContext context &#41;
                        throws Exception &#123;
                    ApplicationContext appCtx = null;
        
                    appCtx = &#40;ApplicationContext&#41;context.getScheduler&#40;&#41;
                        .getContext&#40;&#41;.get&#40;APPLICATION_CONTEXT_KEY&#41;;
                    
                    if &#40;appCtx == null&#41; &#123;
                        throw new JobExecutionException&#40;
                                "No application context available in scheduler context for key \"" + APPLICATION_CONTEXT_KEY + "\""&#41;; 
                    &#125;
                    return appCtx;
                &#125;
            &#125;
            
        &#125;
        applicationContext.xml:

        Code:
          <bean id="scheduler"
           class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
           <property name="applicationContextSchedulerContextKey">
             <value>applicationContext</value>
           </property>
          </bean>
        
          <bean id="reloadscheduler"
           class="app.MyReloadScheduler">
            <constructor-arg index="0">
              <bean class="de.schuerig.util.MethodInvocationSchedulerBean">
                <property name="scheduler"><ref bean="scheduler"/></property>
                <property name="group"><value>MyGroup</value></property>
              </bean>
            </constructor-arg>
          </bean>
        Bean that schedules a method invocation:

        Code:
        public class MyReloadScheduler implements ReloadScheduler &#123;
            private static final String TARGET_BEAN = "someBean";
            private final MethodInvocationSchedulerBean _scheduler;
            
            public MyReloadScheduler&#40;MethodInvocationSchedulerBean scheduler&#41; &#123;
                _scheduler = scheduler;
            &#125;
            
            public void scheduleReload&#40;
                    Date when &#41;
                    throws SchedulerException &#123;
                _scheduler.scheduleInvocation&#40;when, TARGET_BEAN, "reload", null&#41;;
            &#125;
           ...

        Comment

        Working...
        X