/****************************************************************************** * Product: Adempiere ERP & CRM Smart Business Solution * * Copyright (C) 1999-2006 ComPiere, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * * under the terms version 2 of the GNU General Public License as published * * by the Free Software Foundation. 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., * * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. * * For the text or an alternative of this public license, you may reach us * * ComPiere, Inc., 2620 Augustine Dr. #245, Santa Clara, CA 95054, USA * * or via info@compiere.org or http://www.compiere.org/license.html * *****************************************************************************/ package org.compiere.install.util; import javax.swing.SwingUtilities; /** * SwingWorker (based on SwingWorker 3). * To use the SwingWorker class, you create a subclass of it. * In the subclass, you must implement the construct() method contains * the code to perform your lengthy operation. * You invoke start() on your SwingWorker object to start the thread, * which then calls your construct() method. * When you need the object returned by the construct() method, * you call the SwingWorker's get() method. *
 *      SwingWorker worker = new SwingWorker()
 *      {
 *          public Object construct()
 *          {
 *              return new expensiveOperation();
 *          }
 *      };
 *      worker.start();
 *      //  do something
 *      //  when you need the result:
 *      x = worker.get();   //  this blocks the UI !!
 *  
*/ public abstract class SwingWorker { /** * Start a thread that will call the construct method * and then exit. */ public SwingWorker() { /** Finish Runnable */ final Runnable doFinished = new Runnable() { public void run() { finished(); } }; /** Worker Runnable */ Runnable doConstruct = new Runnable() { public void run() { try { setValue(construct()); } finally { m_threadVar.clear(); } SwingUtilities.invokeLater(doFinished); } }; Thread t = new Thread (doConstruct); m_threadVar = new ThreadVar(t); } // SwingWorker /** Worker Thread */ private ThreadVar m_threadVar; /** Return value */ private Object m_value; // see getValue(), setValue() /** * Compute the value to be returned by the get method. * @return value */ public abstract Object construct(); /** * Called on the event dispatching thread (not on the worker thread) * after the construct method has returned. */ public void finished() { } // finished /** * Get the value produced by the worker thread, * or null if it hasn't been constructed yet. * @return value of worker */ protected synchronized Object getValue() { return m_value; } // getValue /** * Set the value produced by worker thread * @param x worker value */ private synchronized void setValue(Object x) { m_value = x; } // setValue /************************************************************************* * Start the worker thread. */ public void start() { Thread t = m_threadVar.get(); if (t != null) t.start(); } // start /** * Return the value created by the construct method. * Returns null if either the constructing thread or the current * thread was interrupted before a value was produced. * (Blocks UI) * @return the value created by the construct method */ public Object get() { while (true) { Thread t = m_threadVar.get(); if (t == null) { return getValue(); } try { t.join(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); // propagate return null; } } } // get /** * A new method that interrupts the worker thread. Call this method * to force the worker to stop what it's doing. */ public void interrupt() { Thread t = m_threadVar.get(); if (t != null) { t.interrupt(); } m_threadVar.clear(); } // interrupt /** * Is worker Alive * @return true if alive */ public boolean isAlive() { Thread t = m_threadVar.get(); if (t == null) return false; return t.isAlive(); } // isAlive /************************************************************************** * Class to maintain reference to current worker thread * under separate synchronization control. */ private static class ThreadVar { /** * Constructor * @param t sync thread */ ThreadVar(Thread t) { thread = t; } /** The Sync Thread */ private Thread thread; /** * Get Sync Thread * @return thread */ synchronized Thread get() { return thread; } // get /** * Clear Sync thread */ synchronized void clear() { thread = null; } // clear } // ThreadVar } // SwingWorker