Timers, Java and CzechIdM – Part 1

This is the first part of an article about timers and time services in java programming language. In today’s article we’ll present two examples of where timers are used. The first example describes the use of timers generally, the second example is specific and describes the use of timers in our CzechIdM system. After that we’ll show how to schedule tasks in Java SE, Java EE 6 and 6 using EJB container.

The next article will be focused more specifically on jBPM timers and on a Quartz project. We’ll show and compare all options. So let’s get started…

Examples of the use of timers

Practically every business information system generates reports and statistics in a form that is required by its users. An example of this would be warehouse systems where warehouse reports can be periodically generated. These systems work with a huge amount of data. This is the reason why generation of these reports can consume a lot of system and database performance. That performance loss can cause a reaction delay during standard user work, which is certainly not pleasant for users. For this reason it would be better to generate them when the system is not being used by users. Timers will be applied exactly for the process of generating such reports.

Another example of using timers can be found in our identity manager CzechIdM, where timers are used for:

Let’s look at some concrete examples of using timers in Identity Manager. In a company, termination of an employment relationship can happen. The HR person enters this fact into a personnel system (We can take this as authoritative source of information). CzechIdM will move all accounts of this user into quarantine. Quarantine is a state where accounts are blocked but have not been deleted yet. This is done to be able to restore them in a given time period (for example when termination of the employment relationship was done in error). After expiration of the quarantine period, the accounts can be permanently deleted. The specific timer is exactly responsible for starting the process that removes accounts after the expiration of the quarantine happens. That is enough examples, now let’s go back to the main topic.

Simplest timers in Java SE

There are java.util.Timer and java.util.TimerTask classes in Java from the version J2SE 1.3. These classes are used for simple task scheduling. Let’s look at an example of this:

import java.util.Calendar;

import java.util.Timer;

import java.util.TimerTask;

/** .

* Class for generating statistics

*

* @author Jarda Mlejnek

*/

public class StatisticGenerator extends TimerTask {

public void run() {

System.out.println("Executing a time consuming task.");

//TODO Application code ...

}

}

/**

* Main class of application

*

* @author Jarda Mlejnek

*

*/

class MainApplication {

public static void main(String[] argv) {

// Create timer

Timer timer = new Timer();

// Set expiration time of timer - friday, 10:30pm

Calendar cal = Calendar.getInstance();

cal.set(Calendar.DAY_OF_WEEK, Calendar.FRIDAY);

cal.set(Calendar.HOUR, 10);

cal.set(Calendar.MINUTE, 30);

cal.set(Calendar.SECOND, 0);

cal.set(Calendar.AM_PM, Calendar.PM);

// Create schedule (starting task defined by class "StatisticGenerator", every friday at 10:30pm).

timer.schedule(new StatisticGenerator(), cal.getTime(), 1000 * 60 * 60 * 24 * 7);

}

}

Class StatisticGenerator extends abstract class TimerTask which overwrites method run. Code written there will be executed after the timer expires. We then need to create a timer, set a schedule and assign an instance of our class StatisticGenerator, ie. create a schedule. In this case there is a method schedule where the last parameter is the period of task repetition specified in milliseconds. In our example, the period is one week. There are more signatures of method schedule. More information can be found in JavaDoc of the appropriate version of Java.

Let’s look at the technical aspects of timers. Because of the fact that Java is a multi platform, there is no way to guarantee that on every platform there will be a scheduled task that is executed at the same time. Tasks (TimerTask) are implemented as Runable objects. This means they are suspended. The timer is then resumed at a specified time, but the exact time when an action will be defined in method run started depends on the scheduling policy of JVM and on a number of processor threads waiting to execute. For this reason, using these timers for real-time systems is not recommended where one needs to work with time accurately. However, this is a problem for all the technologies described in this article. When using times according to the above-described examples, it is not necessary to work with milliseconds accurately.

A delay can be caused by two main problems:

  1. a large number of threads are waiting to execute
  2. a delay can be caused by a garbage collector

In closing we should say that these timers are started as threads running in the background of the application currently running. This means that they cannot be used in a controlled environment (for example in containers of Java EE servers) because they are not in the range of the container. They also don’t support, in any implicit way, persistence. They can therefore be applied only in simple desktop applications or used for timing of interactions in GUI.

EJB Timer services in Java EE 5

If you need to use timers in an application built on EJB technology (from version 2.1), you can use services offered by Java EE 5. The EJB 3 version comes with dependency injection and annotations which simplify creating and working with these timers. Interval timers with a defined period of repetition are supported once again (as well as the previous technology). The main difference between the timers in Java Se is that these timers are running at the application server layer. It is possible to set persistence of these timers such that if the application server crashes and the timer expire times out while the server is down, the timed event will be executed immediately after the start of server.

Look at an example of this use. Suppose that the application server is Jboss AS 5.1 and EJB 3.1 is being used:

package eu.bcvsolutions.examples.ejbtimer;

import java.io.Serializable;

import java.util.Date;

import javax.ejb.Stateless;

import javax.ejb.Timeout;

import javax.ejb.Timer;

import javax.ejb.TimerHandle;

import javax.ejb.TimerService;

import javax.ejb.TransactionAttribute;

import javax.ejb.TransactionAttributeType;

import org.jboss.seam.log.Log;

import org.jboss.seam.log.Logging;

@Stateless

