Home » openjdk-7 » javax » swing » [javadoc | source]

    1   /*
    2    * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved.
    3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    4    *
    5    * This code is free software; you can redistribute it and/or modify it
    6    * under the terms of the GNU General Public License version 2 only, as
    7    * published by the Free Software Foundation.  Oracle designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Oracle in the LICENSE file that accompanied this code.
   10    *
   11    * This code is distributed in the hope that it will be useful, but WITHOUT
   12    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   13    * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14    * version 2 for more details (a copy is included in the LICENSE file that
   15    * accompanied this code).
   16    *
   17    * You should have received a copy of the GNU General Public License version
   18    * 2 along with this work; if not, write to the Free Software Foundation,
   19    * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20    *
   21    * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   22    * or visit www.oracle.com if you need additional information or have any
   23    * questions.
   24    */
   25   package javax.swing;
   26   
   27   import java.lang.ref.WeakReference;
   28   import java.security.AccessController;
   29   import java.security.PrivilegedAction;
   30   import java.beans.PropertyChangeListener;
   31   import java.beans.PropertyChangeSupport;
   32   import java.beans.PropertyChangeEvent;
   33   import java.util.List;
   34   import java.util.concurrent;
   35   import java.util.concurrent.locks;
   36   
   37   import java.awt.event;
   38   
   39   import javax.swing.SwingUtilities;
   40   
   41   import sun.awt.AppContext;
   42   import sun.swing.AccumulativeRunnable;
   43   
   44   /**
   45    * An abstract class to perform lengthy GUI-interaction tasks in a
   46    * background thread. Several background threads can be used to execute such
   47    * tasks. However, the exact strategy of choosing a thread for any particular
   48    * {@code SwingWorker} is unspecified and should not be relied on.
   49    * <p>
   50    * When writing a multi-threaded application using Swing, there are
   51    * two constraints to keep in mind:
   52    * (refer to
   53    * <a href="http://java.sun.com/docs/books/tutorial/uiswing/misc/threads.html">
   54    *   How to Use Threads
   55    * </a> for more details):
   56    * <ul>
   57    *   <li> Time-consuming tasks should not be run on the <i>Event
   58    *        Dispatch Thread</i>. Otherwise the application becomes unresponsive.
   59    *   </li>
   60    *   <li> Swing components should be accessed  on the <i>Event
   61    *        Dispatch Thread</i> only.
   62    *   </li>
   63    * </ul>
   64    *
   65    * <p>
   66    *
   67    * <p>
   68    * These constraints mean that a GUI application with time intensive
   69    * computing needs at least two threads:  1) a thread to perform the lengthy
   70    * task and 2) the <i>Event Dispatch Thread</i> (EDT) for all GUI-related
   71    * activities.  This involves inter-thread communication which can be
   72    * tricky to implement.
   73    *
   74    * <p>
   75    * {@code SwingWorker} is designed for situations where you need to have a long
   76    * running task run in a background thread and provide updates to the UI
   77    * either when done, or while processing.
   78    * Subclasses of {@code SwingWorker} must implement
   79    * the {@link #doInBackground} method to perform the background computation.
   80    *
   81    *
   82    * <p>
   83    * <b>Workflow</b>
   84    * <p>
   85    * There are three threads involved in the life cycle of a
   86    * {@code SwingWorker} :
   87    * <ul>
   88    * <li>
   89    * <p>
   90    * <i>Current</i> thread: The {@link #execute} method is
   91    * called on this thread. It schedules {@code SwingWorker} for the execution on a
   92    * <i>worker</i>
   93    * thread and returns immediately. One can wait for the {@code SwingWorker} to
   94    * complete using the {@link #get get} methods.
   95    * <li>
   96    * <p>
   97    * <i>Worker</i> thread: The {@link #doInBackground}
   98    * method is called on this thread.
   99    * This is where all background activities should happen. To notify
  100    * {@code PropertyChangeListeners} about bound properties changes use the
  101    * {@link #firePropertyChange firePropertyChange} and
  102    * {@link #getPropertyChangeSupport} methods. By default there are two bound
  103    * properties available: {@code state} and {@code progress}.
  104    * <li>
  105    * <p>
  106    * <i>Event Dispatch Thread</i>:  All Swing related activities occur
  107    * on this thread. {@code SwingWorker} invokes the
  108    * {@link #process process} and {@link #done} methods and notifies
  109    * any {@code PropertyChangeListeners} on this thread.
  110    * </ul>
  111    *
  112    * <p>
  113    * Often, the <i>Current</i> thread is the <i>Event Dispatch
  114    * Thread</i>.
  115    *
  116    *
  117    * <p>
  118    * Before the {@code doInBackground} method is invoked on a <i>worker</i> thread,
  119    * {@code SwingWorker} notifies any {@code PropertyChangeListeners} about the
  120    * {@code state} property change to {@code StateValue.STARTED}.  After the
  121    * {@code doInBackground} method is finished the {@code done} method is
  122    * executed.  Then {@code SwingWorker} notifies any {@code PropertyChangeListeners}
  123    * about the {@code state} property change to {@code StateValue.DONE}.
  124    *
  125    * <p>
  126    * {@code SwingWorker} is only designed to be executed once.  Executing a
  127    * {@code SwingWorker} more than once will not result in invoking the
  128    * {@code doInBackground} method twice.
  129    *
  130    * <p>
  131    * <b>Sample Usage</b>
  132    * <p>
  133    * The following example illustrates the simplest use case.  Some
  134    * processing is done in the background and when done you update a Swing
  135    * component.
  136    *
  137    * <p>
  138    * Say we want to find the "Meaning of Life" and display the result in
  139    * a {@code JLabel}.
  140    *
  141    * <pre>
  142    *   final JLabel label;
  143    *   class MeaningOfLifeFinder extends SwingWorker&lt;String, Object&gt; {
  144    *       {@code @Override}
  145    *       public String doInBackground() {
  146    *           return findTheMeaningOfLife();
  147    *       }
  148    *
  149    *       {@code @Override}
  150    *       protected void done() {
  151    *           try {
  152    *               label.setText(get());
  153    *           } catch (Exception ignore) {
  154    *           }
  155    *       }
  156    *   }
  157    *
  158    *   (new MeaningOfLifeFinder()).execute();
  159    * </pre>
  160    *
  161    * <p>
  162    * The next example is useful in situations where you wish to process data
  163    * as it is ready on the <i>Event Dispatch Thread</i>.
  164    *
  165    * <p>
  166    * Now we want to find the first N prime numbers and display the results in a
  167    * {@code JTextArea}.  While this is computing, we want to update our
  168    * progress in a {@code JProgressBar}.  Finally, we also want to print
  169    * the prime numbers to {@code System.out}.
  170    * <pre>
  171    * class PrimeNumbersTask extends
  172    *         SwingWorker&lt;List&lt;Integer&gt;, Integer&gt; {
  173    *     PrimeNumbersTask(JTextArea textArea, int numbersToFind) {
  174    *         //initialize
  175    *     }
  176    *
  177    *     {@code @Override}
  178    *     public List&lt;Integer&gt; doInBackground() {
  179    *         while (! enough &amp;&amp; ! isCancelled()) {
  180    *                 number = nextPrimeNumber();
  181    *                 publish(number);
  182    *                 setProgress(100 * numbers.size() / numbersToFind);
  183    *             }
  184    *         }
  185    *         return numbers;
  186    *     }
  187    *
  188    *     {@code @Override}
  189    *     protected void process(List&lt;Integer&gt; chunks) {
  190    *         for (int number : chunks) {
  191    *             textArea.append(number + &quot;\n&quot;);
  192    *         }
  193    *     }
  194    * }
  195    *
  196    * JTextArea textArea = new JTextArea();
  197    * final JProgressBar progressBar = new JProgressBar(0, 100);
  198    * PrimeNumbersTask task = new PrimeNumbersTask(textArea, N);
  199    * task.addPropertyChangeListener(
  200    *     new PropertyChangeListener() {
  201    *         public  void propertyChange(PropertyChangeEvent evt) {
  202    *             if (&quot;progress&quot;.equals(evt.getPropertyName())) {
  203    *                 progressBar.setValue((Integer)evt.getNewValue());
  204    *             }
  205    *         }
  206    *     });
  207    *
  208    * task.execute();
  209    * System.out.println(task.get()); //prints all prime numbers we have got
  210    * </pre>
  211    *
  212    * <p>
  213    * Because {@code SwingWorker} implements {@code Runnable}, a
  214    * {@code SwingWorker} can be submitted to an
  215    * {@link java.util.concurrent.Executor} for execution.
  216    *
  217    * @author Igor Kushnirskiy
  218    *
  219    * @param <T> the result type returned by this {@code SwingWorker's}
  220    *        {@code doInBackground} and {@code get} methods
  221    * @param <V> the type used for carrying out intermediate results by this
  222    *        {@code SwingWorker's} {@code publish} and {@code process} methods
  223    *
  224    * @since 1.6
  225    */
  226   public abstract class SwingWorker<T, V> implements RunnableFuture<T> {
  227       /**
  228        * number of worker threads.
  229        */
  230       private static final int MAX_WORKER_THREADS = 10;
  231   
  232       /**
  233        * current progress.
  234        */
  235       private volatile int progress;
  236   
  237       /**
  238        * current state.
  239        */
  240       private volatile StateValue state;
  241   
  242       /**
  243        * everything is run inside this FutureTask. Also it is used as
  244        * a delegatee for the Future API.
  245        */
  246       private final FutureTask<T> future;
  247   
  248       /**
  249        * all propertyChangeSupport goes through this.
  250        */
  251       private final PropertyChangeSupport propertyChangeSupport;
  252   
  253       /**
  254        * handler for {@code process} mehtod.
  255        */
  256       private AccumulativeRunnable<V> doProcess;
  257   
  258       /**
  259        * handler for progress property change notifications.
  260        */
  261       private AccumulativeRunnable<Integer> doNotifyProgressChange;
  262   
  263       private final AccumulativeRunnable<Runnable> doSubmit = getDoSubmit();
  264   
  265       /**
  266        * Values for the {@code state} bound property.
  267        * @since 1.6
  268        */
  269       public enum StateValue {
  270           /**
  271            * Initial {@code SwingWorker} state.
  272            */
  273           PENDING,
  274           /**
  275            * {@code SwingWorker} is {@code STARTED}
  276            * before invoking {@code doInBackground}.
  277            */
  278           STARTED,
  279   
  280           /**
  281            * {@code SwingWorker} is {@code DONE}
  282            * after {@code doInBackground} method
  283            * is finished.
  284            */
  285           DONE
  286       }
  287   
  288       /**
  289        * Constructs this {@code SwingWorker}.
  290        */
  291       public SwingWorker() {
  292           Callable<T> callable =
  293                   new Callable<T>() {
  294                       public T call() throws Exception {
  295                           setState(StateValue.STARTED);
  296                           return doInBackground();
  297                       }
  298                   };
  299   
  300           future = new FutureTask<T>(callable) {
  301                          @Override
  302                          protected void done() {
  303                              doneEDT();
  304                              setState(StateValue.DONE);
  305                          }
  306                      };
  307   
  308          state = StateValue.PENDING;
  309          propertyChangeSupport = new SwingWorkerPropertyChangeSupport(this);
  310          doProcess = null;
  311          doNotifyProgressChange = null;
  312       }
  313   
  314       /**
  315        * Computes a result, or throws an exception if unable to do so.
  316        *
  317        * <p>
  318        * Note that this method is executed only once.
  319        *
  320        * <p>
  321        * Note: this method is executed in a background thread.
  322        *
  323        *
  324        * @return the computed result
  325        * @throws Exception if unable to compute a result
  326        *
  327        */
  328       protected abstract T doInBackground() throws Exception ;
  329   
  330       /**
  331        * Sets this {@code Future} to the result of computation unless
  332        * it has been cancelled.
  333        */
  334       public final void run() {
  335           future.run();
  336       }
  337   
  338       /**
  339        * Sends data chunks to the {@link #process} method. This method is to be
  340        * used from inside the {@code doInBackground} method to deliver
  341        * intermediate results
  342        * for processing on the <i>Event Dispatch Thread</i> inside the
  343        * {@code process} method.
  344        *
  345        * <p>
  346        * Because the {@code process} method is invoked asynchronously on
  347        * the <i>Event Dispatch Thread</i>
  348        * multiple invocations to the {@code publish} method
  349        * might occur before the {@code process} method is executed. For
  350        * performance purposes all these invocations are coalesced into one
  351        * invocation with concatenated arguments.
  352        *
  353        * <p>
  354        * For example:
  355        *
  356        * <pre>
  357        * publish(&quot;1&quot;);
  358        * publish(&quot;2&quot;, &quot;3&quot;);
  359        * publish(&quot;4&quot;, &quot;5&quot;, &quot;6&quot;);
  360        * </pre>
  361        *
  362        * might result in:
  363        *
  364        * <pre>
  365        * process(&quot;1&quot;, &quot;2&quot;, &quot;3&quot;, &quot;4&quot;, &quot;5&quot;, &quot;6&quot;)
  366        * </pre>
  367        *
  368        * <p>
  369        * <b>Sample Usage</b>. This code snippet loads some tabular data and
  370        * updates {@code DefaultTableModel} with it. Note that it safe to mutate
  371        * the tableModel from inside the {@code process} method because it is
  372        * invoked on the <i>Event Dispatch Thread</i>.
  373        *
  374        * <pre>
  375        * class TableSwingWorker extends
  376        *         SwingWorker&lt;DefaultTableModel, Object[]&gt; {
  377        *     private final DefaultTableModel tableModel;
  378        *
  379        *     public TableSwingWorker(DefaultTableModel tableModel) {
  380        *         this.tableModel = tableModel;
  381        *     }
  382        *
  383        *     {@code @Override}
  384        *     protected DefaultTableModel doInBackground() throws Exception {
  385        *         for (Object[] row = loadData();
  386        *                  ! isCancelled() &amp;&amp; row != null;
  387        *                  row = loadData()) {
  388        *             publish((Object[]) row);
  389        *         }
  390        *         return tableModel;
  391        *     }
  392        *
  393        *     {@code @Override}
  394        *     protected void process(List&lt;Object[]&gt; chunks) {
  395        *         for (Object[] row : chunks) {
  396        *             tableModel.addRow(row);
  397        *         }
  398        *     }
  399        * }
  400        * </pre>
  401        *
  402        * @param chunks intermediate results to process
  403        *
  404        * @see #process
  405        *
  406        */
  407       @SafeVarargs
  408       protected final void publish(V... chunks) {
  409           synchronized (this) {
  410               if (doProcess == null) {
  411                   doProcess = new AccumulativeRunnable<V>() {
  412                       @Override
  413                       public void run(List<V> args) {
  414                           process(args);
  415                       }
  416                       @Override
  417                       protected void submit() {
  418                           doSubmit.add(this);
  419                       }
  420                   };
  421               }
  422           }
  423           doProcess.add(chunks);
  424       }
  425   
  426       /**
  427        * Receives data chunks from the {@code publish} method asynchronously on the
  428        * <i>Event Dispatch Thread</i>.
  429        *
  430        * <p>
  431        * Please refer to the {@link #publish} method for more details.
  432        *
  433        * @param chunks intermediate results to process
  434        *
  435        * @see #publish
  436        *
  437        */
  438       protected void process(List<V> chunks) {
  439       }
  440   
  441       /**
  442        * Executed on the <i>Event Dispatch Thread</i> after the {@code doInBackground}
  443        * method is finished. The default
  444        * implementation does nothing. Subclasses may override this method to
  445        * perform completion actions on the <i>Event Dispatch Thread</i>. Note
  446        * that you can query status inside the implementation of this method to
  447        * determine the result of this task or whether this task has been cancelled.
  448        *
  449        * @see #doInBackground
  450        * @see #isCancelled()
  451        * @see #get
  452        */
  453       protected void done() {
  454       }
  455   
  456       /**
  457        * Sets the {@code progress} bound property.
  458        * The value should be from 0 to 100.
  459        *
  460        * <p>
  461        * Because {@code PropertyChangeListener}s are notified asynchronously on
  462        * the <i>Event Dispatch Thread</i> multiple invocations to the
  463        * {@code setProgress} method might occur before any
  464        * {@code PropertyChangeListeners} are invoked. For performance purposes
  465        * all these invocations are coalesced into one invocation with the last
  466        * invocation argument only.
  467        *
  468        * <p>
  469        * For example, the following invokations:
  470        *
  471        * <pre>
  472        * setProgress(1);
  473        * setProgress(2);
  474        * setProgress(3);
  475        * </pre>
  476        *
  477        * might result in a single {@code PropertyChangeListener} notification with
  478        * the value {@code 3}.
  479        *
  480        * @param progress the progress value to set
  481        * @throws IllegalArgumentException is value not from 0 to 100
  482        */
  483       protected final void setProgress(int progress) {
  484           if (progress < 0 || progress > 100) {
  485               throw new IllegalArgumentException("the value should be from 0 to 100");
  486           }
  487           if (this.progress == progress) {
  488               return;
  489           }
  490           int oldProgress = this.progress;
  491           this.progress = progress;
  492           if (! getPropertyChangeSupport().hasListeners("progress")) {
  493               return;
  494           }
  495           synchronized (this) {
  496               if (doNotifyProgressChange == null) {
  497                   doNotifyProgressChange =
  498                       new AccumulativeRunnable<Integer>() {
  499                           @Override
  500                           public void run(List<Integer> args) {
  501                               firePropertyChange("progress",
  502                                  args.get(0),
  503                                  args.get(args.size() - 1));
  504                           }
  505                           @Override
  506                           protected void submit() {
  507                               doSubmit.add(this);
  508                           }
  509                       };
  510               }
  511           }
  512           doNotifyProgressChange.add(oldProgress, progress);
  513       }
  514   
  515       /**
  516        * Returns the {@code progress} bound property.
  517        *
  518        * @return the progress bound property.
  519        */
  520       public final int getProgress() {
  521           return progress;
  522       }
  523   
  524       /**
  525        * Schedules this {@code SwingWorker} for execution on a <i>worker</i>
  526        * thread. There are a number of <i>worker</i> threads available. In the
  527        * event all <i>worker</i> threads are busy handling other
  528        * {@code SwingWorkers} this {@code SwingWorker} is placed in a waiting
  529        * queue.
  530        *
  531        * <p>
  532        * Note:
  533        * {@code SwingWorker} is only designed to be executed once.  Executing a
  534        * {@code SwingWorker} more than once will not result in invoking the
  535        * {@code doInBackground} method twice.
  536        */
  537       public final void execute() {
  538           getWorkersExecutorService().execute(this);
  539       }
  540   
  541       // Future methods START
  542       /**
  543        * {@inheritDoc}
  544        */
  545       public final boolean cancel(boolean mayInterruptIfRunning) {
  546           return future.cancel(mayInterruptIfRunning);
  547       }
  548   
  549       /**
  550        * {@inheritDoc}
  551        */
  552       public final boolean isCancelled() {
  553           return future.isCancelled();
  554       }
  555   
  556       /**
  557        * {@inheritDoc}
  558        */
  559       public final boolean isDone() {
  560           return future.isDone();
  561       }
  562   
  563       /**
  564        * {@inheritDoc}
  565        * <p>
  566        * Note: calling {@code get} on the <i>Event Dispatch Thread</i> blocks
  567        * <i>all</i> events, including repaints, from being processed until this
  568        * {@code SwingWorker} is complete.
  569        *
  570        * <p>
  571        * When you want the {@code SwingWorker} to block on the <i>Event
  572        * Dispatch Thread</i> we recommend that you use a <i>modal dialog</i>.
  573        *
  574        * <p>
  575        * For example:
  576        *
  577        * <pre>
  578        * class SwingWorkerCompletionWaiter extends PropertyChangeListener {
  579        *     private JDialog dialog;
  580        *
  581        *     public SwingWorkerCompletionWaiter(JDialog dialog) {
  582        *         this.dialog = dialog;
  583        *     }
  584        *
  585        *     public void propertyChange(PropertyChangeEvent event) {
  586        *         if (&quot;state&quot;.equals(event.getPropertyName())
  587        *                 &amp;&amp; SwingWorker.StateValue.DONE == event.getNewValue()) {
  588        *             dialog.setVisible(false);
  589        *             dialog.dispose();
  590        *         }
  591        *     }
  592        * }
  593        * JDialog dialog = new JDialog(owner, true);
  594        * swingWorker.addPropertyChangeListener(
  595        *     new SwingWorkerCompletionWaiter(dialog));
  596        * swingWorker.execute();
  597        * //the dialog will be visible until the SwingWorker is done
  598        * dialog.setVisible(true);
  599        * </pre>
  600        */
  601       public final T get() throws InterruptedException, ExecutionException {
  602           return future.get();
  603       }
  604   
  605       /**
  606        * {@inheritDoc}
  607        * <p>
  608        * Please refer to {@link #get} for more details.
  609        */
  610       public final T get(long timeout, TimeUnit unit) throws InterruptedException,
  611               ExecutionException, TimeoutException {
  612           return future.get(timeout, unit);
  613       }
  614   
  615       // Future methods END
  616   
  617       // PropertyChangeSupports methods START
  618       /**
  619        * Adds a {@code PropertyChangeListener} to the listener list. The listener
  620        * is registered for all properties. The same listener object may be added
  621        * more than once, and will be called as many times as it is added. If
  622        * {@code listener} is {@code null}, no exception is thrown and no action is taken.
  623        *
  624        * <p>
  625        * Note: This is merely a convenience wrapper. All work is delegated to
  626        * {@code PropertyChangeSupport} from {@link #getPropertyChangeSupport}.
  627        *
  628        * @param listener the {@code PropertyChangeListener} to be added
  629        */
  630       public final void addPropertyChangeListener(PropertyChangeListener listener) {
  631           getPropertyChangeSupport().addPropertyChangeListener(listener);
  632       }
  633   
  634       /**
  635        * Removes a {@code PropertyChangeListener} from the listener list. This
  636        * removes a {@code PropertyChangeListener} that was registered for all
  637        * properties. If {@code listener} was added more than once to the same
  638        * event source, it will be notified one less time after being removed. If
  639        * {@code listener} is {@code null}, or was never added, no exception is
  640        * thrown and no action is taken.
  641        *
  642        * <p>
  643        * Note: This is merely a convenience wrapper. All work is delegated to
  644        * {@code PropertyChangeSupport} from {@link #getPropertyChangeSupport}.
  645        *
  646        * @param listener the {@code PropertyChangeListener} to be removed
  647        */
  648       public final void removePropertyChangeListener(PropertyChangeListener listener) {
  649           getPropertyChangeSupport().removePropertyChangeListener(listener);
  650       }
  651   
  652       /**
  653        * Reports a bound property update to any registered listeners. No event is
  654        * fired if {@code old} and {@code new} are equal and non-null.
  655        *
  656        * <p>
  657        * This {@code SwingWorker} will be the source for
  658        * any generated events.
  659        *
  660        * <p>
  661        * When called off the <i>Event Dispatch Thread</i>
  662        * {@code PropertyChangeListeners} are notified asynchronously on
  663        * the <i>Event Dispatch Thread</i>.
  664        * <p>
  665        * Note: This is merely a convenience wrapper. All work is delegated to
  666        * {@code PropertyChangeSupport} from {@link #getPropertyChangeSupport}.
  667        *
  668        *
  669        * @param propertyName the programmatic name of the property that was
  670        *        changed
  671        * @param oldValue the old value of the property
  672        * @param newValue the new value of the property
  673        */
  674       public final void firePropertyChange(String propertyName, Object oldValue,
  675               Object newValue) {
  676           getPropertyChangeSupport().firePropertyChange(propertyName,
  677               oldValue, newValue);
  678       }
  679   
  680       /**
  681        * Returns the {@code PropertyChangeSupport} for this {@code SwingWorker}.
  682        * This method is used when flexible access to bound properties support is
  683        * needed.
  684        * <p>
  685        * This {@code SwingWorker} will be the source for
  686        * any generated events.
  687        *
  688        * <p>
  689        * Note: The returned {@code PropertyChangeSupport} notifies any
  690        * {@code PropertyChangeListener}s asynchronously on the <i>Event Dispatch
  691        * Thread</i> in the event that {@code firePropertyChange} or
  692        * {@code fireIndexedPropertyChange} are called off the <i>Event Dispatch
  693        * Thread</i>.
  694        *
  695        * @return {@code PropertyChangeSupport} for this {@code SwingWorker}
  696        */
  697       public final PropertyChangeSupport getPropertyChangeSupport() {
  698           return propertyChangeSupport;
  699       }
  700   
  701       // PropertyChangeSupports methods END
  702   
  703       /**
  704        * Returns the {@code SwingWorker} state bound property.
  705        *
  706        * @return the current state
  707        */
  708       public final StateValue getState() {
  709           /*
  710            * DONE is a speacial case
  711            * to keep getState and isDone is sync
  712            */
  713           if (isDone()) {
  714               return StateValue.DONE;
  715           } else {
  716               return state;
  717           }
  718       }
  719   
  720       /**
  721        * Sets this {@code SwingWorker} state bound property.
  722        * @param state the state to set
  723        */
  724       private void setState(StateValue state) {
  725           StateValue old = this.state;
  726           this.state = state;
  727           firePropertyChange("state", old, state);
  728       }
  729   
  730       /**
  731        * Invokes {@code done} on the EDT.
  732        */
  733       private void doneEDT() {
  734           Runnable doDone =
  735               new Runnable() {
  736                   public void run() {
  737                       done();
  738                   }
  739               };
  740           if (SwingUtilities.isEventDispatchThread()) {
  741               doDone.run();
  742           } else {
  743               doSubmit.add(doDone);
  744           }
  745       }
  746   
  747   
  748       /**
  749        * returns workersExecutorService.
  750        *
  751        * returns the service stored in the appContext or creates it if
  752        * necessary.
  753        *
  754        * @return ExecutorService for the {@code SwingWorkers}
  755        */
  756       private static synchronized ExecutorService getWorkersExecutorService() {
  757           final AppContext appContext = AppContext.getAppContext();
  758           ExecutorService executorService =
  759               (ExecutorService) appContext.get(SwingWorker.class);
  760           if (executorService == null) {
  761               //this creates daemon threads.
  762               ThreadFactory threadFactory =
  763                   new ThreadFactory() {
  764                       final ThreadFactory defaultFactory =
  765                           Executors.defaultThreadFactory();
  766                       public Thread newThread(final Runnable r) {
  767                           Thread thread =
  768                               defaultFactory.newThread(r);
  769                           thread.setName("SwingWorker-"
  770                               + thread.getName());
  771                           thread.setDaemon(true);
  772                           return thread;
  773                       }
  774                   };
  775   
  776               executorService =
  777                   new ThreadPoolExecutor(MAX_WORKER_THREADS, MAX_WORKER_THREADS,
  778                                          10L, TimeUnit.MINUTES,
  779                                          new LinkedBlockingQueue<Runnable>(),
  780                                          threadFactory);
  781               appContext.put(SwingWorker.class, executorService);
  782   
  783               // Don't use ShutdownHook here as it's not enough. We should track
  784               // AppContext disposal instead of JVM shutdown, see 6799345 for details
  785               final ExecutorService es = executorService;
  786               appContext.addPropertyChangeListener(AppContext.DISPOSED_PROPERTY_NAME,
  787                   new PropertyChangeListener() {
  788                       @Override
  789                       public void propertyChange(PropertyChangeEvent pce) {
  790                           boolean disposed = (Boolean)pce.getNewValue();
  791                           if (disposed) {
  792                               final WeakReference<ExecutorService> executorServiceRef =
  793                                   new WeakReference<ExecutorService>(es);
  794                               final ExecutorService executorService =
  795                                   executorServiceRef.get();
  796                               if (executorService != null) {
  797                                   AccessController.doPrivileged(
  798                                       new PrivilegedAction<Void>() {
  799                                           public Void run() {
  800                                               executorService.shutdown();
  801                                               return null;
  802                                           }
  803                                       }
  804                                   );
  805                               }
  806                           }
  807                       }
  808                   }
  809               );
  810           }
  811           return executorService;
  812       }
  813   
  814       private static final Object DO_SUBMIT_KEY = new StringBuilder("doSubmit");
  815       private static AccumulativeRunnable<Runnable> getDoSubmit() {
  816           synchronized (DO_SUBMIT_KEY) {
  817               final AppContext appContext = AppContext.getAppContext();
  818               Object doSubmit = appContext.get(DO_SUBMIT_KEY);
  819               if (doSubmit == null) {
  820                   doSubmit = new DoSubmitAccumulativeRunnable();
  821                   appContext.put(DO_SUBMIT_KEY, doSubmit);
  822               }
  823               return (AccumulativeRunnable<Runnable>) doSubmit;
  824           }
  825       }
  826       private static class DoSubmitAccumulativeRunnable
  827             extends AccumulativeRunnable<Runnable> implements ActionListener {
  828           private final static int DELAY = 1000 / 30;
  829           @Override
  830           protected void run(List<Runnable> args) {
  831               for (Runnable runnable : args) {
  832                   runnable.run();
  833               }
  834           }
  835           @Override
  836           protected void submit() {
  837               Timer timer = new Timer(DELAY, this);
  838               timer.setRepeats(false);
  839               timer.start();
  840           }
  841           public void actionPerformed(ActionEvent event) {
  842               run();
  843           }
  844       }
  845   
  846       private class SwingWorkerPropertyChangeSupport
  847               extends PropertyChangeSupport {
  848           SwingWorkerPropertyChangeSupport(Object source) {
  849               super(source);
  850           }
  851           @Override
  852           public void firePropertyChange(final PropertyChangeEvent evt) {
  853               if (SwingUtilities.isEventDispatchThread()) {
  854                   super.firePropertyChange(evt);
  855               } else {
  856                   doSubmit.add(
  857                       new Runnable() {
  858                           public void run() {
  859                               SwingWorkerPropertyChangeSupport.this
  860                                   .firePropertyChange(evt);
  861                           }
  862                       });
  863               }
  864           }
  865       }
  866   }

Home » openjdk-7 » javax » swing » [javadoc | source]