Home | History | Annotate | Download | only in ch
      1 /*
      2  * Copyright (c) 2008, 2009, 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 
     26 package sun.nio.ch;
     27 
     28 import java.nio.channels.*;
     29 import java.util.concurrent.*;
     30 import java.io.IOException;
     31 
     32 /**
     33  * A Future for a pending I/O operation. A PendingFuture allows for the
     34  * attachment of an additional arbitrary context object and a timer task.
     35  */
     36 
     37 final class PendingFuture<V,A> implements Future<V> {
     38     private static final CancellationException CANCELLED =
     39         new CancellationException();
     40 
     41     private final AsynchronousChannel channel;
     42     private final CompletionHandler<V,? super A> handler;
     43     private final A attachment;
     44 
     45     // true if result (or exception) is available
     46     private volatile boolean haveResult;
     47     private volatile V result;
     48     private volatile Throwable exc;
     49 
     50     // latch for waiting (created lazily if needed)
     51     private CountDownLatch latch;
     52 
     53     // optional timer task that is cancelled when result becomes available
     54     private Future<?> timeoutTask;
     55 
     56     // optional context object
     57     private volatile Object context;
     58 
     59     PendingFuture(AsynchronousChannel channel,
     60                   CompletionHandler<V,? super A> handler,
     61                   A attachment,
     62                   Object context)
     63     {
     64         this.channel = channel;
     65         this.handler = handler;
     66         this.attachment = attachment;
     67         this.context = context;
     68     }
     69 
     70     PendingFuture(AsynchronousChannel channel,
     71                   CompletionHandler<V,? super A> handler,
     72                   A attachment)
     73     {
     74         this.channel = channel;
     75         this.handler = handler;
     76         this.attachment = attachment;
     77     }
     78 
     79     PendingFuture(AsynchronousChannel channel) {
     80         this(channel, null, null);
     81     }
     82 
     83     PendingFuture(AsynchronousChannel channel, Object context) {
     84         this(channel, null, null, context);
     85     }
     86 
     87     AsynchronousChannel channel() {
     88         return channel;
     89     }
     90 
     91     CompletionHandler<V,? super A> handler() {
     92         return handler;
     93     }
     94 
     95     A attachment() {
     96         return attachment;
     97     }
     98 
     99     void setContext(Object context) {
    100         this.context = context;
    101     }
    102 
    103     Object getContext() {
    104         return context;
    105     }
    106 
    107     void setTimeoutTask(Future<?> task) {
    108         synchronized (this) {
    109             if (haveResult) {
    110                 task.cancel(false);
    111             } else {
    112                 this.timeoutTask = task;
    113             }
    114         }
    115     }
    116 
    117     // creates latch if required; return true if caller needs to wait
    118     private boolean prepareForWait() {
    119         synchronized (this) {
    120             if (haveResult) {
    121                 return false;
    122             } else {
    123                 if (latch == null)
    124                     latch = new CountDownLatch(1);
    125                 return true;
    126             }
    127         }
    128     }
    129 
    130     /**
    131      * Sets the result, or a no-op if the result or exception is already set.
    132      */
    133     void setResult(V res) {
    134         synchronized (this) {
    135             if (haveResult)
    136                 return;
    137             result = res;
    138             haveResult = true;
    139             if (timeoutTask != null)
    140                 timeoutTask.cancel(false);
    141             if (latch != null)
    142                 latch.countDown();
    143         }
    144     }
    145 
    146     /**
    147      * Sets the result, or a no-op if the result or exception is already set.
    148      */
    149     void setFailure(Throwable x) {
    150         if (!(x instanceof IOException) && !(x instanceof SecurityException))
    151             x = new IOException(x);
    152         synchronized (this) {
    153             if (haveResult)
    154                 return;
    155             exc = x;
    156             haveResult = true;
    157             if (timeoutTask != null)
    158                 timeoutTask.cancel(false);
    159             if (latch != null)
    160                 latch.countDown();
    161         }
    162     }
    163 
    164     /**
    165      * Sets the result
    166      */
    167     void setResult(V res, Throwable x) {
    168         if (x == null) {
    169             setResult(res);
    170         } else {
    171             setFailure(x);
    172         }
    173     }
    174 
    175     @Override
    176     public V get() throws ExecutionException, InterruptedException {
    177         if (!haveResult) {
    178             boolean needToWait = prepareForWait();
    179             if (needToWait)
    180                 latch.await();
    181         }
    182         if (exc != null) {
    183             if (exc == CANCELLED)
    184                 throw new CancellationException();
    185             throw new ExecutionException(exc);
    186         }
    187         return result;
    188     }
    189 
    190     @Override
    191     public V get(long timeout, TimeUnit unit)
    192         throws ExecutionException, InterruptedException, TimeoutException
    193     {
    194         if (!haveResult) {
    195             boolean needToWait = prepareForWait();
    196             if (needToWait)
    197                 if (!latch.await(timeout, unit)) throw new TimeoutException();
    198         }
    199         if (exc != null) {
    200             if (exc == CANCELLED)
    201                 throw new CancellationException();
    202             throw new ExecutionException(exc);
    203         }
    204         return result;
    205     }
    206 
    207     Throwable exception() {
    208         return (exc != CANCELLED) ? exc : null;
    209     }
    210 
    211     V value() {
    212         return result;
    213     }
    214 
    215     @Override
    216     public boolean isCancelled() {
    217         return (exc == CANCELLED);
    218     }
    219 
    220     @Override
    221     public boolean isDone() {
    222         return haveResult;
    223     }
    224 
    225     @Override
    226     public boolean cancel(boolean mayInterruptIfRunning) {
    227         synchronized (this) {
    228             if (haveResult)
    229                 return false;    // already completed
    230 
    231             // notify channel
    232             if (channel() instanceof Cancellable)
    233                 ((Cancellable)channel()).onCancel(this);
    234 
    235             // set result and cancel timer
    236             exc = CANCELLED;
    237             haveResult = true;
    238             if (timeoutTask != null)
    239                 timeoutTask.cancel(false);
    240         }
    241 
    242         // close channel if forceful cancel
    243         if (mayInterruptIfRunning) {
    244             try {
    245                 channel().close();
    246             } catch (IOException ignore) { }
    247         }
    248 
    249         // release waiters
    250         if (latch != null)
    251             latch.countDown();
    252         return true;
    253     }
    254 }
    255