/*
* Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. 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.
*/
package org.wso2.carbon.bpmn.people.substitution.scheduler;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.util.Iterator;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class SchedulerThread implements Runnable {
private static final Log __log = LogFactory.getLog(SchedulerThread.class);
private static final int TODO_QUEUE_INITIAL_CAPACITY = 200;
/** Jobs ready for immediate execution. */
private PriorityBlockingQueue<ScheduledTask> _todo;
/** Lock for managing the queue */
private ReentrantLock _lock = new ReentrantLock();
private Condition _activity = _lock.newCondition();
private volatile boolean _done;
private ScheduledTaskRunner _taskrunner;
private Thread _thread;
SchedulerThread(ScheduledTaskRunner runner) {
_todo = new PriorityBlockingQueue<ScheduledTask>(TODO_QUEUE_INITIAL_CAPACITY,
new ComparatorByDate());
_taskrunner = runner;
}
void start() {
if (_thread != null)
return;
_done = false;
_thread = new Thread(this, "OdeScheduler");
_thread.start();
}
/**
* Shutdown the thread.
*/
void stop() {
if (_thread == null)
return;
_done = true;
_lock.lock();
try {
_activity.signal();
} finally {
_lock.unlock();
}
while (_thread != null)
try {
_thread.join();
_thread = null;
} catch (InterruptedException e) {
;
}
}
/**
* Add a job to the todo queue.
*
* @param task
*/
void enqueue(ScheduledTask task) {
_lock.lock();
try {
_todo.add(task);
_activity.signal();
} finally {
_lock.unlock();
}
}
/**
* Remove a job to the todo queue.
*
* @param task
*/
void dequeue(ScheduledTask task) {
_lock.lock();
try {
_todo.remove(task);
_activity.signal();
} finally {
_lock.unlock();
}
}
/**
* Get the size of the todo queue.
*
* @return
*/
public int size() {
return _todo.size();
}
/**
* Pop items off the todo queue, and send them to the task runner for processing.
*/
public void run() {
while (!_done) {
_lock.lock();
try {
boolean wait = false;
long nextjob;
while ((nextjob = nextJobTime()) > 0 && !_done)
wait = _activity.await(nextjob, TimeUnit.MILLISECONDS);
if (__log.isDebugEnabled()) {
__log.debug("waiting for next job : " + wait);
}
if (!_done && nextjob == 0) {
ScheduledTask task = _todo.take();
_taskrunner.runTask(task);
}
} catch (InterruptedException ex) {
; // ignore
} finally {
_lock.unlock();
}
}
}
/**
* Calculate the time until the next available job.
*
* @return time until next job, 0 if one is one is scheduled to go, and some
* really large number if there are no jobs to speak of
*/
protected long nextJobTime() {
assert _lock.isLocked();
ScheduledTask job = _todo.peek();
if (job == null)
return Long.MAX_VALUE;
return Math.max(0, job.schedDate - System.currentTimeMillis());
}
/**
* Remove the tasks of a given type from the list.
* @param taskType type of task
*/
public void clearTasks(final Class<? extends ScheduledTask> taskType) {
_lock.lock();
try {
Iterator<ScheduledTask> i = _todo.iterator();
while (i.hasNext()) {
if (taskType.isAssignableFrom(i.next().getClass())) {
i.remove();
}
}
} finally {
_lock.unlock();
}
}
}