Home | History | Annotate | Download | only in app
      1 /*
      2  * Copyright (c) 2009-2010 jMonkeyEngine
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions are
      7  * met:
      8  *
      9  * * Redistributions of source code must retain the above copyright
     10  *   notice, this list of conditions and the following disclaimer.
     11  *
     12  * * Redistributions in binary form must reproduce the above copyright
     13  *   notice, this list of conditions and the following disclaimer in the
     14  *   documentation and/or other materials provided with the distribution.
     15  *
     16  * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
     17  *   may be used to endorse or promote products derived from this software
     18  *   without specific prior written permission.
     19  *
     20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     27  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
     28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
     29  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     31  */
     32 package com.jme3.app;
     33 
     34 import java.util.concurrent.*;
     35 import java.util.concurrent.locks.Condition;
     36 import java.util.concurrent.locks.ReentrantLock;
     37 import java.util.logging.Level;
     38 import java.util.logging.Logger;
     39 
     40 /**
     41  * <code>AppTask</code> is used in <code>AppTaskQueue</code> to manage tasks that have
     42  * yet to be accomplished. The AppTask system is used to execute tasks either
     43  * in the OpenGL/Render thread, or outside of it.
     44  *
     45  * @author Matthew D. Hicks, lazloh
     46  */
     47 public class AppTask<V> implements Future<V> {
     48     private static final Logger logger = Logger.getLogger(AppTask.class
     49             .getName());
     50 
     51     private final Callable<V> callable;
     52 
     53     private V result;
     54     private ExecutionException exception;
     55     private boolean cancelled, finished;
     56     private final ReentrantLock stateLock = new ReentrantLock();
     57     private final Condition finishedCondition = stateLock.newCondition();
     58 
     59     /**
     60      * Create an <code>AppTask</code> that will execute the given
     61      * {@link Callable}.
     62      *
     63      * @param callable The callable to be executed
     64      */
     65     public AppTask(Callable<V> callable) {
     66         this.callable = callable;
     67     }
     68 
     69     public boolean cancel(boolean mayInterruptIfRunning) {
     70         stateLock.lock();
     71         try {
     72             if (result != null) {
     73                 return false;
     74             }
     75             cancelled = true;
     76 
     77             finishedCondition.signalAll();
     78 
     79             return true;
     80         } finally {
     81             stateLock.unlock();
     82         }
     83     }
     84 
     85     public V get() throws InterruptedException, ExecutionException {
     86         stateLock.lock();
     87         try {
     88             while (!isDone()) {
     89                 finishedCondition.await();
     90             }
     91             if (exception != null) {
     92                 throw exception;
     93             }
     94             return result;
     95         } finally {
     96             stateLock.unlock();
     97         }
     98     }
     99 
    100     public V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
    101         stateLock.lock();
    102         try {
    103             if (!isDone()) {
    104                 finishedCondition.await(timeout, unit);
    105             }
    106             if (exception != null) {
    107                 throw exception;
    108             }
    109             if (result == null) {
    110                 throw new TimeoutException("Object not returned in time allocated.");
    111             }
    112             return result;
    113         } finally {
    114             stateLock.unlock();
    115         }
    116     }
    117 
    118     public boolean isCancelled() {
    119         stateLock.lock();
    120         try {
    121             return cancelled;
    122         } finally {
    123             stateLock.unlock();
    124         }
    125     }
    126 
    127     public boolean isDone() {
    128         stateLock.lock();
    129         try {
    130             return finished || cancelled || (exception != null);
    131         } finally {
    132             stateLock.unlock();
    133         }
    134     }
    135 
    136     public Callable<V> getCallable() {
    137         return callable;
    138     }
    139 
    140     public void invoke() {
    141         try {
    142             final V tmpResult = callable.call();
    143 
    144             stateLock.lock();
    145             try {
    146                 result = tmpResult;
    147                 finished = true;
    148 
    149                 finishedCondition.signalAll();
    150             } finally {
    151                 stateLock.unlock();
    152             }
    153         } catch (Exception e) {
    154             logger.logp(Level.SEVERE, this.getClass().toString(), "invoke()", "Exception", e);
    155 
    156             stateLock.lock();
    157             try {
    158                 exception = new ExecutionException(e);
    159 
    160                 finishedCondition.signalAll();
    161             } finally {
    162                 stateLock.unlock();
    163             }
    164         }
    165     }
    166 
    167 }