All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.openide.util.Task Maven / Gradle / Ivy

The newest version!
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
 *
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
 * Other names may be trademarks of their respective owners.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common
 * Development and Distribution License("CDDL") (collectively, the
 * "License"). You may not use this file except in compliance with the
 * License. You can obtain a copy of the License at
 * http://www.netbeans.org/cddl-gplv2.html
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
 * specific language governing permissions and limitations under the
 * License.  When distributing the software, include this License Header
 * Notice in each file and include the License file at
 * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the GPL Version 2 section of the License file that
 * accompanied this code. If applicable, add the following below the
 * License Header, with the fields enclosed by brackets [] replaced by
 * your own identifying information:
 * "Portions Copyrighted [year] [name of copyright owner]"
 *
 * Contributor(s):
 *
 * The Original Software is NetBeans. The Initial Developer of the Original
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
 * Microsystems, Inc. All Rights Reserved.
 *
 * If you wish your version of this file to be governed by only the CDDL
 * or only the GPL Version 2, indicate your decision by adding
 * "[Contributor] elects to include this software in this distribution
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
 * single choice of license, a recipient has the option to distribute
 * your version of this file under either the CDDL, the GPL Version 2 or
 * to extend the choice of license to its licensees as provided above.
 * However, if you add GPL Version 2 code and therefore, elected the GPL
 * Version 2 license, then the option applies only if the new code is
 * made subject to such option by the copyright holder.
 */
package org.openide.util;

import java.util.HashSet;
import java.util.Iterator;
import java.util.logging.Level;
import java.util.logging.Logger;


