Chapter 2. Scheduler Programming

Table of Contents

2.1. Overview
2.2. JEUS Scheduler Class
2.3. Defining Tasks
2.3.1. Implementing ScheduleListener Interface
2.3.2. Schedule Class Inheritance
2.3.3. Inheriting RemoteSchedule Class
2.4. Obtaining Scheduler Object
2.4.1. Obtaining Scheduler Object in Local Environment
2.4.2. Obtaining a Scheduler Object in Remote Environment
2.5. Registering Tasks
2.5.1. Registering One-Time Tasks
2.5.2. Registering Recurring Tasks
2.5.3. Registering Schedule Task Objects
2.6. Controlling Tasks
2.7. Using Scheduler
2.7.1. Using In a Standalone Environment
2.7.2. Using on JEUS Server
2.7.3. Using in Java EE Component
2.8. Using Job-list

This chapter describes the basic knowledge and instructions for JEUS Scheduler programming.

2.1. Overview

The following features have been added or changed since JEUS version 5.0. JEUS 5.0 is backward compatible and programs that are written in previous versions can be used without modification.

  • Added the SchedulerListener Interface

    The ScheduleListener interface defines a task.

    This is the top level interface that must be implemented by all tasks. It also implements the existing schedule task classes.

    Therefore, tasks can be defined by implementing ScheduleListener without inheriting a schedule task class.

  • Added SchedulerFactory Class

    The existing SchedulerManager class for client and server is replaced by the SchedulerFactory class. SchedulerFactory is used to get Scheduler objects, and register tasks regardless of environment (client, server, and remote client environments).

  • Added various methods

    Various methods for adding a task have been added. Start time, cycle, termination time, and maximum execution count properties can be set when adding a task.

  • Changed to a multi-thread execution method that uses a thread pool

    While the existing JEUS Scheduler used a single thread to execute tasks, the new JEUS Scheduler executes each task with a separate thread using a thread pool. This prevents a blocked task from affecting other tasks.

  • Added Job-list feature

    Job-list feature allows tasks to be registered on JEUS server configuration instead of through programming.

The next section describes the classes that make up the JEUS Scheduler, and how to define, register, and control a job schedule. All examples explained in this chapter can be found in the JEUS_HOME/samples/scheduler directory.

2.2. JEUS Scheduler Class

JEUS Scheduler is conceptually identical to and contains similar interfaces as J2SE Timer. The java.util.TimerTask class that represents a task corresponds to the jeus.schedule.ScheduleListener interface, and the java.util.Timer class that registers a task corresponds to the jeus.schedule.Scheduler interface. Previous users of J2SE Timer interface can easily use JEUS Scheduler.

The following figure shows each Scheduler API classes.

[Figure 2.1] Scheduler API Classes

Scheduler API Classes

API ClassDescription
package jeus.scheduleAll classes and interfaces of JEUS Scheduler belong to jeus.schedule package and its sub-packages.
interface ScheduleListenerA task that needs to execute at a set time is defined as a class by implementing the ScheduleListener interface. ScheduleListener contains a callback method called onTime() that is invoked at the scheduled time.
abstract class ScheduleAbstract class that implements ScheduleListener which was used in versions earlier than JEUS 5.0. This class contains the nextTime() and onTime() callback methods. The nextTime() method is used dynamically to get the time to execute the task after it is scheduled.
abstract class RemoteScheduleSpecial abstract class that contains the initialize() callback method and receives initialization parameters when creating an object.
class SchedulerFactoryUsed to call a concrete Scheduler object.
interface SchedulerCore interface for registering tasks in JEUS Scheduler. It defines various registerSchedule() methods.
interface ScheduleControllerWhen a task is registered in the Scheduler, the object that implements the ScheduleController interface is returned. This handler object is used to get information about or cancel the task.
exception JeusSchedulerExceptionJeusSchedulerException may be thrown if an internal error occurs while registering or cancelling a task in JEUS Scheduler.

Note

For more information about each interface or class, refer to the JEUS Scheduler Javadoc API.

2.3. Defining Tasks

To execute a task, first the task class must be defined, and then the task according to the execution time and cycle.

2.3.1. Implementing ScheduleListener Interface

A task that executes at a set time is defined by implementing the ScheduleListener interface.

ScheduleListener contains the onTime() callback method that is invoked at the set time. A task class must implement the onTime() method that contains the task implementation.

[Example 2.1] Task Object Example

public class SimpleTask implements ScheduleListener {
    private String name;
    private int count;

    // no-arg constructor is required if classname is used for task registration
    public SimpleTask() {
    }
    
    public SimpleTask(String name) {
        this.name = name;
    }

    public void onTime() {
        count++;
        echo("##### " + name + " is waked on " + new Date());
    }
...
}


2.3.2. Schedule Class Inheritance

Instead of directly implementing a ScheduleListener, it can be defined by inheriting the Schedule class or RemoteSchedule class.

The Schedule and RemoteSchedule classes are used in previous versions of JEUS. In JEUS 5.0, ScheduleListener must be implemented to define tasks in general, but the previous task classes are also provided for backward compatibility.

The Schedule abstract class contains the nextTime() callback method in addition to the onTime() method. The nextTime() method does not schedule the call time when registering tasks, but instead the next call time is scheduled in the task class. Therefore, it is more efficient to use the method for tasks with a variable time cycle than a fixed time cycle.

JEUS Scheduler determines the initial execution time by calling nextTime() after registering a task object. At the set time, onTime() is called and the task executes when onTime() call terminates. The nextTime() method must return the next scheduled execution interval in milliseconds. If it returns 0, the task will no longer execute.

Since the Schedule task object calls nextTime() after onTime() finishes executing, the nextTime() call is delayed while onTime() is executing. Therefore, it is difficult to write programs to execute the task at exact time intervals. Thus, it is recommended to set the execution cycle when registering tasks rather than through the nextTime() method.

[Example 2.2] Schedule Object Example

public class SimpleSchedule extends Schedule {
    private String name;
    private int count;
    private long period = 2000; // 2 seconds

    // no-arg constructor is required if classname is used for task registration
    public SimpleSchedule() {
    }

    public SimpleSchedule(String name) {
        this.name = name;
    }

    public void onTime() {
        count++;
        echo("##### " + name + " is waked on " + new Date());
    }

    public long nextTime(long currentTime) {
        return currentTime + period;
    }
...
}


2.3.3. Inheriting RemoteSchedule Class

The RemoteSchedule class is a Schedule object that can set the initialization parameters when registering tasks remotely. This is mainly used to register task objects using the class name.

The class contains the initialize() Callback method which is called just once after a task is registered. Therefore, it can be used to assign initialization values when using the class name to register a task remotely.

The initialize() callback is only invoked when RemoteSchedule task object is registered by using the Scheduler.registerSchedule(classname, hashtable, daemon_flag) method.

[Example 2.3] RemoteSchedule Object Example

public class SimpleRemoteSchedule extends RemoteSchedule {
    private String name;
    private int count;
    private long period;

    // no-arg constructor is required if classname is used for task registration
    public SimpleRemoteSchedule() {
    }

    // this is called by scheduler after creation
    public void initialize(Hashtable parameters) {
        name = (String) parameters.get("name");
        Long interval = (Long) parameters.get("interval");
        if (interval != null)
            period = interval.longValue();
        else
            period = 2000;
    }

    public void onTime() {
        count++;
        echo("##### " + name + " is waked on " + new Date());
    }

    public long nextTime(long currentTime) {
        return currentTime + period;
    }
...
}


Note

When registering a task by using the Job-list or an API that uses the class name, a no-arg (default) constructor is required because the corresponding class is initialized by the container.

2.4. Obtaining Scheduler Object

This section describes how to obtain a Scheduler object. JEUS Scheduler operates in both local and remote environments.

2.4.1. Obtaining Scheduler Object in Local Environment

When JEUS Scheduler runs in a local environment, a Scheduler instance is created on a local Java Virtual Machine (JVM) and all registered tasks run on the same JVM.

In a local environment, a single instance of JEUS Scheduler is created. This instance is the default scheduler that is shared by all clients on the JVM. JEUS Scheduler in a local environment is used by regular J2SE applications, Java EE application clients, and Java EE components. Use the SchedulerFactory to use JEUS Scheduler in a local environment.

The default Scheduler instance can be easily obtained in the following way.

// Get the default scheduler
Scheduler scheduler = SchedulerFactory.getDefaultScheduler();

2.4.2. Obtaining a Scheduler Object in Remote Environment

When JEUS Scheduler runs in a remote environment, a Scheduler instance is created on a remote JVM, and all registered tasks run on the remote JVM.

Since the remote Scheduler is in the form of an RMI object, JEUS Scheduler can be used through an RMI call. In a JEUS environment, the remote Scheduler service runs on JEUS server. A remote JEUS Scheduler is used when a remote client registers a task on a JEUS node.

JNDI Lookup is used to access the remote JEUS Scheduler on a JEUS node.

A JEUS node Scheduler instance (Stub) can be obtained in the following way.

// Get the remote scheduler
InitialContext ic = new InitialContext();
Scheduler scheduler = (Scheduler)ic.lookup(
    Scheduler.SERVER_SCHEDULER_NAME);

Note

jeus.schedule.server.SchedulerManager and jeus.schedule.client.SchedulerManager used in JEUS 5.0 and earlier versions are no longer used (deprecated). Instead, it is recommended to use Scheduler objects generated by the SchedulerFactory. The deprecated classes, however, are provided for backward compatibility.

2.5. Registering Tasks

This section describes how to register tasks using the Scheduler interface.

The methods for registering tasks are the same in both local and remote Schedulers. The only difference is that the task objects are serialized and run remotely for a remote JEUS Scheduler.

2.5.1. Registering One-Time Tasks

Tasks that execute only once can be registered by specifying the execution time. The execution time can be set as an absolute time by using the java.util.Date object or as a relative time based on the current time in milliseconds.

Tasks can be registered in the following way.

registerSchedule(ScheduleListener task, Date time, boolean isDaemon)
registerSchedule(ScheduleListener task, long delay, boolean isDaemon)

The following shows how to use the method.

SimpleTask task1 = new SimpleTask("task1");
Date firstTime1 = new Date(System.currentTimeMillis() + 2000);
ScheduleController handle1 = scheduler.registerSchedule(task1, firstTime1, false);

Note

For information about method parameters, refer to "2.5.2. Registering Recurring Tasks".

2.5.2. Registering Recurring Tasks

Recurring tasks can be registered by specifying the initial execution time, cycle, termination time, and the maximum number of executions. Select either the fixed-delay or fixed-rate method according to the task.

  • Fixed-delay Type

    The execution interval is fixed. The next execution time is set according to the previous execution time and cycle. If a task execution is delayed (due to long execution time or external reasons such as garbage collection) and the next execution time passes, the next task is executed immediately, but the following tasks will all be delayed. As a result, all task executions are delayed accordingly.

  • Fixed-rate Type

    The ratio of task execution is fixed. The next execution time is determined according to the initial execution time and cycle. Even though a task execution is delayed, the next task is executed immediately after the current task to maintain the rate of executions per hour. In the long term, the task execution times are maintained according to the specified cycle.

Note

For a task registered as fixed-rate, JEUS Scheduler calls the task using another thread when the task execution is delayed, to guarantee the execution time. If a task execution is delayed, same tasks may be executed concurrently and task objects should be checked for thread-safety.

Tasks can be registered using the following methods.

registerSchedule(ScheduleListener task, Date firstTime, long period, Date endTime, 
                 long maxcount, boolean isDaemon)

registerSchedule(ScheduleListener task, long delay, long period, Date endTime, 
                 long maxcount, boolean isDaemon)

