/******************************************************************************* * Copyright (c) 2012 Original authors and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Original authors and others - initial API and implementation ******************************************************************************/ package org.eclipse.nebula.widgets.nattable.util; import java.util.HashMap; import java.util.Map; import java.util.concurrent.locks.ReentrantReadWriteLock; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * GUI Update Event Queue */ public class UpdateQueue { private static final Log log = LogFactory.getLog(UpdateQueue.class); private ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); private Map<String, Runnable> runnableMap = new HashMap<String, Runnable>(); private Thread thread = null; private boolean stop = false; protected long sleep = 100; private static UpdateQueue queue = null; protected UpdateQueue() { // no-op } public static UpdateQueue getInstance() { if (queue == null) { queue = new UpdateQueue(); } return queue; } private Runnable runnable = new Runnable() { @Override public void run() { try { while (!UpdateQueue.this.stop) { // Block thread and make sure that we are doing the // latest orders only UpdateQueue.this.lock.writeLock().lock(); Runnable[] runnables = UpdateQueue.this.runnableMap.values().toArray( new Runnable[UpdateQueue.this.runnableMap.size()]); UpdateQueue.this.runnableMap.clear(); UpdateQueue.this.lock.writeLock().unlock(); int len = runnables != null ? runnables.length : 0; for (int i = 0; i < len; i++) { try { runnables[i].run(); } catch (Exception e) { log.error(e); } } if (len > 0) { // Allow sleep try { Thread.sleep(UpdateQueue.this.sleep); } catch (Exception e) { log.error(e); } } else { // Sleep when nothing to do synchronized (UpdateQueue.this.thread) { try { UpdateQueue.this.thread.wait(); } catch (Exception e) { log.error(e); } } } } } catch (Exception e) { log.error(e); } } }; /** * Add a new runnable to a map along with a unique id<br> * The last update runnable of an id will be executed only. * * @param id * @param runnable */ public void addRunnable(String id, Runnable runnable) { try { // Block thread, ensure no one is going to update the vector this.lock.writeLock().lock(); try { this.runnableMap.put(id, runnable); } finally { this.lock.writeLock().unlock(); } runInThread(); } catch (Exception e) { log.error(e); } } // public void addRunnable(Runnable runnable) { // // Block thread, ensure no one is going to update the vector // lock.writeLock().lock(); // runnableList.add(runnable); // lock.writeLock().unlock(); // runInThread(); // } private void runInThread() { try { if (this.thread == null) { this.thread = new Thread(this.runnable, "GUI Display Delay Queue " //$NON-NLS-1$ + System.nanoTime()); this.thread.setDaemon(true); this.thread.start(); } else { synchronized (this.thread) { this.thread.notify(); } } } catch (Exception e) { log.error(e); } } public void stopThread() { try { if (this.thread != null) { this.stop = true; synchronized (this.thread) { this.thread.notify(); } } } catch (Exception e) { log.error(e); } } }