/**
* Copyright (C) 2012 FuseSource, Inc.
* http://fusesource.com
*
* Licensed 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.fusesource.hawtdispatch.internal.util;
import java.util.*;
import java.util.concurrent.TimeUnit;
public abstract class TimerHeap<V> {
private final TreeMap<Long, LinkedList<V>> timers = new TreeMap<Long, LinkedList<V>>();
private final TimeUnit resolution = TimeUnit.NANOSECONDS;
private int size = 0;
public final void addAbsolute(V timed, long time, TimeUnit timeUnit) {
addInternal(timed, System.nanoTime() + resolution.convert(resolution.convert(time, timeUnit), timeUnit));
}
public final void addRelative(V timed, long delay, TimeUnit timeUnit) {
addInternal(timed, System.nanoTime() + resolution.convert(delay, timeUnit));
}
private void addInternal(V timed, long eTime) {
LinkedList<V> list = new LinkedList<V>();
list.add(timed);
LinkedList<V> old = timers.put(eTime, list);
if (old != null) {
list.addAll(old);
}
size++;
}
public int size() {
return size;
}
/**
* Returns the time of the next scheduled event.
*
* @return -1 if there are no events, otherwise the time that the next timer
* should fire.
*/
public final long timeToNext(TimeUnit unit) {
if (timers.isEmpty()) {
return -1;
} else {
return unit.convert(Math.max(0, timers.firstKey() - System.nanoTime()), resolution);
}
}
/**
* Executes ready timers.
*/
public final void executeReadyTimers() {
LinkedList<V> ready = null;
if (timers.isEmpty()) {
return;
} else {
long now = System.nanoTime();
long first = timers.firstKey();
if (first > now) {
return;
}
ready = new LinkedList<V>();
while (first <= now) {
ready.addAll(timers.remove(first));
if (timers.isEmpty()) {
break;
}
first = timers.firstKey();
}
}
for (V timed : ready) {
try {
execute(timed);
size--;
} catch (Throwable thrown) {
Thread thread = Thread.currentThread();
thread.getUncaughtExceptionHandler().uncaughtException(thread, thrown);
}
}
}
public List<V> clear() {
ArrayList<V> rc = new ArrayList<V>(size());
for (LinkedList<V> t : timers.values()) {
rc.addAll(t);
}
timers.clear();
return rc;
}
/**
* Subclass must override this to execute ready timers
*
* @param ready
* The ready operation.
*/
public abstract void execute(V ready);
}