/******************************************************************************* * Breakout Cave Survey Visualizer * * Copyright (C) 2014 James Edwards * * jedwards8 at fastmail dot fm * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 51 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *******************************************************************************/ package org.andork.swing.async; import java.util.ArrayList; import java.util.List; import javax.swing.SwingUtilities; import org.andork.event.BasicPropertyChangeSupport.External; import org.andork.event.HierarchicalBasicPropertyChangePropagator; import org.andork.event.HierarchicalBasicPropertyChangeSupport; public class SingleThreadedTaskService implements TaskService { private class Runner implements Runnable { @Override public void run() { while (true) { try { Task task; synchronized (lock) { if (taskQueue.isEmpty()) { lock.wait(keepAliveTime); } if (taskQueue.isEmpty()) { thread = null; return; } task = taskQueue.get(0); } try { if (!task.isCanceled()) { task.run(); } } catch (Throwable t) { t.printStackTrace(); } synchronized (lock) { task.changeSupport().removePropertyChangeListener(propagator); taskQueue.remove(0); lock.notifyAll(); } fireTaskRemoved(task); } catch (Throwable t) { t.printStackTrace(); } } } } private final HierarchicalBasicPropertyChangeSupport propertyChangeSupport = new HierarchicalBasicPropertyChangeSupport(); private final HierarchicalBasicPropertyChangePropagator propagator = new HierarchicalBasicPropertyChangePropagator( this, propertyChangeSupport); private final Object lock = new Object(); private Thread thread; private final List<Task> taskQueue = new ArrayList<Task>(); private int keepAliveTime = 1000; @Override public void cancel(Task task) { Task removed = null; synchronized (lock) { Task.State state = task.getState(); if (state != Task.State.CANCELED && state != Task.State.CANCELING) { task.cancel(); } int index = taskQueue.indexOf(task); // TODO figure out how to handle interruption properly // if( index == 0 ) // { // thread.interrupt( ); // } if (index > 0) { removed = taskQueue.remove(index); } } if (removed != null) { fireTaskRemoved(removed); } } @Override public External changeSupport() { return propertyChangeSupport.external(); } private void fireTaskAdded(final Task task) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { propertyChangeSupport.fireChildAdded(SingleThreadedTaskService.this, task); } }); } private void fireTaskRemoved(final Task task) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { propertyChangeSupport.fireChildRemoved(SingleThreadedTaskService.this, task); } }); } @Override public List<Task> getTasks() { synchronized (lock) { return new ArrayList<Task>(taskQueue); } } @Override public boolean hasTasks() { synchronized (lock) { return !taskQueue.isEmpty(); } } @Override public void submit(Task task) { synchronized (lock) { task.setService(this); taskQueue.add(task); task.changeSupport().addPropertyChangeListener(propagator); lock.notifyAll(); if (thread == null) { thread = new Thread(new Runner()); thread.setName(getClass().getSimpleName() + " thread"); thread.start(); } } fireTaskAdded(task); } }