org.ut.biolab.medsavant.client.util.MedSavantWorker.java Source code

Java tutorial

Introduction

Here is the source code for org.ut.biolab.medsavant.client.util.MedSavantWorker.java

Source

/**
 * See the NOTICE file distributed with this work for additional
 * information regarding copyright ownership.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
package org.ut.biolab.medsavant.client.util;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeListener;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import javax.swing.SwingWorker;
import javax.swing.SwingWorker.StateValue;
import javax.swing.Timer;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.ut.biolab.medsavant.shared.model.ProgressStatus;

/**
 * SwingWorker wrapper which provides hooks do the right thing in response to errors, cancellation, etc.
 * 
 * @author tarkvara
 */
public abstract class MedSavantWorker<T> { //extends SwingWorker<T, Object> {
    private static final Log LOG = LogFactory.getLog(MedSavantWorker.class);
    private static final int MAX_MEDSAVANT_WORKER_THREADS = 20;

    private String pageName;
    private SwingWorker<T, Object> swingWorker;

    private static ExecutorService threadPool = Executors.newFixedThreadPool(MAX_MEDSAVANT_WORKER_THREADS);
    protected Timer progressTimer;

    /**
     * @param pageName which view created this worker
     */
    public MedSavantWorker(String pageName) {
        this.pageName = pageName;
        ThreadController.getInstance().addWorker(pageName, this);

        final MedSavantWorker instance = this;
        swingWorker = new SwingWorker<T, Object>() {
            @Override
            public void done() {
                instance.done();
            }

            @Override
            protected T doInBackground() throws Exception {
                return (T) instance.doInBackground();
            }
        };

    }

    public void execute() {
        threadPool.submit(swingWorker);
    }

    protected abstract T doInBackground() throws Exception;

    public boolean isDone() {
        return swingWorker.isDone();
    }

    public boolean cancel(boolean cancel) {
        return swingWorker.cancel(cancel);
    }

    public StateValue getState() {
        return swingWorker.getState();
    }

    public boolean isCancelled() {
        return swingWorker.isCancelled();
    }

    public void firePropertyChange(String propertyName, Object oldValue, Object newValue) {
        swingWorker.firePropertyChange(propertyName, oldValue, newValue);
    }

    public void addPropertyChangeListener(PropertyChangeListener pcl) {
        swingWorker.addPropertyChangeListener(pcl);
    }

    public final int getProgress() {
        return swingWorker.getProgress();
    }

    //@Override
    public void done() {
        if (this.progressTimer != null) {
            this.progressTimer.stop();
        }
        showProgress(1.0);
        try {
            if (!swingWorker.isCancelled()) {
                showSuccess(swingWorker.get());
            } else {
                // Send the server one last checkProgress call so that server knows that we've cancelled.
                try {
                    checkProgress();
                } catch (Exception ex) {
                    LOG.info("Ignoring exception thrown while cancelling.", ex);
                }
                throw new InterruptedException();
            }
        } catch (InterruptedException x) {
            showFailure(x);
        } catch (ExecutionException x) {
            showFailure(x.getCause());
        } finally {
            // Succeed or fail, we want to remove the worker from our page.
            ThreadController.getInstance().removeWorker(this.pageName, this);
        }
    }

    /**
     * Show progress during a lengthy operation. As a special case, pass 1.0 to remove the progress display.  
     * 
     * @param fract the fraction completed (1.0 to indicate full completion; -1.0 as special flag to indicate
     *        indeterminate progress-bar).
     */
    protected void showProgress(double fract) {

    }

    /**
     * Called when the worker has successfully completed its task.
     * 
     * @param result the value returned by <code>doInBackground()</code>.
     */
    protected abstract void showSuccess(T result);

    /**
     * Called when the task has thrown an exception. Default behaviour is to log the exception and put up a dialog box.
     */
    protected void showFailure(Throwable t) {
        if (!(t instanceof InterruptedException)) {
            ClientMiscUtils.reportError("Exception thrown by background task: %s", t);
        }
    }

    /**
     * Base-class does no progress checking.
     */
    protected ProgressStatus checkProgress() throws Exception {
        return null;
    }

    /**
     * Workers which want intermittent progress checks should start a timer which will call checkProgress and
     * showProgress intermittently.
     */
    protected void startProgressTimer() {
        this.progressTimer = new Timer(1000, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent ae) {
                try {
                    ProgressStatus status = checkProgress();
                    if (status != null) {
                        showProgress(status.fractionCompleted);
                    }
                } catch (Exception ex) {
                    LOG.info("Ignoring exception thrown while checking for progress.", ex);
                }
            }
        });
        this.progressTimer.start();
    }
}