In CQ there are a few ways to perform a scheduled action.  I will go over basics for the easiest way to achieve this, a custom class running a cron expressions to fire off a run() method.

An alternative to this tutorial would be to create a scheduled or event workflow that is triggered at a specific time, I won’t go over this but as with most things there is usually more than one way to reach your goal.

Scheduling in CQ uses the open source Quartz library, part Sling Commons:‘org.apache.sling.commons.scheduler.Scheduler’.  The scheduler can be used in two ways, by registering a job method or even more simply by using the scheduler’s whiteboard pattern supported by scheduler’s API.

Let’s begin, we will start with the more simple of the two ways to use scheduler in a custom class; the whiteboard pattern.  Create your custom class:

package your.package.here;

public class YourClass {

Next, let’s build our whiteboard pattern:

/**
 * @scr.component
 * @scr.service interface="java.lang.Runnable"
 * @scr.property name="scheduler.expression" value="0 * * * * ?"
 * @scr.property name="scheduler.concurrent" value="false" type="Boolean"
*/

This pattern says, initiate the scheduler and set the timing expression to trigger every minute, and also only trigger once per minute.  The scheduler.expression uses a cron expression which can set nearly any type of timing you could need.  Once you figure out the scheduler expressions you can setup scheduling for any time even multiple times.

Brief overview on scheduler.expression:
To understand this easier * and ? could be replaced with the word “every”.  Below are some examples.

(seconds minutes hours days months years)

  • 0 * * * * ?
    • on 0 second every minute, every day, every hour… you get the idea.
  • 0 15 12 * * ?
    • on 0 second, of 15th minute, of 12th hour, every day…. at 12:15 trigger event.
  • 0 0-5 10,12,2 ? JAN,APR,JUL,OCT 2012-2020
    • on 0 second, of 0 minute through 5th minute, at 10am 12noon AND 2pm, everyday, in January, April, July AND October, from 2012 until 2020.

For more information on cron expressions visit Oracles page: ‘Cron Expressions’.

The scheduler.concurrent used in my pattern prevents other scheduled events you might be running from being triggered at the same time setting this property is optional and I typically leave it out unless there are multiple schedules running at short intervals on a slower server.

On to the run method, this is simple…

public void run() {
     //place events to run here.
}

Full copy of our completed scheduling class:

package your.package.here;

/**
* @scr.component
* @scr.service interface="java.lang.Runnable"
* @scr.property name="scheduler.expression" value="0 * * * * ?"
*/

public class YourClass implements Runnable {

 public void run() {
      //place events to run here.
 }
}

This concludes the easier way to create a scheduled event.  But what if you need to run multiple schedules with vastly different scheduled expressions?  Then you need to drop using the schedulers whiteboard pattern and use some of Quartz scheduler’s built in methods to trigger events.

Those other methods include:

  • addJob()  –  Use when implementing a schedulingExpression like we did with the whiteboard pattern.
this.scheduler.addJob("myJob", job, null, schedulingExpression, true);
  • addPeriodicJob()  -  Use when you have a preset number of seconds for firing the event.
long period = 3*60; //in seconds
this.scheduler.addPeriodicJob("myJob", job, null, period, true);
  • fireJobAt()  –  Use for triggering your event on a specific date.
SimpleDateFormat formatter = new SimpleDateFormat("yyyy/MM/dd");
String date = "2020/01/10";
java.util.Date fireDate = formatter.parse(date);
this.scheduler.fireJobAt("myJob", job, null, fireDate);

These methods are the bread and butter to achieve multiple schedules for your class events.  Everything else involved around getting this to work is just defining your variables, naming your jobs and defining each run method in association with the name of each job.

Below is a simplified overview of this in action:

package your.package.here;

import java.io.Serializable;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import org.apache.sling.commons.scheduler.Scheduler;
import org.osgi.service.component.ComponentContext;

public class YourClass {
    private Scheduler scheduler;

    protected void activate(ComponentContext componentContext) throws Exception {
    //addJob Method Example.
    	String schedulingExpression = "0 * * * * ?";
    	String jobName1 = "job1";
    	Map<String, Serializable> config1 = new HashMap<String, Serializable>();
    	boolean runConcurrently = true;
        final Runnable job1 = new Runnable() {
            public void run() {
            	//run event here.
            }
        };
        try {
        	this.scheduler.addJob(jobName1, job1, config1, schedulingExpression, runConcurrently);
        } catch (Exception e) {
            job1.run();
        }

   //addPeriodicJob Method Example.
        String jobName2 = "job2";
    	long period = 180;
    	Map<String, Serializable> config2 = new HashMap<String, Serializable>();
        final Runnable job2 = new Runnable() {
            public void run() {
            	//run event here.
            }
        };
        try {
        	this.scheduler.addPeriodicJob(jobName2, job2, config2, period, runConcurrently);
        } catch (Exception e) {
            job2.run();
        }

   //fireJobAt Method Example.
        String jobName3 = "job3";
    	final long delay = 30*1000;
    	final Date fireDate = new Date();
        fireDate.setTime(System.currentTimeMillis() + delay);
    	Map<String, Serializable> config3 = new HashMap<String, Serializable>();
        final Runnable job3 = new Runnable() {
            public void run() {
            	//run event here.
            }
        };
        try {
        	this.scheduler.fireJobAt(jobName3, job3, config3, fireDate);
        } catch (Exception e) {
            job3.run();
        }
    }

}

This sums up bundled scheduling and the overview of CQ’s open source scheduler library Quartz.  If you have any questions, comments or would like to hire 6D staff to implement similar scheduling or other CQ functionality – please contact Six Dimensions.