1762bb9d0ad20320b9f97a841dce57ba5e8e48b07Richard Smith/*
264bffa9a6f40e5a3d5556f994f09f7bf45eecd4cDouglas Gregor * Copyright (c) 2009-2010 jMonkeyEngine
310f04a6267eb07d3be00db1fd0369e1398f5d0a8Sebastian Redl * All rights reserved.
410f04a6267eb07d3be00db1fd0369e1398f5d0a8Sebastian Redl *
5017ab77655b262311a3550342ca19b85380f8f20Richard Smith * Redistribution and use in source and binary forms, with or without
6017ab77655b262311a3550342ca19b85380f8f20Richard Smith * modification, are permitted provided that the following conditions are
710f04a6267eb07d3be00db1fd0369e1398f5d0a8Sebastian Redl * met:
810f04a6267eb07d3be00db1fd0369e1398f5d0a8Sebastian Redl *
964bffa9a6f40e5a3d5556f994f09f7bf45eecd4cDouglas Gregor * * Redistributions of source code must retain the above copyright
1064bffa9a6f40e5a3d5556f994f09f7bf45eecd4cDouglas Gregor *   notice, this list of conditions and the following disclaimer.
1164bffa9a6f40e5a3d5556f994f09f7bf45eecd4cDouglas Gregor *
1264bffa9a6f40e5a3d5556f994f09f7bf45eecd4cDouglas Gregor * * Redistributions in binary form must reproduce the above copyright
1364bffa9a6f40e5a3d5556f994f09f7bf45eecd4cDouglas Gregor *   notice, this list of conditions and the following disclaimer in the
1410f04a6267eb07d3be00db1fd0369e1398f5d0a8Sebastian Redl *   documentation and/or other materials provided with the distribution.
1564bffa9a6f40e5a3d5556f994f09f7bf45eecd4cDouglas Gregor *
1664bffa9a6f40e5a3d5556f994f09f7bf45eecd4cDouglas Gregor * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
1764bffa9a6f40e5a3d5556f994f09f7bf45eecd4cDouglas Gregor *   may be used to endorse or promote products derived from this software
1810f04a6267eb07d3be00db1fd0369e1398f5d0a8Sebastian Redl *   without specific prior written permission.
1964bffa9a6f40e5a3d5556f994f09f7bf45eecd4cDouglas Gregor *
2064bffa9a6f40e5a3d5556f994f09f7bf45eecd4cDouglas Gregor * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2164bffa9a6f40e5a3d5556f994f09f7bf45eecd4cDouglas Gregor * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2210f04a6267eb07d3be00db1fd0369e1398f5d0a8Sebastian Redl * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23d93f0ddba0965ded252e228134b30ce30e863fb0Sebastian Redl * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24d93f0ddba0965ded252e228134b30ce30e863fb0Sebastian Redl * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
2564bffa9a6f40e5a3d5556f994f09f7bf45eecd4cDouglas Gregor * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
2664bffa9a6f40e5a3d5556f994f09f7bf45eecd4cDouglas Gregor * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
2710f04a6267eb07d3be00db1fd0369e1398f5d0a8Sebastian Redl * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
2810f04a6267eb07d3be00db1fd0369e1398f5d0a8Sebastian Redl * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
2910f04a6267eb07d3be00db1fd0369e1398f5d0a8Sebastian Redl * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
3010f04a6267eb07d3be00db1fd0369e1398f5d0a8Sebastian Redl * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31bab497b9f94cd1538c6b3348c2331daf27dd092eDouglas Gregor */
32bab497b9f94cd1538c6b3348c2331daf27dd092eDouglas Gregorpackage com.jme3.app;
33bab497b9f94cd1538c6b3348c2331daf27dd092eDouglas Gregor
34bab497b9f94cd1538c6b3348c2331daf27dd092eDouglas Gregorimport java.util.concurrent.*;
3546f4659f9d012ca2e2050c1fc39a59666114b3f9Anders Carlssonimport java.util.concurrent.locks.Condition;
3646f4659f9d012ca2e2050c1fc39a59666114b3f9Anders Carlssonimport java.util.concurrent.locks.ReentrantLock;
3746f4659f9d012ca2e2050c1fc39a59666114b3f9Anders Carlssonimport java.util.logging.Level;
3846f4659f9d012ca2e2050c1fc39a59666114b3f9Anders Carlssonimport java.util.logging.Logger;
39784f69940755dd66cf244dd84f57a57d358e5c43Anders Carlsson
40784f69940755dd66cf244dd84f57a57d358e5c43Anders Carlsson/**
41784f69940755dd66cf244dd84f57a57d358e5c43Anders Carlsson * <code>AppTask</code> is used in <code>AppTaskQueue</code> to manage tasks that have
422bbae5de98f486d03e10c039668182075b5569ddAnders Carlsson * yet to be accomplished. The AppTask system is used to execute tasks either
432bbae5de98f486d03e10c039668182075b5569ddAnders Carlsson * in the OpenGL/Render thread, or outside of it.
442bbae5de98f486d03e10c039668182075b5569ddAnders Carlsson *
451b36a2fcb2cea310c01fc2a80a9da915e5d2ceb0Anders Carlsson * @author Matthew D. Hicks, lazloh
461b36a2fcb2cea310c01fc2a80a9da915e5d2ceb0Anders Carlsson */
471b36a2fcb2cea310c01fc2a80a9da915e5d2ceb0Anders Carlssonpublic class AppTask<V> implements Future<V> {
481b36a2fcb2cea310c01fc2a80a9da915e5d2ceb0Anders Carlsson    private static final Logger logger = Logger.getLogger(AppTask.class
491b36a2fcb2cea310c01fc2a80a9da915e5d2ceb0Anders Carlsson            .getName());
501b36a2fcb2cea310c01fc2a80a9da915e5d2ceb0Anders Carlsson
5112ce0a085f89f07c76bf034aa6b838ef50542241Rafael Espindola    private final Callable<V> callable;
5212ce0a085f89f07c76bf034aa6b838ef50542241Rafael Espindola
531b36a2fcb2cea310c01fc2a80a9da915e5d2ceb0Anders Carlsson    private V result;
541b36a2fcb2cea310c01fc2a80a9da915e5d2ceb0Anders Carlsson    private ExecutionException exception;
551b36a2fcb2cea310c01fc2a80a9da915e5d2ceb0Anders Carlsson    private boolean cancelled, finished;
561b36a2fcb2cea310c01fc2a80a9da915e5d2ceb0Anders Carlsson    private final ReentrantLock stateLock = new ReentrantLock();
571b36a2fcb2cea310c01fc2a80a9da915e5d2ceb0Anders Carlsson    private final Condition finishedCondition = stateLock.newCondition();
581b36a2fcb2cea310c01fc2a80a9da915e5d2ceb0Anders Carlsson
591b36a2fcb2cea310c01fc2a80a9da915e5d2ceb0Anders Carlsson    /**
601b36a2fcb2cea310c01fc2a80a9da915e5d2ceb0Anders Carlsson     * Create an <code>AppTask</code> that will execute the given
611b36a2fcb2cea310c01fc2a80a9da915e5d2ceb0Anders Carlsson     * {@link Callable}.
621b36a2fcb2cea310c01fc2a80a9da915e5d2ceb0Anders Carlsson     *
631b36a2fcb2cea310c01fc2a80a9da915e5d2ceb0Anders Carlsson     * @param callable The callable to be executed
641b36a2fcb2cea310c01fc2a80a9da915e5d2ceb0Anders Carlsson     */
6512ce0a085f89f07c76bf034aa6b838ef50542241Rafael Espindola    public AppTask(Callable<V> callable) {
661b36a2fcb2cea310c01fc2a80a9da915e5d2ceb0Anders Carlsson        this.callable = callable;
671b36a2fcb2cea310c01fc2a80a9da915e5d2ceb0Anders Carlsson    }
6812ce0a085f89f07c76bf034aa6b838ef50542241Rafael Espindola
691b36a2fcb2cea310c01fc2a80a9da915e5d2ceb0Anders Carlsson    public boolean cancel(boolean mayInterruptIfRunning) {
701b36a2fcb2cea310c01fc2a80a9da915e5d2ceb0Anders Carlsson        stateLock.lock();
711b36a2fcb2cea310c01fc2a80a9da915e5d2ceb0Anders Carlsson        try {
72fb87b89fc9eb103e19fb8e4b925c23f0bd091b99Douglas Gregor            if (result != null) {
73fb87b89fc9eb103e19fb8e4b925c23f0bd091b99Douglas Gregor                return false;
74fb87b89fc9eb103e19fb8e4b925c23f0bd091b99Douglas Gregor            }
75fb87b89fc9eb103e19fb8e4b925c23f0bd091b99Douglas Gregor            cancelled = true;
76fb87b89fc9eb103e19fb8e4b925c23f0bd091b99Douglas Gregor
77fb87b89fc9eb103e19fb8e4b925c23f0bd091b99Douglas Gregor            finishedCondition.signalAll();
78fb87b89fc9eb103e19fb8e4b925c23f0bd091b99Douglas Gregor
79fb87b89fc9eb103e19fb8e4b925c23f0bd091b99Douglas Gregor            return true;
80fb87b89fc9eb103e19fb8e4b925c23f0bd091b99Douglas Gregor        } finally {
81fb87b89fc9eb103e19fb8e4b925c23f0bd091b99Douglas Gregor            stateLock.unlock();
82fb87b89fc9eb103e19fb8e4b925c23f0bd091b99Douglas Gregor        }
83fb87b89fc9eb103e19fb8e4b925c23f0bd091b99Douglas Gregor    }
84fb87b89fc9eb103e19fb8e4b925c23f0bd091b99Douglas Gregor
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}