eXo Platform 3.5

## Chapter 61. Job Scheduler Service

## What is Job Scheduler?

Job scheduler defines a job to execute a given number of times during a given period. It is a service that is in charge of unattended background executions, commonly known for historical reasons as batch processing. It is used to create and run jobs automatically and continuously, to schedule event-driven jobs and reports.

## Where is Job Scheduler Service used in eXo Products?

Job Scheduler Service is widely used in many eXo products such as Social, DMS, WCM, eXo Knowledge and eXo Collaboration.

In eXo products, Job Schedulers are used to do some tasks as below:

- Automatically send notification, such as task/event reminder in the Calendar application of eXo Collaboration.

- Automatically save chat messages from Openfire Server to History in the Chat application of eXo Collaboration.

- Inactivate topics in the Forum application of eXo Knowledge.

- Calculate the number of active and online users in the Forum application of eXo Knowledge.

- Automatically collect RSS items from various RSS resources to post to the activity stream of users and spaces in eXo Social.

- Automatically send Newsletters to users in WCM.

Also, it is used in Schedule lifecycle in DMS.

By using Job Scheduler Service in eXo kernel, many kinds of job can be configured to run, such as, addPeriodJob, addCronJob, addGlobalJobListener, addJobListener and many more. Just write a job (a class implements Job interface of quartz library and configures plug-in for JobSchedulerService and you're done.

## How does Job Scheduler work?

Jobs are scheduled to run when a given Trigger occurs. Triggers can be created with nearly any combination of the following directives:

- at a certain time of day (to the millisecond)

- on certain days of the week

- on certain days of the month

- on certain days of the year

- not on certain days listed within a registered Calendar (such as business holidays)

- repeated a specific number of times

- repeated until a specific time/date

- repeated indefinitely

- repeated with a delay interval

Jobs are given names by their creator and can also be organized into named groups. Triggers may also be given names and placed into groups, in order to easily organize them within the scheduler. Jobs can be added to the scheduler once, but registered with multiple Triggers. Within a J2EE environment, Jobs can perform their work as part of a distributed (XA) transaction.

(Source: quartz-scheduler.org)

### How can Job Scheduler Service be used in Kernel?

Kernel leverages Quartz for its scheduler service and wraps `org.quartz.Scheduler` in `org.exoplatform.services.scheduler.impl.QuartzSheduler` for easier service wiring and configuration like any other services. To work with Quartz in Kernel, you will mostly work with `org.exoplatform.services.scheduler.JobSchedulerService` (implemented by `org.exoplatform.services.scheduler.impl.JobSchedulerServiceImpl`.

To use `JobSchedulerService`, you can configure it as a component in the configuration.xml. Because `JobSchedulerService` requires `QuartzSheduler` and `QueueTasks`, you also have to configure these two components.

    <?xml version="1.0" encoding="UTF-8"?>

    <configuration

      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

      xsi:schemaLocation="http://www.exoplatform.org/xml/ns/kernel_1_2.xsd http://www.exoplatform.org/xml/ns/kernel_1_2.xsd"

      xmlns="http://www.exoplatform.org/xml/ns/kernel_1_2.xsd">

      <component>

        <type>org.exoplatform.services.scheduler.impl.QuartzSheduler</type>

      </component>

      <component>

        <type>org.exoplatform.services.scheduler.QueueTasks</type>

      </component>

      <component>

        <key>org.exoplatform.services.scheduler.JobSchedulerService</key>

        <type>org.exoplatform.services.scheduler.impl.JobSchedulerServiceImpl</type>

      </component>

    </configuration>

### Samples

### Note

You can download the project code from here

Work with `JobSchedulerService` by creating a sample project and use GateIn-3.1.0-GA for testing.

Firstly, create a project by using maven archetype plugin:

    mvn archetype:generate

- For project type: select maven-archetype-quickstart

- For groupId: select org.exoplatform.samples

- For artifactId: select exo.samples.scheduler

- For version: select 1.0.0-SNAPSHOT

- For package: select org.exoplatform.samples.scheduler

Edit the pom.xml as follows:

    <project

      xmlns="http://maven.apache.org/POM/4.0.0"

      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

      <modelVersion>4.0.0</modelVersion>

      <parent>

        <artifactId>exo.portal.parent</artifactId>

        <groupId>org.exoplatform.portal</groupId>

        <version>3.1.0-GA</version>

      </parent>

      <groupId>org.exoplatform.samples</groupId>

      <artifactId>exo.samples.scheduler</artifactId>

      <version>1.0.0-SNAPSHOT</version>

      <name>eXo Samples For Scheduler</name>

      <description>eXo Samples Code For Scheduler</description>

    </project>

Generate an eclipse project by using maven eclipse plugin and then import into eclipse:

    mvn eclipse:eclipse

eXo Kernel makes it easier to work with job scheduler service. All you need is just to define your "job" class to be performed by implementing org.quartz.Job interface and add configuration for it.

#### Define a job

To define a job, do as follows:

Define your job to be performed. For example, the job DumbJob is defined as follows:

    package org.exoplatform.samples.scheduler.jobs;

    import org.exoplatform.services.log.ExoLogger;

    import org.exoplatform.services.log.Log;

    import org.quartz.Job;

    import org.quartz.JobExecutionContext;

    import org.quartz.JobExecutionException;

    /**

     * DumbJob for executing a defined dumb job.

     */

    public class DumbJob implements Job {

      /**

       * The logger

       */

      private static final Log LOG = ExoLogger.getLogger(DumbJob.class);

      /**

       * The job of the DumbJob will be done by executing this method.

       *

       * @param context

       * @throws JobExecutionException

       */

      public void execute(JobExecutionContext context) throws JobExecutionException {

        LOG.info("DumbJob is executing...");

      }

    }

All jobs are required to implement the method execute from org.quartz.Job interface. This method will be called whenever a job is performed. With DumbJob, you just use logging to see that it will work. By looking at the terminal, you will see the the log message: "DumbJob is executing..."

#### Job configuration

After defining the "job", the only next step is to configure it by using external-component-plugin configuration for org.exoplatform.services.scheduler.JobSchedulerService. You can use these methods below for setting component plugin:

    public void addPeriodJob(ComponentPlugin plugin) throws Exception;

The component plugin for this method must be the type of org.exoplatform.services.scheduler.PeriodJob. This type of job is used to perform actions that are executed in a period of time. You have to define when this job is performed, when it ends, when it performs the first action, how many times it is executed and the period of time to perform the action. See the configuration sample below to understand more clearly:

    <external-component-plugins>

       <target-component>org.exoplatform.services.scheduler.JobSchedulerService</target-component>

        <component-plugin>

          <name>PeriodJob Plugin</name>

          <set-method>addPeriodJob</set-method>

          <type>org.exoplatform.services.scheduler.PeriodJob</type>

          <description>period job configuration</description>

          <init-params>

            <properties-param>

              <name>job.info</name>

              <description>dumb job executed  periodically</description>

              <property name="jobName" value="DumbJob"/>

              <property name="groupName" value="DumbJobGroup"/>

              <property name="job" value="org.exoplatform.samples.scheduler.jobs.DumbJob"/>

              <property name="repeatCount" value="0"/>

              <property name="period" value="60000"/>

              <property name="startTime" value="+45"/>

              <property name="endTime" value=""/>

            </properties-param>

          </init-params>

        </component-plugin>

     </external-component-plugins>

    public void addCronJob(ComponentPlugin plugin) throws Exception;

The component plugin for this method must be the type of org.exoplatform.services.scheduler.CronJob. This type of job is used to perform actions at specified time with Unix 'cron-like' definitions. The plugin uses "expression" field for specifying the 'cron-like' definitions to execute the job. This is considered as the most powerful and flexible job to define when it will execute. For example, at 12pm every day => "0 0 12 * * ?"; or at 10:15am every Monday, Tuesday, Wednesday, Thursday and Friday => "0 15 10 ? * MON-FRI". To see more about Cron expression, please refer to this article:

CRON expression.

See the configuration sample below to understand more clearly:

    <external-component-plugins>

        <target-component>org.exoplatform.services.scheduler.JobSchedulerService</target-component>

        <component-plugin>

          <name>CronJob Plugin</name>

          <set-method>addCronJob</set-method>

          <type>org.exoplatform.services.scheduler.CronJob</type>

          <description>cron job configuration</description>

          <init-params>

            <properties-param>

              <name>job.info</name>

              <description>dumb job executed by cron expression</description>

              <property name="jobName" value="DumbJob"/>

              <property name="groupName" value="DumbJobGroup"/>

              <property name="job" value="org.exoplatform.samples.scheduler.jobs.DumbJob"/>

              <!-- The job will be performed at 10:15am every day -->

              <property name="expression" value="0 15 10 * * ?"/>

            </properties-param>

          </init-params>

        </component-plugin>

      </external-component-plugins>

    public void addGlobalJobListener(ComponentPlugin plugin) throws Exception;

    public void addJobListener(ComponentPlugin plugin) throws Exception;

The component plugin for two methods above must be the type of org.quartz.JobListener. This job listener is used so that it will be informed when a org.quartz.JobDetail executes.

    public void addGlobalTriggerListener(ComponentPlugin plugin) throws Exception;

    public void addTriggerListener(ComponentPlugin plugin) throws Exception;

The component plugin for two methods above must be the type of org.quartz.TriggerListener. This trigger listener is used so that it will be informed when a org.quartz.Trigger fires.

#### Run the project

Create conf.portal package in your sample project. Add the configuration.xml file with the content as follows:

    <?xml version="1.0" encoding="UTF-8"?>

    <configuration

      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

      xsi:schemaLocation="http://www.exoplatform.org/xml/ns/kernel_1_2.xsd http://www.exoplatform.org/xml/ns/kernel_1_2.xsd"

      xmlns="http://www.exoplatform.org/xml/ns/kernel_1_2.xsd">

      <component>

        <type>org.exoplatform.services.scheduler.impl.QuartzSheduler</type>

      </component>

      <component>

        <type>org.exoplatform.services.scheduler.QueueTasks</type>

      </component>

      <component>

        <key>org.exoplatform.services.scheduler.JobSchedulerService</key>

        <type>org.exoplatform.services.scheduler.impl.JobSchedulerServiceImpl</type>

      </component>

      <external-component-plugins>

        <target-component>org.exoplatform.services.scheduler.JobSchedulerService</target-component>

        <component-plugin>

          <name>PeriodJob Plugin</name>

          <set-method>addPeriodJob</set-method>

          <type>org.exoplatform.services.scheduler.PeriodJob</type>

          <description>period job configuration</description>

          <init-params>

            <properties-param>

              <name>job.info</name>

              <description>dumb job executed periodically</description>

              <property name="jobName" value="DumbJob"/>

              <property name="groupName" value="DumbJobGroup"/>

              <property name="job" value="org.exoplatform.samples.scheduler.jobs.DumbJob"/>

              <property name="repeatCount" value="0"/>

              <property name="period" value="60000"/>

              <property name="startTime" value="+45"/>

              <property name="endTime" value=""/>

            </properties-param>

          </init-params>

        </component-plugin>

      </external-component-plugins>

    </configuration>

mvn clean install the project. Copy .jar file to lib in tomcat bundled with GateIn-3.1.0-GA. Run bin/gatein.sh to see the DumbJob to be executed on the terminal when portal containers are initialized. Please look at the terminal to see the log message of DumbJob.

From now on, you can easily create any job to be executed in GateIn's portal by defining your job and configuring it.

## Reference

To further understand about Job Scheduler, you can refer the following links:

- http://www.quartz-scheduler.org/

- http://en.wikipedia.org/wiki/Job_scheduler

- http://www.theserverside.com/news/1364726/Job-Scheduling-in-J2EE-Applications

- http://technet.microsoft.com/en-us/library/cc720070%28WS.10%29.aspx