Thursday 26 March 2009

Scheduling and thread pooling in Spring tutorial

The Spring Framework contains integration classes for scheduling support and thread pooling.

The scheduling support classes act as a wrapper for the java Quartz Scheduler

They are as follows:

org.springframework.scheduling.quartz.QuartzJobBean
org.springframework.scheduling.quartz.JobDetailBean
org.springframework.scheduling.quartz.SimpleTriggerBean
org.springframework.scheduling.quartz.CronTriggerBean
org.springframework.scheduling.quartz.SchedulerFactoryBean


Some of the thread pooling support classes are as follows:

org.springframework.scheduling.quartz.SimpleThreadPoolTaskExecutor
org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor


Please see below a simple example using Spring Framework's Quartz scheduling and threadpooling features:

UML Diagram of example using Spring's scheduling and thread pooling features


click on diagram to view larger picture











Please see below example Code:

MonitorJob.java

import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.context.ApplicationContext;
import org.springframework.scheduling.quartz.QuartzJobBean;

public class MonitorJob extends QuartzJobBean {

   private int timeout;

   private static final String APPLICATION_CONTEXT_KEY = "applicationContext";


   public void setTimeout(int timeout){
     this.timeout = timeout;
   }

   @Override
   protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
     // TODO Auto-generated method stub

     processJobs(context);
     }

   private ApplicationContext getApplicationContext(JobExecutionContext context )
throws Exception {

     ApplicationContext appCtx = null;
     appCtx = (ApplicationContext)context.getScheduler().getContext().get(APPLICATION_CONTEXT_KEY);

     if (appCtx == null) {
       throw new JobExecutionException(
"No application context available in scheduler context for key \"" + APPLICATION_CONTEXT_KEY + "\"");
     }
     return appCtx;
   }

   private void processJobs(JobExecutionContext context) {

     MonitorProcessDelegate procDelegate = null;

     try {

         ApplicationContext ctx = getApplicationContext(context);
         procDelegate = (MonitorProcessDelegate)ctx.getBean("MonitorProcessDelegate");


     }catch (Exception e) { e.printStackTrace();}

     System.out.println("Running job monitor");

     procDelegate.ListBusinessExceptionCases();
     procDelegate.ListActiveProcesses();


     }
   }

MonitorProcessDelegate.java

import org.springframework.core.task.TaskExecutor;

public class MonitorProcessDelegate {

   private class ActiveProcesses implements Runnable {

   // code for identifying and listing active processes

     public void run() {
       .....
     }
   }

   private class BusinessExceptionCasesBacklog implements Runnable {

   // code for identifying and listing business exception cases

     public void run() {
       .....
     }
   }

   private TaskExecutor taskExecutor;

   public MonitorProcessDelegate;(TaskExecutor taskExecutor) {

     this.taskExecutor = taskExecutor;
   }

   public void ListActiveProcesses() {

     taskExecutor.execute(new ActiveProcesses());

   }

public void ListBusinessExceptionCases() {

     taskExecutor.execute(new BusinessExceptionCasesBacklog());

   }
}

Spring's Dispatcher servlet's configuration file settings

click on diagram to view larger picture

Abstract Factory Pattern tutorial creating threads

Say for e.g.

Finance module uses threads with the following attributes:

ThreadGroup = "Finance"
Priority = 7

Reporting module uses threads with the following attributes:

ThreadGroup = "Report"
Priority = 5

Using an AbstractFactoryPattern it is possible to design a framework which will provide transparency to developers in creating threads with application module-specific attributes and also maintaining a centralized control on module-specific thread properties.

Please see below UML Diagram of the Framework:

Please click on diagram to view larger picture












Sample code of framework:

AbstractIF.java

public interface AbstractIF {
   public Thread createThread();
}

AbstractFactoryIF.java

public interface AbstractFactoryIF {
   public AbstractIF createThread(Runnable runnable);
}

ThreadFactory.java

public class ThreadFactory implements AbstractFactoryIF {

   String moduleName;

   public ThreadFactory(String moduleName) {
     this.moduleName = moduleName;
   }
   public AbstractIF createThread(Runnable runnable) {
   // TODO Auto-generated method stub

     if(moduleName.equals("Finance")) {
       return new CreateFinanceThread(moduleName,runnable);
     }
     else if(moduleName.equals("Report")){
       return new CreateReportThread(moduleName,runnable);
     }
     else
       return null;
     }

}

CreateFinanceThread.java

public class CreateFinanceThread implements AbstractIF {

   private String moduleName;
   private ThreadGroup threadGroup;
   private Runnable runnable;
   private Thread t;
   private int priority = 7;

   public CreateFinanceThread(String moduleName,Runnable runnable) {
     this.runnable = runnable;
     this.moduleName = moduleName;
   }

   public Thread createThread() {
   // TODO Auto-generated method stub
     threadGroup = new ThreadGroup(moduleName);
     t = new Thread(threadGroup,runnable);
     t.setPriority(priority);
     return t;
   }
}

CreateReportThread.java

public class CreateReportThread implements AbstractIF {

   private String moduleName;
   private ThreadGroup threadGroup;
   private Runnable runnable;
   private Thread t;
   private int priority = 5;

   public CreateReportThread(String moduleName,Runnable runnable) {
     this.runnable = runnable;
     this.moduleName = moduleName;
   }

   public Thread createThread() {
   // TODO Auto-generated method stub
     threadGroup = new ThreadGroup(moduleName);
     t = new Thread(threadGroup,runnable);
     t.setPriority(priority);
     return t;
   }
}

ProcessDelegate.java

public class ProcessDelegate {

   private ThreadFactory threadFactory;
   private String moduleName;
   private Thread t;

   public ProcessDelegate(String moduleName) {
     this.moduleName = moduleName;
   }

   public void doproc() {
     AbstractFactoryIF factory = new ThreadFactory(moduleName);
     AbstractIF thread = factory.createThread(new Runnable() {
       public void run() {
         doStuff(moduleName);
        }
     });

     t = thread.createThread();
     t.start();
}

   public void doStuff(String moduleName) {
      // do module specific stuff here based on the value of moduleName parameter..

     /* The Finance stuff will be run in a thread with:

          - ThreadGroup="Finance"
          - priority = 7

     The Reporting stuff will be run in a thread with:

          - ThreadGroup="Report"
          - priority = 5

     But this will be transparent to the developer using the ProcessDelegate class.
*/

   }
}