Mega Code Archive

 
Categories / Java / JDK
 

Swing worker from org jdesktop swingworker

/*   * $Id: AccumulativeRunnable.java,v 1.2 2006/09/28 20:20:28 idk Exp $  *   * Copyright ?2005 Sun Microsystems, Inc. All rights  * reserved. Use is subject to license terms.  */ package org.jdesktop.swingworker; import java.util.*; import javax.swing.SwingUtilities; /**  * An abstract class to be used in the cases where we need {@code Runnable}  * to perform  some actions on an appendable set of data.  * The set of data might be appended after the {@code Runnable} is  * sent for the execution. Usually such {@code Runnables} are sent to  * the EDT.  *  * <p>  * Usage example:  *   * <p>  * Say we want to implement JLabel.setText(String text) which sends  * {@code text} string to the JLabel.setTextImpl(String text) on the EDT.   * In the event JLabel.setText is called rapidly many times off the EDT  * we will get many updates on the EDT but only the last one is important.  * (Every next updates overrides the previous one.)  * We might want to implement this {@code setText} in a way that only  * the last update is delivered.  * <p>  * Here is how one can do this using {@code AccumulativeRunnable}:  * <pre>  * AccumulativeRunnable<String> doSetTextImpl =   * new  AccumulativeRunnable<String>() {  *     @Override   *     protected void run(List&lt;String&gt; args) {  *         //set to the last string being passed  *         setTextImpl(args.get(args.size() - 1);  *     }  * }  * void setText(String text) {  *     //add text and send for the execution if needed.  *     doSetTextImpl.add(text);  * }  * </pre>  *  * <p>  * Say we want want to implement addDirtyRegion(Rectangle rect)  * which sends this region to the   * handleDirtyRegions(List<Rect> regions) on the EDT.  * addDirtyRegions better be accumulated before handling on the EDT.  *   * <p>  * Here is how it can be implemented using AccumulativeRunnable:  * <pre>  * AccumulativeRunnable<Rectangle> doHandleDirtyRegions =   *     new AccumulativeRunnable<Rectangle>() {  *         @Override   *         protected void run(List&lt;Rectangle&gt; args) {  *             handleDirtyRegions(args);  *         }  *     };  *  void addDirtyRegion(Rectangle rect) {  *      doHandleDirtyRegions.add(rect);  *  }  * </pre>  *  * @author Igor Kushnirskiy  * @version $Revision: 1.2 $ $Date: 2006/09/28 20:20:28 $  *  * @param <T> the type this {@code Runnable} accumulates  *   */ abstract class AccumulativeRunnable<T> implements Runnable {     private List<T> arguments = null;          /**      * Equivalent to {@code Runnable.run} method with the      * accumulated arguments to process.      *      * @param args accumulated arguments to process.      */     protected abstract void run(List<T> args);          /**      * {@inheritDoc}      *      * <p>      * This implementation calls {@code run(List<T> args)} method      * with the list of accumulated arguments.      */     public final void run() {         run(flush());     }          /**      * appends arguments and sends this {@code Runnable} for the      * execution if needed.      * <p>      * This implementation uses {@see #submit} to send this       * {@code Runnable} for execution.       * @param args the arguments to accumulate      */     public final synchronized void add(T... args) {         boolean isSubmitted = true;         if (arguments == null) {             isSubmitted = false;             arguments = new ArrayList<T>();         }         Collections.addAll(arguments, args);         if (!isSubmitted) {             submit();         }     }     /**      * Sends this {@code Runnable} for the execution      *      * <p>      * This method is to be executed only from {@code add} method.      *      * <p>      * This implementation uses {@code SwingWorker.invokeLater}.      */     protected void submit() {         SwingUtilities.invokeLater(this);     }              /**      * Returns accumulated arguments and flashes the arguments storage.      *      * @return accumulated arguments      */     private final synchronized List<T> flush() {         List<T> list = arguments;         arguments = null;         return list;     } } /////////////////////////////////////////////////////////// /*   * $Id: SwingPropertyChangeSupport.java,v 1.1 2005/06/18 21:27:14 idk Exp $  *   * Copyright ?2005 Sun Microsystems, Inc. All rights  * reserved. Use is subject to license terms.  */ package org.jdesktop.swingworker; import java.beans.PropertyChangeSupport; import java.beans.PropertyChangeEvent; import javax.swing.SwingUtilities; /**  * This subclass of {@code java.beans.PropertyChangeSupport} is almost  * identical in functionality. The only difference is if constructed with   * {@code SwingPropertyChangeSupport(sourceBean, true)} it ensures  * listeners are only ever notified on the <i>Event Dispatch Thread</i>.  *  * @author Igor Kushnirskiy  * @version $Revision: 1.1 $ $Date: 2005/06/18 21:27:14 $  */ public final class SwingPropertyChangeSupport extends PropertyChangeSupport {     /**      * Constructs a SwingPropertyChangeSupport object.      *      * @param sourceBean  The bean to be given as the source for any      *        events.      * @throws NullPointerException if {@code sourceBean} is       *         {@code null}      */     public SwingPropertyChangeSupport(Object sourceBean) {         this(sourceBean, false);     }     /**      * Constructs a SwingPropertyChangeSupport object.      *       * @param sourceBean the bean to be given as the source for any events      * @param notifyOnEDT whether to notify listeners on the <i>Event      *        Dispatch Thread</i> only      *      * @throws NullPointerException if {@code sourceBean} is       *         {@code null}      * @since 1.6      */     public SwingPropertyChangeSupport(Object sourceBean, boolean notifyOnEDT) {         super(sourceBean);         this.notifyOnEDT = notifyOnEDT;     }     /**      * {@inheritDoc}      *      * <p>      * If {@see #isNotifyOnEDT} is {@code true} and called off the      * <i>Event Dispatch Thread</i> this implementation uses       * {@code SwingUtilities.invokeLater} to send out the notification      * on the <i>Event Dispatch Thread</i>. This ensures  listeners      * are only ever notified on the <i>Event Dispatch Thread</i>.      *      * @throws NullPointerException if {@code evt} is       *         {@code null}      * @since 1.6      */     public void firePropertyChange(final PropertyChangeEvent evt) {         if (evt == null) {             throw new NullPointerException();         }         if (! isNotifyOnEDT()             || SwingUtilities.isEventDispatchThread()) {             super.firePropertyChange(evt);         } else {             SwingUtilities.invokeLater(                 new Runnable() {                     public void run() {                         firePropertyChange(evt);                     }                 });         }     }     /**      * Returns {@code notifyOnEDT} property.      *       * @return {@code notifyOnEDT} property      * @see #SwingPropertyChangeSupport(Object sourceBean, boolean notifyOnEDT)      * @since 1.6      */     public final boolean isNotifyOnEDT() {         return notifyOnEDT;     }     // Serialization version ID     static final long serialVersionUID = 7162625831330845068L;     /**      * whether to notify listeners on EDT      *       * @serial       * @since 1.6      */      private final boolean notifyOnEDT; } /////////////////////////////////////////////////////////// /*   * $Id: SwingWorker.java,v 1.5 2007/03/01 19:55:54 idk Exp $  *   * Copyright ?2005 Sun Microsystems, Inc. All rights  * reserved. Use is subject to license terms.  */ package org.jdesktop.swingworker; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.beans.PropertyChangeEvent; import java.util.List; import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.*; import java.awt.event.*; import javax.swing.SwingUtilities; import javax.swing.Timer; /**  * An abstract class to perform lengthy GUI-interacting tasks in a  * dedicated thread.  *   * <p>  * When writing a multi-threaded application using Swing, there are  * two constraints to keep in mind:  * (refer to   * <a href="http://java.sun.com/docs/books/tutorial/uiswing/misc/threads.html">  *   How to Use Threads  * </a> for more details):  * <ul>  *   <li> Time-consuming tasks should not be run on the <i>Event  *        Dispatch Thread</i>. Otherwise the application becomes unresponsive.  *   </li>  *   <li> Swing components should be accessed  on the <i>Event  *        Dispatch Thread</i> only.  *   </li>  * </ul>  *  * <p>  *  * <p>  * These constraints mean that a GUI application with time intensive  * computing needs at least two threads:  1) a thread to perform the lengthy  * task and 2) the <i>Event Dispatch Thread</i> (EDT) for all GUI-related  * activities.  This involves inter-thread communication which can be  * tricky to implement.  *  * <p>  * {@code SwingWorker} is designed for situations where you need to have a long   * running task run in a background thread and provide updates to the UI   * either when done, or while processing.   * Subclasses of {@code SwingWorker} must implement   * the {@see #doInBackground} method to perform the background computation.  *  *  * <p>  * <b>Workflow</b>  * <p>  * There are three threads involved in the life cycle of a   * {@code SwingWorker} :  * <ul>  * <li>  * <p>  * <i>Current</i> thread: The {@link #execute} method is  * called on this thread. It schedules {@code SwingWorker} for the execution on a  * <i>worker</i>  * thread and returns immediately. One can wait for the {@code SwingWorker} to  * complete using the {@link #get get} methods.  * <li>  * <p>  * <i>Worker</i> thread: The {@link #doInBackground}   * method is called on this thread.  * This is where all background activities should happen. To notify  * {@code PropertyChangeListeners} about bound properties changes use the  * {@link #firePropertyChange firePropertyChange} and  * {@link #getPropertyChangeSupport} methods. By default there are two bound  * properties available: {@code state} and {@code progress}.  * <li>  * <p>  * <i>Event Dispatch Thread</i>:  All Swing related activities occur  * on this thread. {@code SwingWorker} invokes the  * {@link #process process} and {@link #done} methods and notifies  * any {@code PropertyChangeListeners} on this thread.  * </ul>  *   * <p>  * Often, the <i>Current</i> thread is the <i>Event Dispatch  * Thread</i>.   *  *  * <p>  * Before the {@code doInBackground} method is invoked on a <i>worker</i> thread,  * {@code SwingWorker} notifies any {@code PropertyChangeListeners} about the  * {@code state} property change to {@code StateValue.STARTED}.  After the  * {@code doInBackground} method is finished the {@code done} method is  * executed.  Then {@code SwingWorker} notifies any {@code PropertyChangeListeners}  * about the {@code state} property change to {@code StateValue.DONE}.  *  * <p>  * {@code SwingWorker} is only designed to be executed once.  Executing a  * {@code SwingWorker} more than once will not result in invoking the  * {@code doInBackground} method twice.  *  * <p>  * <b>Sample Usage</b>  * <p>  * The following example illustrates the simplest use case.  Some   * processing is done in the background and when done you update a Swing   * component.  *  * <p>  * Say we want to find the "Meaning of Life" and display the result in  * a {@code JLabel}.  *   * <pre>  *   final JLabel label;  *   class MeaningOfLifeFinder extends SwingWorker&lt;String, Object&gt; {  *       {@code @Override}  *       public String doInBackground() {  *           return findTheMeaningOfLife();  *       }  *  *       {@code @Override}  *       protected void done() {  *           try {   *               label.setText(get());  *           } catch (Exception ignore) {  *           }  *       }  *   }  *   *   (new MeaningOfLifeFinder()).execute();  * </pre>  *   * <p>  * The next example is useful in situations where you wish to process data   * as it is ready on the <i>Event Dispatch Thread</i>.  *  * <p>  * Now we want to find the first N prime numbers and display the results in a  * {@code JTextArea}.  While this is computing, we want to update our  * progress in a {@code JProgressBar}.  Finally, we also want to print   * the prime numbers to {@code System.out}.  * <pre>  * class PrimeNumbersTask extends   *         SwingWorker&lt;List&lt;Integer&gt;, Integer&gt; {  *     PrimeNumbersTask(JTextArea textArea, int numbersToFind) {   *         //initialize   *     }  *  *     {@code @Override}  *     public List&lt;Integer&gt; doInBackground() {  *         while (! enough &amp;&amp; ! isCancelled()) {  *                 number = nextPrimeNumber();  *                 publish(number);  *                 setProgress(100 * numbers.size() / numbersToFind);  *             }  *         }  *         return numbers;  *     }  *  *     {@code @Override}  *     protected void process(List&lt;Integer&gt; chunks) {   *         for (int number : chunks) {  *             textArea.append(number + &quot;\n&quot;);  *         }  *     }  * }  *  * JTextArea textArea = new JTextArea();  * final JProgressBar progressBar = new JProgressBar(0, 100);  * PrimeNumbersTask task = new PrimeNumbersTask(textArea, N);  * task.addPropertyChangeListener(  *     new PropertyChangeListener() {  *         public  void propertyChange(PropertyChangeEvent evt) {  *             if (&quot;progress&quot;.equals(evt.getPropertyName())) {  *                 progressBar.setValue((Integer)evt.getNewValue());  *             }  *         }  *     });  *  * task.execute();  * System.out.println(task.get()); //prints all prime numbers we have got  * </pre>  *   * <p>  * Because {@code SwingWorker} implements {@code Runnable}, a  * {@code SwingWorker} can be submitted to an  * {@link java.util.concurrent.Executor} for execution.  *    * @author Igor Kushnirskiy  * @version $Revision: 1.5 $ $Date: 2007/03/01 19:55:54 $  *   * @param <T> the result type returned by this {@code SwingWorker's}  *        {@code doInBackground} and {@code get} methods  * @param <V> the type used for carrying out intermediate results by this  *        {@code SwingWorker's} {@code publish} and {@code process} methods  *   */ public abstract class SwingWorker<T, V> implements Future<T>, Runnable {     /**      * number of worker threads.      */     private static final int MAX_WORKER_THREADS = 10;     /**      * current progress.      */     private volatile int progress;     /**      * current state.      */     private volatile StateValue state;     /**      * everything is run inside this FutureTask. Also it is used as      * a delegatee for the Future API.      */     private final FutureTask<T> future;     /**      * all propertyChangeSupport goes through this.      */     private final PropertyChangeSupport propertyChangeSupport;     /**      * handler for {@code process} method.      */     private AccumulativeRunnable<V> doProcess;     /**      * handler for progress property change notifications.      */     private AccumulativeRunnable<Integer> doNotifyProgressChange;          private static final AccumulativeRunnable<Runnable> doSubmit =          new DoSubmitAccumulativeRunnable();          private static ExecutorService executorService = null;     /**      * Values for the {@code state} bound property.      */     public enum StateValue {         /**          * Initial {@code SwingWorker} state.          */         PENDING,         /**          * {@code SwingWorker} is {@code STARTED}           * before invoking {@code doInBackground}.          */         STARTED,         /**          * {@code SwingWorker} is {@code DONE}          * after {@code doInBackground} method          * is finished.          */         DONE     };     /**      * Constructs this {@code SwingWorker}.      */     public SwingWorker() {         Callable<T> callable =                  new Callable<T>() {                     public T call() throws Exception {                         setState(StateValue.STARTED);                         return doInBackground();                     }                 };         future = new FutureTask<T>(callable) {                        @Override                        protected void done() {                            doneEDT();                            setState(StateValue.DONE);                        }                    };        state = StateValue.PENDING;        propertyChangeSupport = new SwingWorkerPropertyChangeSupport(this);        doProcess = null;        doNotifyProgressChange = null;     }          /**      * Computes a result, or throws an exception if unable to do so.      *      * <p>      * Note that this method is executed only once.      *       * <p>      * Note: this method is executed in a background thread.      *        *      * @return the computed result      * @throws Exception if unable to compute a result      *       */     protected abstract T doInBackground() throws Exception ;          /**      * Sets this {@code Future} to the result of computation unless      * it has been cancelled.      */     public final void run() {         future.run();     }          /**      * Sends data chunks to the {@link #process} method. This method is to be      * used from inside the {@code doInBackground} method to deliver       * intermediate results      * for processing on the <i>Event Dispatch Thread</i> inside the      * {@code process} method.      *       * <p>      * Because the {@code process} method is invoked asynchronously on      * the <i>Event Dispatch Thread</i>      * multiple invocations to the {@code publish} method      * might occur before the {@code process} method is executed. For      * performance purposes all these invocations are coalesced into one      * invocation with concatenated arguments.      *       * <p>      * For example:      *       * <pre>      * publish(&quot;1&quot;);      * publish(&quot;2&quot;, &quot;3&quot;);      * publish(&quot;4&quot;, &quot;5&quot;, &quot;6&quot;);      * </pre>      *       * might result in:      *       * <pre>      * process(&quot;1&quot;, &quot;2&quot;, &quot;3&quot;, &quot;4&quot;, &quot;5&quot;, &quot;6&quot;)      * </pre>      *      * <p>      * <b>Sample Usage</b>. This code snippet loads some tabular data and      * updates {@code DefaultTableModel} with it. Note that it safe to mutate      * the tableModel from inside the {@code process} method because it is       * invoked on the <i>Event Dispatch Thread</i>.      *       * <pre>      * class TableSwingWorker extends       *         SwingWorker&lt;DefaultTableModel, Object[]&gt; {      *     private final DefaultTableModel tableModel;      *       *     public TableSwingWorker(DefaultTableModel tableModel) {      *         this.tableModel = tableModel;      *     }      *       *     {@code @Override}      *     protected DefaultTableModel doInBackground() throws Exception {      *         for (Object[] row = loadData();       *                  ! isCancelled() &amp;&amp; row != null;       *                  row = loadData()) {      *             publish((Object[]) row);      *         }      *         return tableModel;      *     }      *       *     {@code @Override}      *     protected void process(List&lt;Object[]&gt; chunks) {      *         for (Object[] row : chunks) {      *             tableModel.addRow(row);      *         }      *     }      * }      * </pre>      *       * @param chunks intermediate results to process      *       * @see #process      *       */     protected final void publish(V... chunks) {         synchronized (this) {             if (doProcess == null) {                 doProcess = new AccumulativeRunnable<V>() {                     @Override                     public void run(List<V> args) {                         process(args);                     }                     @Override                     protected void submit() {                         doSubmit.add(this);                     }                 };             }         }         doProcess.add(chunks);     }     /**      * Receives data chunks from the {@code publish} method asynchronously on the      * <i>Event Dispatch Thread</i>.      *       * <p>      * Please refer to the {@link #publish} method for more details.      *       * @param chunks intermediate results to process      *       * @see #publish      *       */     protected void process(List<V> chunks) {     }     /**      * Executed on the <i>Event Dispatch Thread</i> after the {@code doInBackground}      * method is finished. The default      * implementation does nothing. Subclasses may override this method to      * perform completion actions on the <i>Event Dispatch Thread</i>. Note      * that you can query status inside the implementation of this method to      * determine the result of this task or whether this task has been cancelled.      *       * @see #doInBackground      * @see #isCancelled()      * @see #get      */     protected void done() {     }     /**      * Sets the {@code progress} bound property.      * The value should be from 0 to 100.      *      * <p>      * Because {@code PropertyChangeListener}s are notified asynchronously on      * the <i>Event Dispatch Thread</i> multiple invocations to the      * {@code setProgress} method might occur before any      * {@code PropertyChangeListeners} are invoked. For performance purposes      * all these invocations are coalesced into one invocation with the last      * invocation argument only.      *       * <p>      * For example, the following invocations:      *       * <pre>      * setProgress(1);      * setProgress(2);      * setProgress(3);      * </pre>      *       * might result in a single {@code PropertyChangeListener} notification with      * the value {@code 3}.      *       * @param progress the progress value to set      * @throws IllegalArgumentException is value not from 0 to 100      */     protected final void setProgress(int progress) {         if (progress < 0 || progress > 100) {             throw new IllegalArgumentException("the value should be from 0 to 100");         }         if (this.progress == progress) {             return;         }         int oldProgress = this.progress;         this.progress = progress;         if (! getPropertyChangeSupport().hasListeners("progress")) {             return;         }         synchronized (this) {             if (doNotifyProgressChange == null) {                 doNotifyProgressChange =                      new AccumulativeRunnable<Integer>() {                         @Override                         public void run(List<Integer> args) {                             firePropertyChange("progress",                                 args.get(0),                                 args.get(args.size() - 1));                         }                         @Override                         protected void submit() {                             doSubmit.add(this);                         }                     };             }         }         doNotifyProgressChange.add(oldProgress, progress);     }     /**      * Returns the {@code progress} bound property.      *       * @return the progress bound property.      */     public final int getProgress() {         return progress;     }     /**      * Schedules this {@code SwingWorker} for execution on a <i>worker</i>      * thread. There are a number of <i>worker</i> threads available. In the      * event all <i>worker</i> threads are busy handling other      * {@code SwingWorkers} this {@code SwingWorker} is placed in a waiting      * queue.      *      * <p>      * Note:      * {@code SwingWorker} is only designed to be executed once.  Executing a      * {@code SwingWorker} more than once will not result in invoking the      * {@code doInBackground} method twice.      */     public final void execute() {         getWorkersExecutorService().execute(this);     }     // Future methods START     /**      * {@inheritDoc}      */     public final boolean cancel(boolean mayInterruptIfRunning) {         return future.cancel(mayInterruptIfRunning);     }     /**      * {@inheritDoc}      */     public final boolean isCancelled() {         return future.isCancelled();     }     /**      * {@inheritDoc}      */     public final boolean isDone() {         return future.isDone();     }     /**      * {@inheritDoc}      * <p>      * Note: calling {@code get} on the <i>Event Dispatch Thread</i> blocks      * <i>all</i> events, including repaints, from being processed until this      * {@code SwingWorker} is complete.      *       * <p>      * When you want the {@code SwingWorker} to block on the <i>Event      * Dispatch Thread</i> we recommend that you use a <i>modal dialog</i>.      *      * <p>      * For example:      *       * <pre>      * class SwingWorkerCompletionWaiter extends PropertyChangeListener {      *     private JDialog dialog;      *       *     public SwingWorkerCompletionWaiter(JDialog dialog) {      *         this.dialog = dialog;      *     }      *       *     public void propertyChange(PropertyChangeEvent event) {      *         if (&quot;state&quot;.equals(event.getPropertyName())      *                 &amp;&amp; SwingWorker.StateValue.DONE == event.getNewValue()) {      *             dialog.setVisible(false);      *             dialog.dispose();      *         }      *     }      * }      * JDialog dialog = new JDialog(owner, true);      * swingWorker.addPropertyChangeListener(      *     new SwingWorkerCompletionWaiter(dialog));      * swingWorker.execute();      * //the dialog will be visible until the SwingWorker is done      * dialog.setVisible(true);       * </pre>      */     public final T get() throws InterruptedException, ExecutionException {         return future.get();     }     /**      * {@inheritDoc}      * <p>      * Please refer to {@link #get} for more details.      */     public final T get(long timeout, TimeUnit unit) throws InterruptedException,             ExecutionException, TimeoutException {         return future.get(timeout, unit);     }     // Future methods END     // PropertyChangeSupports methods START     /**      * Adds a {@code PropertyChangeListener} to the listener list. The listener      * is registered for all properties. The same listener object may be added      * more than once, and will be called as many times as it is added. If      * {@code listener} is {@code null}, no exception is thrown and no action is taken.      *       * <p>      * Note: This is merely a convenience wrapper. All work is delegated to      * {@code PropertyChangeSupport} from {@link #getPropertyChangeSupport}.      *       * @param listener the {@code PropertyChangeListener} to be added      */     public final void addPropertyChangeListener(PropertyChangeListener listener) {         getPropertyChangeSupport().addPropertyChangeListener(listener);     }     /**      * Removes a {@code PropertyChangeListener} from the listener list. This      * removes a {@code PropertyChangeListener} that was registered for all      * properties. If {@code listener} was added more than once to the same      * event source, it will be notified one less time after being removed. If      * {@code listener} is {@code null}, or was never added, no exception is      * thrown and no action is taken.      *       * <p>      * Note: This is merely a convenience wrapper. All work is delegated to      * {@code PropertyChangeSupport} from {@link #getPropertyChangeSupport}.      *       * @param listener the {@code PropertyChangeListener} to be removed      */     public final void removePropertyChangeListener(PropertyChangeListener listener) {         getPropertyChangeSupport().removePropertyChangeListener(listener);     }     /**      * Reports a bound property update to any registered listeners. No event is      * fired if {@code old} and {@code new} are equal and non-null.      *       * <p>      * This {@code SwingWorker} will be the source for       * any generated events.      *      * <p>      * When called off the <i>Event Dispatch Thread</i>      * {@code PropertyChangeListeners} are notified asynchronously on      * the <i>Event Dispatch Thread</i>.      * <p>      * Note: This is merely a convenience wrapper. All work is delegated to      * {@code PropertyChangeSupport} from {@link #getPropertyChangeSupport}.      *       *       * @param propertyName the programmatic name of the property that was      *        changed      * @param oldValue the old value of the property      * @param newValue the new value of the property      */     public final void firePropertyChange(String propertyName, Object oldValue,             Object newValue) {         getPropertyChangeSupport().firePropertyChange(propertyName,             oldValue, newValue);     }     /**      * Returns the {@code PropertyChangeSupport} for this {@code SwingWorker}.       * This method is used when flexible access to bound properties support is      * needed.      * <p>      * This {@code SwingWorker} will be the source for       * any generated events.      *       * <p>      * Note: The returned {@code PropertyChangeSupport} notifies any      * {@code PropertyChangeListener}s asynchronously on the <i>Event Dispatch      * Thread</i> in the event that {@code firePropertyChange} or      * {@code fireIndexedPropertyChange} are called off the <i>Event Dispatch      * Thread</i>.      *       * @return {@code PropertyChangeSupport} for this {@code SwingWorker}      */     public final PropertyChangeSupport getPropertyChangeSupport() {         return propertyChangeSupport;     }     // PropertyChangeSupports methods END     /**      * Returns the {@code SwingWorker} state bound property.      *       * @return the current state      */     public final StateValue getState() {         /*          * DONE is a special case          * to keep getState and isDone is sync          */         if (isDone()) {             return StateValue.DONE;         } else {             return state;         }     }          /**      * Sets this {@code SwingWorker} state bound property.      * @param the state state to set      */     private void setState(StateValue state) {         StateValue old = this.state;         this.state = state;         firePropertyChange("state", old, state);     }     /**      * Invokes {@code done} on the EDT.      */     private void doneEDT() {         Runnable doDone =              new Runnable() {                 public void run() {                     done();                 }             };         if (SwingUtilities.isEventDispatchThread()) {             doDone.run();         } else {             doSubmit.add(doDone);         }     }     /**      * returns workersExecutorService.      *      * returns the service stored in the appContext or creates it if      * necessary. If the last one it triggers autoShutdown thread to      * get started.      *       * @return ExecutorService for the {@code SwingWorkers}      * @see #startAutoShutdownThread      */     private static synchronized ExecutorService getWorkersExecutorService() {         if (executorService == null) {             //this creates non-daemon threads.              ThreadFactory threadFactory =                  new ThreadFactory() {                     final AtomicInteger threadNumber = new AtomicInteger(1);                     public Thread newThread(final Runnable r) {                         StringBuilder name =                              new StringBuilder("SwingWorker-pool-");                         name.append(System.identityHashCode(this));                         name.append("-thread-");                         name.append(threadNumber.getAndIncrement());                                                       Thread t = new Thread(r, name.toString());;                         if (t.isDaemon())                             t.setDaemon(false);                         if (t.getPriority() != Thread.NORM_PRIORITY)                             t.setPriority(Thread.NORM_PRIORITY);                         return t;                     }                 };             /*              * We want a to have no more than MAX_WORKER_THREADS              * running threads.              *              * We want a worker thread to wait no longer than 1 second              * for new tasks before terminating.              */             executorService = new ThreadPoolExecutor(0, MAX_WORKER_THREADS,                                          5L, TimeUnit.SECONDS,                                          new LinkedBlockingQueue<Runnable>(),                                          threadFactory) {                     private final ReentrantLock pauseLock = new ReentrantLock();                     private final Condition unpaused = pauseLock.newCondition();                     private boolean isPaused = false;                     private final ReentrantLock executeLock = new ReentrantLock();                                          @Override                     public void execute(Runnable command) {                         /*                          * ThreadPoolExecutor first tries to run task                          * in a corePool. If all threads are busy it                          * tries to add task to the waiting queue. If it                          * fails it run task in maximumPool.                          *                          * We want corePool to be 0 and                          * maximumPool to be MAX_WORKER_THREADS                          * We need to change the order of the execution.                          * First try corePool then try maximumPool                          * pool and only then store to the waiting                          * queue. We can not do that because we would                          * need access to the private methods.                          *                          * Instead we enlarge corePool to                          * MAX_WORKER_THREADS before the execution and                          * shrink it back to 0 after.                           * It does pretty much what we need.                          *                          * While we changing the corePoolSize we need                          * to stop running worker threads from accepting new                          * tasks.                          */                                                  //we need atomicity for the execute method.                         executeLock.lock();                         try {                             pauseLock.lock();                             try {                                 isPaused = true;                             } finally {                                 pauseLock.unlock();                             }                                                          setCorePoolSize(MAX_WORKER_THREADS);                             super.execute(command);                             setCorePoolSize(0);                                                          pauseLock.lock();                             try {                                 isPaused = false;                                 unpaused.signalAll();                             } finally {                                 pauseLock.unlock();                             }                         } finally {                             executeLock.unlock();                         }                     }                     @Override                      protected void afterExecute(Runnable r, Throwable t) {                          super.afterExecute(r, t);                         pauseLock.lock();                         try {                             while(isPaused) {                                 unpaused.await();                             }                         } catch(InterruptedException ignore) {                                                      } finally {                             pauseLock.unlock();                         }                     }                 };         }         return executorService;      }         private static class DoSubmitAccumulativeRunnable            extends AccumulativeRunnable<Runnable> implements ActionListener {         private final static int DELAY = (int) (1000 / 30);         @Override         protected void run(List<Runnable> args) {             for (Runnable runnable : args) {                 runnable.run();             }         }         @Override         protected void submit() {             Timer timer = new Timer(DELAY, this);             timer.setRepeats(false);             timer.start();         }         public void actionPerformed(ActionEvent event) {             run();         }     }          private class SwingWorkerPropertyChangeSupport              extends PropertyChangeSupport {         SwingWorkerPropertyChangeSupport(Object source) {             super(source);         }         @Override         public void firePropertyChange(final PropertyChangeEvent evt) {             if (SwingUtilities.isEventDispatchThread()) {                 super.firePropertyChange(evt);             } else {                 doSubmit.add(                     new Runnable() {                         public void run() {                             SwingWorkerPropertyChangeSupport.this                                 .firePropertyChange(evt);                         }                     });             }         }     } } /////////////////////////////////////////////////////////// /*   * $Id: PrimeNumbersDemo.java,v 1.2 2006/09/28 20:20:30 idk Exp $  *   * Copyright ?2005 Sun Microsystems, Inc. All rights  * reserved. Use is subject to license terms.  */ package org.jdesktop.swingworker; import java.awt.BorderLayout; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.ArrayList; import java.util.List; import javax.swing.JFrame; import javax.swing.JProgressBar; import javax.swing.JScrollPane; import javax.swing.JTextArea; public class PrimeNumbersDemo {     public static void main(String[] args) throws Exception {         JFrame frame = new JFrame("Prime Numbers Demo");         frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);         JTextArea textArea = new JTextArea();         textArea.setEditable(false);         frame.add(new JScrollPane(textArea), BorderLayout.CENTER);         PrimeNumbersTask task = new PrimeNumbersTask(textArea, 10000);         final JProgressBar progressBar = new JProgressBar(0, 100);         progressBar.setIndeterminate(true);         frame.add(progressBar, BorderLayout.NORTH);         frame.setSize(500, 500);         frame.setVisible(true);         task.addPropertyChangeListener(             new PropertyChangeListener() {                 public  void propertyChange(PropertyChangeEvent evt) {                     if ("progress".equals(evt.getPropertyName())) {                         progressBar.setIndeterminate(false);                         progressBar.setValue((Integer)evt.getNewValue());                     }                 }             });         task.execute();         return;     }          /**      * Finds first N prime numbers.      */     static class PrimeNumbersTask extends SwingWorker<List<Integer>, Integer> {         final int numbersToFind;         //sorted list of consequent prime numbers         private final List<Integer> primeNumbers;         private final JTextArea textArea;         PrimeNumbersTask(JTextArea textArea, int numbersToFind) {             this.textArea = textArea;             this.numbersToFind = numbersToFind;             this.primeNumbers = new ArrayList<Integer>(numbersToFind);         }         @Override         public List<Integer> doInBackground() {             int number = 2;             while(primeNumbers.size() < numbersToFind                   && !isCancelled()) {                 if (isPrime(number)) {                     primeNumbers.add(number);                     setProgress(100 * primeNumbers.size() / numbersToFind);                     publish(number);                 }                 number++;             }             return primeNumbers;         }         @Override         protected void process(List<Integer> chunks) {             StringBuilder strBuilder = new StringBuilder();             for (int number : chunks) {                 strBuilder.append(number).append('\n');             }             textArea.append(strBuilder.toString());         }         private boolean isPrime(int number) {             for (int prime : primeNumbers) {                 if (number % prime == 0) {                     return false;                 }             }             return true;         }     } } /////////////////////////////////////////////////////////// /*   * $Id: SwingWorkerTest.java,v 1.3 2007/03/01 19:34:02 idk Exp $  *   * Copyright ?2005 Sun Microsystems, Inc. All rights  * reserved. Use is subject to license terms.  */ package org.jdesktop.swingworker; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.concurrent.Exchanger; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import javax.swing.SwingUtilities; import junit.framework.TestCase; import org.jdesktop.swingworker.SwingWorker.StateValue; public class SwingWorkerTest extends TestCase {     private final static int TIME_OUT = 30;     private final static TimeUnit TIME_OUT_UNIT = TimeUnit.SECONDS;          public static void main(String[] args) {         junit.swingui.TestRunner.run(SwingWorkerTest.class);     }              // is to be run on a worker thread.     public final void testdoInBackground() throws Exception {         SwingWorker<Thread,?> test = new SwingWorker<Thread, Object>() {             @Override             protected Thread doInBackground() throws Exception {                 return Thread.currentThread();             }         };         test.execute();         Thread result = test.get(TIME_OUT, TIME_OUT_UNIT);         assertNotNull(result);         assertNotSame(Thread.currentThread(), result);     }     //{@code process} gets everything from {@code publish}     //should be executed on the EDT     public final void testPublishAndProcess() throws Exception {         final Exchanger<List<Integer>> listExchanger =              new Exchanger<List<Integer>>();         final Exchanger<Boolean> boolExchanger =              new Exchanger<Boolean>();         SwingWorker<List<Integer>,Integer> test =              new SwingWorker<List<Integer>, Integer>() {                 List<Integer> receivedArgs =                      Collections.synchronizedList(new ArrayList<Integer>());                 Boolean isOnEDT = Boolean.TRUE;                 final int NUMBERS = 100;                 @Override                 protected List<Integer> doInBackground() throws Exception {                     List<Integer> ret =                          Collections.synchronizedList(                             new ArrayList<Integer>(NUMBERS));                     for (int i = 0; i < NUMBERS; i++) {                         publish(i);                         ret.add(i);                     }                     return ret;                 }                 @Override                 protected void process(List<Integer> args) {                     for(Integer i : args) {                         receivedArgs.add(i);                     }                     isOnEDT = isOnEDT && SwingUtilities.isEventDispatchThread();                     if (receivedArgs.size() == NUMBERS) {                         try {                             boolExchanger.exchange(isOnEDT);                             listExchanger.exchange(receivedArgs);                         } catch (InterruptedException ignore) {                             ignore.printStackTrace();                         }                     }                 }         };         test.execute();         assertTrue(boolExchanger.exchange(null, TIME_OUT, TIME_OUT_UNIT));         assertEquals(test.get(TIME_OUT, TIME_OUT_UNIT),              listExchanger.exchange(null, TIME_OUT, TIME_OUT_UNIT));     }     // done is executed on the EDT     // receives the return value from doInBackground using get()     public final void testDone() throws Exception {         final String testString  = "test";          final Exchanger<Boolean> exchanger = new Exchanger<Boolean>();         SwingWorker<?,?> test = new SwingWorker<String, Object>() {             @Override             protected String doInBackground() throws Exception {                 return testString;             }             @Override             protected void done() {                 try {                     exchanger.exchange(                         testString == get()                         && SwingUtilities.isEventDispatchThread());                 } catch (Exception ignore) {                 }             }         };         test.execute();         assertTrue(exchanger.exchange(null, TIME_OUT, TIME_OUT_UNIT));     }     //PropertyChangeListener should be notified on the EDT only     public final void testPropertyChange() throws Exception {         final Exchanger<Boolean> boolExchanger =              new Exchanger<Boolean>();         final SwingWorker<?,?> test =              new SwingWorker<Object, Object>() {                 @Override                 protected Object doInBackground() throws Exception {                     firePropertyChange("test", null, "test");                     return null;                 }             };         test.addPropertyChangeListener(             new PropertyChangeListener() {                 boolean isOnEDT = true;                 public  void propertyChange(PropertyChangeEvent evt) {                     isOnEDT &= SwingUtilities.isEventDispatchThread();                     if ("state".equals(evt.getPropertyName())                         && StateValue.DONE == evt.getNewValue()) {                         try {                             boolExchanger.exchange(isOnEDT);                         } catch (Exception ignore) {                             ignore.printStackTrace();                         }                     }                 }             });         test.execute();         assertTrue(boolExchanger.exchange(null, TIME_OUT, TIME_OUT_UNIT));     }          //the sequence should be     //StateValue.STARTED, done, StateValue.DONE     public final void testWorkFlow() throws Exception {         final List<Object> goldenSequence =              Arrays.asList(new Object[]{StateValue.STARTED, "done",                                         StateValue.DONE});         final List<Object> sequence =                      Collections.synchronizedList(new ArrayList<Object>());         final Exchanger<List<Object>> listExchanger = new Exchanger<List<Object>>();                  final SwingWorker<?,?> test =              new SwingWorker<Object,Object>() {                 @Override                 protected Object doInBackground() throws Exception {                     return null;                 }                 @Override                 protected void done() {                     sequence.add("done");                 }             };         test.addPropertyChangeListener(             new PropertyChangeListener() {                 public  void propertyChange(PropertyChangeEvent evt) {                     if ("state".equals(evt.getPropertyName())) {                         sequence.add(evt.getNewValue());                         if (StateValue.DONE == evt.getNewValue()) {                             try {                                 listExchanger.exchange(sequence);                             } catch (Exception ignore) {                                 ignore.printStackTrace();                             }                         }                     }                 }             });         test.execute();         assertEquals(goldenSequence,                       listExchanger.exchange(null, TIME_OUT, TIME_OUT_UNIT));     }          /*       * regression test for 6493680      * [SwingWorker notifications might be out of order.]      */      public final void test6493680() throws Exception {         final AtomicInteger lastProgressValue = new AtomicInteger(-1);         final Exchanger<Boolean> exchanger = new Exchanger<Boolean>();         class Test {             private final AtomicInteger lastProgressValue =                  new AtomicInteger(-1);             private final Exchanger<Boolean> exchanger =                  new Exchanger<Boolean>();             boolean test() throws Exception {                 TestSwingWorker swingWorker = new TestSwingWorker();                 swingWorker.addPropertyChangeListener(                     new PropertyChangeListener() {                         public void propertyChange(PropertyChangeEvent evt) {                             if ("progress" == evt.getPropertyName()) {                                 lastProgressValue.set((Integer) evt.getNewValue());                             }                         }                     });                 swingWorker.execute();                 return exchanger.exchange(true);             }             class TestSwingWorker extends SwingWorker<Void, Void> {                 @Override                 protected Void doInBackground() throws Exception {                     for (int i = 0; i <= 100; i++) {                         Thread.sleep(1);                         setProgress(i);                     }                     return null;                 }                 @Override                 protected void done() {                     boolean isPassed = (lastProgressValue.get() == 100);                     try {                         exchanger.exchange(isPassed);                     } catch (Exception ingore) {                     }                 }             }         }         /*          * because timing is involved in this bug we will run the test          * NUMBER_OF_TRIES times.          * the tes`t passes if it does not fail once.          */          final int NUMBER_OF_TRIES = 50;          for (int i = 0; i < NUMBER_OF_TRIES; i++) {              assertTrue((new Test()).test());          }     } } ///////////////////////////////////////////////////////////                     swing-worker-src-1.1.zip( 27 k)