registerScheduleAtFixedRate(ScheduleListener task, Date firstTime, long period, 
                 Date endTime, long maxcount, boolean isDaemon)

registerScheduleAtFixedRate(ScheduleListener task, long delay, long period, 
                 Date endTime, long maxcount, boolean isDaemon)

The following describes each parameter.

ParameterDescription
Date firstTimeInitial execution time.
long delayNext execution time relative to the current time (unit: milliseconds).
long periodRecurring execution cycle (unit: milliseconds).
Date endTimeTermination time after which a task is no longer executed. If set to null, the recurring task executes indefinitely.
long maxcountMaximum number of executions. If set to Scheduler.UNLIMITED, there is no constraint.
boolean isDaemon

Used only if the Schedule is registered remotely. If set to true, the task terminates when connection to a client is lost.

A client decides whether a connection is lost according to the DGC (Distributed Garbage Collection) policy of RMI Runtime. Schedule is cancelled after 15 minutes from the time the client is disconnected.

boolean isThreadedDeprecated.

The following example shows how to register tasks.

[Example 2.4] Registering Recurring Jobs

SimpleTask task2 = new SimpleTask("task2");
ScheduleController handle2 = scheduler.registerSchedule(task2, 2000, 2000, null, 
                         Scheduler.UNLIMITED, false);

SimpleTask task3 = new SimpleTask("task3");
Date firstTime3 = new Date(System.currentTimeMillis() + 2000);
Date endTime3 = new Date(System.currentTimeMillis() + 10 * 1000);
ScheduleController handle3 = scheduler.registerScheduleAtFixedRate(task3, 
                             firstTime3, 2000, endTime3, 10, false);


2.5.3. Registering Schedule Task Objects

The function for registering Schedule or RemoteSchedule task objects is provided for backward compatibility.

Since the nextTime() method of the Schedule task object is used for the initial and recurring execution times, separate parameters are not required for registering a task. The following method is used to register a task.

registerSchedule(Schedule task, boolean isDaemon)
registerSchedule(String classname, Hashtable params, boolean isDaemon)

The following example shows how to register tasks.

[Example 2.5] Registering Schedule Task Objects

Hashtable params = new Hashtable();
params.put("name", "task3");
params.put("interval", new Long(3000));
ScheduleController handle3 = scheduler.registerSchedule(
    "samples.scheduler.SimpleRemoteSchedule", params, true);

SimpleSchedule task4 = new SimpleSchedule("task4");
ScheduleController handle4 = scheduler.registerSchedule(task4, true);


Caution

Scheduler must be configured correctly since it is a main service provided by Managed Server (MS). If MS fails to create the Scheduler, it displays an error and fails to start.

2.6. Controlling Tasks

When a task is registered in JEUS Scheduler, the ScheduleController handler object is returned. This object is created for each registered task and is used to control the task. The handler can be used to get information about the task and to cancel the task.

The following example shows how to cancel tasks by calling the ScheduleController.cancel() method.

[Example 2.6] Calling the ScheduleController.cancel Method

SimpleTask task2 = new SimpleTask("task2");
ScheduleController handle2 = scheduler.registerSchedule(task2, 2000, 2000, null, 
                              Scheduler.UNLIMITED, false);
Thread.sleep(10 * 1000);
handle2.cancel();


2.7. Using Scheduler

JEUS Scheduler can only be used after the tasks have been defined, obtained, registered, and controlled.

This section explains how to use Scheduler in various environments.

2.7.1. Using In a Standalone Environment

JEUS Scheduler can be used by regular J2SE applications or Java EE application clients. In these cases, JEUS Scheduler and J2SE Timer can be used as libraries. The SchedulerFactory class is used to obtain the Scheduler object. A daemon flag can be set to any value because it is not used when tasks are registered in a local environment.

The following is an example of a standalone client:

[Example 2.7] Using Scheduler on a Standalone Client

public class StandAloneClient {
    public static void main(String args[]) {
        try {
            // Get the default scheduler
            Scheduler scheduler = SchedulerFactory.getDefaultScheduler();

            // Register SimpleTask which runs just one time
            echo("Register task1 which runs just one time...");
            SimpleTask task1 = new SimpleTask("task1");
            Date firstTime1 = new Date(System.currentTimeMillis() + 2000);
            ScheduleController handle1 = scheduler.registerSchedule(task1, 
                            firstTime1, false);

            Thread.sleep(5 * 1000);
            echo("");

            // Register SimpleTask which is repeated
            // with fixed-delay
            echo("Register task2 which is repeated " + "until it is canceled...");
            SimpleTask task2 = new SimpleTask("task2");
            ScheduleController handle2 = scheduler.registerSchedule(task2, 2000, 
                          2000, null, Scheduler.UNLIMITED, false);

            Thread.sleep(10 * 1000);
            handle2.cancel();
            echo("");

            // Register SimpleTask which is repeated
            // with fixed-rate
            echo("Register task3 which is repeated " + "for 10 seconds...");
            SimpleTask task3 = new SimpleTask("task3");
            Date firstTime3 = new Date(System.currentTimeMillis() + 2000);
            Date endTime3 = new Date(System.currentTimeMillis() + 10 * 1000);
            ScheduleController handle3 = scheduler.registerScheduleAtFixedRate(
                    task3, firstTime3, 2000, endTime3, 10, false);

            Thread.sleep(12 * 1000);
            echo("");

            // Register SimpleSchedule which is repeated
            // every 2 seconds
            echo("Register task4 which is repeated " + "every 2 seconds...");
            SimpleSchedule task4 = new SimpleSchedule("task4");
            ScheduleController handle4 = scheduler.registerSchedule(task4, false);

            Thread.sleep(10 * 1000);
            echo("");

            // Cancel all tasks
            echo("Cancel all tasks registerd on the scheduler...");
            scheduler.cancel();
            Thread.sleep(5 * 1000);

            System.out.println("Program terminated.");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static void echo(String s) {
        System.out.println(s);
    }

}


If JEUS Scheduler is used on Java EE application clients, JEUS Scheduler's thread pool configuration can be set in the deployment descriptor (jeus-client-dd.xml).

Note

1.For information about how to set a Scheduler's thread pool, refer to the JEUS Reference Book. "4.2.5. Thread Management Commands".

2. To compile or execute source code that uses Scheduler, JEUS related classes such as jeus.jar must be specified in the class path.

2.7.2. Using on JEUS Server

Remote clients can access scheduler services that are running on JEUS server if the scheduler service startup configuration is set on the JEUS server.

The scheduler service on JEUS server registers the RMI Scheduler object with JNDI. Therefore, clients can obtain the remote scheduler objects (stub object) using JNDI Lookup. The name of the object is “jeus_service/Scheduler”, and it uses the Scheduler.SERVER_SCHEDULER_NAME constant.

After obtaining the Scheduler object, same method is used to register tasks. However, the registered task objects are serialized and run from remote Schedulers, which means they run on JEUS servers.

During task registration, if the daemon flag is set to true, the remote tasks terminate when the remote clients terminate.

Note

For more information about how to configure Scheduler service to execute on JEUS server, refer to JEUS Reference Book. "4.2.5. Thread Management Commands".

The following is an example of a remote client:

[Example 2.8] Using Scheduler on a Remote Client

public class RemoteClient {
    public static void main(String args[]) {
        try {
            // Get the remote scheduler
            InitialContext ic = new InitialContext();
            Scheduler scheduler = (Scheduler)ic.lookup(
                Scheduler.SERVER_SCHEDULER_NAME);

            // Register SimpleTask which runs just one time
            echo("Register task1 which runs just one time...");
            SimpleTask task1 = new SimpleTask("task1");
            Date firstTime1 = new Date(System.currentTimeMillis() + 2000);
            ScheduleController handle1 = scheduler.registerSchedule(task1, 
                             firstTime1, true);

            Thread.sleep(5 * 1000);
            echo("");

            // Register SimpleTask which is repeated
            // with fixed-delay
            echo("Register task2 which is repeated " + "until it is canceled...");
            SimpleTask task2 = new SimpleTask("task2");
            ScheduleController handle2 = scheduler.registerSchedule(task2, 
                    2000, 2000, null, Scheduler.UNLIMITED, true);

            Thread.sleep(10 * 1000);
            handle2.cancel();
            echo("");

            // Register SimpleRemoteSchedule which is repeated
            // every 3 seconds
            echo("Register task3 which is repeated " + "every 3 seconds...");
            Hashtable params = new Hashtable();
            params.put("name", "task3");
            params.put("interval", new Long(3000));
            ScheduleController handle3 = scheduler.registerSchedule(
                    "samples.scheduler.SimpleRemoteSchedule", params, true);

            Thread.sleep(10 * 1000);
            echo("");

            // Cancel all tasks
            echo("Cancel all tasks registerd on the scheduler...");
            scheduler.cancel();
            Thread.sleep(5 * 1000);

            System.out.println("Program terminated.");
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    private static void echo(String s) {
        System.out.println(s);
    }
}

Caution

To execute the previous example, compress relevant task class files into a jar file and save them in the 'DOMAIN_HOME/lib/application' or 'SERVER_HOME/lib/application' directory. The JEUS server loads the class files to execute the task, and JEUS must be restarted if it is running.

2.7.3. Using in Java EE Component

JEUS Scheduler can be used in Java EE components such as EJB and Servlet. In this case, JEUS Scheduler runs on JEUS server.

JEUS 5.0 provides the EJB Timer Service that is specified in the EJB 2.1 standard. Therefore, it is recommended to use the EJB Timer Service for EJB components instead of JEUS Scheduler to comply with the Java EE standard. However, JEUS Scheduler should be used for other JAVA EE components besides EJB components since EJB Timer Service cannot be used.

Using JEUS Scheduler in Java EE components is same as using a Standalone JEUS Scheduler. First the SchedulerFactory class is used to obtain a Scheduler object running on the server, and then the necessary method is called to register the task.

The following example shows how to use JEUS Scheduler in EJB.

[Example 2.9] Using JEUS Scheduler in EJB

public class HelloEJB implements SessionBean {
    private SimpleTask task;
    private ScheduleController taskHandler;
    private boolean isStarted;

    public HelloEJB() {
    }

    public void ejbCreate() {
        task = new SimpleTask("HelloTask");
        isStarted = false;
    }

    public void trigger() throws RemoteException {
        if (!isStarted) {
            Scheduler scheduler =
                SchedulerFactory.getDefaultScheduler();
            taskHandler = scheduler.registerSchedule(
                task, 2000, 2000, null, Scheduler.UNLIMITED, false);
            isStarted = true;
        }
    }

    public void ejbRemove() throws RemoteException {
        if (isStarted) {
            taskHandler.cancel();
            isStarted = false;
        }
    }

    public void setSessionContext(SessionContext sc) {
    }

    public void ejbActivate() {
    }

    public void ejbPassivate() {
    }
}
public class HelloClient {
    public static void main(String args[]) {
        try {
            InitialContext ctx = new InitialContext();

            HelloHome home = (HelloHome) ctx.lookup("helloApp");
            Hello hello = (Hello) home.create();
            hello.trigger();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}


Note

A thread pool and Job-list can be configured for JEUS Scheduler that runs on JEUS server. For information about the configuration, refer to "3.4. Configuring Thread Pool".

2.8. Using Job-list

Job-list registers tasks on JEUS server using the configuration file instead of the programming method. It can be registered on JEUS server Scheduler. If tasks are registered through Job-list, the tasks are executed at fixed-rate.

Note

Job-list can be set for JEUS Scheduler that runs on JEUS server. For more information about how to configure the Job-list, refer to "3.2. Configuring Job-list".