Changing Akka Futures to better conform to spec
This commit is contained in:
parent
48adb3c2b6
commit
b3e5da2377
5 changed files with 123 additions and 118 deletions
|
|
@ -3,6 +3,7 @@ package akka.dispatch;
|
||||||
import akka.actor.Timeout;
|
import akka.actor.Timeout;
|
||||||
import akka.actor.ActorSystem;
|
import akka.actor.ActorSystem;
|
||||||
|
|
||||||
|
import akka.japi.*;
|
||||||
import akka.util.Duration;
|
import akka.util.Duration;
|
||||||
import org.junit.AfterClass;
|
import org.junit.AfterClass;
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
|
|
@ -14,10 +15,6 @@ import java.lang.Iterable;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import akka.japi.Function;
|
|
||||||
import akka.japi.Function2;
|
|
||||||
import akka.japi.Procedure;
|
|
||||||
import akka.japi.Option;
|
|
||||||
import akka.testkit.AkkaSpec;
|
import akka.testkit.AkkaSpec;
|
||||||
|
|
||||||
public class JavaFutureTests {
|
public class JavaFutureTests {
|
||||||
|
|
@ -97,8 +94,8 @@ public class JavaFutureTests {
|
||||||
final CountDownLatch latch = new CountDownLatch(1);
|
final CountDownLatch latch = new CountDownLatch(1);
|
||||||
Promise<String> cf = Futures.promise(system.dispatcher());
|
Promise<String> cf = Futures.promise(system.dispatcher());
|
||||||
Future<String> f = cf;
|
Future<String> f = cf;
|
||||||
f.onComplete(new Procedure<Future<String>>() {
|
f.onComplete(new Procedure2<Throwable,String>() {
|
||||||
public void apply(akka.dispatch.Future<String> future) {
|
public void apply(Throwable t, String r) {
|
||||||
latch.countDown();
|
latch.countDown();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -330,11 +330,9 @@ object TypedActor extends ExtensionId[TypedActorExtension] with ExtensionIdProvi
|
||||||
if (m.returnsFuture_?) {
|
if (m.returnsFuture_?) {
|
||||||
val s = sender
|
val s = sender
|
||||||
m(me).asInstanceOf[Future[Any]] onComplete {
|
m(me).asInstanceOf[Future[Any]] onComplete {
|
||||||
_.value.get match {
|
|
||||||
case Left(f) ⇒ s ! Status.Failure(f)
|
case Left(f) ⇒ s ! Status.Failure(f)
|
||||||
case Right(r) ⇒ s ! r
|
case Right(r) ⇒ s ! r
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
sender ! m(me)
|
sender ! m(me)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,8 +30,10 @@ package object actor {
|
||||||
|
|
||||||
implicit def future2actor[T](f: akka.dispatch.Future[T]) = new {
|
implicit def future2actor[T](f: akka.dispatch.Future[T]) = new {
|
||||||
def pipeTo(actor: ActorRef): this.type = {
|
def pipeTo(actor: ActorRef): this.type = {
|
||||||
def send(f: akka.dispatch.Future[T]) { f.value.get.fold(f ⇒ actor ! Status.Failure(f), r ⇒ actor ! r) }
|
f onComplete {
|
||||||
if (f.isCompleted) send(f) else f onComplete send
|
case Right(r) ⇒ actor ! r
|
||||||
|
case Left(f) ⇒ actor ! Status.Failure(f)
|
||||||
|
}
|
||||||
this
|
this
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -79,19 +79,19 @@ object Futures {
|
||||||
* the result will be the first failure of any of the futures, or any failure in the actual fold,
|
* the result will be the first failure of any of the futures, or any failure in the actual fold,
|
||||||
* or the result of the fold.
|
* or the result of the fold.
|
||||||
*/
|
*/
|
||||||
def fold[T <: AnyRef, R <: AnyRef](zero: R, futures: java.lang.Iterable[Future[T]], fun: akka.japi.Function2[R, T, R], dispatcher: MessageDispatcher): Future[R] =
|
def fold[T <: AnyRef, R <: AnyRef](zero: R, futures: JIterable[Future[T]], fun: akka.japi.Function2[R, T, R], dispatcher: MessageDispatcher): Future[R] =
|
||||||
Future.fold(scala.collection.JavaConversions.iterableAsScalaIterable(futures))(zero)(fun.apply _)(dispatcher)
|
Future.fold(scala.collection.JavaConversions.iterableAsScalaIterable(futures))(zero)(fun.apply _)(dispatcher)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Java API.
|
* Java API.
|
||||||
* Initiates a fold over the supplied futures where the fold-zero is the result value of the Future that's completed first
|
* Initiates a fold over the supplied futures where the fold-zero is the result value of the Future that's completed first
|
||||||
*/
|
*/
|
||||||
def reduce[T <: AnyRef, R >: T](futures: java.lang.Iterable[Future[T]], fun: akka.japi.Function2[R, T, T], dispatcher: MessageDispatcher): Future[R] =
|
def reduce[T <: AnyRef, R >: T](futures: JIterable[Future[T]], fun: akka.japi.Function2[R, T, T], dispatcher: MessageDispatcher): Future[R] =
|
||||||
Future.reduce(scala.collection.JavaConversions.iterableAsScalaIterable(futures))(fun.apply _)(dispatcher)
|
Future.reduce(scala.collection.JavaConversions.iterableAsScalaIterable(futures))(fun.apply _)(dispatcher)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Java API.
|
* Java API.
|
||||||
* Simple version of Future.traverse. Transforms a java.lang.Iterable[Future[A]] into a Future[java.lang.Iterable[A]].
|
* Simple version of Future.traverse. Transforms a JIterable[Future[A]] into a Future[JIterable[A]].
|
||||||
* Useful for reducing many Futures into a single Future.
|
* Useful for reducing many Futures into a single Future.
|
||||||
*/
|
*/
|
||||||
def sequence[A](in: JIterable[Future[A]], dispatcher: MessageDispatcher): Future[JIterable[A]] = {
|
def sequence[A](in: JIterable[Future[A]], dispatcher: MessageDispatcher): Future[JIterable[A]] = {
|
||||||
|
|
@ -105,7 +105,7 @@ object Futures {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Java API.
|
* Java API.
|
||||||
* Transforms a java.lang.Iterable[A] into a Future[java.lang.Iterable[B]] using the provided Function A ⇒ Future[B].
|
* Transforms a JIterable[A] into a Future[JIterable[B]] using the provided Function A ⇒ Future[B].
|
||||||
* This is useful for performing a parallel map. For example, to apply a function to all items of a list
|
* This is useful for performing a parallel map. For example, to apply a function to all items of a list
|
||||||
* in parallel.
|
* in parallel.
|
||||||
*/
|
*/
|
||||||
|
|
@ -152,10 +152,10 @@ object Future {
|
||||||
/**
|
/**
|
||||||
* Returns a Future to the result of the first future in the list that is completed
|
* Returns a Future to the result of the first future in the list that is completed
|
||||||
*/
|
*/
|
||||||
def firstCompletedOf[T](futures: Iterable[Future[T]])(implicit dispatcher: MessageDispatcher): Future[T] = {
|
def firstCompletedOf[T](futures: Traversable[Future[T]])(implicit dispatcher: MessageDispatcher): Future[T] = {
|
||||||
val futureResult = Promise[T]()
|
val futureResult = Promise[T]()
|
||||||
|
|
||||||
val completeFirst: Future[T] ⇒ Unit = _.value.foreach(futureResult complete _)
|
val completeFirst: Either[Throwable, T] ⇒ Unit = futureResult complete _
|
||||||
futures.foreach(_ onComplete completeFirst)
|
futures.foreach(_ onComplete completeFirst)
|
||||||
|
|
||||||
futureResult
|
futureResult
|
||||||
|
|
@ -164,13 +164,13 @@ object Future {
|
||||||
/**
|
/**
|
||||||
* Returns a Future that will hold the optional result of the first Future with a result that matches the predicate
|
* Returns a Future that will hold the optional result of the first Future with a result that matches the predicate
|
||||||
*/
|
*/
|
||||||
def find[T](futures: Iterable[Future[T]])(predicate: T ⇒ Boolean)(implicit dispatcher: MessageDispatcher): Future[Option[T]] = {
|
def find[T](futures: Traversable[Future[T]])(predicate: T ⇒ Boolean)(implicit dispatcher: MessageDispatcher): Future[Option[T]] = {
|
||||||
if (futures.isEmpty) Promise.successful[Option[T]](None)
|
if (futures.isEmpty) Promise.successful[Option[T]](None)
|
||||||
else {
|
else {
|
||||||
val result = Promise[Option[T]]()
|
val result = Promise[Option[T]]()
|
||||||
val ref = new AtomicInteger(futures.size)
|
val ref = new AtomicInteger(futures.size)
|
||||||
val search: Future[T] ⇒ Unit = f ⇒ try {
|
val search: Either[Throwable, T] ⇒ Unit = v ⇒ try {
|
||||||
f.value.get match {
|
v match {
|
||||||
case Right(r) ⇒ if (predicate(r)) result success Some(r)
|
case Right(r) ⇒ if (predicate(r)) result success Some(r)
|
||||||
case _ ⇒
|
case _ ⇒
|
||||||
}
|
}
|
||||||
|
|
@ -195,7 +195,7 @@ object Future {
|
||||||
* val result = Futures.fold(0)(futures)(_ + _).await.result
|
* val result = Futures.fold(0)(futures)(_ + _).await.result
|
||||||
* </pre>
|
* </pre>
|
||||||
*/
|
*/
|
||||||
def fold[T, R](futures: Iterable[Future[T]])(zero: R)(foldFun: (R, T) ⇒ R)(implicit dispatcher: MessageDispatcher): Future[R] = {
|
def fold[T, R](futures: Traversable[Future[T]])(zero: R)(foldFun: (R, T) ⇒ R)(implicit dispatcher: MessageDispatcher): Future[R] = {
|
||||||
if (futures.isEmpty) Promise.successful(zero)
|
if (futures.isEmpty) Promise.successful(zero)
|
||||||
else {
|
else {
|
||||||
val result = Promise[R]()
|
val result = Promise[R]()
|
||||||
|
|
@ -203,8 +203,8 @@ object Future {
|
||||||
val done = new Switch(false)
|
val done = new Switch(false)
|
||||||
val allDone = futures.size
|
val allDone = futures.size
|
||||||
|
|
||||||
val aggregate: Future[T] ⇒ Unit = f ⇒ if (done.isOff && !result.isCompleted) {
|
val aggregate: Either[Throwable, T] ⇒ Unit = v ⇒ if (done.isOff && !result.isCompleted) {
|
||||||
f.value.get match {
|
v match {
|
||||||
case Right(value) ⇒
|
case Right(value) ⇒
|
||||||
val added = results add value
|
val added = results add value
|
||||||
if (added && results.size == allDone) { //Only one thread can get here
|
if (added && results.size == allDone) { //Only one thread can get here
|
||||||
|
|
@ -240,25 +240,12 @@ object Future {
|
||||||
* Initiates a fold over the supplied futures where the fold-zero is the result value of the Future that's completed first
|
* Initiates a fold over the supplied futures where the fold-zero is the result value of the Future that's completed first
|
||||||
* Example:
|
* Example:
|
||||||
* <pre>
|
* <pre>
|
||||||
* val result = Futures.reduce(futures)(_ + _).await.result
|
* val result = Await.result(Futures.reduce(futures)(_ + _), 5 seconds)
|
||||||
* </pre>
|
* </pre>
|
||||||
*/
|
*/
|
||||||
def reduce[T, R >: T](futures: Iterable[Future[T]])(op: (R, T) ⇒ T)(implicit dispatcher: MessageDispatcher): Future[R] = {
|
def reduce[T, R >: T](futures: Traversable[Future[T]])(op: (R, T) ⇒ T)(implicit dispatcher: MessageDispatcher): Future[R] = {
|
||||||
if (futures.isEmpty) Promise[R].failure(new UnsupportedOperationException("empty reduce left"))
|
if (futures.isEmpty) Promise[R].failure(new UnsupportedOperationException("empty reduce left"))
|
||||||
else {
|
else sequence(futures).map(_ reduce op)
|
||||||
val result = Promise[R]()
|
|
||||||
val seedFound = new AtomicBoolean(false)
|
|
||||||
val seedFold: Future[T] ⇒ Unit = f ⇒ {
|
|
||||||
if (seedFound.compareAndSet(false, true)) { //Only the first completed should trigger the fold
|
|
||||||
f.value.get match {
|
|
||||||
case Right(value) ⇒ result.completeWith(fold(futures.filterNot(_ eq f))(value)(op))
|
|
||||||
case Left(exception) ⇒ result.failure(exception)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (f ← futures) f onComplete seedFold //Attach the listener to the Futures
|
|
||||||
result
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Transforms a Traversable[A] into a Future[Traversable[B]] using the provided Function A ⇒ Future[B].
|
* Transforms a Traversable[A] into a Future[Traversable[B]] using the provided Function A ⇒ Future[B].
|
||||||
|
|
@ -394,7 +381,7 @@ sealed trait Future[+T] extends japi.Future[T] with Await.Awaitable[T] {
|
||||||
* callbacks may be registered; there is no guarantee that they will be
|
* callbacks may be registered; there is no guarantee that they will be
|
||||||
* executed in a particular order.
|
* executed in a particular order.
|
||||||
*/
|
*/
|
||||||
def onComplete(func: Future[T] ⇒ Unit): this.type
|
def onComplete(func: Either[Throwable, T] ⇒ Unit): this.type
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When the future is completed with a valid result, apply the provided
|
* When the future is completed with a valid result, apply the provided
|
||||||
|
|
@ -406,12 +393,10 @@ sealed trait Future[+T] extends japi.Future[T] with Await.Awaitable[T] {
|
||||||
* }
|
* }
|
||||||
* </pre>
|
* </pre>
|
||||||
*/
|
*/
|
||||||
final def onSuccess(pf: PartialFunction[T, Unit]): this.type = onComplete {
|
final def onSuccess[U](pf: PartialFunction[T, U]): this.type = onComplete {
|
||||||
_.value match {
|
case Right(r) if pf isDefinedAt r ⇒ pf(r)
|
||||||
case Some(Right(r)) if pf isDefinedAt r ⇒ pf(r)
|
|
||||||
case _ ⇒
|
case _ ⇒
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When the future is completed with an exception, apply the provided
|
* When the future is completed with an exception, apply the provided
|
||||||
|
|
@ -422,12 +407,10 @@ sealed trait Future[+T] extends japi.Future[T] with Await.Awaitable[T] {
|
||||||
* }
|
* }
|
||||||
* </pre>
|
* </pre>
|
||||||
*/
|
*/
|
||||||
final def onFailure(pf: PartialFunction[Throwable, Unit]): this.type = onComplete {
|
final def onFailure[U](pf: PartialFunction[Throwable, U]): this.type = onComplete {
|
||||||
_.value match {
|
case Left(ex) if pf isDefinedAt ex ⇒ pf(ex)
|
||||||
case Some(Left(ex)) if pf isDefinedAt ex ⇒ pf(ex)
|
|
||||||
case _ ⇒
|
case _ ⇒
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a failure projection of this Future
|
* Returns a failure projection of this Future
|
||||||
|
|
@ -436,10 +419,10 @@ sealed trait Future[+T] extends japi.Future[T] with Await.Awaitable[T] {
|
||||||
*/
|
*/
|
||||||
final def failed: Future[Throwable] = {
|
final def failed: Future[Throwable] = {
|
||||||
val p = Promise[Throwable]()
|
val p = Promise[Throwable]()
|
||||||
this.onComplete(_.value.get match {
|
this.onComplete {
|
||||||
case Left(t) ⇒ p success t
|
case Left(t) ⇒ p success t
|
||||||
case Right(r) ⇒ p failure new NoSuchElementException("Future.failed not completed with a throwable. Instead completed with: " + r)
|
case Right(r) ⇒ p failure new NoSuchElementException("Future.failed not completed with a throwable. Instead completed with: " + r)
|
||||||
})
|
}
|
||||||
p
|
p
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -464,11 +447,9 @@ sealed trait Future[+T] extends japi.Future[T] with Await.Awaitable[T] {
|
||||||
final def recover[A >: T](pf: PartialFunction[Throwable, A]): Future[A] = {
|
final def recover[A >: T](pf: PartialFunction[Throwable, A]): Future[A] = {
|
||||||
val future = Promise[A]()
|
val future = Promise[A]()
|
||||||
onComplete {
|
onComplete {
|
||||||
_.value.get match {
|
|
||||||
case Left(e) if pf isDefinedAt e ⇒ future.complete(try { Right(pf(e)) } catch { case x: Exception ⇒ Left(x) })
|
case Left(e) if pf isDefinedAt e ⇒ future.complete(try { Right(pf(e)) } catch { case x: Exception ⇒ Left(x) })
|
||||||
case otherwise ⇒ future complete otherwise
|
case otherwise ⇒ future complete otherwise
|
||||||
}
|
}
|
||||||
}
|
|
||||||
future
|
future
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -488,7 +469,6 @@ sealed trait Future[+T] extends japi.Future[T] with Await.Awaitable[T] {
|
||||||
final def map[A](f: T ⇒ A): Future[A] = {
|
final def map[A](f: T ⇒ A): Future[A] = {
|
||||||
val future = Promise[A]()
|
val future = Promise[A]()
|
||||||
onComplete {
|
onComplete {
|
||||||
_.value.get match {
|
|
||||||
case l: Left[_, _] ⇒ future complete l.asInstanceOf[Either[Throwable, A]]
|
case l: Left[_, _] ⇒ future complete l.asInstanceOf[Either[Throwable, A]]
|
||||||
case Right(res) ⇒
|
case Right(res) ⇒
|
||||||
future complete (try {
|
future complete (try {
|
||||||
|
|
@ -499,7 +479,6 @@ sealed trait Future[+T] extends japi.Future[T] with Await.Awaitable[T] {
|
||||||
Left(e)
|
Left(e)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
|
||||||
future
|
future
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -509,15 +488,13 @@ sealed trait Future[+T] extends japi.Future[T] with Await.Awaitable[T] {
|
||||||
*/
|
*/
|
||||||
final def mapTo[A](implicit m: Manifest[A]): Future[A] = {
|
final def mapTo[A](implicit m: Manifest[A]): Future[A] = {
|
||||||
val fa = Promise[A]()
|
val fa = Promise[A]()
|
||||||
onComplete { ft ⇒
|
onComplete {
|
||||||
fa complete (ft.value.get match {
|
case l: Left[_, _] ⇒ fa complete l.asInstanceOf[Either[Throwable, A]]
|
||||||
case l: Left[_, _] ⇒ l.asInstanceOf[Either[Throwable, A]]
|
|
||||||
case Right(t) ⇒
|
case Right(t) ⇒
|
||||||
try {
|
fa complete (try {
|
||||||
Right(BoxedType(m.erasure).cast(t).asInstanceOf[A])
|
Right(BoxedType(m.erasure).cast(t).asInstanceOf[A])
|
||||||
} catch {
|
} catch {
|
||||||
case e: ClassCastException ⇒ Left(e)
|
case e: ClassCastException ⇒ Left(e)
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
fa
|
fa
|
||||||
|
|
@ -538,29 +515,26 @@ sealed trait Future[+T] extends japi.Future[T] with Await.Awaitable[T] {
|
||||||
* </pre>
|
* </pre>
|
||||||
*/
|
*/
|
||||||
final def flatMap[A](f: T ⇒ Future[A]): Future[A] = {
|
final def flatMap[A](f: T ⇒ Future[A]): Future[A] = {
|
||||||
val future = Promise[A]()
|
val p = Promise[A]()
|
||||||
|
|
||||||
onComplete {
|
onComplete {
|
||||||
_.value.get match {
|
case l: Left[_, _] ⇒ p complete l.asInstanceOf[Either[Throwable, A]]
|
||||||
case l: Left[_, _] ⇒ future complete l.asInstanceOf[Either[Throwable, A]]
|
case Right(r) ⇒
|
||||||
case Right(r) ⇒ try {
|
try {
|
||||||
future.completeWith(f(r))
|
p completeWith f(r)
|
||||||
} catch {
|
} catch {
|
||||||
case e: Exception ⇒
|
case e: Exception ⇒
|
||||||
|
p complete Left(e)
|
||||||
dispatcher.prerequisites.eventStream.publish(Error(e, "Future.flatMap", e.getMessage))
|
dispatcher.prerequisites.eventStream.publish(Error(e, "Future.flatMap", e.getMessage))
|
||||||
future complete Left(e)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
p
|
||||||
future
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final def foreach(f: T ⇒ Unit): Unit = onComplete {
|
final def foreach(f: T ⇒ Unit): Unit = onComplete {
|
||||||
_.value.get match {
|
|
||||||
case Right(r) ⇒ f(r)
|
case Right(r) ⇒ f(r)
|
||||||
case _ ⇒
|
case _ ⇒
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
final def withFilter(p: T ⇒ Boolean) = new FutureWithFilter[T](this, p)
|
final def withFilter(p: T ⇒ Boolean) = new FutureWithFilter[T](this, p)
|
||||||
|
|
||||||
|
|
@ -571,21 +545,19 @@ sealed trait Future[+T] extends japi.Future[T] with Await.Awaitable[T] {
|
||||||
def withFilter(q: A ⇒ Boolean): FutureWithFilter[A] = new FutureWithFilter[A](self, x ⇒ p(x) && q(x))
|
def withFilter(q: A ⇒ Boolean): FutureWithFilter[A] = new FutureWithFilter[A](self, x ⇒ p(x) && q(x))
|
||||||
}
|
}
|
||||||
|
|
||||||
final def filter(p: T ⇒ Boolean): Future[T] = {
|
final def filter(pred: T ⇒ Boolean): Future[T] = {
|
||||||
val future = Promise[T]()
|
val p = Promise[T]()
|
||||||
onComplete {
|
onComplete {
|
||||||
_.value.get match {
|
case l: Left[_, _] ⇒ p complete l.asInstanceOf[Either[Throwable, T]]
|
||||||
case l: Left[_, _] ⇒ future complete l.asInstanceOf[Either[Throwable, T]]
|
case r @ Right(res) ⇒ p complete (try {
|
||||||
case r @ Right(res) ⇒ future complete (try {
|
if (pred(res)) r else Left(new MatchError(res))
|
||||||
if (p(res)) r else Left(new MatchError(res))
|
|
||||||
} catch {
|
} catch {
|
||||||
case e: Exception ⇒
|
case e: Exception ⇒
|
||||||
dispatcher.prerequisites.eventStream.publish(Error(e, "Future.filter", e.getMessage))
|
dispatcher.prerequisites.eventStream.publish(Error(e, "Future.filter", e.getMessage))
|
||||||
Left(e)
|
Left(e)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
p
|
||||||
future
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -648,7 +620,7 @@ trait Promise[T] extends Future[T] {
|
||||||
* @return this.
|
* @return this.
|
||||||
*/
|
*/
|
||||||
final def completeWith(other: Future[T]): this.type = {
|
final def completeWith(other: Future[T]): this.type = {
|
||||||
other onComplete { f ⇒ complete(f.value.get) }
|
other onComplete { complete(_) }
|
||||||
this
|
this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -656,9 +628,10 @@ trait Promise[T] extends Future[T] {
|
||||||
|
|
||||||
final def <<(other: Future[T]): Future[T] @cps[Future[Any]] = shift { cont: (Future[T] ⇒ Future[Any]) ⇒
|
final def <<(other: Future[T]): Future[T] @cps[Future[Any]] = shift { cont: (Future[T] ⇒ Future[Any]) ⇒
|
||||||
val fr = Promise[Any]()
|
val fr = Promise[Any]()
|
||||||
this completeWith other onComplete { f ⇒
|
val thisPromise = this
|
||||||
|
thisPromise completeWith other onComplete { v ⇒
|
||||||
try {
|
try {
|
||||||
fr completeWith cont(f)
|
fr completeWith cont(thisPromise)
|
||||||
} catch {
|
} catch {
|
||||||
case e: Exception ⇒
|
case e: Exception ⇒
|
||||||
dispatcher.prerequisites.eventStream.publish(Error(e, "Promise.completeWith", e.getMessage))
|
dispatcher.prerequisites.eventStream.publish(Error(e, "Promise.completeWith", e.getMessage))
|
||||||
|
|
@ -670,7 +643,8 @@ trait Promise[T] extends Future[T] {
|
||||||
|
|
||||||
final def <<(stream: PromiseStreamOut[T]): Future[T] @cps[Future[Any]] = shift { cont: (Future[T] ⇒ Future[Any]) ⇒
|
final def <<(stream: PromiseStreamOut[T]): Future[T] @cps[Future[Any]] = shift { cont: (Future[T] ⇒ Future[Any]) ⇒
|
||||||
val fr = Promise[Any]()
|
val fr = Promise[Any]()
|
||||||
stream.dequeue(this).onComplete { f ⇒
|
val f = stream.dequeue(this)
|
||||||
|
f.onComplete { _ ⇒
|
||||||
try {
|
try {
|
||||||
fr completeWith cont(f)
|
fr completeWith cont(f)
|
||||||
} catch {
|
} catch {
|
||||||
|
|
@ -692,7 +666,7 @@ private[dispatch] object DefaultPromise {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
sealed trait FState[+T] { def value: Option[Either[Throwable, T]] }
|
sealed trait FState[+T] { def value: Option[Either[Throwable, T]] }
|
||||||
case class Pending[T](listeners: List[Future[T] ⇒ Unit] = Nil) extends FState[T] {
|
case class Pending[T](listeners: List[Either[Throwable, T] ⇒ Unit] = Nil) extends FState[T] {
|
||||||
def value: Option[Either[Throwable, T]] = None
|
def value: Option[Either[Throwable, T]] = None
|
||||||
}
|
}
|
||||||
case class Success[T](value: Option[Either[Throwable, T]] = None) extends FState[T] {
|
case class Success[T](value: Option[Either[Throwable, T]] = None) extends FState[T] {
|
||||||
|
|
@ -752,10 +726,10 @@ class DefaultPromise[T](implicit val dispatcher: MessageDispatcher) extends Abst
|
||||||
protected final def getState: FState[T] = updater.get(this)
|
protected final def getState: FState[T] = updater.get(this)
|
||||||
|
|
||||||
def tryComplete(value: Either[Throwable, T]): Boolean = {
|
def tryComplete(value: Either[Throwable, T]): Boolean = {
|
||||||
val callbacks: List[Future[T] ⇒ Unit] = {
|
val callbacks: List[Either[Throwable, T] ⇒ Unit] = {
|
||||||
try {
|
try {
|
||||||
@tailrec
|
@tailrec
|
||||||
def tryComplete: List[Future[T] ⇒ Unit] = {
|
def tryComplete: List[Either[Throwable, T] ⇒ Unit] = {
|
||||||
val cur = getState
|
val cur = getState
|
||||||
|
|
||||||
cur match {
|
cur match {
|
||||||
|
|
@ -778,7 +752,7 @@ class DefaultPromise[T](implicit val dispatcher: MessageDispatcher) extends Abst
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def onComplete(func: Future[T] ⇒ Unit): this.type = {
|
def onComplete(func: Either[Throwable, T] ⇒ Unit): this.type = {
|
||||||
@tailrec //Returns whether the future has already been completed or not
|
@tailrec //Returns whether the future has already been completed or not
|
||||||
def tryAddCallback(): Boolean = {
|
def tryAddCallback(): Boolean = {
|
||||||
val cur = getState
|
val cur = getState
|
||||||
|
|
@ -795,9 +769,8 @@ class DefaultPromise[T](implicit val dispatcher: MessageDispatcher) extends Abst
|
||||||
this
|
this
|
||||||
}
|
}
|
||||||
|
|
||||||
private def notifyCompleted(func: Future[T] ⇒ Unit) {
|
private final def notifyCompleted(func: Either[Throwable, T] ⇒ Unit) {
|
||||||
// TODO FIXME catching all and continue isn't good for OOME, ticket #1418
|
try { func(this.value.get) } catch { case e ⇒ dispatcher.prerequisites.eventStream.publish(Error(e, "Future", "Future onComplete-callback raised an exception")) }
|
||||||
try { func(this) } catch { case e ⇒ dispatcher.prerequisites.eventStream.publish(Error(e, "Future", "Future onComplete-callback raised an exception")) }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -809,8 +782,9 @@ final class KeptPromise[T](suppliedValue: Either[Throwable, T])(implicit val dis
|
||||||
val value = Some(suppliedValue)
|
val value = Some(suppliedValue)
|
||||||
|
|
||||||
def tryComplete(value: Either[Throwable, T]): Boolean = true
|
def tryComplete(value: Either[Throwable, T]): Boolean = true
|
||||||
def onComplete(func: Future[T] ⇒ Unit): this.type = {
|
def onComplete(func: Either[Throwable, T] ⇒ Unit): this.type = {
|
||||||
Future dispatchTask (() ⇒ func(this))
|
val completedAs = value.get
|
||||||
|
Future dispatchTask (() ⇒ func(completedAs))
|
||||||
this
|
this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,17 +3,51 @@
|
||||||
*/
|
*/
|
||||||
package akka.dispatch.japi
|
package akka.dispatch.japi
|
||||||
|
|
||||||
import akka.japi.{ Procedure, Function ⇒ JFunc, Option ⇒ JOption }
|
|
||||||
import akka.actor.Timeout
|
import akka.actor.Timeout
|
||||||
|
import akka.japi.{ Procedure2, Procedure, Function ⇒ JFunc, Option ⇒ JOption }
|
||||||
|
|
||||||
/* Java API */
|
/* Java API */
|
||||||
trait Future[+T] { self: akka.dispatch.Future[T] ⇒
|
trait Future[+T] { self: akka.dispatch.Future[T] ⇒
|
||||||
|
/**
|
||||||
|
* Asynchronously called when this Future gets a successful result
|
||||||
|
*/
|
||||||
private[japi] final def onSuccess[A >: T](proc: Procedure[A]): this.type = self.onSuccess({ case r ⇒ proc(r.asInstanceOf[A]) }: PartialFunction[T, Unit])
|
private[japi] final def onSuccess[A >: T](proc: Procedure[A]): this.type = self.onSuccess({ case r ⇒ proc(r.asInstanceOf[A]) }: PartialFunction[T, Unit])
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asynchronously called when this Future gets a failed result
|
||||||
|
*/
|
||||||
private[japi] final def onFailure(proc: Procedure[Throwable]): this.type = self.onFailure({ case t: Throwable ⇒ proc(t) }: PartialFunction[Throwable, Unit])
|
private[japi] final def onFailure(proc: Procedure[Throwable]): this.type = self.onFailure({ case t: Throwable ⇒ proc(t) }: PartialFunction[Throwable, Unit])
|
||||||
private[japi] final def onComplete[A >: T](proc: Procedure[akka.dispatch.Future[A]]): this.type = self.onComplete(proc(_))
|
|
||||||
|
/**
|
||||||
|
* Asynchronously called when this future is completed with either a failed or a successful result
|
||||||
|
* In case of a success, the first parameter (Throwable) will be null
|
||||||
|
* In case of a failure, the second parameter (T) will be null
|
||||||
|
* For no reason will both be null or neither be null
|
||||||
|
*/
|
||||||
|
private[japi] final def onComplete[A >: T](proc: Procedure2[Throwable, A]): this.type = self.onComplete(_.fold(t ⇒ proc(t, null.asInstanceOf[T]), r ⇒ proc(null, r)))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asynchronously applies the provided function to the (if any) successful result of this Future
|
||||||
|
* Any failure of this Future will be propagated to the Future returned by this method.
|
||||||
|
*/
|
||||||
private[japi] final def map[A >: T, B](f: JFunc[A, B]): akka.dispatch.Future[B] = self.map(f(_))
|
private[japi] final def map[A >: T, B](f: JFunc[A, B]): akka.dispatch.Future[B] = self.map(f(_))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asynchronously applies the provided function to the (if any) successful result of this Future and flattens it.
|
||||||
|
* Any failure of this Future will be propagated to the Future returned by this method.
|
||||||
|
*/
|
||||||
private[japi] final def flatMap[A >: T, B](f: JFunc[A, akka.dispatch.Future[B]]): akka.dispatch.Future[B] = self.flatMap(f(_))
|
private[japi] final def flatMap[A >: T, B](f: JFunc[A, akka.dispatch.Future[B]]): akka.dispatch.Future[B] = self.flatMap(f(_))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asynchronously applies the provided Procedure to the (if any) successful result of this Future
|
||||||
|
* Provided Procedure will not be called in case of no-result or in case of failed result
|
||||||
|
*/
|
||||||
private[japi] final def foreach[A >: T](proc: Procedure[A]): Unit = self.foreach(proc(_))
|
private[japi] final def foreach[A >: T](proc: Procedure[A]): Unit = self.foreach(proc(_))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new Future whose successful result will be the successful result of this Future if that result conforms to the provided predicate
|
||||||
|
* Any failure of this Future will be propagated to the Future returned by this method.
|
||||||
|
*/
|
||||||
private[japi] final def filter[A >: T](p: JFunc[A, java.lang.Boolean]): akka.dispatch.Future[A] =
|
private[japi] final def filter[A >: T](p: JFunc[A, java.lang.Boolean]): akka.dispatch.Future[A] =
|
||||||
self.filter((a: Any) ⇒ p(a.asInstanceOf[A])).asInstanceOf[akka.dispatch.Future[A]]
|
self.filter((a: Any) ⇒ p(a.asInstanceOf[A])).asInstanceOf[akka.dispatch.Future[A]]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue