/*
 * The MIT License
 * 
 * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, CloudBees, Inc.
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package hudson.remoting;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.CancellationException;

/**
 * {@link Future} implementation whose computation is carried out elsewhere.
 *
 * Call the {@link #set(Object)} method or {@link #set(Throwable)} method to set the value to the future.
 * 
 * @author Kohsuke Kawaguchi
 */
public class AsyncFutureImpl<V> implements Future<V> {
    /**
     * Setting this field to true will indicate that the computation is completed.
     *
     * <p>
     * One of the following three fields also needs to be set at the same time.
     */
    private boolean completed;

    private V value;
    private Throwable problem;
    private boolean cancelled;

    public AsyncFutureImpl() {}
    public AsyncFutureImpl(V value) {
        set(value);
    }
    public AsyncFutureImpl(Throwable value) {
        set(value);
    }

    public boolean cancel(boolean mayInterruptIfRunning) {
        return false;
    }

    public synchronized boolean isCancelled() {
        return cancelled;
    }

    public synchronized boolean isDone() {
        return completed;
    }

    public synchronized V get() throws InterruptedException, ExecutionException {
        while(!completed)
            wait();
        if(problem!=null)
            throw new ExecutionException(problem);
        if(cancelled)
            throw new CancellationException();
        return value;
    }

    public synchronized V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
        if(!completed)
            wait(unit.toMillis(timeout));
        if(!completed)
            throw new TimeoutException();
        if(cancelled)
            throw new CancellationException();
        return get();
    }

    public synchronized void set(V value) {
        completed = true;
        this.value = value;
        notifyAll();
    }

    public synchronized void set(Throwable problem) {
        completed = true;
        this.problem = problem;
        notifyAll();
    }

    /**
     * Marks this task as cancelled.
     */
    public synchronized void setAsCancelled() {
        completed = true;
        cancelled = true;
        notifyAll();
    }
}

@@ -1214,16 +1214,91 @@
 oting;%0A%0A
+import javax.annotation.CheckForNull;%0Aimport javax.annotation.Nonnegative;%0A
 import j
@@ -2777,32 +2777,50 @@
 n value;%0A    %7D%0A%0A
+    @CheckForNull%0A
     public synch
@@ -2833,16 +2833,29 @@
 d V get(
+@Nonnegative 
 long tim
@@ -2943,34 +2943,188 @@
 ption %7B%0A        
-if
+// The accuracy of wait(long) operation is milliseconds anyway, but ok.%0A        long endWaitTime = System.nanoTime() + unit.toNanos(timeout);%0A        while 
 (!completed)%0A   
@@ -3111,32 +3111,34 @@
 ile (!completed)
+ %7B
 %0A            wai
@@ -3138,171 +3138,603 @@
     
-wait(unit.toMillis(timeout));%0A        if(!completed)%0A            throw new TimeoutException();%0A        if(cancelled)%0A            throw new CancellationException();
+long timeToWait = endWaitTime - System.nanoTime();%0A            if (timeToWait %3C 0) %7B%0A                break;%0A            %7D%0A%0A            wait(timeToWait / 1000000, (int)(timeToWait %25 1000000));%0A        %7D%0A%0A        if(!completed)%0A            throw new TimeoutException();%0A        if(cancelled)%0A            throw new CancellationException();%0A%0A        //TODO: we may be calling a complex get() implementation in the override, which may hang the code%0A        // The only missing behavior is %22problem!=null%22 branch, but probably we cannot just replace the code without%0A        // an override issue risk.
 %0A   

- Prevent TimeoutException in AsyncFutureImpl in the case of spurious wakeups (#240)