public class SchedulerBean implements Scheduler {

protected static Log log = Logging.getLog(SchedulerBean.class);

@Resource

protected TimerService timerService;

@Timeout

@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)

public void onTimeout(Timer timer) {

Serializable info = timer.getInfo();

if (info instanceof Integer[]) {

// Spustíme příslušnou úlohu

Integer schedulerTask = ((Integer[]) info)[0];

executeSchedulerTask(schedulerTaskId, timer);

} else {

// Zrušíme časovač a zaloguje chybu.

timer.calcel();

log.wand("Timer: Bad object type.")

}

}

protected void disableTimer(SchedulerTask task) {

Timer timer = getTimerFromTask(task);

if (timer != null) {

timer.cancel();

}

task.setTimerHandle(null);

}

protected void createTimer(SchedulerTask task) {

Integer[] taskId = task.getTaskId();

long intervalDuration = task.getIntervalDuration();

Date initialExpiration = task.getInitialExpiration();

Timer timer = null;

if (intervalDuration != null && intervalDuration > 0) {

timer = this.timerService.createTimer(

initialExpiration, intervalDuration, taskId

);

} else {

timer = this.timerService.createTimer(

initialExpiration, taskId

);

}

task.setTimerHandle(timer.getHandle());

}

private Timer getTimerFromTask(SchedulerTask task) {

return task.getTimerHandle().getTimer();

}

}

It is a simple stateless bean which implements a method to create a timer for the specified task of SchedulerTask type (method createTimer), to disable the timer of the specified task (method disableTimer) and to execute the specified task. To create a timer it is necessary to inject class TimerSource as the source. An id is determined while creating the timer as welol as expiration time or interval until next expiration. Finally, the task which will be performed is assigned to the TimerHandle object through which it’s possible to get back a reference to the associated timer. We can use this reference if we want to cancel the timer executing the specified task.

 

The method annotated by annotation @OnTimeout can be in every class which works with timers only once and must always receive as input an attribute object of class javax.ejb.Timer and must return a void value. Content of this method is executed when the timer expires. In our example this means that after expiration of the determined ID of scheduled task, the task is then executed. If the ID is not stored in the timer then it’s an error and the timer is cancelled.

 

Configuration of EJB timers is carried out in file JBOSS_HOME/{server_type}/deploy/ejb2-timer-service.xml.

 

Timers are implicitly persistent, which means they are stored in the internal database of JBoss application server, specifically into the PUBLIC.TIMERS table (they can be changed in the specified configuration file). Persistence can be disabled by adding the following code into comment:

 

<!--

A persistence policy that persists timers to a database.

The 2 supported db persistence plugins are:

org.jboss.ejb.txtimer.GeneralPurposeDatabasePersistencePlugin

org.jboss.ejb.txtimer.OracleDatabasePersistencePlugin

The table name defaults to "TIMERS". It can be overriden using the

'TimersTable' attribute if the persistence plugin supports it.

When overriding the timers table, an optional schema can be specified

using the syntax [schema.]table

-->

<mbean code="org.jboss.ejb.txtimer.DatabasePersistencePolicy" name="jboss.ejb:service=EJBTimerService,persistencePolicy=database">

<!-- DataSourceBinding ObjectName -->

<depends optional-attribute-name="DataSource">jboss.jca:service=DataSourceBinding,name=DefaultDS</depends>

<!-- The plugin that handles database persistence -->

<attribute name="DatabasePersistencePlugin">org.jboss.ejb.txtimer.GeneralPurposeDatabasePersistencePlugin</attribute>

<!-- The timers table name -->

<attribute name="TimersTable">TIMERS</attribute>

<depends>jboss.jdbc:datasource=DefaultDS,service=metadata</depends>

</mbean>

And uncommenting:

<!-- A persistence policy that does not persist the timer

<mbean code="org.jboss.ejb.txtimer.NoopPersistencePolicy" name="jboss.ejb:service=EJBTimerService,persistencePolicy=noop"/>

-->

 

And what about Java EE 6?

 

Java EE 6 extends timer options of Java EE 5. It provides two types of enterprise timers:

  1. Programmable timers: based on timers from Java EE 5, explicitly are called methods to create timers
  2. automatic timers – timers are automatically created after deploy of application on application server; timers are created for methods that are annotated by annotations java.ejb.Schedule or java.ejb.Schedules.

 

Configuration of timers is described by annotations or in the descriptor ejb-jar.xml.

 

Examples of automatic timers

Method cleanupData will be executed every sunday at noon:

@Schedule(dayOfWeek="Sun", hour="12")

public void cleanupData() { ... }

Time expressions can be combined, i.e. next example:

@Schedules ({

@Schedule(dayOfMonth="Last"),

@Schedule(dayOfWeek="Fri", hour="23")

})

public void doPeriodicCleanup() { ... }

At the end of the first part

In the first part we looked at the basic timing of tasks in Java SE and Java EE. Next time we’ll look at the more specified methods (it doesn’t mean better or worst :) ). Don’t miss it.

Sources

  1. The Java EE 5 Tutorial, Online at http://download.oracle.com/javaee/5/tutorial/doc/
  2. The Java EE 6 Tutorial, Online at: http://download.oracle.com/javaee/6/tutorial/doc/
  3. JBoss Application Server Documentation, Online at http://docs.jboss.org/jbossas/docs/Installation_And_Getting_Started_Guide/5/html/index.html

Like this:

Další témata