<?xml version="1.0"?>
<!--
 Licensed to the Apache Software Foundation (ASF) under one
 or more contributor license agreements.  See the NOTICE file
 distributed with this work for additional information
 regarding copyright ownership.  The ASF licenses this file
 to you under the Apache License, Version 2.0 (the
 "License"); you may not use this file except in compliance
 with the License.  You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing,
 software distributed under the License is distributed on an
 "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 KIND, either express or implied.  See the License for the
 specific language governing permissions and limitations
 under the License.
-->

<document>

 <properties>
  <title>Turbine Services - Scheduler Service</title>
 </properties>

<body>

<section name="Scheduler Service">

<p>
    The Scheduler is modeled after Unix Cron. The Scheduler runs as a background
    process that executes timed scheduled tasks independently of HTTP requests.
    Tasks are either stored in the database in the TURBINE_SCHEDULED_JOB table and once
    entered in the database are loaded automatically when Turbine initializes or as a non persistent service using TurbineNonPersistentSchedulerService.
</p>

<p>
    For the Scheduler to load classes that extend the ScheduledJob Class,
    the scheduler needs to be enabled via the TurbineResources.properties
    file, where the directive services.SchedulerService.enabled needs to be
    set to true.
</p>

<p>
    The Scheduler Service should be accessed in one of two ways.
    <ul>
        <li>
            Get an instance of type org.apache.turbine.services.schedule.ScheduleService (eihter using annnotation @TurbineService or by using static call to TurbineServices.getInstance().getService with parameter ScheduleService.SERVICE_NAME) - This interface provides  methods to access the scheduler service.  This is the preferred method of access from within java code.
        </li>
        <li>
            org.apache.turbine.services.schedule.SchedulerTool - This is a pull
            tool for providing access to the scheduler service from within a
            Velocity template.
        </li>
    </ul>
</p>

</section>

<section name="Configuration">

<source><![CDATA[
# -------------------------------------------------------------------
#
#  S E R V I C E S
#
# -------------------------------------------------------------------
# Classes for Turbine Services should be defined here.
# Format: services.[name].classname=[implementing class]
#
# To specify properties of a service use the following syntax:
# service.[name].[property]=[value]

services.SchedulerService.classname=org.apache.turbine.services.schedule.QuartzSchedulerService
.
.
.
# -------------------------------------------------------------------
#
#  S C H E D U L E R  S E R V I C E
#
# -------------------------------------------------------------------

#
# Set enabled to true to start the scheduler.  The scheduler can be
# stopped and started after Turbine has been intialized.  See the
# javadocs for org.apache.turbine.services.schedule.TurbineScheduler
# for the methods calls.
#
# Default = false
#

services.SchedulerService.enabled=false

# Determines if the scheduler service should be initialized early.  This
# Should always be set to true!!!!

services.SchedulerService.earlyInit=true

# -------------------------------------------------------------------
#
#  P U L L  S E R V I C E
#
# -------------------------------------------------------------------
# These are the properties for the Pull Service, the service
# that works in conjuction with the Turbine Pull Model API.
# -------------------------------------------------------------------

# This is a tool that allows access to the scheduler service.
tool.request.scheduler=org.apache.turbine.services.schedule.SchedulerTool

]]></source>

<p>
    Jobs are stored and retrieved from the database using Torque
    generated objects.  The objects are based on the definition
    stored in <code>scheduler-schema.xml</code>.  If you want to
    add additional fields to track more information about your
    scheduled tasks, you can modify this file to do so.  You will
    need to rebuild Turbine using MAven after making your modifications.
</p>

</section>

<section name="Usage">

<p>
To create an object that takes advantage of the Schedule Service, the task
to be executed will need to be embedded in the run() method of an object
which extends the ScheduledJob Class. For instance:
</p>

<source><![CDATA[

package com.mycompany.modules.scheduledjobs;


//JDK
import java.util.Date;

//Turbine
import org.apache.turbine.modules.ScheduledJob;
import org.apache.turbine.services.schedule.JobEntry;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;


public class SimpleScheduledTask extends ScheduledJob
{
    /** Logging */
    private static Log log = LogFactory.getLog(SimpleScheduledTask.class);

    private int taskcount = 0;

    /**
     * Constructor
     */
     public SimpleScheduledTask()
     {
         //do Task initialization here
     }


    /**
     * Run the Jobentry from the scheduler queue.
     * From ScheduledJob.
     *
     * @param job The job to run.
     */
    public void run( JobEntry job ) throws Exception
    {
        log.note("Scheduled job " + job.getJobId() + " : " +
                 "task: " + job.getTask() +
                 " ran @: " +
                 new Date(System.currentTimeMillis()).toString() +
                 " taskcount " + taskcount
                 );
        //iterate the task counter
        taskcount++;
    }
}

]]></source>

<p>
The SimpleScheduledTask object makes an entry into the turbine.log each
time the Task is run by the Schedule Service. The JobEntry object carries the
information the Service uses to determine the frequency of the Task.
Note that the object is in the com.mycompany.modules. This assumes that the
package com.mycompany.modules is in the Turbine module path, which is in the
module.packages directive in the TurbineResources.properties.
The ScheduledJobLoader object loads the Task upon Turbine initilization also
searches for a <i>scheduledjobs</i> package which contains the Task object.
</p>

<p>
Control of the time between, or to, execution of the Task, is controlled by
the JobEntry object. The JobEntry serves as a wrapper for the scheduled task.
The constructor is as follows:
</p>

<source><![CDATA[

public JobEntry(int sec, int min, int hour,
                int wd, int day_mo, String task)
                throws Exception

]]></source>

<p>
The granularity of the Task's next execution can be controlled to the level
of seconds. In the above constructor, sec represents the seconds with a valid
range of 0-59, min represents the minutes with a valid range of 0-59,
hour represents the hours with a valid range of 0-23, wd is the day of the
week with a valid range of 1-7, day_mo is the day of the month with a valid
range of 1-31 and task is the name of the object. The JobEntry constructor
allows for the Task to be run at a certain point in time. For example:
</p>

<source><![CDATA[

JobEntry je = new JobEntry(0,25,-1,-1,-1,"SimpleScheduledTask");

  o run every 25 minutes.

JobEntry je = new JobEntry(0,0,8,-1,15,"SimpleScheduledTask");

  o run at 8:00am on the 15th of the month every month.

]]></source>

<p>
The Schedule Service will only execute Tasks at Turbine Initialization that
are present in the Database. To add a Task to the Database we need to set up
an Action class that can be accessed from a template with:
</p>

<source><![CDATA[

$page.SetTitle("SimpleScheduleTask Starter Page")

Set Values for SimpleScheduleTask and then start it for the first time.
<br />

<form>
<input type="hidden" name="action" value="SchedulerStart" />
<input type="text" name="second" size="20" /> : seconds (0-59)<br />
<input type="text" name="minute" size="20" /> : minutes (0-59)<br />
<input type="text" name="hour" size="20" /> : hours (0-23)<br />
<input type="text" name="weekday" size="20" /> : Day of the Week (1-7)<br />
<input type="text" name="day_of_month" size="20" /> Day of the Month (1-31)<br />
<input type="text" name="task" value="SimpleSchedulerTask" /> : The Task being scheduled. <br />
<input type="text" name="email" /> : Email<br />
</form>

]]></source>

<p>
and the appropriate Action class:
</p>

<source><![CDATA[

package com.mycompany.modules.actions;


//Turbine
import org.apache.turbine.modules.actions.VelocityAction;
import org.apache.turbine.services.schedule.JobEntry;
import org.apache.turbine.services.schedule.TurbineScheduler;
import org.apache.turbine.services.TurbineServices;
import org.apache.turbine.util.ParameterParser;
import org.apache.turbine.util.RunData;


public class AddScheduledTask extends VelocityAction
{

     public void doPerform(RunData data) throws Exception
     {
        ParameterParser params = data.getParameters();

        int second = params.getInt("second",-1);
        int minute = params.getInt("minute",-1);
        int hour = params.getInt("hour",-1);
        int weekday = params.getInt("weekday",-1);
        int dom = params.getInt("day_of_month",-1);
        String task = params.getString("task","");
        String email = params.getString("email","");

        try
        {
            //create a new JobEntry with the time constraints from
            //the template as the arguments
            JobEntry je =  new JobEntry(second,minute,hour,weekday,dom,task);

            //set the email for notification
            je.setEmail(email);

            //add the job to the queue
            TurbineScheduler.addJob(je);

            //set the Message
            data.setMessage("Task " + task + " added successfully");
        }
        catch (Exception e)
        {
            //set the Message
            data.setMessage("Task " + task + " could not be added!");
        }

        // Note: The template "SchedulerStatus.vm" is not part of Turbine.
        // It is only here as an example how you might implement this action.
        setTemplate(data, "SchedulerStatus.vm");

     }
}

]]></source>

<p>
    The AddScheduledTask action class adds the task to the job queue.  The job
    will also be written to database so that it will be automatically loaded
    the next time that Turbine starts.
</p>
<p>
    The AddScheduledTask action class is really only part of what you would need
    to implement in order to control the job scheduler from a web interface.  It
    is given as a VERY simple example of how you might implement such functionality.
    In a more complete implementation, you would have templates to create/edit a scheduled
    task, display all tasks, and control the scheduler.  You would also have action(s)
    to enable/disable the scheduler and add/update/remove scheduled tasks.
</p>
<p>
    The TurbineScheduler class exposes methods that allow the
    Scheduler process to be monitored and controlled, such as getJob(int oid),
    removeJob(JobEntry je), updateJob(JobEntry je), listJobs(), startScheduler(),
    stopScheduler(), and others.  See the javadocs on this class for more details.
</p>
<p>
    There is also a pull tool for use with the scheduler service (assuming the pull service
    is enabled).  This tool allows you to get basic information from the scheduler service
    for use in a Velocity template.  It provides methods such as getJob(jobId), listJobs(),
    isEnabled(), and others.  See the javadocs for more details.
</p>

<p>
    The Scheduler Service uses a seperate thread for each Task it runs to ensure
    that every job runs on time. It's the programmer's responsibility to ensure
    that proper precautions to handle issues such as synchronization and long
    running jobs. As always, check through the relevant Javadocs and source code
    for more details on the Scheduler Service.
</p>

</section>

</body>
</document>
