Improve Future API when using UntypedActors, and add overloads for Java API
This commit is contained in:
parent
89f2bf3cb9
commit
67ead66b32
3 changed files with 66 additions and 13 deletions
|
|
@ -7,7 +7,7 @@ package akka.dispatch
|
||||||
import akka.AkkaException
|
import akka.AkkaException
|
||||||
import akka.actor.{Actor, EventHandler}
|
import akka.actor.{Actor, EventHandler}
|
||||||
import akka.routing.Dispatcher
|
import akka.routing.Dispatcher
|
||||||
import akka.japi.Procedure
|
import akka.japi.{ Procedure, Function => JFunc }
|
||||||
|
|
||||||
import java.util.concurrent.locks.ReentrantLock
|
import java.util.concurrent.locks.ReentrantLock
|
||||||
import java.util.concurrent. {ConcurrentLinkedQueue, TimeUnit, Callable}
|
import java.util.concurrent. {ConcurrentLinkedQueue, TimeUnit, Callable}
|
||||||
|
|
@ -144,7 +144,7 @@ object Future {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed trait Future[T] {
|
sealed trait Future[+T] {
|
||||||
/**
|
/**
|
||||||
* Blocks the current thread until the Future has been completed or the
|
* Blocks the current thread until the Future has been completed or the
|
||||||
* timeout has expired. In the case of the timeout expiring a
|
* timeout has expired. In the case of the timeout expiring a
|
||||||
|
|
@ -240,6 +240,37 @@ sealed trait Future[T] {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new Future by applying a PartialFunction to the successful
|
||||||
|
* result of this Future if a match is found, or else return a MatchError.
|
||||||
|
* If this Future is completed with an exception then the new Future will
|
||||||
|
* also contain this exception.
|
||||||
|
*/
|
||||||
|
final def collect[A](pf: PartialFunction[Any, A]): Future[A] = {
|
||||||
|
val fa = new DefaultCompletableFuture[A](timeoutInNanos, NANOS)
|
||||||
|
onComplete { ft =>
|
||||||
|
val optv = ft.value
|
||||||
|
if (optv.isDefined) {
|
||||||
|
val v = optv.get
|
||||||
|
fa complete {
|
||||||
|
if (v.isLeft) v.asInstanceOf[Either[Throwable, A]]
|
||||||
|
else {
|
||||||
|
try {
|
||||||
|
val r = v.right.get
|
||||||
|
if (pf isDefinedAt r) Right(pf(r))
|
||||||
|
else Left(new MatchError(r))
|
||||||
|
} catch {
|
||||||
|
case e: Exception =>
|
||||||
|
EventHandler notifyListeners EventHandler.Error(e, this)
|
||||||
|
Left(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fa
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new Future by applying a function to the successful result of
|
* Creates a new Future by applying a function to the successful result of
|
||||||
* this Future. If this Future is completed with an exception then the new
|
* this Future. If this Future is completed with an exception then the new
|
||||||
|
|
@ -338,7 +369,15 @@ sealed trait Future[T] {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Java API */
|
/* Java API */
|
||||||
final def onComplete(proc: Procedure[Future[T]]): Future[T] = onComplete(proc(_))
|
final def onComplete[A >: T](proc: Procedure[Future[A]]): Future[T] = onComplete(proc(_))
|
||||||
|
|
||||||
|
final def map[A >: T, B](f: JFunc[A,B]): Future[B] = map(f(_))
|
||||||
|
|
||||||
|
final def flatMap[A >: T, B](f: JFunc[A,Future[B]]): Future[B] = flatMap(f(_))
|
||||||
|
|
||||||
|
final def foreach[A >: T](proc: Procedure[A]): Unit = foreach(proc(_))
|
||||||
|
|
||||||
|
final def filter[A >: T](p: JFunc[A,Boolean]): Future[T] = filter(p(_))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,8 @@ package akka.dispatch;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
import scala.runtime.AbstractFunction1;
|
import akka.japi.Function;
|
||||||
|
import akka.japi.Procedure;
|
||||||
import scala.Some;
|
import scala.Some;
|
||||||
import scala.Right;
|
import scala.Right;
|
||||||
import static akka.dispatch.Futures.future;
|
import static akka.dispatch.Futures.future;
|
||||||
|
|
@ -17,7 +18,7 @@ import static akka.dispatch.Futures.future;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Future f2 = f1.map(new AbstractFunction1<String, String>() {
|
Future f2 = f1.map(new Function<String, String>() {
|
||||||
public String apply(String s) {
|
public String apply(String s) {
|
||||||
return s + " World";
|
return s + " World";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -59,8 +59,21 @@ class FutureSpec extends JUnitSuite {
|
||||||
@Test def shouldFutureCompose {
|
@Test def shouldFutureCompose {
|
||||||
val actor1 = actorOf[TestActor].start
|
val actor1 = actorOf[TestActor].start
|
||||||
val actor2 = actorOf(new Actor { def receive = { case s: String => self reply s.toUpperCase } } ).start
|
val actor2 = actorOf(new Actor { def receive = { case s: String => self reply s.toUpperCase } } ).start
|
||||||
val future1 = actor1.!! flatMap { case s: String => actor2.!! }
|
val future1 = actor1 !!! "Hello" flatMap ((s: String) => actor2 !!! s)
|
||||||
val future2 = actor1.!! flatMap { case s: Int => actor2.!! }
|
val future2 = actor1 !!! "Hello" flatMap (actor2 !!! (_: String))
|
||||||
|
val future3 = actor1 !!! "Hello" flatMap (actor2 !!! (_: Int))
|
||||||
|
assert(Some(Right("WORLD")) === future1.await.value)
|
||||||
|
assert(Some(Right("WORLD")) === future2.await.value)
|
||||||
|
intercept[ClassCastException] { future3.await.resultOrException }
|
||||||
|
actor1.stop
|
||||||
|
actor2.stop
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test def shouldFutureComposePatternMatch {
|
||||||
|
val actor1 = actorOf[TestActor].start
|
||||||
|
val actor2 = actorOf(new Actor { def receive = { case s: String => self reply s.toUpperCase } } ).start
|
||||||
|
val future1 = actor1 !!! "Hello" collect { case (s: String) => s } flatMap (actor2 !!! _)
|
||||||
|
val future2 = actor1 !!! "Hello" collect { case (n: Int) => n } flatMap (actor2 !!! _)
|
||||||
assert(Some(Right("WORLD")) === future1.await.value)
|
assert(Some(Right("WORLD")) === future1.await.value)
|
||||||
intercept[MatchError] { future2.await.resultOrException }
|
intercept[MatchError] { future2.await.resultOrException }
|
||||||
actor1.stop
|
actor1.stop
|
||||||
|
|
@ -103,15 +116,15 @@ class FutureSpec extends JUnitSuite {
|
||||||
}).start
|
}).start
|
||||||
|
|
||||||
val future1 = for {
|
val future1 = for {
|
||||||
Res(a: Int) <- (actor !!! Req("Hello")): Future[Any]
|
a <- actor !!! Req("Hello") collect { case Res(x: Int) => x }
|
||||||
Res(b: String) <- (actor !!! Req(a)): Future[Any]
|
b <- actor !!! Req(a) collect { case Res(x: String) => x }
|
||||||
Res(c: String) <- (actor !!! Req(7)): Future[Any]
|
c <- actor !!! Req(7) collect { case Res(x: String) => x }
|
||||||
} yield b + "-" + c
|
} yield b + "-" + c
|
||||||
|
|
||||||
val future2 = for {
|
val future2 = for {
|
||||||
Res(a: Int) <- (actor !!! Req("Hello")): Future[Any]
|
a <- actor !!! Req("Hello") collect { case Res(x: Int) => x }
|
||||||
Res(b: Int) <- (actor !!! Req(a)): Future[Any]
|
b <- actor !!! Req(a) collect { case Res(x: Int) => x }
|
||||||
Res(c: String) <- (actor !!! Req(7)): Future[Any]
|
c <- actor !!! Req(7) collect { case Res(x: String) => x }
|
||||||
} yield b + "-" + c
|
} yield b + "-" + c
|
||||||
|
|
||||||
assert(Some(Right("10-14")) === future1.await.value)
|
assert(Some(Right("10-14")) === future1.await.value)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue