diff --git a/tools/cooja/java/se/sics/cooja/dialogs/UpdateAggregator.java b/tools/cooja/java/se/sics/cooja/dialogs/UpdateAggregator.java new file mode 100644 index 000000000..599f4fe39 --- /dev/null +++ b/tools/cooja/java/se/sics/cooja/dialogs/UpdateAggregator.java @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2010, Swedish Institute of Computer Science. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. 2. Redistributions in + * binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. 3. Neither the name of the + * Institute nor the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $Id: UpdateAggregator.java,v 1.1 2010/03/26 09:27:58 fros4943 Exp $ + */ + +package se.sics.cooja.dialogs; + +import java.awt.EventQueue; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.ArrayList; +import java.util.List; + +import javax.swing.Timer; + +import se.sics.cooja.plugins.LogListener; + +/** + * Help class to avoid EventQueue flooding by aggregating several update events. + * + * To be used by plugins et. al. that receive updates at a high rate + * (such as new Log Output messages), and must handle them from the Event thread. + * + * @author Fredrik Osterlind, Niclas Finne + * + * @param Event whose update event are aggregated + * @see LogListener + */ +public abstract class UpdateAggregator { + private static final int DEFAULT_MAX_PENDING = 256; + private int maxPending; + + private ArrayList pending; + private Timer t; + + /** + * @param interval Max interval (ms) + */ + public UpdateAggregator(int interval) { + this(interval, DEFAULT_MAX_PENDING); + } + /** + * @param delay Max interval (ms) + * @param maxEvents Max pending events (default 256) + */ + public UpdateAggregator(int interval, int maxEvents) { + this.maxPending = maxEvents; + pending = new ArrayList(); + t = new Timer(interval, new ActionListener() { + public void actionPerformed(ActionEvent e) { + consume.run(); + } + }); + t.setInitialDelay(0); + t.setCoalesce(true); + t.setRepeats(true); + } + + /** + * Consumer: called from event queue + */ + private Runnable consume = new Runnable() { + public void run() { + if (pending.isEmpty()) { + return; + }; + + List q = getPending(); + if (q != null) { + /* Handle objects */ + handle(q); + } + + synchronized (UpdateAggregator.this) { + UpdateAggregator.this.notifyAll(); + } + } + }; + + /** + * @param l All events since last update + */ + protected abstract void handle(List l); + + private synchronized List getPending() { + /* Queue pending packets */ + ArrayList tmp = pending; + pending = new ArrayList(); + return tmp; + } + + /** + * @param a Add new event (any thread). May block. + */ + public synchronized void add(A a) { + try { + while (pending.size() > maxPending) { + /* Delay producer thread; events are coming in too fast */ + EventQueue.invokeLater(consume); /* Request immediate consume */ + wait(); + } + } catch (InterruptedException e) { + } + pending.add(a); + } + + public void start() { + t.start(); + } + public void stop() { + t.stop(); + } +}