package restx.common.watch;
import com.google.common.eventbus.EventBus;
import java.io.Closeable;
import java.io.IOException;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
* Used to coalesce events occuring in a short period of time.
*
* <p>
* You submit events to the coalescor using the #post(Object) method,
* and if no similar (compared with #equals) event occur within the
* coalesce period, the event is forwarded to the underlying EventBus.
* </p>
* <p>
* Other similar events occuring within the period are simply not discarded.
* </p>
*/
public abstract class EventCoalescor<T> implements Closeable {
/**
* Create an instance of an {@link EventCoalescor} which accept all kind of events,
* as it is untyped.
*
* @param eventBus the event bus where to post processed events
* @param coalescePeriod the coalesce period
* @return the generic event coalescor
*/
public static EventCoalescor<Object> generic(EventBus eventBus, long coalescePeriod) {
return new GenericEventCoalescor(eventBus, coalescePeriod);
}
final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
final EventBus eventBus;
final long coalescePeriod;
EventCoalescor(EventBus eventBus, long coalescePeriod) {
this.eventBus = eventBus;
this.coalescePeriod = coalescePeriod;
}
public abstract void post(final T event);
@Override
public void close() throws IOException {
executor.shutdownNow();
}
/**
* generic coalescor, using untyped events
*/
private static class GenericEventCoalescor extends EventCoalescor<Object> {
private final Set<Object> queue = new LinkedHashSet<>();
private GenericEventCoalescor(EventBus eventBus, long coalescePeriod) {
super(eventBus, coalescePeriod);
}
public void post(final Object event) {
synchronized (queue) {
if (queue.add(event)) {
executor.schedule(new Runnable() {
@Override
public void run() {
try {
eventBus.post(event);
} finally {
synchronized (queue) {
queue.remove(event);
}
}
}
}, coalescePeriod, TimeUnit.MILLISECONDS);
}
}
}
}
}