Skip to content

Schedule a task in Adobe/Day CQ 5

January 30, 2012

In Day CQ WCM platform helps to schedule a job.  The job need to be Runnable job which will be registered to the CQ platform and will be executed upon the defined periodicity.
The sling scheduler documentation can be found here:
http://sling.apache.org/site/scheduler-service-commons-scheduler.html
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.
In other words the schedulers can be implemented in two ways:

  1.     Annotated way
  2.     Declarative way

1. Annotated Way
When scheudler is implemented using annotations then the pom.xml need to include the sling schduler annotation processor.

package your.package.here;
/**
* @scr.component
* @scr.service interface="java.lang.Runnable"
* @scr.property name="scheduler.expression" value="0 * * * * ?"
*/
public class YourClass implements Runnable {
/* Job runs every minute*/
public void run() {
log.debug("Executing scheduled job at: " + new Date(System.currentTimeMillis()));
}
}

When scheduler is implemented using annotations then the pom.xml need to include the sling annotation processor for processing the annotations.

<pom.xml>
....
<dependency>
<groupId>org.apache.felix</groupId>
<artifactId>org.apache.felix.scr.annotations</artifactId>
<version>1.2.0</version>
</dependency>
....
</pom.xml>

Using annotations is the simplest way of creating scheduler jobs.

2. Declarative way – 1
If a newly developed scheduler need to embedded into an existing OSGi bundle then declaratively the scheduler need to be registered as a runnable at the start of the bundle. Something as below:

class Activator {
......
public void start(){
registerSchedulerService();
}
public void registerSchedulerService(BundleContext bundleContext){
final Dictionary&lt;String, String&gt; schedulerProps = new Hashtable&lt;String, String&gt;();
String cronExpression = "30 0 * * * ?";// runs at 00:30 AM every day
schedulerProps.put(scheduler.expression, cronExpression);
MyPeriodicScheduler periodicScheduler = new MyPeriodicScheduler ();
log.debug("Registering MyPeriodicScheduler scheduler");
bundleContext.registerService(Runnable.class, periodicScheduler, schedulerProps);
}
......
}

MyPeriodicScheduler is a sample runnable class as below:

package your.package.here;
public class MyPeriodicScheduler implements Runnable {
/* Runnable runs every minute*/
public void run() {
log.debug("Running scheduled job at: " + new Date(System.currentTimeMillis()));
}
}

3. Declarative way – 2
The developed runnable can be registered directly to the underlying CQ scheduler instance be invoking addJob(), addPeriodicJob() or fireJobAt() methods by passible relevant parameters.

package sling.docu.examples;
</br>
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;
</br>
/**
* This service executes scheduled jobs
*
* @scr.component immediate="true" metatype="false"
*/
public class HelloWorldScheduledService {
/**
* The scheduler for rescheduling jobs.
*
* @scr.reference
*/
private Scheduler scheduler;
</br>
protected void activate(ComponentContext componentContext) throws Exception {
// case 1: with addJob() method: executes the job every minute
String schedulingExpression = "0 * * * * ?";
String jobName1 = "case1";
Map&lt;String, Serializable&gt; config1 = new HashMap&lt;String, Serializable&gt;();
boolean canRunConcurrently = true;
final Runnable job1 = new Runnable() {
public void run() {
log.info("Executing job1");
}
};
try {
this.scheduler.addJob(jobName1, job1, config1,
schedulingExpression, canRunConcurrently);
} catch (Exception e) {
job1.run();
}
// case 2: with addPeriodicJob(): executes the job every 3 minutes
String jobName2 = "case2";
long period = 180;
Map&lt;String, Serializable&gt; config2 = new HashMap&lt;String, Serializable&gt;();
final Runnable job2 = new Runnable() {
public void run() {
log.info("Executing job2");
}
};
try {
this.scheduler.addPeriodicJob(jobName2, job2, config2, period,
canRunConcurrently);
} catch (Exception e) {
job2.run();
}
// case 3: with fireJobAt(): executes the job at a specific date (date
// of deployment + delay of 30 seconds)
String jobName3 = "case3";
final long delay = 30 * 1000;
final Date fireDate = new Date();
fireDate.setTime(System.currentTimeMillis() + delay);
Map&lt;String, Serializable&gt; config3 = new HashMap&lt;String, Serializable&gt;();
final Runnable job3 = new Runnable() {
public void run() {
log.info(
"Executing job3 at date: {} with a delay of: {} seconds",
fireDate, delay / 1000);
}
};
try {
this.scheduler.fireJobAt(jobName3, job3, config3, fireDate);
} catch (Exception e) {
job3.run();
}
}
</br>
protected void deactivate(ComponentContext componentContext) {
log.info("Deactivated, goodbye!");
}
}

Happy scheduling ;).

From → Day/Adobe CQ

4 Comments
  1. Colin permalink

    Why in example two does the PeriodicScheduler contain a comment saying it runs every minute, but it seems to be scheduled from a crontab style rule, to run daily at 3am

  2. Raj permalink

    hi have a question.
    How do i ensure the scheduler has ran successfully and if not i want have the scheduler try to run again.

    • Raj! you can enclose scheduler in try catch. This will guarantee the execution of the job.
      try {
      this.scheduler.addJob(jobName1, job1, config1,
      schedulingExpression, canRunConcurrently);
      } catch (Exception e) {
      job1.run();
      }

  3. Maruthi permalink

    Hi I added one schedular which will do DAM migration. If I want to stop the schedular in between is there any UI in CQ where I can see the job running and I can stop it.

Leave a reply to Maruthi Cancel reply