AEM Scheduler

Scheduler is used to trigger an activity at particular or period of time.

Scheduler can be created by two ways:

whiteboard pattern — Creation of scheduler with the help of Runnable interface implementation and overriding protected void activate(final Config config) method.

Note: Please avoid using whiteboard pattern scheduler as felix scr(org.apache.felix.scr.annotations.Property) is deprecated.

Scheduler API — Scheduler created with the help of Scheduler OSGI Service using @Reference annotation.

Create Scheduler using Scheduler API

For scheduler API we are going to use R6 annotation follow this link for more detail on R6 annotation.

Follow below steps to create scheduler:

  1. Create a class implementing Runnable interface and override run method.
    public class SimpleScheduledTask implements Runnable {

2. Mention @Component annotation from org.osgi.service.component.annotations package and register it as an OSGI service.
@Component(service=Runnable.class, immediate = true)
public class SimpleScheduledTask implements Runnable {

3. Provide one more @Designate annotation to consume R6 annotation:
@Designate(ocd=SimpleScheduledTask.Config.class)
@Component(service=Runnable.class)
public class SimpleScheduledTask implements Runnable {

4. Create R6 annotation OSGI Configuration for Scheduler:

package com.javadoubts.core.schedulers;


import org.osgi.service.metatype.annotations.AttributeDefinition;
import org.osgi.service.metatype.annotations.AttributeType;
import org.osgi.service.metatype.annotations.ObjectClassDefinition;

@ObjectClassDefinition(name = "SimpleSchedulerConfiguration OCD",
description = "SimpleSchedulerConfiguration OCD description"
)
public @interface SimpleSchedulerConfiguration {

@AttributeDefinition(
name = "Scheduler name",
description = "Scheduler name",
type = AttributeType.STRING)
String scheduler_name() default "practice";

// cron job for every minute
@AttributeDefinition(
name = "Cron job expression",
description = "Cron job expression",
type = AttributeType.STRING)
String scheduler_expression() default "0 * * * * ?";

@AttributeDefinition(
name = "Enable Scheduler",
description = "Enable Scheduler",
type = AttributeType.BOOLEAN)
boolean enable_scheduler() default true;

@AttributeDefinition(
name = "Concurrent Scheduler",
description = "Concurrent Scheduler",
type = AttributeType.BOOLEAN)
boolean concurrent_scheduler() default false;

@AttributeDefinition(
name = "Custom Property",
description = "Custom Property",
type = AttributeType.STRING)
String customProperty() default "Test";
}

5. Create R6 annotation OSGI configuration to provide properties values for SimpleSchedulerConfiguration.java class.
File Name: com.javadoubts.core.schedulers.SimpleSchedulerConfiguration.xml

<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0"
xmlns:jcr="http://www.jcp.org/jcr/1.0"
jcr:primaryType="sling:OsgiConfig"
scheduler.expression="0 * * * * ?"
enable.scheduler="Practice Concurrent task"
scheduler.name="Practice"
name="Practice Custom Param"/>

6. Below is the sample PracticeScheduledTask.java Scheduler class:

Note: Read comment while reading code will make easy to understand.

package com.javadoubts.core.schedulers;

import org.apache.sling.commons.scheduler.ScheduleOptions;
import org.apache.sling.commons.scheduler.Scheduler;
import org.osgi.service.component.annotations.*;
import org.osgi.service.metatype.annotations.Designate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


@Component(service= PracticeScheduledTask.class, immediate = true)
@Designate(ocd=SimpleSchedulerConfiguration.class)
public class PracticeScheduledTask implements Runnable {

private final Logger logger = LoggerFactory.getLogger(getClass());

@Reference
private Scheduler scheduler;

@Activate
protected void activate(final SimpleSchedulerConfiguration config) {

logger.error(" PracticeScheduledTask activate method called");

// Execute this method to add scheduler.
addScheduler(config);

}

// Add all configurations to Schedule a scheduler depending on name and expression.
public void addScheduler(SimpleSchedulerConfiguration config) {
logger.error("Scheduler added successfully >>>>>>> ");
if (config.enable_scheduler()) {
ScheduleOptions options = scheduler.EXPR(config.scheduler_expression());
options.name(config.scheduler_name());
options.canRunConcurrently(config.concurrent_scheduler());

// Add scheduler to call depending on option passed.
scheduler.schedule(this, options);
logger.error("Scheduler added successfully name='{}'", config.scheduler_name());
} else {
logger.error("SimpleScheduledTask disabled");
}
}


// Custom method to deactivate or unschedule scheduler
public void removeScheduler(SimpleSchedulerConfiguration config) {
scheduler.unschedule(config.scheduler_name());
}

// On deactivate component it will unschedule scheduler
@Deactivate
protected void deactivate(SimpleSchedulerConfiguration config) {
removeScheduler(config);
}

// On component modification change status will remove and add scheduler
@Modified
protected void modified(SimpleSchedulerConfiguration config) {
removeScheduler(config);
addScheduler(config);
}

// run() method will get call every minute
@Override
public void run() {
logger.error("PracticeScheduledTask run >>>>>>>>>>>");
}
}

7. Deploy code on AEM instance and open http://localhost:4502/system/console/components URL and ctrl + f for “PracticeScheduledTask”. Verify PracticeScheduledTask service is in active state.

8. Open error.log file and check for below log printing every minute:
PracticeScheduledTask run >>>>>>>>>>> as shown below.

There are multiple methods from Scheduler interface:

  1. schedule(String name) schedule job based on name.
  2. EXPR(String expression) schedule a job based on expression.
  3. unschedule(String name) remove scheduled job based on name.
  4. scheduler.AT(Date date) will trigger scheduler at given date and only one.
  5. scheduler.AT(Date date, int times, long period) will trigger scheduler at given date and more than once.
  6. scheduler.NOW() will trigger scheduler as soon as build is done and only one.
  7. scheduler.NOW(int times, long period) will trigger scheduler as soon as build is done and more than once.

Note: All below methods are now deprecated addJob(), addPeriodicJob, fireJob, fireJobAt, removeJob.

Imran Khan, Adobe Community Advisor, AEM certified developer and Java Geek, is an experienced AEM developer with over 11 years of expertise in designing and implementing robust web applications. He leverages Adobe Experience Manager, Analytics, and Target to create dynamic digital experiences. Imran possesses extensive expertise in J2EE, Sightly, Struts 2.0, Spring, Hibernate, JPA, React, HTML, jQuery, and JavaScript.

0