2009-05-25 14:48:43 +02:00
|
|
|
/**
|
2009-12-27 16:01:53 +01:00
|
|
|
* Copyright (C) 2009-2010 Scalable Solutions AB <http://scalablesolutions.se>
|
2009-05-25 14:48:43 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Based on code from the actorom actor framework by Sergio Bossa [http://code.google.com/p/actorom/].
|
|
|
|
|
*/
|
2009-10-08 19:01:04 +02:00
|
|
|
package se.scalablesolutions.akka.dispatch
|
2009-05-25 14:48:43 +02:00
|
|
|
|
2009-10-17 00:37:56 +02:00
|
|
|
import java.util.concurrent.locks.ReentrantLock
|
2009-05-25 14:48:43 +02:00
|
|
|
import java.util.concurrent.TimeUnit
|
|
|
|
|
|
2009-06-10 20:04:33 +02:00
|
|
|
class FutureTimeoutException(message: String) extends RuntimeException(message)
|
|
|
|
|
|
2009-05-25 14:48:43 +02:00
|
|
|
sealed trait FutureResult {
|
2009-06-29 15:01:20 +02:00
|
|
|
def await
|
|
|
|
|
def awaitBlocking
|
2009-05-25 14:48:43 +02:00
|
|
|
def isCompleted: Boolean
|
|
|
|
|
def isExpired: Boolean
|
|
|
|
|
def timeoutInNanos: Long
|
2009-12-08 08:51:10 +01:00
|
|
|
def result: Option[Any]
|
2009-06-21 14:08:43 +02:00
|
|
|
def exception: Option[Tuple2[AnyRef, Throwable]]
|
2009-05-25 14:48:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
trait CompletableFutureResult extends FutureResult {
|
2009-12-08 08:51:10 +01:00
|
|
|
def completeWithResult(result: Any)
|
2009-06-21 14:08:43 +02:00
|
|
|
def completeWithException(toBlame: AnyRef, exception: Throwable)
|
2009-05-25 14:48:43 +02:00
|
|
|
}
|
|
|
|
|
|
2009-06-05 22:08:53 +02:00
|
|
|
class DefaultCompletableFutureResult(timeout: Long) extends CompletableFutureResult {
|
|
|
|
|
private val TIME_UNIT = TimeUnit.MILLISECONDS
|
|
|
|
|
def this() = this(0)
|
|
|
|
|
|
|
|
|
|
val timeoutInNanos = TIME_UNIT.toNanos(timeout)
|
2009-05-25 14:48:43 +02:00
|
|
|
private val _startTimeInNanos = currentTimeInNanos
|
|
|
|
|
private val _lock = new ReentrantLock
|
|
|
|
|
private val _signal = _lock.newCondition
|
|
|
|
|
private var _completed: Boolean = _
|
2009-12-08 08:51:10 +01:00
|
|
|
private var _result: Option[Any] = None
|
2009-06-21 14:08:43 +02:00
|
|
|
private var _exception: Option[Tuple2[AnyRef, Throwable]] = None
|
|
|
|
|
|
2009-06-29 15:01:20 +02:00
|
|
|
def await = try {
|
2009-05-25 14:48:43 +02:00
|
|
|
_lock.lock
|
2009-06-05 22:08:53 +02:00
|
|
|
var wait = timeoutInNanos - (currentTimeInNanos - _startTimeInNanos)
|
2009-05-25 14:48:43 +02:00
|
|
|
while (!_completed && wait > 0) {
|
|
|
|
|
var start = currentTimeInNanos
|
|
|
|
|
try {
|
|
|
|
|
wait = _signal.awaitNanos(wait)
|
2009-06-10 20:04:33 +02:00
|
|
|
if (wait <= 0) throw new FutureTimeoutException("Future timed out after [" + timeout + "] milliseconds")
|
2009-05-25 14:48:43 +02:00
|
|
|
} catch {
|
|
|
|
|
case e: InterruptedException =>
|
2009-06-05 22:08:53 +02:00
|
|
|
wait = wait - (currentTimeInNanos - start)
|
2009-05-25 14:48:43 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} finally {
|
|
|
|
|
_lock.unlock
|
|
|
|
|
}
|
|
|
|
|
|
2009-06-29 15:01:20 +02:00
|
|
|
def awaitBlocking = try {
|
2009-06-05 22:08:53 +02:00
|
|
|
_lock.lock
|
|
|
|
|
while (!_completed) {
|
|
|
|
|
_signal.await
|
|
|
|
|
}
|
|
|
|
|
} finally {
|
|
|
|
|
_lock.unlock
|
|
|
|
|
}
|
|
|
|
|
|
2009-06-25 13:07:58 +02:00
|
|
|
def isCompleted: Boolean = try {
|
2009-05-25 14:48:43 +02:00
|
|
|
_lock.lock
|
|
|
|
|
_completed
|
|
|
|
|
} finally {
|
|
|
|
|
_lock.unlock
|
|
|
|
|
}
|
|
|
|
|
|
2009-06-25 13:07:58 +02:00
|
|
|
def isExpired: Boolean = try {
|
2009-05-25 14:48:43 +02:00
|
|
|
_lock.lock
|
2009-06-05 22:08:53 +02:00
|
|
|
timeoutInNanos - (currentTimeInNanos - _startTimeInNanos) <= 0
|
2009-05-25 14:48:43 +02:00
|
|
|
} finally {
|
|
|
|
|
_lock.unlock
|
|
|
|
|
}
|
|
|
|
|
|
2009-12-08 08:51:10 +01:00
|
|
|
def result: Option[Any] = try {
|
2009-05-25 14:48:43 +02:00
|
|
|
_lock.lock
|
|
|
|
|
_result
|
|
|
|
|
} finally {
|
|
|
|
|
_lock.unlock
|
|
|
|
|
}
|
|
|
|
|
|
2009-06-25 13:07:58 +02:00
|
|
|
def exception: Option[Tuple2[AnyRef, Throwable]] = try {
|
2009-05-25 14:48:43 +02:00
|
|
|
_lock.lock
|
|
|
|
|
_exception
|
|
|
|
|
} finally {
|
|
|
|
|
_lock.unlock
|
|
|
|
|
}
|
|
|
|
|
|
2009-12-08 08:51:10 +01:00
|
|
|
def completeWithResult(result: Any) = try {
|
2009-05-25 14:48:43 +02:00
|
|
|
_lock.lock
|
|
|
|
|
if (!_completed) {
|
|
|
|
|
_completed = true
|
2009-06-05 22:08:53 +02:00
|
|
|
_result = Some(result)
|
2009-05-25 14:48:43 +02:00
|
|
|
}
|
|
|
|
|
} finally {
|
|
|
|
|
_signal.signalAll
|
|
|
|
|
_lock.unlock
|
|
|
|
|
}
|
|
|
|
|
|
2009-06-25 13:07:58 +02:00
|
|
|
def completeWithException(toBlame: AnyRef, exception: Throwable) = try {
|
2009-05-25 14:48:43 +02:00
|
|
|
_lock.lock
|
|
|
|
|
if (!_completed) {
|
|
|
|
|
_completed = true
|
2009-06-21 14:08:43 +02:00
|
|
|
_exception = Some((toBlame, exception))
|
2009-05-25 14:48:43 +02:00
|
|
|
}
|
|
|
|
|
} finally {
|
|
|
|
|
_signal.signalAll
|
|
|
|
|
_lock.unlock
|
|
|
|
|
}
|
|
|
|
|
|
2009-06-05 22:08:53 +02:00
|
|
|
private def currentTimeInNanos: Long = TIME_UNIT.toNanos(System.currentTimeMillis)
|
2009-05-25 14:48:43 +02:00
|
|
|
}
|