001/*
002 * $Id: BackgroundTask.java,v 1.4 2011/03/24 16:06:35 davep Exp $
003 *
004 * This file is part of McIDAS-V
005 *
006 * Copyright 2007-2011
007 * Space Science and Engineering Center (SSEC)
008 * University of Wisconsin - Madison
009 * 1225 W. Dayton Street, Madison, WI 53706, USA
010 * https://www.ssec.wisc.edu/mcidas
011 * 
012 * All Rights Reserved
013 * 
014 * McIDAS-V is built on Unidata's IDV and SSEC's VisAD libraries, and
015 * some McIDAS-V source code is based on IDV and VisAD source code.  
016 * 
017 * McIDAS-V is free software; you can redistribute it and/or modify
018 * it under the terms of the GNU Lesser Public License as published by
019 * the Free Software Foundation; either version 3 of the License, or
020 * (at your option) any later version.
021 * 
022 * McIDAS-V is distributed in the hope that it will be useful,
023 * but WITHOUT ANY WARRANTY; without even the implied warranty of
024 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
025 * GNU Lesser Public License for more details.
026 * 
027 * You should have received a copy of the GNU Lesser Public License
028 * along with this program.  If not, see http://www.gnu.org/licenses.
029 */
030package edu.wisc.ssec.mcidasv.util;
031
032import java.util.concurrent.Callable;
033import java.util.concurrent.CancellationException;
034import java.util.concurrent.ExecutionException;
035import java.util.concurrent.Future;
036import java.util.concurrent.FutureTask;
037import java.util.concurrent.TimeUnit;
038import java.util.concurrent.TimeoutException;
039
040/**
041 * Background task class supporting cancellation, completion notification, 
042 * and progress notification. Courtesy of <i>Java Concurrency in Practice</i>, 
043 * written by Brian Goetz and Tim Peierls.
044 */
045//TODO: couldn't find a license for this code? is it public domain?
046public abstract class BackgroundTask <V> implements Runnable, Future<V> {
047    private final FutureTask<V> computation = new Computation();
048
049    private class Computation extends FutureTask<V> {
050        public Computation() {
051            super(new Callable<V>() {
052                public V call() throws Exception {
053                    return BackgroundTask.this.compute();
054                }
055            });
056        }
057
058        protected final void done() {
059            GuiExecutor.instance().execute(new Runnable() {
060                public void run() {
061                    V value = null;
062                    Throwable thrown = null;
063                    boolean cancelled = false;
064                    try {
065                        value = get();
066                    } catch (ExecutionException e) {
067                        thrown = e.getCause();
068                    } catch (CancellationException e) {
069                        cancelled = true;
070                    } catch (InterruptedException consumed) {
071                    } finally {
072                        onCompletion(value, thrown, cancelled);
073                    }
074                };
075            });
076        }
077    }
078
079    protected void setProgress(final int current, final int max) {
080        GuiExecutor.instance().execute(new Runnable() {
081            public void run() {
082                onProgress(current, max);
083            }
084        });
085    }
086
087    // Called in the background thread
088    protected abstract V compute() throws Exception;
089
090    // Called in the event thread
091    protected void onCompletion(V result, Throwable exception,
092                                boolean cancelled) {
093    }
094
095    protected void onProgress(int current, int max) {
096    }
097
098    // Other Future methods just forwarded to computation
099    public boolean cancel(boolean mayInterruptIfRunning) {
100        return computation.cancel(mayInterruptIfRunning);
101    }
102
103    public V get() throws InterruptedException, ExecutionException {
104        return computation.get();
105    }
106
107    public V get(long timeout, TimeUnit unit)
108            throws InterruptedException,
109            ExecutionException,
110            TimeoutException {
111        return computation.get(timeout, unit);
112    }
113
114    public boolean isCancelled() {
115        return computation.isCancelled();
116    }
117
118    public boolean isDone() {
119        return computation.isDone();
120    }
121
122    public void run() {
123        computation.run();
124    }
125}