Announcement Announcement Module
Collapse
No announcement yet.
Manually creating a MethodInvokingJobDetailFactoryBean? Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Manually creating a MethodInvokingJobDetailFactoryBean?

    We have an enterprise application that uses a Quartz Scheduler to invoke CronJobs. Spring has the ability to create the scheduler and invoke the cronjobs via XML configuration, unfortunately, we need our clients to be able to modify these jobs via our application. Also, we want to read & write the jobs from the database using our Hibernate Layer.

    So, what we have is Spring set to startup quartz using the xml config, then in our WebContextLoaderListener we have an initialize method which reads the jobs from the DB and creates the CronJobs. The jobs are part of our action layer (old hangover from Struts), and need to call specific methods, so we are trying to manually instantiate MethodInvokingJobDetailFactoryBeans.

    Everything seems to startup fine, and we can manipulate the jobs on the fly while persisting the changes to the DB (in case of server restart), but when the scheduler runs, we get a "IllegalArgumentException: Target method must not be non-static without a target" exception.

    Any ideas? (Besides, use the examples.. unless you can point me to an example of Sprig creating the jobs by accessing the database via Hibernate Objects)

    I figure I'm missing a step in the MethodInvokingJobDetailFactoryBean creation, I just can't figure out what it is...


    XML Config:

    Code:
    <bean id="Scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
    	<property name="autoStartup">
    		<value>false</value> <!-- RuleManager should be the one starting the Scheduler -->
    	</property>
    	<property name="schedulerName">
    		<value>ACISScheduler</value>
    	</property>
    	<property name="waitForJobsToCompleteOnShutdown">
    		<value>true</value>
    	</property>
    </bean>


    Job/Trigger Creation:

    Code:
    Scheduler scheduler = SpringContext.getInstance().getScheduler();
    List<CronJob> cronJobList = SpringContext.getInstance().getCronJobLogic().list();
    try
    {
    	scheduler.start();
    	for (CronJob cronJob : cronJobList)
    	{
    		try
    		{
    			MethodInvokingJobDetailFactoryBean jobDetail = new MethodInvokingJobDetailFactoryBean();
    			jobDetail.setTargetMethod(cronJob.getTargetMethod());
    			jobDetail.setTargetClass(Class.forName(cronJob.getTargetObject()));
    			jobDetail.setName(cronJob.toString());
    			jobDetail.afterPropertiesSet();
    			CronTrigger cronTrigger = new CronTrigger(cronJob.getTriggerName(), cronJob.getGroupName(), cronJob.getExpression());
    			scheduler.scheduleJob((JobDetail)jobDetail.getObject(), cronTrigger);
    		}
    		catch (Exception e)
    		{
    			logger.error(e.getMessage(), e);
    		}
    	}
    }
    catch(SchedulerException se)
    {
    	logger.error(se.getMessage(), se);
    }



    Thanks,


    /Christien
    Last edited by thecatwhisperer; Dec 17th, 2008, 02:14 PM. Reason: cleanup

  • #2
    Allright, So I figured it out, and it is mainly me not understanding how th object is supposed to be initialized (better documentation would help though:P ).

    First of all, I need to be setting the Target Object, not the Class, and second (and this issue isn't shown, I needed to initialize the object passed in via the Spring Context...)

    Begin Code:

    Code:
    Scheduler scheduler = SpringContext.getInstance().getScheduler();
    List<CronJob> cronJobList = SpringContext.getInstance().getCronJobLogic().list();
    try
    {
    	scheduler.start();
    	for (CronJob cronJob : cronJobList)
    	{
    		try
    		{
    			MethodInvokingJobDetailFactoryBean jobDetail = new MethodInvokingJobDetailFactoryBean();
    			jobDetail.setTargetMethod(cronJob.getTargetMethod());
    			jobDetail.setTargetObject(SpringContext.getInstance().getApplicationContext().getBean(cronJob.getTargetObject()));
    			jobDetail.setName(cronJob.toString());
    			jobDetail.afterPropertiesSet();
    			CronTrigger cronTrigger = new CronTrigger(cronJob.getTriggerName(), cronJob.getGroupName(), cronJob.getExpression());
    			scheduler.scheduleJob((JobDetail)jobDetail.getObject(), cronTrigger);
    		}
    		catch (Exception e)
    		{
    			logger.error(e.getMessage(), e);
    		}
    	}
    }
    catch(SchedulerException se)
    {
    	logger.error(se.getMessage(), se);
    }


    End Code:

    BTW, the list of cron jobs come from our Hibernate Layer. And yes, the name "CronJob" is probably a poor naming choice.

    Comment


    • #3
      Manaully creating a MethodInvokingJobDetailFactoryBean

      I wanted to schedule a job, with parameters, on demand in Java. The following example shows how I did this.

      BEGIN CODE

      XML

      <bean id="scheduler" class="org.springframework.scheduling.quartz.Sched ulerFactoryBean" scope="prototype">
      <property name="autoStartup" value="false"/>
      <property name="waitForJobsToCompleteOnShutdown" value="true"/>
      </bean>

      JAVA

      private class exampleClass {

      private long exampleValue;

      public exampleClass( long value ){
      this.exampleValue = value;
      }

      public void exampleMethod() {
      exampleValue++;
      }

      public long getValue(){ return exampleValue; }
      }

      @Autowired
      StdScheduler scheduler;

      @Test
      public void testScheduleTriggerToInvokeAMethod() {
      System.out.println("testScheduleTriggerToInvokeAMe thod");
      try {

      MethodInvokingJobDetailFactoryBean jobDetail = new MethodInvokingJobDetailFactoryBean();
      exampleClass example = new exampleClass( 0 );
      jobDetail.setTargetObject( example );
      jobDetail.setTargetMethod("exampleMethod");
      jobDetail.setName("example");
      jobDetail.setGroup("test");
      jobDetail.setConcurrent(false);
      jobDetail.afterPropertiesSet();


      SimpleTriggerBean trigger = new SimpleTriggerBean();
      trigger.setBeanName("Example");
      trigger.setJobDetail( (JobDetail)(jobDetail.getObject()) );
      trigger.setRepeatCount( 3 );
      trigger.setRepeatInterval(100);
      trigger.setStartDelay( 0 );
      trigger.afterPropertiesSet();

      scheduler.start();
      scheduler.scheduleJob( (JobDetail)(jobDetail.getObject()), trigger );

      Thread.sleep( 1000 );

      assertEquals( 4, example.getValue() );

      } catch (InterruptedException ex) {
      //complain
      } catch (ClassNotFoundException ex) {
      //complain
      } catch (NoSuchMethodException ex) {
      //complain
      } catch (ParseException ex) {
      //complain
      } catch (SchedulerException ex) {
      //complain
      }
      }

      END CODE

      Comment

      Working...
      X