/*
This file is part of Cyclos (www.cyclos.org).
A project of the Social Trade Organisation (www.socialtrade.org).
Cyclos is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
Cyclos is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Cyclos; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package nl.strohalm.cyclos.scheduling.polling;
import java.util.Random;
import java.util.concurrent.Callable;
import nl.strohalm.cyclos.utils.tasks.TaskRunner;
/**
* Base class for tasks which keeps looking for available data to be processed. When running in a cluster, it is guaranteed that only a single node
* runs the same polling task at the same time.
* @author luis
*/
public abstract class PollingTask extends Thread {
private int sleepSeconds;
private String key;
private TaskRunner taskRunner;
public PollingTask() {
setSleepSeconds(10);
setKey(getClass().getSimpleName());
}
/**
* Awakes this polling task from sleep, if it is sleeping
*/
public void awake() {
synchronized (this) {
notify();
}
}
public String getKey() {
return key;
}
public int getSleepSeconds() {
return sleepSeconds;
}
public TaskRunner getTaskRunner() {
return taskRunner;
}
@Override
public final void run() {
// Sleep the first time. The random time is to help not having multiple polling tasks running at the same second
try {
int initialSleepSeconds = new Random().nextInt(sleepSeconds);
Thread.sleep(initialSleepSeconds * 1000);
} catch (InterruptedException e) {
return;
}
while (true) {
// Execute the task
boolean runImmediately = taskRunner.runPollingTask(getKey(), new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
return runTask();
}
});
// Sleep if no more data for now
if (!runImmediately) {
synchronized (this) {
try {
wait(sleepSeconds * 1000);
} catch (InterruptedException e) {
return;
}
}
}
}
}
public void setKey(final String key) {
this.key = key;
setName("Polling task: " + key);
}
public void setSleepSeconds(final int sleepSeconds) {
this.sleepSeconds = sleepSeconds;
}
public void setTaskRunner(final TaskRunner taskRunner) {
this.taskRunner = taskRunner;
}
/**
* Should be implemented by subclasses to perform the actual task. Returning true means that this method should be immediately invoked right after
* this execution. False means the thread will sleep until the next execution.
*/
protected abstract boolean runTask();
}