/** A task that may be executed in a separate thread and permits examination of its status.
* Other threads can check if it is finished or wait for it
* to finish.
* 

* For example: *

* Runnable r = new Runnable () {
*   public void run () {
*     // do something
*   }
* };
* Task task = new Task (r);
* RequestProcessor.postRequest (task);
* 
*

In a different thread one can then test task.isFinished () * or wait for it with task.waitFinished (). * * @author Jaroslav Tulach */ public class Task extends Object implements Runnable { /** Dummy task which is already finished. */ public static final Task EMPTY = new Task(); private static final Logger LOG = Logger.getLogger(Task.class.getName()); static { EMPTY.finished = true; } /** map of subclasses to booleans whether they override waitFinished() or not */ private static java.util.WeakHashMap overrides; /** request processor for workarounding compatibility problem with * classes that do not override waitFinished (long) */ private static RequestProcessor RP; /** what to run */ final Runnable run; /** flag if we have finished */ private boolean finished; /** listeners for the finish of task (TaskListener) */ private HashSet list; /** Create a new task. * The runnable should provide its own error-handling, as * by default thrown exceptions are simply logged and not rethrown. * @param run runnable to run that computes the task */ public Task(Runnable run) { this.run = run; if (run == null) { finished = true; } } /** Constructor for subclasses that wants to control whole execution * itself. * @since 1.5 */ protected Task() { this.run = null; } /** Test whether the task has finished running. * @return true if so */ public final boolean isFinished() { synchronized (this) { return finished; } } /** Wait until the task is finished. * Changed not to be final in version 1.5 */ public void waitFinished() { synchronized (this) { while (!finished) { try { wait(); } catch (InterruptedException ex) { } } } } /** Wait until the task is finished, but only a given time. * waitFinished(0) means indefinite timeout (similar to wait(0)) * @param milliseconds time in milliseconds to wait for the result * @exception InterruptedException when the waiting has been interrupted * @return true if the task is really finished, or false if the time out * has been exceeded * @since 5.0 */ public boolean waitFinished(long milliseconds) throws InterruptedException { synchronized (this) { if (overridesTimeoutedWaitFinished()) { // the the task overrides waitFinished (timeout) or is // one of the basic tasks, then we can just simply do our bese // code. Otherwise we have to execute threading workaround if (finished) { return true; } long expectedEnd = System.currentTimeMillis() + milliseconds; for (;;) { LOG.log(Level.FINE, "About to wait {0} ms", milliseconds); wait(milliseconds); if (finished) { LOG.log(Level.FINER, "finished, return"); // NOI18N return true; } if (milliseconds == 0) { LOG.log(Level.FINER, "infinite wait, again"); // NOI18N continue; } long now = System.currentTimeMillis(); long remains = expectedEnd - now; LOG.log(Level.FINER, "remains {0} ms", remains); if (remains <= 0) { LOG.log(Level.FINER, "exit, timetout"); return false; } milliseconds = remains; } } } // as we know that RequestProcessor implements the waitFinished(long) // correctly we just post a task for waitFinished() into some // of its threads and wait just the given milliseconds time // for the result, by that we can guarantee the semantics // of the call class Run implements Runnable { @Override public void run() { Task.this.waitFinished(); } } LOG.fine("Using compatibility waiting"); RequestProcessor.Task task = RP.post(new Run()); return task.waitFinished(milliseconds); } /** Changes the state of the task to be running. Any call after this * one and before notifyFinished to waitFinished blocks. * @since 1.5 */ protected final void notifyRunning() { synchronized (this) { RequestProcessor.logger().log(Level.FINE, "notifyRunning: {0}", this); // NOI18N this.finished = false; notifyAll(); } } /** Notify all waiters that this task has finished. * @see #run */ protected final void notifyFinished() { Iterator it; synchronized (this) { finished = true; RequestProcessor.logger().log(Level.FINE, "notifyFinished: {0}", this); // NOI18N notifyAll(); // fire the listeners if (list == null) { return; } it = ((HashSet) list.clone()).iterator(); } while (it.hasNext()) { TaskListener l = (TaskListener) it.next(); l.taskFinished(this); } } /** Start the task. * When it finishes (even with an exception) it calls * {@link #notifyFinished}. * Subclasses may override this method, but they * then need to call {@link #notifyFinished} explicitly. *

Note that this call runs synchronously, but typically the creator * of the task will call this method in a separate thread. */ public void run() { try { notifyRunning(); if (run != null) { run.run(); } } finally { notifyFinished(); } } /** Add a listener to the task. The listener will be called once the * task {@link #isFinished()}. In case the task is already finished, the * listener is called immediately. * * @param l the listener to add */ public void addTaskListener(TaskListener l) { boolean callNow; synchronized (this) { if (list == null) { list = new HashSet(); } list.add(l); callNow = finished; } if (callNow) { l.taskFinished(this); } } /** Remove a listener from the task. * @param l the listener to remove */ public synchronized void removeTaskListener(TaskListener l) { if (list == null) { return; } list.remove(l); } public String toString() { return "task " + run; // NOI18N } /** Checks whether the class overrides wait finished. */ private boolean overridesTimeoutedWaitFinished() { // yes we implement it corretly if (getClass() == Task.class) { return true; } // RequestProcessor.Task overrides correctly if (getClass() == RequestProcessor.Task.class) { return true; } java.util.WeakHashMap m; Boolean does; synchronized (Task.class) { if (overrides == null) { overrides = new java.util.WeakHashMap(); RP = new RequestProcessor("Timeout waitFinished compatibility processor", 255); // NOI18N } m = overrides; does = m.get(getClass()); if (does != null) { return does.booleanValue(); } try { java.lang.reflect.Method method = getClass().getMethod("waitFinished", new Class[] { Long.TYPE }); // NOI18N does = Boolean.valueOf(method.getDeclaringClass() != Task.class); m.put(getClass(), does); return does.booleanValue(); } catch (Exception ex) { Exceptions.printStackTrace(ex); return true; } } } /** Reveal the identity of the worker runnable. * Used for debugging from RequestProcessor. */ String debug() { return (run == null) ? "null" : run.getClass().getName(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy