Merge branch 'master' into wip-1503-remove-stm-patriknw

Conflicts:
	akka-actor-tests/src/test/scala/akka/actor/SchedulerSpec.scala
	akka-actor-tests/src/test/scala/akka/dispatch/FutureSpec.scala
	akka-docs/modules/camel.rst
This commit is contained in:
Patrik Nordwall 2011-12-14 18:56:39 +01:00
commit e456213e31
179 changed files with 2334 additions and 2138 deletions

View file

@ -20,7 +20,7 @@ public class JavaAPI {
@AfterClass
public static void afterAll() {
system.stop();
system.shutdown();
system = null;
}

View file

@ -58,7 +58,7 @@ public class JavaExtension {
@AfterClass
public static void afterAll() {
system.stop();
system.shutdown();
system = null;
}

View file

@ -3,6 +3,8 @@ package akka.dispatch;
import akka.actor.Timeout;
import akka.actor.ActorSystem;
import akka.japi.*;
import akka.util.Duration;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
@ -13,74 +15,68 @@ import java.lang.Iterable;
import java.util.concurrent.CountDownLatch;
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;
public class JavaFutureTests {
private static ActorSystem system;
private static FutureFactory ff;
private static Timeout t;
private final Duration timeout = Duration.create(5, TimeUnit.SECONDS);
@BeforeClass
public static void beforeAll() {
system = ActorSystem.create("JavaFutureTests", AkkaSpec.testConf());
t = system.settings().ActorTimeout();
ff = new FutureFactory(system.dispatcher(), t);
}
@AfterClass
public static void afterAll() {
system.stop();
system.shutdown();
system = null;
}
@Test
public void mustBeAbleToMapAFuture() {
Future<String> f1 = ff.future(new Callable<String>() {
Future<String> f1 = Futures.future(new Callable<String>() {
public String call() {
return "Hello";
}
});
}, system.dispatcher());
Future<String> f2 = f1.map(new Function<String, String>() {
public String apply(String s) {
return s + " World";
}
}, t);
});
assertEquals("Hello World", f2.get());
assertEquals("Hello World", Await.result(f2, timeout));
}
@Test
public void mustBeAbleToExecuteAnOnResultCallback() throws Throwable {
final CountDownLatch latch = new CountDownLatch(1);
Promise<String> cf = new akka.dispatch.DefaultPromise<String>(1000, TimeUnit.MILLISECONDS, system
.dispatcherFactory().defaultGlobalDispatcher());
Promise<String> cf = Futures.promise(system.dispatcher());
Future<String> f = cf;
f.onResult(new Procedure<String>() {
f.onSuccess(new Procedure<String>() {
public void apply(String result) {
if (result.equals("foo"))
latch.countDown();
}
});
cf.completeWithResult("foo");
cf.success("foo");
assertTrue(latch.await(5000, TimeUnit.MILLISECONDS));
assertEquals(f.get(), "foo");
assertEquals(Await.result(f, timeout), "foo");
}
@Test
public void mustBeAbleToExecuteAnOnExceptionCallback() throws Throwable {
final CountDownLatch latch = new CountDownLatch(1);
Promise<String> cf = new akka.dispatch.DefaultPromise<String>(1000, TimeUnit.MILLISECONDS, system
.dispatcherFactory().defaultGlobalDispatcher());
Promise<String> cf = Futures.promise(system.dispatcher());
Future<String> f = cf;
f.onException(new Procedure<Throwable>() {
f.onFailure(new Procedure<Throwable>() {
public void apply(Throwable t) {
if (t instanceof NullPointerException)
latch.countDown();
@ -88,49 +84,31 @@ public class JavaFutureTests {
});
Throwable exception = new NullPointerException();
cf.completeWithException(exception);
cf.failure(exception);
assertTrue(latch.await(5000, TimeUnit.MILLISECONDS));
assertEquals(f.exception().get(), exception);
}
@Test
public void mustBeAbleToExecuteAnOnTimeoutCallback() throws Throwable {
final CountDownLatch latch = new CountDownLatch(1);
Promise<String> cf = new akka.dispatch.DefaultPromise<String>(1000, TimeUnit.MILLISECONDS, system
.dispatcherFactory().defaultGlobalDispatcher());
Future<String> f = cf;
f.onTimeout(new Procedure<Future<String>>() {
public void apply(Future<String> future) {
latch.countDown();
}
});
assertTrue(latch.await(5000, TimeUnit.MILLISECONDS));
assertTrue(f.value().isEmpty());
assertEquals(f.value().get().left().get(), exception);
}
@Test
public void mustBeAbleToExecuteAnOnCompleteCallback() throws Throwable {
final CountDownLatch latch = new CountDownLatch(1);
Promise<String> cf = new akka.dispatch.DefaultPromise<String>(1000, TimeUnit.MILLISECONDS, system
.dispatcherFactory().defaultGlobalDispatcher());
Promise<String> cf = Futures.promise(system.dispatcher());
Future<String> f = cf;
f.onComplete(new Procedure<Future<String>>() {
public void apply(akka.dispatch.Future<String> future) {
f.onComplete(new Procedure2<Throwable,String>() {
public void apply(Throwable t, String r) {
latch.countDown();
}
});
cf.completeWithResult("foo");
cf.success("foo");
assertTrue(latch.await(5000, TimeUnit.MILLISECONDS));
assertEquals(f.get(), "foo");
assertEquals(Await.result(f, timeout), "foo");
}
@Test
public void mustBeAbleToForeachAFuture() throws Throwable {
final CountDownLatch latch = new CountDownLatch(1);
Promise<String> cf = new akka.dispatch.DefaultPromise<String>(1000, TimeUnit.MILLISECONDS, system
.dispatcherFactory().defaultGlobalDispatcher());
Promise<String> cf = Futures.promise(system.dispatcher());
Future<String> f = cf;
f.foreach(new Procedure<String>() {
public void apply(String future) {
@ -138,50 +116,47 @@ public class JavaFutureTests {
}
});
cf.completeWithResult("foo");
cf.success("foo");
assertTrue(latch.await(5000, TimeUnit.MILLISECONDS));
assertEquals(f.get(), "foo");
assertEquals(Await.result(f, timeout), "foo");
}
@Test
public void mustBeAbleToFlatMapAFuture() throws Throwable {
final CountDownLatch latch = new CountDownLatch(1);
Promise<String> cf = new akka.dispatch.DefaultPromise<String>(1000, TimeUnit.MILLISECONDS, system
.dispatcherFactory().defaultGlobalDispatcher());
cf.completeWithResult("1000");
Promise<String> cf = Futures.promise(system.dispatcher());
cf.success("1000");
Future<String> f = cf;
Future<Integer> r = f.flatMap(new Function<String, Future<Integer>>() {
public Future<Integer> apply(String r) {
latch.countDown();
Promise<Integer> cf = new akka.dispatch.DefaultPromise<Integer>(1000, TimeUnit.MILLISECONDS, system
.dispatcherFactory().defaultGlobalDispatcher());
cf.completeWithResult(Integer.parseInt(r));
Promise<Integer> cf = Futures.promise(system.dispatcher());
cf.success(Integer.parseInt(r));
return cf;
}
}, t);
});
assertEquals(f.get(), "1000");
assertEquals(r.get().intValue(), 1000);
assertEquals(Await.result(f, timeout), "1000");
assertEquals(Await.result(r, timeout).intValue(), 1000);
assertTrue(latch.await(5000, TimeUnit.MILLISECONDS));
}
@Test
public void mustBeAbleToFilterAFuture() throws Throwable {
final CountDownLatch latch = new CountDownLatch(1);
Promise<String> cf = new akka.dispatch.DefaultPromise<String>(1000, TimeUnit.MILLISECONDS, system
.dispatcherFactory().defaultGlobalDispatcher());
Promise<String> cf = Futures.promise(system.dispatcher());
Future<String> f = cf;
Future<String> r = f.filter(new Function<String, Boolean>() {
public Boolean apply(String r) {
latch.countDown();
return r.equals("foo");
}
}, t);
});
cf.completeWithResult("foo");
cf.success("foo");
assertTrue(latch.await(5000, TimeUnit.MILLISECONDS));
assertEquals(f.get(), "foo");
assertEquals(r.get(), "foo");
assertEquals(Await.result(f, timeout), "foo");
assertEquals(Await.result(r, timeout), "foo");
}
// TODO: Improve this test, perhaps with an Actor
@ -192,16 +167,16 @@ public class JavaFutureTests {
for (int i = 0; i < 10; i++) {
listExpected.add("test");
listFutures.add(ff.future(new Callable<String>() {
listFutures.add(Futures.future(new Callable<String>() {
public String call() {
return "test";
}
}));
}, system.dispatcher()));
}
Future<Iterable<String>> futureList = ff.sequence(listFutures, t);
Future<Iterable<String>> futureList = Futures.sequence(listFutures, system.dispatcher());
assertEquals(futureList.get(), listExpected);
assertEquals(Await.result(futureList, timeout), listExpected);
}
// TODO: Improve this test, perhaps with an Actor
@ -212,20 +187,20 @@ public class JavaFutureTests {
for (int i = 0; i < 10; i++) {
expected.append("test");
listFutures.add(ff.future(new Callable<String>() {
listFutures.add(Futures.future(new Callable<String>() {
public String call() {
return "test";
}
}));
}, system.dispatcher()));
}
Future<String> result = ff.fold("", 15000, listFutures, new Function2<String, String, String>() {
Future<String> result = Futures.fold("", listFutures, new Function2<String, String, String>() {
public String apply(String r, String t) {
return r + t;
}
});
}, system.dispatcher());
assertEquals(result.get(), expected.toString());
assertEquals(Await.result(result, timeout), expected.toString());
}
@Test
@ -235,20 +210,20 @@ public class JavaFutureTests {
for (int i = 0; i < 10; i++) {
expected.append("test");
listFutures.add(ff.future(new Callable<String>() {
listFutures.add(Futures.future(new Callable<String>() {
public String call() {
return "test";
}
}));
}, system.dispatcher()));
}
Future<String> result = ff.reduce(listFutures, 15000, new Function2<String, String, String>() {
Future<String> result = Futures.reduce(listFutures, new Function2<String, String, String>() {
public String apply(String r, String t) {
return r + t;
}
});
}, system.dispatcher());
assertEquals(result.get(), expected.toString());
assertEquals(Await.result(result, timeout), expected.toString());
}
@Test
@ -261,17 +236,17 @@ public class JavaFutureTests {
listStrings.add("test");
}
Future<Iterable<String>> result = ff.traverse(listStrings, t, new Function<String, Future<String>>() {
Future<Iterable<String>> result = Futures.traverse(listStrings, new Function<String, Future<String>>() {
public Future<String> apply(final String r) {
return ff.future(new Callable<String>() {
return Futures.future(new Callable<String>() {
public String call() {
return r.toUpperCase();
}
});
}, system.dispatcher());
}
});
}, system.dispatcher());
assertEquals(result.get(), expectedStrings);
assertEquals(Await.result(result, timeout), expectedStrings);
}
@Test
@ -279,20 +254,28 @@ public class JavaFutureTests {
LinkedList<Future<Integer>> listFutures = new LinkedList<Future<Integer>>();
for (int i = 0; i < 10; i++) {
final Integer fi = i;
listFutures.add(ff.future(new Callable<Integer>() {
listFutures.add(Futures.future(new Callable<Integer>() {
public Integer call() {
return fi;
}
}));
}, system.dispatcher()));
}
final Integer expect = 5;
Future<Option<Integer>> f = ff.find(listFutures, new Function<Integer, Boolean>() {
Future<Option<Integer>> f = Futures.find(listFutures, new Function<Integer, Boolean>() {
public Boolean apply(Integer i) {
return i == 5;
}
}, t);
}, system.dispatcher());
final Integer got = f.get().get();
assertEquals(expect, got);
assertEquals(expect, Await.result(f, timeout));
}
@Test
public void BlockMustBeCallable() {
Promise<String> p = Futures.promise(system.dispatcher());
Duration d = Duration.create(1, TimeUnit.SECONDS);
p.success("foo");
Await.ready(p, d);
assertEquals(Await.result(p, d), "foo");
}
}

View file

@ -7,7 +7,7 @@ package akka.actor
import akka.testkit._
import org.scalatest.BeforeAndAfterEach
import akka.util.duration._
import akka.dispatch.Dispatchers
import akka.dispatch.Await
object ActorFireForgetRequestReplySpec {
@ -81,13 +81,13 @@ class ActorFireForgetRequestReplySpec extends AkkaSpec with BeforeAndAfterEach w
"should shutdown crashed temporary actor" in {
filterEvents(EventFilter[Exception]("Expected exception")) {
val supervisor = system.actorOf(Props[Supervisor].withFaultHandler(OneForOneStrategy(List(classOf[Exception]), Some(0))))
val actor = (supervisor ? Props[CrashingActor]).as[ActorRef].get
val actor = Await.result((supervisor ? Props[CrashingActor]).mapTo[ActorRef], timeout.duration)
actor.isTerminated must be(false)
actor ! "Die"
state.finished.await
1.second.dilated.sleep()
actor.isTerminated must be(true)
supervisor.stop()
system.stop(supervisor)
}
}
}

View file

@ -11,6 +11,7 @@ import akka.actor.Actor._
import akka.testkit._
import akka.util.duration._
import java.util.concurrent.atomic._
import akka.dispatch.Await
object ActorLifeCycleSpec {
@ -40,7 +41,7 @@ class ActorLifeCycleSpec extends AkkaSpec with BeforeAndAfterEach with ImplicitS
override def preRestart(reason: Throwable, message: Option[Any]) { report("preRestart") }
override def postRestart(reason: Throwable) { report("postRestart") }
})
val restarter = (supervisor ? restarterProps).as[ActorRef].get
val restarter = Await.result((supervisor ? restarterProps).mapTo[ActorRef], timeout.duration)
expectMsg(("preStart", id, 0))
restarter ! Kill
@ -61,7 +62,7 @@ class ActorLifeCycleSpec extends AkkaSpec with BeforeAndAfterEach with ImplicitS
restarter ! Kill
expectMsg(("postStop", id, 3))
expectNoMsg(1 seconds)
supervisor.stop
system.stop(supervisor)
}
}
@ -71,7 +72,7 @@ class ActorLifeCycleSpec extends AkkaSpec with BeforeAndAfterEach with ImplicitS
val supervisor = system.actorOf(Props[Supervisor].withFaultHandler(OneForOneStrategy(List(classOf[Exception]), Some(3))))
val gen = new AtomicInteger(0)
val restarterProps = Props(new LifeCycleTestActor(testActor, id, gen))
val restarter = (supervisor ? restarterProps).as[ActorRef].get
val restarter = Await.result((supervisor ? restarterProps).mapTo[ActorRef], timeout.duration)
expectMsg(("preStart", id, 0))
restarter ! Kill
@ -92,7 +93,7 @@ class ActorLifeCycleSpec extends AkkaSpec with BeforeAndAfterEach with ImplicitS
restarter ! Kill
expectMsg(("postStop", id, 3))
expectNoMsg(1 seconds)
supervisor.stop
system.stop(supervisor)
}
}
@ -101,14 +102,14 @@ class ActorLifeCycleSpec extends AkkaSpec with BeforeAndAfterEach with ImplicitS
val supervisor = system.actorOf(Props[Supervisor].withFaultHandler(OneForOneStrategy(List(classOf[Exception]), Some(3))))
val gen = new AtomicInteger(0)
val props = Props(new LifeCycleTestActor(testActor, id, gen))
val a = (supervisor ? props).as[ActorRef].get
val a = Await.result((supervisor ? props).mapTo[ActorRef], timeout.duration)
expectMsg(("preStart", id, 0))
a ! "status"
expectMsg(("OK", id, 0))
a.stop
system.stop(a)
expectMsg(("postStop", id, 0))
expectNoMsg(1 seconds)
supervisor.stop
system.stop(supervisor)
}
}

View file

@ -5,6 +5,7 @@ package akka.actor
import akka.testkit._
import akka.util.duration._
import akka.dispatch.Await
object ActorLookupSpec {
@ -36,7 +37,7 @@ class ActorLookupSpec extends AkkaSpec with DefaultTimeout {
val c1 = system.actorOf(p, "c1")
val c2 = system.actorOf(p, "c2")
val c21 = (c2 ? Create("c21")).as[ActorRef].get
val c21 = Await.result((c2 ? Create("c21")).mapTo[ActorRef], timeout.duration)
val user = system.asInstanceOf[ActorSystemImpl].guardian
val syst = system.asInstanceOf[ActorSystemImpl].systemGuardian
@ -122,7 +123,7 @@ class ActorLookupSpec extends AkkaSpec with DefaultTimeout {
f.isCompleted must be === false
a ! 42
f.isCompleted must be === true
f.get must be === 42
Await.result(f, timeout.duration) must be === 42
// clean-up is run as onComplete callback, i.e. dispatched on another thread
awaitCond(system.actorFor(a.path) == system.deadLetters, 1 second)
}
@ -135,7 +136,7 @@ class ActorLookupSpec extends AkkaSpec with DefaultTimeout {
"find actors by looking up their path" in {
def check(looker: ActorRef, pathOf: ActorRef, result: ActorRef) {
(looker ? LookupPath(pathOf.path)).get must be === result
Await.result(looker ? LookupPath(pathOf.path), timeout.duration) must be === result
}
for {
looker all
@ -145,8 +146,8 @@ class ActorLookupSpec extends AkkaSpec with DefaultTimeout {
"find actors by looking up their string representation" in {
def check(looker: ActorRef, pathOf: ActorRef, result: ActorRef) {
(looker ? LookupString(pathOf.path.toString)).get must be === result
(looker ? LookupString(pathOf.path.toString + "/")).get must be === result
Await.result(looker ? LookupString(pathOf.path.toString), timeout.duration) must be === result
Await.result(looker ? LookupString(pathOf.path.toString + "/"), timeout.duration) must be === result
}
for {
looker all
@ -156,8 +157,8 @@ class ActorLookupSpec extends AkkaSpec with DefaultTimeout {
"find actors by looking up their root-anchored relative path" in {
def check(looker: ActorRef, pathOf: ActorRef, result: ActorRef) {
(looker ? LookupString(pathOf.path.elements.mkString("/", "/", ""))).get must be === result
(looker ? LookupString(pathOf.path.elements.mkString("/", "/", "/"))).get must be === result
Await.result(looker ? LookupString(pathOf.path.elements.mkString("/", "/", "")), timeout.duration) must be === result
Await.result(looker ? LookupString(pathOf.path.elements.mkString("/", "/", "/")), timeout.duration) must be === result
}
for {
looker all
@ -167,9 +168,9 @@ class ActorLookupSpec extends AkkaSpec with DefaultTimeout {
"find actors by looking up their relative path" in {
def check(looker: ActorRef, result: ActorRef, elems: String*) {
(looker ? LookupElems(elems)).get must be === result
(looker ? LookupString(elems mkString "/")).get must be === result
(looker ? LookupString(elems mkString ("", "/", "/"))).get must be === result
Await.result(looker ? LookupElems(elems), timeout.duration) must be === result
Await.result(looker ? LookupString(elems mkString "/"), timeout.duration) must be === result
Await.result(looker ? LookupString(elems mkString ("", "/", "/")), timeout.duration) must be === result
}
check(c1, user, "..")
for {
@ -184,11 +185,11 @@ class ActorLookupSpec extends AkkaSpec with DefaultTimeout {
"find system-generated actors" in {
def check(target: ActorRef) {
for (looker all) {
(looker ? LookupPath(target.path)).get must be === target
(looker ? LookupString(target.path.toString)).get must be === target
(looker ? LookupString(target.path.toString + "/")).get must be === target
(looker ? LookupString(target.path.elements.mkString("/", "/", ""))).get must be === target
if (target != root) (looker ? LookupString(target.path.elements.mkString("/", "/", "/"))).get must be === target
Await.result(looker ? LookupPath(target.path), timeout.duration) must be === target
Await.result(looker ? LookupString(target.path.toString), timeout.duration) must be === target
Await.result(looker ? LookupString(target.path.toString + "/"), timeout.duration) must be === target
Await.result(looker ? LookupString(target.path.elements.mkString("/", "/", "")), timeout.duration) must be === target
if (target != root) Await.result(looker ? LookupString(target.path.elements.mkString("/", "/", "/")), timeout.duration) must be === target
}
}
for (target Seq(root, syst, user, system.deadLetters)) check(target)
@ -198,7 +199,7 @@ class ActorLookupSpec extends AkkaSpec with DefaultTimeout {
import scala.collection.JavaConverters._
def checkOne(looker: ActorRef, query: Query) {
(looker ? query).get must be === system.deadLetters
Await.result(looker ? query, timeout.duration) must be === system.deadLetters
}
def check(looker: ActorRef) {
Seq(LookupString("a/b/c"),
@ -217,21 +218,21 @@ class ActorLookupSpec extends AkkaSpec with DefaultTimeout {
val f = c1 ? GetSender(testActor)
val a = expectMsgType[ActorRef]
a.path.elements.head must be === "temp"
(c2 ? LookupPath(a.path)).get must be === a
(c2 ? LookupString(a.path.toString)).get must be === a
(c2 ? LookupString(a.path.elements.mkString("/", "/", ""))).get must be === a
(c2 ? LookupString("../../" + a.path.elements.mkString("/"))).get must be === a
(c2 ? LookupString(a.path.toString + "/")).get must be === a
(c2 ? LookupString(a.path.elements.mkString("/", "/", "") + "/")).get must be === a
(c2 ? LookupString("../../" + a.path.elements.mkString("/") + "/")).get must be === a
(c2 ? LookupElems(Seq("..", "..") ++ a.path.elements)).get must be === a
(c2 ? LookupElems(Seq("..", "..") ++ a.path.elements :+ "")).get must be === a
Await.result(c2 ? LookupPath(a.path), timeout.duration) must be === a
Await.result(c2 ? LookupString(a.path.toString), timeout.duration) must be === a
Await.result(c2 ? LookupString(a.path.elements.mkString("/", "/", "")), timeout.duration) must be === a
Await.result(c2 ? LookupString("../../" + a.path.elements.mkString("/")), timeout.duration) must be === a
Await.result(c2 ? LookupString(a.path.toString + "/"), timeout.duration) must be === a
Await.result(c2 ? LookupString(a.path.elements.mkString("/", "/", "") + "/"), timeout.duration) must be === a
Await.result(c2 ? LookupString("../../" + a.path.elements.mkString("/") + "/"), timeout.duration) must be === a
Await.result(c2 ? LookupElems(Seq("..", "..") ++ a.path.elements), timeout.duration) must be === a
Await.result(c2 ? LookupElems(Seq("..", "..") ++ a.path.elements :+ ""), timeout.duration) must be === a
f.isCompleted must be === false
a ! 42
f.isCompleted must be === true
f.get must be === 42
Await.result(f, timeout.duration) must be === 42
// clean-up is run as onComplete callback, i.e. dispatched on another thread
awaitCond((c2 ? LookupPath(a.path)).get == system.deadLetters, 1 second)
awaitCond(Await.result(c2 ? LookupPath(a.path), timeout.duration) == system.deadLetters, 1 second)
}
}

View file

@ -11,9 +11,9 @@ import akka.testkit._
import akka.util.duration._
import java.lang.IllegalStateException
import akka.util.ReflectiveAccess
import akka.dispatch.{ DefaultPromise, Promise, Future }
import akka.serialization.Serialization
import java.util.concurrent.{ CountDownLatch, TimeUnit }
import akka.dispatch.{ Await, DefaultPromise, Promise, Future }
object ActorRefSpec {
@ -42,7 +42,7 @@ object ActorRefSpec {
case "work" {
work
sender ! "workDone"
self.stop()
context.stop(self)
}
case ReplyTo(replyTo) {
work
@ -117,18 +117,18 @@ class ActorRefSpec extends AkkaSpec with DefaultTimeout {
def promiseIntercept(f: Actor)(to: Promise[Actor]): Actor = try {
val r = f
to.completeWithResult(r)
to.success(r)
r
} catch {
case e
to.completeWithException(e)
to.failure(e)
throw e
}
def wrap[T](f: Promise[Actor] T): T = {
val result = new DefaultPromise[Actor](10 * 60 * 1000)
val result = Promise[Actor]()
val r = f(result)
result.get
Await.result(result, 1 minute)
r
}
@ -306,7 +306,7 @@ class ActorRefSpec extends AkkaSpec with DefaultTimeout {
def receive = { case _ sender ! nested }
}))
val nested = (a ? "any").as[ActorRef].get
val nested = Await.result((a ? "any").mapTo[ActorRef], timeout.duration)
a must not be null
nested must not be null
(a ne nested) must be === true
@ -314,13 +314,13 @@ class ActorRefSpec extends AkkaSpec with DefaultTimeout {
"support advanced nested actorOfs" in {
val a = system.actorOf(Props(new OuterActor(system.actorOf(Props(new InnerActor)))))
val inner = (a ? "innerself").as[Any].get
val inner = Await.result(a ? "innerself", timeout.duration)
(a ? a).as[ActorRef].get must be(a)
(a ? "self").as[ActorRef].get must be(a)
Await.result(a ? a, timeout.duration) must be(a)
Await.result(a ? "self", timeout.duration) must be(a)
inner must not be a
(a ? "msg").as[String] must be === Some("msg")
Await.result(a ? "msg", timeout.duration) must be === "msg"
}
"support reply via sender" in {
@ -344,8 +344,8 @@ class ActorRefSpec extends AkkaSpec with DefaultTimeout {
latch.await
clientRef.stop()
serverRef.stop()
system.stop(clientRef)
system.stop(serverRef)
}
"stop when sent a poison pill" in {
@ -361,8 +361,8 @@ class ActorRefSpec extends AkkaSpec with DefaultTimeout {
val fnull = (ref ? (null, timeout)).mapTo[String]
ref ! PoisonPill
ffive.get must be("five")
fnull.get must be("null")
Await.result(ffive, timeout.duration) must be("five")
Await.result(fnull, timeout.duration) must be("null")
awaitCond(ref.isTerminated, 2000 millis)
}

View file

@ -4,10 +4,11 @@
package akka.actor
import org.scalatest.BeforeAndAfterAll
import akka.dispatch.FutureTimeoutException
import akka.util.duration._
import akka.testkit.AkkaSpec
import akka.testkit.DefaultTimeout
import java.util.concurrent.TimeoutException
import akka.dispatch.Await
@org.junit.runner.RunWith(classOf[org.scalatest.junit.JUnitRunner])
class ActorTimeoutSpec extends AkkaSpec with BeforeAndAfterAll with DefaultTimeout {
@ -28,8 +29,8 @@ class ActorTimeoutSpec extends AkkaSpec with BeforeAndAfterAll with DefaultTimeo
val echo = actorWithTimeout(Timeout(12))
try {
val f = echo ? "hallo"
intercept[FutureTimeoutException] { f.await }
} finally { echo.stop }
intercept[TimeoutException] { Await.ready(f, system.settings.ActorTimeout.duration) }
} finally { system.stop(echo) }
}
}
@ -39,16 +40,20 @@ class ActorTimeoutSpec extends AkkaSpec with BeforeAndAfterAll with DefaultTimeo
val echo = actorWithTimeout(Props.defaultTimeout)
try {
val f = (echo ? "hallo").mapTo[String]
intercept[FutureTimeoutException] { f.await }
intercept[TimeoutException] { Await.ready(f, timeout.duration) }
f.value must be(None)
} finally { echo.stop }
} finally { system.stop(echo) }
}
}
"use explicitly supplied timeout" in {
within(testTimeout - 100.millis, testTimeout + 300.millis) {
val echo = actorWithTimeout(Props.defaultTimeout)
try { (echo.?("hallo", testTimeout)).as[String] must be(None) } finally { echo.stop }
val f = echo.?("hallo", testTimeout)
try {
intercept[TimeoutException] { Await.ready(f, testTimeout) }
f.value must be === None
} finally { system.stop(echo) }
}
}
}

View file

@ -85,7 +85,7 @@ object Chameneos {
sumMeetings += i
if (numFaded == numChameneos) {
Chameneos.end = System.currentTimeMillis
self.stop()
context.stop(self)
}
case msg @ Meet(a, c)
@ -107,10 +107,11 @@ object Chameneos {
def run {
// System.setProperty("akka.config", "akka.conf")
Chameneos.start = System.currentTimeMillis
val system = ActorSystem().actorOf(Props(new Mall(1000000, 4)))
val system = ActorSystem()
val actor = system.actorOf(Props(new Mall(1000000, 4)))
Thread.sleep(10000)
println("Elapsed: " + (end - start))
system.stop()
system.shutdown()
}
def main(args: Array[String]): Unit = run

View file

@ -26,7 +26,7 @@ object ConsistencySpec {
}
lastStep = step
case "done" sender ! "done"; self.stop()
case "done" sender ! "done"; context.stop(self)
}
}
}

View file

@ -8,6 +8,7 @@ import org.scalatest.BeforeAndAfterEach
import akka.testkit._
import akka.util.duration._
import java.util.concurrent.atomic._
import akka.dispatch.Await
@org.junit.runner.RunWith(classOf[org.scalatest.junit.JUnitRunner])
class DeathWatchSpec extends AkkaSpec with BeforeAndAfterEach with ImplicitSender with DefaultTimeout {
@ -43,9 +44,9 @@ class DeathWatchSpec extends AkkaSpec with BeforeAndAfterEach with ImplicitSende
expectTerminationOf(terminal)
expectTerminationOf(terminal)
monitor1.stop()
monitor2.stop()
monitor3.stop()
system.stop(monitor1)
system.stop(monitor2)
system.stop(monitor3)
}
"notify with _current_ monitors with one Terminated message when an Actor is stopped" in {
@ -69,28 +70,28 @@ class DeathWatchSpec extends AkkaSpec with BeforeAndAfterEach with ImplicitSende
expectTerminationOf(terminal)
expectTerminationOf(terminal)
monitor1.stop()
monitor2.stop()
monitor3.stop()
system.stop(monitor1)
system.stop(monitor2)
system.stop(monitor3)
}
"notify with a Terminated message once when an Actor is stopped but not when restarted" in {
filterException[ActorKilledException] {
val supervisor = system.actorOf(Props[Supervisor].withFaultHandler(OneForOneStrategy(List(classOf[Exception]), Some(2))))
val terminalProps = Props(context { case x context.sender ! x })
val terminal = (supervisor ? terminalProps).as[ActorRef].get
val terminal = Await.result((supervisor ? terminalProps).mapTo[ActorRef], timeout.duration)
val monitor = startWatching(terminal)
terminal ! Kill
terminal ! Kill
(terminal ? "foo").as[String] must be === Some("foo")
Await.result(terminal ? "foo", timeout.duration) must be === "foo"
terminal ! Kill
expectTerminationOf(terminal)
terminal.isTerminated must be === true
supervisor.stop()
system.stop(supervisor)
}
}
@ -99,17 +100,17 @@ class DeathWatchSpec extends AkkaSpec with BeforeAndAfterEach with ImplicitSende
case class FF(fail: Failed)
val supervisor = system.actorOf(Props[Supervisor]
.withFaultHandler(new OneForOneStrategy(FaultHandlingStrategy.makeDecider(List(classOf[Exception])), Some(0)) {
override def handleFailure(child: ActorRef, cause: Throwable, stats: ChildRestartStats, children: Iterable[ChildRestartStats]) = {
override def handleFailure(context: ActorContext, child: ActorRef, cause: Throwable, stats: ChildRestartStats, children: Iterable[ChildRestartStats]) = {
testActor.tell(FF(Failed(cause)), child)
super.handleFailure(child, cause, stats, children)
super.handleFailure(context, child, cause, stats, children)
}
}))
val failed = (supervisor ? Props.empty).as[ActorRef].get
val brother = (supervisor ? Props(new Actor {
val failed = Await.result((supervisor ? Props.empty).mapTo[ActorRef], timeout.duration)
val brother = Await.result((supervisor ? Props(new Actor {
context.watch(failed)
def receive = Actor.emptyBehavior
})).as[ActorRef].get
})).mapTo[ActorRef], timeout.duration)
startWatching(brother)

View file

@ -95,7 +95,7 @@ class DeployerSpec extends AkkaSpec(DeployerSpec.deployerConf) {
}
""", ConfigParseOptions.defaults).withFallback(AkkaSpec.testConf)
ActorSystem("invalid", invalidDeployerConf).stop()
ActorSystem("invalid", invalidDeployerConf).shutdown()
}
}

View file

@ -187,7 +187,7 @@ class FSMActorSpec extends AkkaSpec(Map("akka.actor.debug.fsm" -> true)) with Im
}
val ref = system.actorOf(Props(fsm))
started.await
ref.stop()
system.stop(ref)
expectMsg(1 second, fsm.StopEvent(Shutdown, 1, null))
}
@ -233,7 +233,7 @@ class FSMActorSpec extends AkkaSpec(Map("akka.actor.debug.fsm" -> true)) with Im
}
}
} finally {
fsmEventSystem.stop()
fsmEventSystem.shutdown()
}
}

View file

@ -78,7 +78,7 @@ class FSMTransitionSpec extends AkkaSpec with ImplicitSender {
within(300 millis) {
fsm ! SubscribeTransitionCallBack(forward)
expectMsg(CurrentState(fsm, 0))
forward.stop()
system.stop(forward)
fsm ! "tick"
expectNoMsg
}

View file

@ -8,6 +8,7 @@ import akka.testkit._
import akka.util.duration._
import Actor._
import akka.util.Duration
import akka.dispatch.Await
object ForwardActorSpec {
val ExpectedMessage = "FOO"
@ -32,20 +33,21 @@ class ForwardActorSpec extends AkkaSpec {
"A Forward Actor" must {
"forward actor reference when invoking forward on bang" in {
"forward actor reference when invoking forward on tell" in {
val latch = new TestLatch(1)
val replyTo = system.actorOf(Props(new Actor { def receive = { case ExpectedMessage latch.countDown() } }))
val replyTo = system.actorOf(Props(new Actor { def receive = { case ExpectedMessage testActor ! ExpectedMessage } }))
val chain = createForwardingChain(system)
chain.tell(ExpectedMessage, replyTo)
latch.await(Duration(5, "s")) must be === true
expectMsg(5 seconds, ExpectedMessage)
}
"forward actor reference when invoking forward on bang bang" in {
"forward actor reference when invoking forward on ask" in {
val chain = createForwardingChain(system)
chain.ask(ExpectedMessage, 5000).get must be === ExpectedMessage
chain.ask(ExpectedMessage, 5000) onSuccess { case ExpectedMessage testActor ! ExpectedMessage }
expectMsg(5 seconds, ExpectedMessage)
}
}
}

View file

@ -8,9 +8,9 @@ import org.scalatest.BeforeAndAfterEach
import akka.util.ByteString
import akka.util.cps._
import akka.dispatch.Future
import scala.util.continuations._
import akka.testkit._
import akka.dispatch.{ Await, Future }
object IOActorSpec {
import IO._
@ -193,12 +193,12 @@ class IOActorSpec extends AkkaSpec with BeforeAndAfterEach with DefaultTimeout {
val f1 = client ? ByteString("Hello World!1")
val f2 = client ? ByteString("Hello World!2")
val f3 = client ? ByteString("Hello World!3")
f1.get must equal(ByteString("Hello World!1"))
f2.get must equal(ByteString("Hello World!2"))
f3.get must equal(ByteString("Hello World!3"))
client.stop
server.stop
ioManager.stop
Await.result(f1, timeout.duration) must equal(ByteString("Hello World!1"))
Await.result(f2, timeout.duration) must equal(ByteString("Hello World!2"))
Await.result(f3, timeout.duration) must equal(ByteString("Hello World!3"))
system.stop(client)
system.stop(server)
system.stop(ioManager)
}
"run echo server under high load" in {
@ -209,10 +209,10 @@ class IOActorSpec extends AkkaSpec with BeforeAndAfterEach with DefaultTimeout {
val client = system.actorOf(Props(new SimpleEchoClient("localhost", 8065, ioManager)))
val list = List.range(0, 1000)
val f = Future.traverse(list)(i client ? ByteString(i.toString))
assert(f.get.size === 1000)
client.stop
server.stop
ioManager.stop
assert(Await.result(f, timeout.duration).size === 1000)
system.stop(client)
system.stop(server)
system.stop(ioManager)
}
"run echo server under high load with small buffer" in {
@ -223,10 +223,10 @@ class IOActorSpec extends AkkaSpec with BeforeAndAfterEach with DefaultTimeout {
val client = system.actorOf(Props(new SimpleEchoClient("localhost", 8066, ioManager)))
val list = List.range(0, 1000)
val f = Future.traverse(list)(i client ? ByteString(i.toString))
assert(f.get.size === 1000)
client.stop
server.stop
ioManager.stop
assert(Await.result(f, timeout.duration).size === 1000)
system.stop(client)
system.stop(server)
system.stop(ioManager)
}
"run key-value store" in {
@ -239,21 +239,21 @@ class IOActorSpec extends AkkaSpec with BeforeAndAfterEach with DefaultTimeout {
val f1 = client1 ? (('set, "hello", ByteString("World")))
val f2 = client1 ? (('set, "test", ByteString("No one will read me")))
val f3 = client1 ? (('get, "hello"))
f2.await
Await.ready(f2, timeout.duration)
val f4 = client2 ? (('set, "test", ByteString("I'm a test!")))
f4.await
Await.ready(f4, timeout.duration)
val f5 = client1 ? (('get, "test"))
val f6 = client2 ? 'getall
f1.get must equal("OK")
f2.get must equal("OK")
f3.get must equal(ByteString("World"))
f4.get must equal("OK")
f5.get must equal(ByteString("I'm a test!"))
f6.get must equal(Map("hello" -> ByteString("World"), "test" -> ByteString("I'm a test!")))
client1.stop
client2.stop
server.stop
ioManager.stop
Await.result(f1, timeout.duration) must equal("OK")
Await.result(f2, timeout.duration) must equal("OK")
Await.result(f3, timeout.duration) must equal(ByteString("World"))
Await.result(f4, timeout.duration) must equal("OK")
Await.result(f5, timeout.duration) must equal(ByteString("I'm a test!"))
Await.result(f6, timeout.duration) must equal(Map("hello" -> ByteString("World"), "test" -> ByteString("I'm a test!")))
system.stop(client1)
system.stop(client2)
system.stop(server)
system.stop(ioManager)
}
}

View file

@ -6,7 +6,7 @@ package akka.actor
import akka.testkit._
import akka.util.duration._
import akka.dispatch.Future
import akka.dispatch.{ Await, Future }
@org.junit.runner.RunWith(classOf[org.scalatest.junit.JUnitRunner])
class LocalActorRefProviderSpec extends AkkaSpec {
@ -32,7 +32,7 @@ class LocalActorRefProviderSpec extends AkkaSpec {
val address = "new-actor" + i
implicit val timeout = Timeout(5 seconds)
val actors = for (j 1 to 4) yield Future(system.actorOf(Props(c { case _ }), address))
val set = Set() ++ actors.map(_.await.value match {
val set = Set() ++ actors.map(a Await.ready(a, timeout.duration).value match {
case Some(Right(a: ActorRef)) 1
case Some(Left(ex: InvalidActorNameException)) 2
case x x

View file

@ -26,7 +26,7 @@ class ReceiveTimeoutSpec extends AkkaSpec {
}))
timeoutLatch.await
timeoutActor.stop()
system.stop(timeoutActor)
}
"reschedule timeout after regular receive" in {
@ -45,7 +45,7 @@ class ReceiveTimeoutSpec extends AkkaSpec {
timeoutActor ! Tick
timeoutLatch.await
timeoutActor.stop()
system.stop(timeoutActor)
}
"be able to turn off timeout if desired" in {
@ -69,7 +69,7 @@ class ReceiveTimeoutSpec extends AkkaSpec {
timeoutLatch.await
count.get must be(1)
timeoutActor.stop()
system.stop(timeoutActor)
}
"not receive timeout message when not specified" in {
@ -82,7 +82,7 @@ class ReceiveTimeoutSpec extends AkkaSpec {
}))
timeoutLatch.awaitTimeout(1 second) // timeout expected
timeoutActor.stop()
system.stop(timeoutActor)
}
"have ReceiveTimeout eq to Actors ReceiveTimeout" in {

View file

@ -6,6 +6,7 @@ package akka.actor
import java.lang.Thread.sleep
import org.scalatest.BeforeAndAfterAll
import akka.dispatch.Await
import akka.testkit.TestEvent._
import akka.testkit.EventFilter
import java.util.concurrent.{ TimeUnit, CountDownLatch }
@ -52,7 +53,7 @@ class RestartStrategySpec extends AkkaSpec with DefaultTimeout {
stopLatch.open()
}
})
val slave = (boss ? slaveProps).as[ActorRef].get
val slave = Await.result((boss ? slaveProps).mapTo[ActorRef], timeout.duration)
slave ! Ping
slave ! Crash
@ -87,7 +88,7 @@ class RestartStrategySpec extends AkkaSpec with DefaultTimeout {
countDownLatch.countDown()
}
})
val slave = (boss ? slaveProps).as[ActorRef].get
val slave = Await.result((boss ? slaveProps).mapTo[ActorRef], timeout.duration)
(1 to 100) foreach { _ slave ! Crash }
assert(countDownLatch.await(120, TimeUnit.SECONDS))
@ -125,7 +126,7 @@ class RestartStrategySpec extends AkkaSpec with DefaultTimeout {
}
}
})
val slave = (boss ? slaveProps).as[ActorRef].get
val slave = Await.result((boss ? slaveProps).mapTo[ActorRef], timeout.duration)
slave ! Ping
slave ! Crash
@ -176,7 +177,7 @@ class RestartStrategySpec extends AkkaSpec with DefaultTimeout {
stopLatch.open()
}
})
val slave = (boss ? slaveProps).as[ActorRef].get
val slave = Await.result((boss ? slaveProps).mapTo[ActorRef], timeout.duration)
slave ! Ping
slave ! Crash
@ -228,7 +229,7 @@ class RestartStrategySpec extends AkkaSpec with DefaultTimeout {
stopLatch.open()
}
})
val slave = (boss ? slaveProps).as[ActorRef].get
val slave = Await.result((boss ? slaveProps).mapTo[ActorRef], timeout.duration)
slave ! Ping
slave ! Crash

View file

@ -7,6 +7,7 @@ import akka.util.duration._
import java.util.concurrent.{ CountDownLatch, ConcurrentLinkedQueue, TimeUnit }
import akka.testkit.DefaultTimeout
import akka.testkit.TestLatch
import akka.dispatch.Await
@org.junit.runner.RunWith(classOf[org.scalatest.junit.JUnitRunner])
class SchedulerSpec extends AkkaSpec with BeforeAndAfterEach with DefaultTimeout {
@ -113,7 +114,7 @@ class SchedulerSpec extends AkkaSpec with BeforeAndAfterEach with DefaultTimeout
override def postRestart(reason: Throwable) = restartLatch.open
})
val actor = (supervisor ? props).as[ActorRef].get
val actor = Await.result((supervisor ? props).mapTo[ActorRef], timeout.duration)
collectCancellable(system.scheduler.schedule(500 milliseconds, 500 milliseconds, actor, Ping))
// appx 2 pings before crash

View file

@ -7,4 +7,6 @@ class Supervisor extends Actor {
def receive = {
case x: Props sender ! context.actorOf(x)
}
// need to override the default of stopping all children upon restart, tests rely on keeping them around
override def preRestart(cause: Throwable, msg: Option[Any]) {}
}

View file

@ -7,6 +7,7 @@ package akka.actor
import akka.testkit._
import java.util.concurrent.{ TimeUnit, CountDownLatch }
import akka.dispatch.Await
object SupervisorHierarchySpec {
class FireWorkerException(msg: String) extends Exception(msg)
@ -15,6 +16,8 @@ object SupervisorHierarchySpec {
protected def receive = {
case p: Props sender ! context.actorOf(p)
}
// test relies on keeping children around during restart
override def preRestart(cause: Throwable, msg: Option[Any]) {}
override def postRestart(reason: Throwable) = {
countDown.countDown()
}
@ -33,10 +36,10 @@ class SupervisorHierarchySpec extends AkkaSpec with DefaultTimeout {
val boss = system.actorOf(Props[Supervisor].withFaultHandler(OneForOneStrategy(List(classOf[Exception]), None, None)))
val managerProps = Props(new CountDownActor(countDown)).withFaultHandler(AllForOneStrategy(List(), None, None))
val manager = (boss ? managerProps).as[ActorRef].get
val manager = Await.result((boss ? managerProps).mapTo[ActorRef], timeout.duration)
val workerProps = Props(new CountDownActor(countDown))
val workerOne, workerTwo, workerThree = (manager ? workerProps).as[ActorRef].get
val workerOne, workerTwo, workerThree = Await.result((manager ? workerProps).mapTo[ActorRef], timeout.duration)
filterException[ActorKilledException] {
workerOne ! Kill

View file

@ -4,7 +4,7 @@
package akka.actor
import akka.testkit.{ filterEvents, EventFilter }
import akka.dispatch.{ PinnedDispatcher, Dispatchers }
import akka.dispatch.{ PinnedDispatcher, Dispatchers, Await }
import java.util.concurrent.{ TimeUnit, CountDownLatch }
import akka.testkit.AkkaSpec
import akka.testkit.DefaultTimeout
@ -24,17 +24,15 @@ class SupervisorMiscSpec extends AkkaSpec with DefaultTimeout {
override def postRestart(cause: Throwable) { countDownLatch.countDown() }
protected def receive = {
case "status" this.sender ! "OK"
case _ this.self.stop()
case _ this.context.stop(self)
}
})
val actor1 = (supervisor ? workerProps.withDispatcher(system.dispatcherFactory.newPinnedDispatcher("pinned"))).as[ActorRef].get
val actor1, actor2 = Await.result((supervisor ? workerProps.withDispatcher(system.dispatcherFactory.newPinnedDispatcher("pinned"))).mapTo[ActorRef], timeout.duration)
val actor2 = (supervisor ? workerProps.withDispatcher(system.dispatcherFactory.newPinnedDispatcher("pinned"))).as[ActorRef].get
val actor3 = Await.result((supervisor ? workerProps.withDispatcher(system.dispatcherFactory.newDispatcher("test").build)).mapTo[ActorRef], timeout.duration)
val actor3 = (supervisor ? workerProps.withDispatcher(system.dispatcherFactory.newDispatcher("test").build)).as[ActorRef].get
val actor4 = (supervisor ? workerProps.withDispatcher(system.dispatcherFactory.newPinnedDispatcher("pinned"))).as[ActorRef].get
val actor4 = Await.result((supervisor ? workerProps.withDispatcher(system.dispatcherFactory.newPinnedDispatcher("pinned"))).mapTo[ActorRef], timeout.duration)
actor1 ! Kill
actor2 ! Kill
@ -42,10 +40,10 @@ class SupervisorMiscSpec extends AkkaSpec with DefaultTimeout {
actor4 ! Kill
countDownLatch.await(10, TimeUnit.SECONDS)
assert((actor1 ? "status").as[String].get == "OK", "actor1 is shutdown")
assert((actor2 ? "status").as[String].get == "OK", "actor2 is shutdown")
assert((actor3 ? "status").as[String].get == "OK", "actor3 is shutdown")
assert((actor4 ? "status").as[String].get == "OK", "actor4 is shutdown")
assert(Await.result(actor1 ? "status", timeout.duration) == "OK", "actor1 is shutdown")
assert(Await.result(actor2 ? "status", timeout.duration) == "OK", "actor2 is shutdown")
assert(Await.result(actor3 ? "status", timeout.duration) == "OK", "actor3 is shutdown")
assert(Await.result(actor4 ? "status", timeout.duration) == "OK", "actor4 is shutdown")
}
}
}

View file

@ -7,11 +7,10 @@ package akka.actor
import org.scalatest.BeforeAndAfterEach
import akka.util.duration._
import akka.{ Die, Ping }
import akka.actor.Actor._
import akka.testkit.TestEvent._
import akka.testkit._
import java.util.concurrent.atomic.AtomicInteger
import java.util.concurrent.LinkedBlockingQueue
import akka.dispatch.Await
object SupervisorSpec {
val Timeout = 5 seconds
@ -73,7 +72,7 @@ class SupervisorSpec extends AkkaSpec with BeforeAndAfterEach with ImplicitSende
// Creating actors and supervisors
// =====================================================
private def child(supervisor: ActorRef, props: Props): ActorRef = (supervisor ? props).as[ActorRef].get
private def child(supervisor: ActorRef, props: Props): ActorRef = Await.result((supervisor ? props).mapTo[ActorRef], props.timeout.duration)
def temporaryActorAllForOne = {
val supervisor = system.actorOf(Props[Supervisor].withFaultHandler(AllForOneStrategy(List(classOf[Exception]), Some(0))))
@ -129,14 +128,14 @@ class SupervisorSpec extends AkkaSpec with BeforeAndAfterEach with ImplicitSende
}
def ping(pingPongActor: ActorRef) = {
(pingPongActor.?(Ping, TimeoutMillis)).as[String] must be === Some(PongMessage)
Await.result(pingPongActor.?(Ping, TimeoutMillis), TimeoutMillis millis) must be === PongMessage
expectMsg(Timeout, PingMessage)
}
def kill(pingPongActor: ActorRef) = {
val result = (pingPongActor ? (DieReply, TimeoutMillis))
expectMsg(Timeout, ExceptionMessage)
intercept[RuntimeException] { result.get }
intercept[RuntimeException] { Await.result(result, TimeoutMillis millis) }
}
"A supervisor" must {
@ -152,7 +151,7 @@ class SupervisorSpec extends AkkaSpec with BeforeAndAfterEach with ImplicitSende
"not restart temporary actor" in {
val (temporaryActor, _) = temporaryActorAllForOne
intercept[RuntimeException] { (temporaryActor.?(DieReply, TimeoutMillis)).get }
intercept[RuntimeException] { Await.result(temporaryActor.?(DieReply, TimeoutMillis), TimeoutMillis millis) }
expectNoMsg(1 second)
}
@ -293,20 +292,20 @@ class SupervisorSpec extends AkkaSpec with BeforeAndAfterEach with ImplicitSende
throw e
}
})
val dyingActor = (supervisor ? dyingProps).as[ActorRef].get
val dyingActor = Await.result((supervisor ? dyingProps).mapTo[ActorRef], timeout.duration)
filterEvents(EventFilter[RuntimeException]("Expected", occurrences = 1),
EventFilter[IllegalStateException]("error while creating actor", occurrences = 1)) {
intercept[RuntimeException] {
(dyingActor.?(DieReply, TimeoutMillis)).get
Await.result(dyingActor.?(DieReply, TimeoutMillis), TimeoutMillis millis)
}
}
(dyingActor.?(Ping, TimeoutMillis)).as[String] must be === Some(PongMessage)
Await.result(dyingActor.?(Ping, TimeoutMillis), TimeoutMillis millis) must be === PongMessage
inits.get must be(3)
supervisor.stop()
system.stop(supervisor)
}
}
}

View file

@ -6,12 +6,12 @@ package akka.actor
import org.scalatest.WordSpec
import org.scalatest.matchers.MustMatchers
import akka.util.duration._
import akka.dispatch.Dispatchers
import akka.actor.Actor._
import akka.testkit.{ TestKit, EventFilter, filterEvents, filterException }
import akka.testkit.AkkaSpec
import akka.testkit.ImplicitSender
import akka.testkit.DefaultTimeout
import akka.dispatch.{ Await, Dispatchers }
@org.junit.runner.RunWith(classOf[org.scalatest.junit.JUnitRunner])
class SupervisorTreeSpec extends AkkaSpec with ImplicitSender with DefaultTimeout {
@ -28,14 +28,14 @@ class SupervisorTreeSpec extends AkkaSpec with ImplicitSender with DefaultTimeou
override def preRestart(cause: Throwable, msg: Option[Any]) { testActor ! self.path }
}).withFaultHandler(OneForOneStrategy(List(classOf[Exception]), 3, 1000))
val headActor = system.actorOf(p)
val middleActor = (headActor ? p).as[ActorRef].get
val lastActor = (middleActor ? p).as[ActorRef].get
val middleActor = Await.result((headActor ? p).mapTo[ActorRef], timeout.duration)
val lastActor = Await.result((middleActor ? p).mapTo[ActorRef], timeout.duration)
middleActor ! Kill
expectMsg(middleActor.path)
expectMsg(lastActor.path)
expectNoMsg(2 seconds)
headActor.stop()
system.stop(headActor)
}
}
}

View file

@ -10,6 +10,7 @@ import akka.testkit.{ TestKit, filterEvents, EventFilter }
import akka.testkit.AkkaSpec
import akka.testkit.ImplicitSender
import akka.testkit.DefaultTimeout
import akka.dispatch.Await
@org.junit.runner.RunWith(classOf[org.scalatest.junit.JUnitRunner])
class Ticket669Spec extends AkkaSpec with BeforeAndAfterAll with ImplicitSender with DefaultTimeout {
@ -24,22 +25,22 @@ class Ticket669Spec extends AkkaSpec with BeforeAndAfterAll with ImplicitSender
"be able to reply on failure during preRestart" in {
filterEvents(EventFilter[Exception]("test", occurrences = 1)) {
val supervisor = system.actorOf(Props[Supervisor].withFaultHandler(AllForOneStrategy(List(classOf[Exception]), 5, 10000)))
val supervised = (supervisor ? Props[Supervised]).as[ActorRef].get
val supervised = Await.result((supervisor ? Props[Supervised]).mapTo[ActorRef], timeout.duration)
supervised.!("test")(testActor)
expectMsg("failure1")
supervisor.stop()
system.stop(supervisor)
}
}
"be able to reply on failure during postStop" in {
filterEvents(EventFilter[Exception]("test", occurrences = 1)) {
val supervisor = system.actorOf(Props[Supervisor].withFaultHandler(AllForOneStrategy(List(classOf[Exception]), Some(0), None)))
val supervised = (supervisor ? Props[Supervised]).as[ActorRef].get
val supervised = Await.result((supervisor ? Props[Supervised]).mapTo[ActorRef], timeout.duration)
supervised.!("test")(testActor)
expectMsg("failure2")
supervisor.stop()
system.stop(supervisor)
}
}
}

View file

@ -7,7 +7,6 @@ package akka.actor
import org.scalatest.{ BeforeAndAfterAll, BeforeAndAfterEach }
import akka.util.Duration
import akka.util.duration._
import akka.dispatch.{ Dispatchers, Future, KeptPromise }
import akka.serialization.Serialization
import java.util.concurrent.atomic.AtomicReference
import annotation.tailrec
@ -17,6 +16,7 @@ import akka.actor.TypedActor.{ PostRestart, PreRestart, PostStop, PreStart }
import java.util.concurrent.{ TimeUnit, CountDownLatch }
import akka.japi.{ Creator, Option JOption }
import akka.testkit.DefaultTimeout
import akka.dispatch.{ Await, Dispatchers, Future, Promise }
object TypedActorSpec {
@ -85,7 +85,7 @@ object TypedActorSpec {
def pigdog = "Pigdog"
def futurePigdog(): Future[String] = new KeptPromise(Right(pigdog))
def futurePigdog(): Future[String] = Promise.successful(pigdog)
def futurePigdog(delay: Long): Future[String] = {
Thread.sleep(delay)
@ -94,7 +94,7 @@ object TypedActorSpec {
def futurePigdog(delay: Long, numbered: Int): Future[String] = {
Thread.sleep(delay)
new KeptPromise(Right(pigdog + numbered))
Promise.successful(pigdog + numbered)
}
def futureComposePigdogFrom(foo: Foo): Future[String] = {
@ -247,7 +247,7 @@ class TypedActorSpec extends AkkaSpec with BeforeAndAfterEach with BeforeAndAfte
val t = newFooBar
val f = t.futurePigdog(200)
f.isCompleted must be(false)
f.get must be("Pigdog")
Await.result(f, timeout.duration) must be("Pigdog")
mustStop(t)
}
@ -255,7 +255,7 @@ class TypedActorSpec extends AkkaSpec with BeforeAndAfterEach with BeforeAndAfte
val t = newFooBar
val futures = for (i 1 to 20) yield (i, t.futurePigdog(20, i))
for ((i, f) futures) {
f.get must be("Pigdog" + i)
Await.result(f, timeout.duration) must be("Pigdog" + i)
}
mustStop(t)
}
@ -278,7 +278,7 @@ class TypedActorSpec extends AkkaSpec with BeforeAndAfterEach with BeforeAndAfte
val t, t2 = newFooBar(Duration(2, "s"))
val f = t.futureComposePigdogFrom(t2)
f.isCompleted must be(false)
f.get must equal("PIGDOG")
Await.result(f, timeout.duration) must equal("PIGDOG")
mustStop(t)
mustStop(t2)
}
@ -290,13 +290,13 @@ class TypedActorSpec extends AkkaSpec with BeforeAndAfterEach with BeforeAndAfte
}).withFaultHandler(OneForOneStrategy {
case e: IllegalStateException if e.getMessage == "expected" FaultHandlingStrategy.Resume
}))
val t = (boss ? Props().withTimeout(2 seconds)).as[Foo].get
val t = Await.result((boss ? Props().withTimeout(2 seconds)).mapTo[Foo], timeout.duration)
t.incr()
t.failingPigdog()
t.read() must be(1) //Make sure state is not reset after failure
t.failingFuturePigdog.await.exception.get.getMessage must be("expected")
intercept[IllegalStateException] { Await.result(t.failingFuturePigdog, 2 seconds) }.getMessage must be("expected")
t.read() must be(1) //Make sure state is not reset after failure
(intercept[IllegalStateException] { t.failingJOptionPigdog }).getMessage must be("expected")
@ -323,7 +323,7 @@ class TypedActorSpec extends AkkaSpec with BeforeAndAfterEach with BeforeAndAfte
val f2 = t.futurePigdog(0)
f2.isCompleted must be(false)
f.isCompleted must be(false)
f.get must equal(f2.get)
Await.result(f, timeout.duration) must equal(Await.result(f2, timeout.duration))
mustStop(t)
}
@ -348,7 +348,7 @@ class TypedActorSpec extends AkkaSpec with BeforeAndAfterEach with BeforeAndAfte
val results = for (i 1 to 120) yield (i, iterator.next.futurePigdog(200L, i))
for ((i, r) results) r.get must be("Pigdog" + i)
for ((i, r) results) Await.result(r, timeout.duration) must be("Pigdog" + i)
for (t thais) mustStop(t)
}

View file

@ -31,7 +31,7 @@ object ActorModelSpec {
case class Increment(counter: AtomicLong) extends ActorModelMessage
case class Await(latch: CountDownLatch) extends ActorModelMessage
case class AwaitLatch(latch: CountDownLatch) extends ActorModelMessage
case class Meet(acknowledge: CountDownLatch, waitFor: CountDownLatch) extends ActorModelMessage
@ -68,7 +68,7 @@ object ActorModelSpec {
}
def receive = {
case Await(latch) ack; latch.await(); busy.switchOff()
case AwaitLatch(latch) ack; latch.await(); busy.switchOff()
case Meet(sign, wait) ack; sign.countDown(); wait.await(); busy.switchOff()
case Wait(time) ack; Thread.sleep(time); busy.switchOff()
case WaitAck(time, l) ack; Thread.sleep(time); l.countDown(); busy.switchOff()
@ -77,7 +77,7 @@ object ActorModelSpec {
case Forward(to, msg) ack; to.forward(msg); busy.switchOff()
case CountDown(latch) ack; latch.countDown(); busy.switchOff()
case Increment(count) ack; count.incrementAndGet(); busy.switchOff()
case CountDownNStop(l) ack; l.countDown(); self.stop(); busy.switchOff()
case CountDownNStop(l) ack; l.countDown(); context.stop(self); busy.switchOff()
case Restart ack; busy.switchOff(); throw new Exception("Restart requested")
case Interrupt ack; sender ! Status.Failure(new ActorInterruptedException(new InterruptedException("Ping!"))); busy.switchOff(); throw new InterruptedException("Ping!")
case ThrowException(e: Throwable) ack; busy.switchOff(); throw e
@ -239,7 +239,7 @@ abstract class ActorModelSpec extends AkkaSpec with DefaultTimeout {
assertDispatcher(dispatcher)(stops = 0)
val a = newTestActor(dispatcher)
assertDispatcher(dispatcher)(stops = 0)
a.stop()
system.stop(a)
assertDispatcher(dispatcher)(stops = 1)
assertRef(a, dispatcher)(
suspensions = 0,
@ -260,7 +260,7 @@ abstract class ActorModelSpec extends AkkaSpec with DefaultTimeout {
assertDispatcher(dispatcher)(stops = 2)
a2.stop
system.stop(a2)
assertDispatcher(dispatcher)(stops = 3)
}
@ -279,7 +279,7 @@ abstract class ActorModelSpec extends AkkaSpec with DefaultTimeout {
assertCountDown(oneAtATime, (1.5 seconds).dilated.toMillis, "Processed message when allowed")
assertRefDefaultZero(a)(registers = 1, msgsReceived = 3, msgsProcessed = 3)
a.stop()
system.stop(a)
assertRefDefaultZero(a)(registers = 1, unregisters = 1, msgsReceived = 3, msgsProcessed = 3)
}
@ -298,7 +298,7 @@ abstract class ActorModelSpec extends AkkaSpec with DefaultTimeout {
assertCountDown(counter, 3.seconds.dilated.toMillis, "Should process 200 messages")
assertRefDefaultZero(a)(registers = 1, msgsReceived = 200, msgsProcessed = 200)
a.stop()
system.stop(a)
}
def spawn(f: Unit) {
@ -328,7 +328,7 @@ abstract class ActorModelSpec extends AkkaSpec with DefaultTimeout {
assertRefDefaultZero(a)(registers = 1, msgsReceived = 1, msgsProcessed = 1,
suspensions = 1, resumes = 1)
a.stop()
system.stop(a)
assertRefDefaultZero(a)(registers = 1, unregisters = 1, msgsReceived = 1, msgsProcessed = 1,
suspensions = 1, resumes = 1)
}
@ -370,7 +370,7 @@ abstract class ActorModelSpec extends AkkaSpec with DefaultTimeout {
throw e
}
assertCountDown(stopLatch, waitTime, "Expected all children to stop")
boss.stop()
system.stop(boss)
}
for (run 1 to 3) {
flood(50000)
@ -385,17 +385,17 @@ abstract class ActorModelSpec extends AkkaSpec with DefaultTimeout {
val a = newTestActor(dispatcher)
val f1 = a ? Reply("foo")
val f2 = a ? Reply("bar")
val f3 = try { a ? Interrupt } catch { case ie: InterruptedException new KeptPromise(Left(ActorInterruptedException(ie))) }
val f3 = try { a ? Interrupt } catch { case ie: InterruptedException Promise.failed(ActorInterruptedException(ie)) }
val f4 = a ? Reply("foo2")
val f5 = try { a ? Interrupt } catch { case ie: InterruptedException new KeptPromise(Left(ActorInterruptedException(ie))) }
val f5 = try { a ? Interrupt } catch { case ie: InterruptedException Promise.failed(ActorInterruptedException(ie)) }
val f6 = a ? Reply("bar2")
assert(f1.get === "foo")
assert(f2.get === "bar")
assert(f4.get === "foo2")
assert(intercept[ActorInterruptedException](f3.get).getMessage === "Ping!")
assert(f6.get === "bar2")
assert(intercept[ActorInterruptedException](f5.get).getMessage === "Ping!")
assert(Await.result(f1, timeout.duration) === "foo")
assert(Await.result(f2, timeout.duration) === "bar")
assert(Await.result(f4, timeout.duration) === "foo2")
assert(intercept[ActorInterruptedException](Await.result(f3, timeout.duration)).getMessage === "Ping!")
assert(Await.result(f6, timeout.duration) === "bar2")
assert(intercept[ActorInterruptedException](Await.result(f5, timeout.duration)).getMessage === "Ping!")
}
}
@ -410,12 +410,12 @@ abstract class ActorModelSpec extends AkkaSpec with DefaultTimeout {
val f5 = a ? ThrowException(new RemoteException("RemoteException"))
val f6 = a ? Reply("bar2")
assert(f1.get === "foo")
assert(f2.get === "bar")
assert(f4.get === "foo2")
assert(f6.get === "bar2")
assert(f3.result === None)
assert(f5.result === None)
assert(Await.result(f1, timeout.duration) === "foo")
assert(Await.result(f2, timeout.duration) === "bar")
assert(Await.result(f4, timeout.duration) === "foo2")
assert(Await.result(f6, timeout.duration) === "bar2")
assert(f3.value.isEmpty)
assert(f5.value.isEmpty)
}
}
}
@ -447,8 +447,8 @@ class DispatcherModelSpec extends ActorModelSpec {
aStop.countDown()
a.stop
b.stop
system.stop(a)
system.stop(b)
while (!a.isTerminated && !b.isTerminated) {} //Busy wait for termination
@ -484,8 +484,8 @@ class BalancingDispatcherModelSpec extends ActorModelSpec {
aStop.countDown()
a.stop
b.stop
system.stop(a)
system.stop(b)
while (!a.isTerminated && !b.isTerminated) {} //Busy wait for termination

View file

@ -74,8 +74,8 @@ class BalancingDispatcherSpec extends AkkaSpec {
fast.underlying.actor.asInstanceOf[DelayableActor].invocationCount must be > sentToFast
fast.underlying.actor.asInstanceOf[DelayableActor].invocationCount must be >
(slow.underlying.actor.asInstanceOf[DelayableActor].invocationCount)
slow.stop()
fast.stop()
system.stop(slow)
system.stop(fast)
}
}
}

View file

@ -3,11 +3,11 @@ package akka.actor.dispatch
import java.util.concurrent.{ CountDownLatch, TimeUnit }
import java.util.concurrent.atomic.{ AtomicBoolean, AtomicInteger }
import akka.testkit.{ filterEvents, EventFilter, AkkaSpec }
import akka.dispatch.{ PinnedDispatcher, Dispatchers, Dispatcher }
import akka.actor.{ Props, Actor }
import akka.util.Duration
import akka.util.duration._
import akka.testkit.DefaultTimeout
import akka.dispatch.{ Await, PinnedDispatcher, Dispatchers, Dispatcher }
object DispatcherActorSpec {
class TestActor extends Actor {
@ -39,14 +39,13 @@ class DispatcherActorSpec extends AkkaSpec with DefaultTimeout {
val actor = system.actorOf(Props[OneWayTestActor].withDispatcher(system.dispatcherFactory.newDispatcher("test").build))
val result = actor ! "OneWay"
assert(OneWayTestActor.oneWay.await(1, TimeUnit.SECONDS))
actor.stop()
system.stop(actor)
}
"support ask/reply" in {
val actor = system.actorOf(Props[TestActor].withDispatcher(system.dispatcherFactory.newDispatcher("test").build))
val result = (actor ? "Hello").as[String]
assert("World" === result.get)
actor.stop()
assert("World" === Await.result(actor ? "Hello", timeout.duration))
system.stop(actor)
}
"respect the throughput setting" in {
@ -67,13 +66,13 @@ class DispatcherActorSpec extends AkkaSpec with DefaultTimeout {
case "ping" if (works.get) latch.countDown()
}).withDispatcher(throughputDispatcher))
assert((slowOne ? "hogexecutor").get === "OK")
assert(Await.result(slowOne ? "hogexecutor", timeout.duration) === "OK")
(1 to 100) foreach { _ slowOne ! "ping" }
fastOne ! "sabotage"
start.countDown()
latch.await(10, TimeUnit.SECONDS)
fastOne.stop()
slowOne.stop()
system.stop(fastOne)
system.stop(slowOne)
assert(latch.getCount() === 0)
}
@ -90,13 +89,13 @@ class DispatcherActorSpec extends AkkaSpec with DefaultTimeout {
val fastOne = system.actorOf(
Props(context {
case "ping" if (works.get) latch.countDown(); context.self.stop()
case "ping" if (works.get) latch.countDown(); context.stop(context.self)
}).withDispatcher(throughputDispatcher))
val slowOne = system.actorOf(
Props(context {
case "hogexecutor" ready.countDown(); start.await
case "ping" works.set(false); context.self.stop()
case "ping" works.set(false); context.stop(context.self)
}).withDispatcher(throughputDispatcher))
slowOne ! "hogexecutor"

View file

@ -49,8 +49,8 @@ class DispatcherActorsSpec extends AkkaSpec {
assert(sFinished.getCount > 0)
sFinished.await
assert(sFinished.getCount === 0)
f.stop()
s.stop()
system.stop(f)
system.stop(s)
}
}
}

View file

@ -3,10 +3,10 @@ package akka.actor.dispatch
import java.util.concurrent.{ CountDownLatch, TimeUnit }
import akka.testkit._
import akka.dispatch.{ PinnedDispatcher, Dispatchers }
import akka.actor.{ Props, Actor }
import akka.testkit.AkkaSpec
import org.scalatest.BeforeAndAfterEach
import akka.dispatch.{ Await, PinnedDispatcher, Dispatchers }
object PinnedActorSpec {
class TestActor extends Actor {
@ -30,14 +30,13 @@ class PinnedActorSpec extends AkkaSpec with BeforeAndAfterEach with DefaultTimeo
val actor = system.actorOf(Props(self { case "OneWay" oneWay.countDown() }).withDispatcher(system.dispatcherFactory.newPinnedDispatcher("test")))
val result = actor ! "OneWay"
assert(oneWay.await(1, TimeUnit.SECONDS))
actor.stop()
system.stop(actor)
}
"support ask/reply" in {
val actor = system.actorOf(Props[TestActor].withDispatcher(system.dispatcherFactory.newPinnedDispatcher("test")))
val result = (actor ? "Hello").as[String]
assert("World" === result.get)
actor.stop()
assert("World" === Await.result(actor ? "Hello", timeout.duration))
system.stop(actor)
}
}
}

View file

@ -50,7 +50,7 @@ class ListenerSpec extends AkkaSpec {
fooLatch.await
for (a List(broadcast, a1, a2, a3)) a.stop()
for (a List(broadcast, a1, a2, a3)) system.stop(a)
}
}
}

View file

@ -4,7 +4,7 @@
package akka.dataflow
import akka.actor.{ Actor, Props }
import akka.dispatch.Future
import akka.dispatch.{ Future, Await }
import akka.actor.future2actor
import akka.util.duration._
import akka.testkit.AkkaSpec
@ -26,9 +26,9 @@ class Future2ActorSpec extends AkkaSpec with DefaultTimeout {
case "ex" Future(throw new AssertionError) pipeTo context.sender
}
}))
(actor ? "do").as[Int] must be(Some(31))
Await.result(actor ? "do", timeout.duration) must be(31)
intercept[AssertionError] {
(actor ? "ex").get
Await.result(actor ? "ex", timeout.duration)
}
}
}

View file

@ -9,12 +9,12 @@ import org.scalacheck.Gen._
import akka.actor._
import akka.testkit.{ EventFilter, filterEvents, filterException }
import akka.util.duration._
import java.util.concurrent.{ TimeUnit, CountDownLatch }
import akka.testkit.AkkaSpec
import org.scalatest.junit.JUnitSuite
import java.lang.ArithmeticException
import akka.testkit.DefaultTimeout
import akka.testkit.TestLatch
import java.util.concurrent.{ TimeoutException, TimeUnit, CountDownLatch }
object FutureSpec {
class TestActor extends Actor {
@ -37,6 +37,7 @@ object FutureSpec {
}
}
@org.junit.runner.RunWith(classOf[org.scalatest.junit.JUnitRunner])
class JavaFutureSpec extends JavaFutureTests with JUnitSuite
@org.junit.runner.RunWith(classOf[org.scalatest.junit.JUnitRunner])
@ -47,8 +48,9 @@ class FutureSpec extends AkkaSpec with Checkers with BeforeAndAfterAll with Defa
"never completed" must {
behave like emptyFuture(_(Promise()))
"return supplied value on timeout" in {
val promise = Promise[String](100) orElse "Timedout"
promise.get must be("Timedout")
val timedOut = Promise.successful[String]("Timedout")
val promise = Promise[String]() orElse timedOut
Await.result(promise, timeout.duration) must be("Timedout")
}
}
"completed with a result" must {
@ -61,9 +63,6 @@ class FutureSpec extends AkkaSpec with Checkers with BeforeAndAfterAll with Defa
val future = Promise[String]().complete(Left(new RuntimeException(message)))
behave like futureWithException[RuntimeException](_(future, message))
}
"expired" must {
behave like expiredFuture(_(Promise(0)))
}
}
"A Future" when {
@ -78,7 +77,7 @@ class FutureSpec extends AkkaSpec with Checkers with BeforeAndAfterAll with Defa
}
test(future)
latch.open()
future.await
Await.ready(future, timeout.duration)
}
}
"is completed" must {
@ -90,7 +89,7 @@ class FutureSpec extends AkkaSpec with Checkers with BeforeAndAfterAll with Defa
result
}
latch.open()
future.await
Await.ready(future, timeout.duration)
test(future, result)
}
}
@ -99,8 +98,8 @@ class FutureSpec extends AkkaSpec with Checkers with BeforeAndAfterAll with Defa
filterException[ArithmeticException] {
check({ (future: Future[Int], actions: List[FutureAction])
val result = (future /: actions)(_ /: _)
val expected = (future.await.value.get /: actions)(_ /: _)
((result.await.value.get, expected) match {
val expected = (Await.ready(future, timeout.duration).value.get /: actions)(_ /: _)
((Await.ready(result, timeout.duration).value.get, expected) match {
case (Right(a), Right(b)) a == b
case (Left(a), Left(b)) if a.toString == b.toString true
case (Left(a), Left(b)) if a.getStackTrace.isEmpty || b.getStackTrace.isEmpty
@ -118,9 +117,9 @@ class FutureSpec extends AkkaSpec with Checkers with BeforeAndAfterAll with Defa
behave like futureWithResult { test
val actor = system.actorOf(Props[TestActor])
val future = actor ? "Hello"
future.await
Await.ready(future, timeout.duration)
test(future, "World")
actor.stop()
system.stop(actor)
}
}
"throws an exception" must {
@ -128,9 +127,9 @@ class FutureSpec extends AkkaSpec with Checkers with BeforeAndAfterAll with Defa
filterException[RuntimeException] {
val actor = system.actorOf(Props[TestActor])
val future = actor ? "Failure"
future.await
Await.ready(future, timeout.duration)
test(future, "Expected exception; to test fault-tolerance")
actor.stop()
system.stop(actor)
}
}
}
@ -142,10 +141,10 @@ class FutureSpec extends AkkaSpec with Checkers with BeforeAndAfterAll with Defa
val actor1 = system.actorOf(Props[TestActor])
val actor2 = system.actorOf(Props(new Actor { def receive = { case s: String sender ! s.toUpperCase } }))
val future = actor1 ? "Hello" flatMap { case s: String actor2 ? s }
future.await
Await.ready(future, timeout.duration)
test(future, "WORLD")
actor1.stop()
actor2.stop()
system.stop(actor1)
system.stop(actor2)
}
}
"will throw an exception" must {
@ -154,10 +153,10 @@ class FutureSpec extends AkkaSpec with Checkers with BeforeAndAfterAll with Defa
val actor1 = system.actorOf(Props[TestActor])
val actor2 = system.actorOf(Props(new Actor { def receive = { case s: String sender ! Status.Failure(new ArithmeticException("/ by zero")) } }))
val future = actor1 ? "Hello" flatMap { case s: String actor2 ? s }
future.await
Await.ready(future, timeout.duration)
test(future, "/ by zero")
actor1.stop()
actor2.stop()
system.stop(actor1)
system.stop(actor2)
}
}
}
@ -167,10 +166,10 @@ class FutureSpec extends AkkaSpec with Checkers with BeforeAndAfterAll with Defa
val actor1 = system.actorOf(Props[TestActor])
val actor2 = system.actorOf(Props(new Actor { def receive = { case s: String sender ! s.toUpperCase } }))
val future = actor1 ? "Hello" flatMap { case i: Int actor2 ? i }
future.await
Await.ready(future, timeout.duration)
test(future, "World (of class java.lang.String)")
actor1.stop()
actor2.stop()
system.stop(actor1)
system.stop(actor2)
}
}
}
@ -201,10 +200,10 @@ class FutureSpec extends AkkaSpec with Checkers with BeforeAndAfterAll with Defa
c (actor ? 7).mapTo[String]
} yield b + "-" + c
future1.get must be("10-14")
Await.result(future1, timeout.duration) must be("10-14")
assert(checkType(future1, manifest[String]))
intercept[ClassCastException] { future2.get }
actor.stop()
intercept[ClassCastException] { Await.result(future2, timeout.duration) }
system.stop(actor)
}
}
@ -231,9 +230,9 @@ class FutureSpec extends AkkaSpec with Checkers with BeforeAndAfterAll with Defa
Res(c: Int) actor ? Req(7)
} yield b + "-" + c
future1.get must be("10-14")
intercept[MatchError] { future2.get }
actor.stop()
Await.result(future1, timeout.duration) must be("10-14")
intercept[MatchError] { Await.result(future2, timeout.duration) }
system.stop(actor)
}
}
@ -268,34 +267,34 @@ class FutureSpec extends AkkaSpec with Checkers with BeforeAndAfterAll with Defa
}
val future11 = actor ? "Failure" recover { case _ "Oops!" }
future1.get must be(5)
intercept[ArithmeticException] { future2.get }
intercept[ArithmeticException] { future3.get }
future4.get must be("5")
future5.get must be("0")
intercept[ArithmeticException] { future6.get }
future7.get must be("You got ERROR")
intercept[RuntimeException] { future8.get }
future9.get must be("FAIL!")
future10.get must be("World")
future11.get must be("Oops!")
Await.result(future1, timeout.duration) must be(5)
intercept[ArithmeticException] { Await.result(future2, timeout.duration) }
intercept[ArithmeticException] { Await.result(future3, timeout.duration) }
Await.result(future4, timeout.duration) must be("5")
Await.result(future5, timeout.duration) must be("0")
intercept[ArithmeticException] { Await.result(future6, timeout.duration) }
Await.result(future7, timeout.duration) must be("You got ERROR")
intercept[RuntimeException] { Await.result(future8, timeout.duration) }
Await.result(future9, timeout.duration) must be("FAIL!")
Await.result(future10, timeout.duration) must be("World")
Await.result(future11, timeout.duration) must be("Oops!")
actor.stop()
system.stop(actor)
}
}
"firstCompletedOf" in {
val futures = Vector.fill[Future[Int]](10)(new DefaultPromise[Int]()) :+ new KeptPromise[Int](Right(5))
Future.firstCompletedOf(futures).get must be(5)
val futures = Vector.fill[Future[Int]](10)(Promise[Int]()) :+ Promise.successful[Int](5)
Await.result(Future.firstCompletedOf(futures), timeout.duration) must be(5)
}
"find" in {
val futures = for (i 1 to 10) yield Future { i }
val result = Future.find[Int](futures)(_ == 3)
result.get must be(Some(3))
Await.result(result, timeout.duration) must be(Some(3))
val notFound = Future.find[Int](futures)(_ == 11)
notFound.get must be(None)
Await.result(notFound, timeout.duration) must be(None)
}
"fold" in {
@ -306,7 +305,7 @@ class FutureSpec extends AkkaSpec with Checkers with BeforeAndAfterAll with Defa
}
val timeout = 10000
def futures = actors.zipWithIndex map { case (actor: ActorRef, idx: Int) actor.?((idx, idx * 200), timeout).mapTo[Int] }
Future.fold(futures, timeout)(0)(_ + _).get must be(45)
Await.result(Future.fold(futures)(0)(_ + _), timeout millis) must be(45)
}
"fold by composing" in {
@ -316,7 +315,7 @@ class FutureSpec extends AkkaSpec with Checkers with BeforeAndAfterAll with Defa
}))
}
def futures = actors.zipWithIndex map { case (actor: ActorRef, idx: Int) actor.?((idx, idx * 200), 10000).mapTo[Int] }
futures.foldLeft(Future(0))((fr, fa) for (r fr; a fa) yield (r + a)).get must be(45)
Await.result(futures.foldLeft(Future(0))((fr, fa) for (r fr; a fa) yield (r + a)), timeout.duration) must be(45)
}
"fold with an exception" in {
@ -333,18 +332,19 @@ class FutureSpec extends AkkaSpec with Checkers with BeforeAndAfterAll with Defa
}
val timeout = 10000
def futures = actors.zipWithIndex map { case (actor: ActorRef, idx: Int) actor.?((idx, idx * 100), timeout).mapTo[Int] }
Future.fold(futures, timeout)(0)(_ + _).await.exception.get.getMessage must be("shouldFoldResultsWithException: expected")
intercept[Throwable] { Await.result(Future.fold(futures)(0)(_ + _), timeout millis) }.getMessage must be("shouldFoldResultsWithException: expected")
}
}
"fold mutable zeroes safely" in {
import scala.collection.mutable.ArrayBuffer
def test(testNumber: Int) {
val fs = (0 to 1000) map (i Future(i, 10000))
val result = Future.fold(fs, 10000)(ArrayBuffer.empty[AnyRef]) {
val fs = (0 to 1000) map (i Future(i))
val f = Future.fold(fs)(ArrayBuffer.empty[AnyRef]) {
case (l, i) if i % 2 == 0 l += i.asInstanceOf[AnyRef]
case (l, _) l
}.get.asInstanceOf[ArrayBuffer[Int]].sum
}
val result = Await.result(f.mapTo[ArrayBuffer[Int]], 10000 millis).sum
assert(result === 250500)
}
@ -353,7 +353,7 @@ class FutureSpec extends AkkaSpec with Checkers with BeforeAndAfterAll with Defa
}
"return zero value if folding empty list" in {
Future.fold(List[Future[Int]]())(0)(_ + _).get must be(0)
Await.result(Future.fold(List[Future[Int]]())(0)(_ + _), timeout.duration) must be(0)
}
"shouldReduceResults" in {
@ -364,7 +364,7 @@ class FutureSpec extends AkkaSpec with Checkers with BeforeAndAfterAll with Defa
}
val timeout = 10000
def futures = actors.zipWithIndex map { case (actor: ActorRef, idx: Int) actor.?((idx, idx * 200), timeout).mapTo[Int] }
assert(Future.reduce(futures, timeout)(_ + _).get === 45)
assert(Await.result(Future.reduce(futures)(_ + _), timeout millis) === 45)
}
"shouldReduceResultsWithException" in {
@ -381,22 +381,22 @@ class FutureSpec extends AkkaSpec with Checkers with BeforeAndAfterAll with Defa
}
val timeout = 10000
def futures = actors.zipWithIndex map { case (actor: ActorRef, idx: Int) actor.?((idx, idx * 100), timeout).mapTo[Int] }
assert(Future.reduce(futures, timeout)(_ + _).await.exception.get.getMessage === "shouldFoldResultsWithException: expected")
intercept[Throwable] { Await.result(Future.reduce(futures)(_ + _), timeout millis) }.getMessage must be === "shouldFoldResultsWithException: expected"
}
}
"shouldReduceThrowIAEOnEmptyInput" in {
filterException[IllegalArgumentException] {
intercept[UnsupportedOperationException] { Future.reduce(List[Future[Int]]())(_ + _).get }
intercept[java.util.NoSuchElementException] { Await.result(Future.reduce(List[Future[Int]]())(_ + _), timeout.duration) }
}
}
"receiveShouldExecuteOnComplete" in {
val latch = new TestLatch
val actor = system.actorOf(Props[TestActor])
actor ? "Hello" onResult { case "World" latch.open() }
actor ? "Hello" onSuccess { case "World" latch.open() }
assert(latch.await(5 seconds))
actor.stop()
system.stop(actor)
}
"shouldTraverseFutures" in {
@ -410,52 +410,46 @@ class FutureSpec extends AkkaSpec with Checkers with BeforeAndAfterAll with Defa
}))
val oddFutures = List.fill(100)(oddActor ? 'GetNext mapTo manifest[Int])
assert(Future.sequence(oddFutures).get.sum === 10000)
oddActor.stop()
assert(Await.result(Future.sequence(oddFutures), timeout.duration).sum === 10000)
system.stop(oddActor)
val list = (1 to 100).toList
assert(Future.traverse(list)(x Future(x * 2 - 1)).get.sum === 10000)
assert(Await.result(Future.traverse(list)(x Future(x * 2 - 1)), timeout.duration).sum === 10000)
}
"shouldHandleThrowables" in {
class ThrowableTest(m: String) extends Throwable(m)
filterException[ThrowableTest] {
val f1 = Future { throw new ThrowableTest("test") }
f1.await
intercept[ThrowableTest] { f1.get }
val f1 = Future[Any] { throw new ThrowableTest("test") }
intercept[ThrowableTest] { Await.result(f1, timeout.duration) }
val latch = new TestLatch
val f2 = Future { latch.await(5 seconds); "success" }
f2 foreach (_ throw new ThrowableTest("dispatcher foreach"))
f2 onResult { case _ throw new ThrowableTest("dispatcher receive") }
f2 onSuccess { case _ throw new ThrowableTest("dispatcher receive") }
val f3 = f2 map (s s.toUpperCase)
latch.open()
f2.await
assert(f2.get === "success")
assert(Await.result(f2, timeout.duration) === "success")
f2 foreach (_ throw new ThrowableTest("current thread foreach"))
f2 onResult { case _ throw new ThrowableTest("current thread receive") }
f3.await
assert(f3.get === "SUCCESS")
f2 onSuccess { case _ throw new ThrowableTest("current thread receive") }
assert(Await.result(f3, timeout.duration) === "SUCCESS")
}
}
"shouldBlockUntilResult" in {
val latch = new TestLatch
val f = Future({ latch.await; 5 })
val f2 = Future({ f.get + 5 })
val f = Future { latch.await; 5 }
val f2 = Future { Await.result(f, timeout.duration) + 5 }
assert(f2.resultOrException === None)
intercept[TimeoutException](Await.ready(f2, 100 millis))
latch.open()
assert(f2.get === 10)
assert(Await.result(f2, timeout.duration) === 10)
val f3 = Future({ Thread.sleep(10); 5 }, 10 millis)
filterException[FutureTimeoutException] {
intercept[FutureTimeoutException] {
f3.get
}
}
val f3 = Future { Thread.sleep(100); 5 }
filterException[TimeoutException] { intercept[TimeoutException] { Await.ready(f3, 0 millis) } }
}
"futureComposingWithContinuations" in {
@ -468,9 +462,9 @@ class FutureSpec extends AkkaSpec with Checkers with BeforeAndAfterAll with Defa
val r = flow(x() + " " + y() + "!")
assert(r.get === "Hello World!")
assert(Await.result(r, timeout.duration) === "Hello World!")
actor.stop
system.stop(actor)
}
"futureComposingWithContinuationsFailureDivideZero" in {
@ -482,7 +476,7 @@ class FutureSpec extends AkkaSpec with Checkers with BeforeAndAfterAll with Defa
val r = flow(x() + " " + y.map(_ / 0).map(_.toString).apply, 100)
intercept[java.lang.ArithmeticException](r.get)
intercept[java.lang.ArithmeticException](Await.result(r, timeout.duration))
}
}
@ -497,7 +491,7 @@ class FutureSpec extends AkkaSpec with Checkers with BeforeAndAfterAll with Defa
val r = flow(x() + y(), 100)
intercept[ClassCastException](r.get)
intercept[ClassCastException](Await.result(r, timeout.duration))
}
}
@ -512,7 +506,7 @@ class FutureSpec extends AkkaSpec with Checkers with BeforeAndAfterAll with Defa
val r = flow(x() + y())
intercept[ClassCastException](r.get)
intercept[ClassCastException](Await.result(r, timeout.duration))
}
}
@ -536,44 +530,30 @@ class FutureSpec extends AkkaSpec with Checkers with BeforeAndAfterAll with Defa
flow { x << 5 }
assert(y.get === 5)
assert(z.get === 5)
assert(Await.result(y, timeout.duration) === 5)
assert(Await.result(z, timeout.duration) === 5)
assert(lz.isOpen)
assert(result.get === 10)
assert(Await.result(result, timeout.duration) === 10)
val a, b, c = Promise[Int]()
val result2 = flow {
val n = (a << c).result.get + 10
val n = (a << c).value.get.right.get + 10
b << (c() - 2)
a() + n * b()
}
c completeWith Future(5)
assert(a.get === 5)
assert(b.get === 3)
assert(result2.get === 50)
}
"shouldNotAddOrRunCallbacksAfterFailureToBeCompletedBeforeExpiry" in {
val latch = new TestLatch
val f = Promise[Int](0)
Thread.sleep(25)
f.onComplete(_ latch.open()) //Shouldn't throw any exception here
assert(f.isExpired) //Should be expired
f.complete(Right(1)) //Shouldn't complete the Future since it is expired
assert(f.value.isEmpty) //Shouldn't be completed
assert(!latch.isOpen) //Shouldn't run the listener
assert(Await.result(a, timeout.duration) === 5)
assert(Await.result(b, timeout.duration) === 3)
assert(Await.result(result2, timeout.duration) === 50)
}
"futureDataFlowShouldEmulateBlocking1" in {
import Future.flow
val one, two = Promise[Int](1000 * 60)
val one, two = Promise[Int]()
val simpleResult = flow {
one() + two()
}
@ -582,23 +562,23 @@ class FutureSpec extends AkkaSpec with Checkers with BeforeAndAfterAll with Defa
flow { one << 1 }
one.await
Await.ready(one, 1 minute)
assert(one.isCompleted)
assert(List(two, simpleResult).forall(_.isCompleted == false))
flow { two << 9 }
two.await
Await.ready(two, 1 minute)
assert(List(one, two).forall(_.isCompleted == true))
assert(simpleResult.get === 10)
assert(Await.result(simpleResult, timeout.duration) === 10)
}
"futureDataFlowShouldEmulateBlocking2" in {
import Future.flow
val x1, x2, y1, y2 = Promise[Int](1000 * 60)
val x1, x2, y1, y2 = Promise[Int]()
val lx, ly, lz = new TestLatch
val result = flow {
lx.open()
@ -616,17 +596,17 @@ class FutureSpec extends AkkaSpec with Checkers with BeforeAndAfterAll with Defa
flow { y1 << 1 } // When this is set, it should cascade down the line
assert(ly.await(2000 milliseconds))
assert(x1.get === 1)
assert(Await.result(x1, 1 minute) === 1)
assert(!lz.isOpen)
flow { y2 << 9 } // When this is set, it should cascade down the line
assert(lz.await(2000 milliseconds))
assert(x2.get === 9)
assert(Await.result(x2, 1 minute) === 9)
assert(List(x1, x2, y1, y2).forall(_.isCompleted == true))
assert(List(x1, x2, y1, y2).forall(_.isCompleted))
assert(result.get === 10)
assert(Await.result(result, 1 minute) === 10)
}
"dataFlowAPIshouldbeSlick" in {
@ -646,7 +626,7 @@ class FutureSpec extends AkkaSpec with Checkers with BeforeAndAfterAll with Defa
assert(i2.await(2000 milliseconds))
s1.open()
s2.open()
assert(result.get === 10)
assert(Await.result(result, timeout.duration) === 10)
}
"futureCompletingWithContinuationsFailure" in {
@ -670,8 +650,8 @@ class FutureSpec extends AkkaSpec with Checkers with BeforeAndAfterAll with Defa
flow { x << 5 }
assert(y.get === 5)
intercept[java.lang.ArithmeticException](result.get)
assert(Await.result(y, timeout.duration) === 5)
intercept[java.lang.ArithmeticException](Await.result(result, timeout.duration))
assert(z.value === None)
assert(!lz.isOpen)
}
@ -694,7 +674,7 @@ class FutureSpec extends AkkaSpec with Checkers with BeforeAndAfterAll with Defa
latch.open()
assert(result.get === Some("Hello"))
assert(Await.result(result, timeout.duration) === Some("Hello"))
}
"futureFlowShouldBeTypeSafe" in {
@ -717,8 +697,8 @@ class FutureSpec extends AkkaSpec with Checkers with BeforeAndAfterAll with Defa
assert(!checkType(rInt, manifest[Nothing]))
assert(!checkType(rInt, manifest[Any]))
rString.await
rInt.await
Await.result(rString, timeout.duration)
Await.result(rInt, timeout.duration)
}
"futureFlowSimpleAssign" in {
@ -732,7 +712,7 @@ class FutureSpec extends AkkaSpec with Checkers with BeforeAndAfterAll with Defa
flow { x << 40 }
flow { y << 2 }
assert(z.get === 42)
assert(Await.result(z, timeout.duration) === 42)
}
"futureFlowLoops" in {
@ -754,7 +734,7 @@ class FutureSpec extends AkkaSpec with Checkers with BeforeAndAfterAll with Defa
var i = 0
promises foreach { p
assert(p.get === i)
assert(Await.result(p, timeout.duration) === i)
i += 1
}
@ -810,88 +790,102 @@ class FutureSpec extends AkkaSpec with Checkers with BeforeAndAfterAll with Defa
latch(8).open()
latch(9).await
f4.await must be('completed)
Await.ready(f4, timeout.duration) must be('completed)
}
"should not deadlock with nested await (ticket 1313)" in {
val simple = Future() map (_ (Future(()) map (_ ())).get)
simple.await must be('completed)
val simple = Future() map (_ Await.result((Future(()) map (_ ())), timeout.duration))
Await.ready(simple, timeout.duration) must be('completed)
val l1, l2 = new TestLatch
val complex = Future() map { _
Future.blocking()
val nested = Future()
Future.blocking(system.dispatcher)
val nested = Future(())
nested foreach (_ l1.open())
l1.await // make sure nested is completed
nested foreach (_ l2.open())
l2.await
}
assert(complex.await.isCompleted)
Await.ready(complex, timeout.duration) must be('completed)
}
}
}
def emptyFuture(f: (Future[Any] Unit) Unit) {
"not be completed" in { f(_ must not be ('completed)) }
"not be expired" in { f(_ must not be ('expired)) }
"not contain a value" in { f(_.value must be(None)) }
"not contain a result" in { f(_.result must be(None)) }
"not contain an exception" in { f(_.exception must be(None)) }
}
def futureWithResult(f: ((Future[Any], Any) Unit) Unit) {
"be completed" in { f((future, _) future must be('completed)) }
"not be expired" in { f((future, _) future must not be ('expired)) }
"contain a value" in { f((future, result) future.value must be(Some(Right(result)))) }
"contain a result" in { f((future, result) future.result must be(Some(result))) }
"not contain an exception" in { f((future, _) future.exception must be(None)) }
"return result with 'get'" in { f((future, result) future.get must be(result)) }
"return result with 'resultOrException'" in { f((future, result) future.resultOrException must be(Some(result))) }
"not timeout" in { f((future, _) future.await) }
"return result with 'get'" in { f((future, result) Await.result(future, timeout.duration) must be(result)) }
"return result with 'Await.sync'" in { f((future, result) Await.result(future, timeout.duration) must be(result)) }
"not timeout" in { f((future, _) Await.ready(future, 0 millis)) }
"filter result" in {
f { (future, result)
(future filter (_ true)).get must be(result)
(evaluating { (future filter (_ false)).get } must produce[MatchError]).getMessage must startWith(result.toString)
Await.result((future filter (_ true)), timeout.duration) must be(result)
(evaluating { Await.result((future filter (_ false)), timeout.duration) } must produce[MatchError]).getMessage must startWith(result.toString)
}
}
"transform result with map" in { f((future, result) (future map (_.toString.length)).get must be(result.toString.length)) }
"compose result with flatMap" is pending
"perform action with foreach" is pending
"match result with collect" is pending
"not recover from exception" is pending
"perform action on result" is pending
"transform result with map" in { f((future, result) Await.result((future map (_.toString.length)), timeout.duration) must be(result.toString.length)) }
"compose result with flatMap" in {
f { (future, result)
val r = for (r future; p Promise.successful("foo")) yield r.toString + p
Await.result(r, timeout.duration) must be(result.toString + "foo")
}
}
"perform action with foreach" in {
f { (future, result)
val p = Promise[Any]()
future foreach p.success
Await.result(p, timeout.duration) must be(result)
}
}
"not recover from exception" in { f((future, result) Await.result(future.recover({ case _ "pigdog" }), timeout.duration) must be(result)) }
"perform action on result" in {
f { (future, result)
val p = Promise[Any]()
future.onSuccess { case x p.success(x) }
Await.result(p, timeout.duration) must be(result)
}
}
"not project a failure" in { f((future, result) (evaluating { Await.result(future.failed, timeout.duration) } must produce[NoSuchElementException]).getMessage must be("Future.failed not completed with a throwable. Instead completed with: " + result)) }
"not perform action on exception" is pending
"cast using mapTo" is pending
"cast using mapTo" in { f((future, result) Await.result(future.mapTo[Boolean].recover({ case _: ClassCastException false }), timeout.duration) must be(false)) }
}
def futureWithException[E <: Throwable: Manifest](f: ((Future[Any], String) Unit) Unit) {
"be completed" in { f((future, _) future must be('completed)) }
"not be expired" in { f((future, _) future must not be ('expired)) }
"contain a value" in { f((future, _) future.value must be('defined)) }
"not contain a result" in { f((future, _) future.result must be(None)) }
"contain an exception" in { f((future, message) future.exception.get.getMessage must be(message)) }
"throw exception with 'get'" in { f((future, message) (evaluating { future.get } must produce[E]).getMessage must be(message)) }
"throw exception with 'resultOrException'" in { f((future, message) (evaluating { future.resultOrException } must produce[E]).getMessage must be(message)) }
"not timeout" in { f((future, _) future.await) }
"contain a value" in {
f((future, message) {
future.value must be('defined)
future.value.get must be('left)
future.value.get.left.get.getMessage must be(message)
})
}
"throw exception with 'get'" in { f((future, message) (evaluating { Await.result(future, timeout.duration) } must produce[E]).getMessage must be(message)) }
"throw exception with 'Await.sync'" in { f((future, message) (evaluating { Await.result(future, timeout.duration) } must produce[E]).getMessage must be(message)) }
"retain exception with filter" in {
f { (future, message)
(evaluating { (future filter (_ true)).get } must produce[E]).getMessage must be(message)
(evaluating { (future filter (_ false)).get } must produce[E]).getMessage must be(message)
(evaluating { Await.result(future filter (_ true), timeout.duration) } must produce[E]).getMessage must be(message)
(evaluating { Await.result(future filter (_ false), timeout.duration) } must produce[E]).getMessage must be(message)
}
}
"retain exception with map" in { f((future, message) (evaluating { (future map (_.toString.length)).get } must produce[E]).getMessage must be(message)) }
"retain exception with flatMap" is pending
"retain exception with map" in { f((future, message) (evaluating { Await.result(future map (_.toString.length), timeout.duration) } must produce[E]).getMessage must be(message)) }
"retain exception with flatMap" in { f((future, message) (evaluating { Await.result(future flatMap (_ Promise.successful[Any]("foo")), timeout.duration) } must produce[E]).getMessage must be(message)) }
"not perform action with foreach" is pending
"retain exception with collect" is pending
"recover from exception" is pending
"recover from exception" in { f((future, message) Await.result(future.recover({ case e if e.getMessage == message "pigdog" }), timeout.duration) must be("pigdog")) }
"not perform action on result" is pending
"perform action on exception" is pending
"always cast successfully using mapTo" is pending
"project a failure" in { f((future, message) Await.result(future.failed, timeout.duration).getMessage must be(message)) }
"perform action on exception" in {
f { (future, message)
val p = Promise[Any]()
future.onFailure { case _ p.success(message) }
Await.result(p, timeout.duration) must be(message)
}
def expiredFuture(f: (Future[Any] Unit) Unit) {
"not be completed" in { f(_ must not be ('completed)) }
"be expired" in { f(_ must be('expired)) }
}
"always cast successfully using mapTo" in { f((future, message) (evaluating { Await.result(future.mapTo[java.lang.Thread], timeout.duration) } must produce[E]).getMessage must be(message)) }
}
sealed trait IntAction { def apply(that: Int): Int }

View file

@ -17,13 +17,9 @@ abstract class MailboxSpec extends AkkaSpec with BeforeAndAfterAll with BeforeAn
val q = factory(config)
ensureInitialMailboxState(config, q)
implicit val within = 1 second
val f = spawn { q.dequeue }
val f = spawn {
q.dequeue
}
f.await.resultOrException must be === Some(null)
Await.result(f, 1 second) must be(null)
}
"create a bounded mailbox with 10 capacity and with push timeout" in {
@ -61,13 +57,13 @@ abstract class MailboxSpec extends AkkaSpec with BeforeAndAfterAll with BeforeAn
}
//CANDIDATE FOR TESTKIT
def spawn[T <: AnyRef](fun: T)(implicit within: Duration): Future[T] = {
val result = new DefaultPromise[T](within.length, within.unit)
def spawn[T <: AnyRef](fun: T): Future[T] = {
val result = Promise[T]()
val t = new Thread(new Runnable {
def run = try {
result.completeWithResult(fun)
result.success(fun)
} catch {
case e: Throwable result.completeWithException(e)
case e: Throwable result.failure(e)
}
})
t.start
@ -119,8 +115,8 @@ abstract class MailboxSpec extends AkkaSpec with BeforeAndAfterAll with BeforeAn
val consumers = for (i (1 to 4).toList) yield createConsumer
val ps = producers.map(_.await.resultOrException.get)
val cs = consumers.map(_.await.resultOrException.get)
val ps = producers.map(Await.result(_, within))
val cs = consumers.map(Await.result(_, within))
ps.map(_.size).sum must be === totalMessages //Must have produced 1000 messages
cs.map(_.size).sum must be === totalMessages //Must have consumed all produced messages

View file

@ -43,7 +43,7 @@ class PriorityDispatcherSpec extends AkkaSpec with DefaultTimeout {
actor.resume //Signal the actor to start treating it's message backlog
actor.?('Result).as[List[Int]].get must be === (msgs.reverse)
Await.result(actor.?('Result).mapTo[List[Int]], timeout.duration) must be === msgs.reverse
}
}

View file

@ -21,9 +21,9 @@ class PromiseStreamSpec extends AkkaSpec with DefaultTimeout {
b << q
c << q()
}
assert(a.get === 1)
assert(b.get === 2)
assert(c.get === 3)
assert(Await.result(a, timeout.duration) === 1)
assert(Await.result(b, timeout.duration) === 2)
assert(Await.result(c, timeout.duration) === 3)
}
"pend" in {
@ -35,43 +35,9 @@ class PromiseStreamSpec extends AkkaSpec with DefaultTimeout {
c << q
}
flow { q <<< List(1, 2, 3) }
assert(a.get === 1)
assert(b.get === 2)
assert(c.get === 3)
}
"timeout" in {
val a, c = Promise[Int]()
val b = Promise[Int](0)
val q = PromiseStream[Int](1000)
flow {
a << q()
b << q()
c << q()
}
Thread.sleep(10)
flow {
q << (1, 2)
q << 3
}
assert(a.get === 1)
intercept[FutureTimeoutException] { b.get }
assert(c.get === 3)
}
"timeout again" in {
val q = PromiseStream[Int](500)
val a = q.dequeue()
val b = q.dequeue()
q += 1
Thread.sleep(500)
q += (2, 3)
val c = q.dequeue()
val d = q.dequeue()
assert(a.get === 1)
intercept[FutureTimeoutException] { b.get }
assert(c.get === 2)
assert(d.get === 3)
assert(Await.result(a, timeout.duration) === 1)
assert(Await.result(b, timeout.duration) === 2)
assert(Await.result(c, timeout.duration) === 3)
}
"pend again" in {
@ -88,10 +54,10 @@ class PromiseStreamSpec extends AkkaSpec with DefaultTimeout {
c << q1
d << q1
}
assert(a.get === 1)
assert(b.get === 2)
assert(c.get === 3)
assert(d.get === 4)
assert(Await.result(a, timeout.duration) === 1)
assert(Await.result(b, timeout.duration) === 2)
assert(Await.result(c, timeout.duration) === 3)
assert(Await.result(d, timeout.duration) === 4)
}
"enque" in {
@ -105,10 +71,10 @@ class PromiseStreamSpec extends AkkaSpec with DefaultTimeout {
}
q ++= List(1, 2, 3, 4)
assert(a.get === 1)
assert(b.get === 2)
assert(c.get === 3)
assert(d.get === 4)
assert(Await.result(a, timeout.duration) === 1)
assert(Await.result(b, timeout.duration) === 2)
assert(Await.result(c, timeout.duration) === 3)
assert(Await.result(d, timeout.duration) === 4)
}
"map" in {
@ -124,9 +90,9 @@ class PromiseStreamSpec extends AkkaSpec with DefaultTimeout {
flow {
qs << ("Hello", "World!", "Test")
}
assert(a.get === 5)
assert(b.get === "World!")
assert(c.get === 4)
assert(Await.result(a, timeout.duration) === 5)
assert(Await.result(b, timeout.duration) === "World!")
assert(Await.result(c, timeout.duration) === 4)
}
"not fail under concurrent stress" in {
@ -162,8 +128,7 @@ class PromiseStreamSpec extends AkkaSpec with DefaultTimeout {
}
}
val result = future.get
assert(result === (1L to 100000L).sum)
assert(Await.result(future, timeout.duration) === (1L to 100000L).sum)
}
}
}

View file

@ -8,7 +8,7 @@ import org.scalatest.BeforeAndAfterEach
import akka.testkit._
import akka.util.duration._
import java.util.concurrent.atomic._
import akka.actor.{ Props, Actor, ActorRef }
import akka.actor.{ Props, Actor, ActorRef, ActorSystem }
import java.util.Comparator
import akka.japi.{ Procedure, Function }
@ -33,7 +33,7 @@ abstract class EventBusSpec(busName: String) extends AkkaSpec with BeforeAndAfte
def classifierFor(event: BusType#Event): BusType#Classifier
def disposeSubscriber(subscriber: BusType#Subscriber): Unit
def disposeSubscriber(system: ActorSystem, subscriber: BusType#Subscriber): Unit
busName must {
@ -58,7 +58,7 @@ abstract class EventBusSpec(busName: String) extends AkkaSpec with BeforeAndAfte
"not allow to unsubscribe non-existing subscriber" in {
val sub = createNewSubscriber()
bus.unsubscribe(sub, classifier) must be === false
disposeSubscriber(sub)
disposeSubscriber(system, sub)
}
"not allow for the same subscriber to subscribe to the same channel twice" in {
@ -80,7 +80,7 @@ abstract class EventBusSpec(busName: String) extends AkkaSpec with BeforeAndAfte
subscribers.zip(classifiers) forall { case (s, c) bus.subscribe(s, c) } must be === true
subscribers.zip(classifiers) forall { case (s, c) bus.unsubscribe(s, c) } must be === true
subscribers foreach disposeSubscriber
subscribers foreach (disposeSubscriber(system, _))
}
"publishing events without any subscribers shouldn't be a problem" in {
@ -113,7 +113,7 @@ abstract class EventBusSpec(busName: String) extends AkkaSpec with BeforeAndAfte
subscribers foreach { s bus.subscribe(s, classifier) must be === true }
bus.publish(event)
range foreach { _ expectMsg(event) }
subscribers foreach { s bus.unsubscribe(s, classifier) must be === true; disposeSubscriber(s) }
subscribers foreach { s bus.unsubscribe(s, classifier) must be === true; disposeSubscriber(system, s) }
}
"not publish the given event to any other subscribers than the intended ones" in {
@ -136,7 +136,7 @@ abstract class EventBusSpec(busName: String) extends AkkaSpec with BeforeAndAfte
}
"cleanup subscriber" in {
disposeSubscriber(subscriber)
disposeSubscriber(system, subscriber)
}
}
}
@ -165,7 +165,7 @@ class ActorEventBusSpec extends EventBusSpec("ActorEventBus") {
def classifierFor(event: BusType#Event) = event.toString
def disposeSubscriber(subscriber: BusType#Subscriber): Unit = subscriber.stop()
def disposeSubscriber(system: ActorSystem, subscriber: BusType#Subscriber): Unit = system.stop(subscriber)
}
object ScanningEventBusSpec {
@ -194,7 +194,7 @@ class ScanningEventBusSpec extends EventBusSpec("ScanningEventBus") {
def classifierFor(event: BusType#Event) = event.toString
def disposeSubscriber(subscriber: BusType#Subscriber): Unit = ()
def disposeSubscriber(system: ActorSystem, subscriber: BusType#Subscriber): Unit = ()
}
object LookupEventBusSpec {
@ -219,5 +219,5 @@ class LookupEventBusSpec extends EventBusSpec("LookupEventBus") {
def classifierFor(event: BusType#Event) = event.toString
def disposeSubscriber(subscriber: BusType#Subscriber): Unit = ()
def disposeSubscriber(system: ActorSystem, subscriber: BusType#Subscriber): Unit = ()
}

View file

@ -52,9 +52,9 @@ class LoggingReceiveSpec extends WordSpec with BeforeAndAfterEach with BeforeAnd
}
override def afterAll {
appLogging.stop()
appAuto.stop()
appLifecycle.stop()
appLogging.shutdown()
appAuto.shutdown()
appLifecycle.shutdown()
}
"A LoggingReceive" must {
@ -201,7 +201,7 @@ class LoggingReceiveSpec extends WordSpec with BeforeAndAfterEach with BeforeAnd
assert(set == Set(1, 2, 3), set + " was not Set(1, 2, 3)")
}
supervisor.stop()
system.stop(supervisor)
expectMsg(Logging.Debug(sname, "stopping"))
expectMsg(Logging.Debug(aname, "stopped"))
expectMsg(Logging.Debug(sname, "stopped"))

View file

@ -75,7 +75,7 @@ class TellLatencyPerformanceSpec extends PerformanceSpec {
ok must be(true)
logMeasurement(numberOfClients, durationNs, stat)
}
clients.foreach(_.stop())
clients.foreach(system.stop(_))
}
}

View file

@ -173,8 +173,8 @@ class TellThroughput10000PerformanceSpec extends PerformanceSpec {
ok must be(true)
logMeasurement(numberOfClients, durationNs, repeat)
}
clients.foreach(_.stop())
destinations.foreach(_.stop())
clients.foreach(system.stop(_))
destinations.foreach(system.stop(_))
}
}

View file

@ -147,8 +147,8 @@ class TellThroughputComputationPerformanceSpec extends PerformanceSpec {
ok must be(true)
logMeasurement(numberOfClients, durationNs, repeat)
}
clients.foreach(_.stop())
destinations.foreach(_.stop())
clients.foreach(system.stop(_))
destinations.foreach(system.stop(_))
}
}

View file

@ -78,8 +78,8 @@ class TellThroughputPerformanceSpec extends PerformanceSpec {
ok must be(true)
logMeasurement(numberOfClients, durationNs, repeat)
}
clients.foreach(_.stop())
destinations.foreach(_.stop())
clients.foreach(system.stop(_))
destinations.foreach(system.stop(_))
}
}

View file

@ -159,8 +159,8 @@ class TellThroughputSeparateDispatchersPerformanceSpec extends PerformanceSpec {
ok must be(true)
logMeasurement(numberOfClients, durationNs, repeat)
}
clients.foreach(_.stop())
destinations.foreach(_.stop())
clients.foreach(system.stop(_))
destinations.foreach(system.stop(_))
}
}

View file

@ -2,9 +2,6 @@ package akka.performance.trading.system
import akka.performance.trading.domain._
import akka.actor._
import akka.dispatch.Future
import akka.dispatch.FutureTimeoutException
import akka.dispatch.MessageDispatcher
trait MatchingEngine {
val meId: String

View file

@ -108,7 +108,7 @@ class TradingLatencyPerformanceSpec extends PerformanceSpec {
}
logMeasurement(numberOfClients, durationNs, stat)
}
clients.foreach(_.stop())
clients.foreach(system.stop(_))
}
}

View file

@ -105,7 +105,7 @@ class TradingThroughputPerformanceSpec extends PerformanceSpec {
}
logMeasurement(numberOfClients, durationNs, totalNumberOfOrders)
}
clients.foreach(_.stop())
clients.foreach(system.stop(_))
}
}

View file

@ -1,11 +1,11 @@
package akka.routing
import akka.dispatch.{ KeptPromise, Future }
import akka.actor._
import akka.testkit._
import akka.util.duration._
import java.util.concurrent.atomic.{ AtomicBoolean, AtomicInteger }
import akka.testkit.AkkaSpec
import akka.dispatch.{ Await, Promise, Future }
object ActorPoolSpec {
@ -17,7 +17,7 @@ object ActorPoolSpec {
import TypedActor.dispatcher
def sq(x: Int, sleep: Long): Future[Int] = {
if (sleep > 0) Thread.sleep(sleep)
new KeptPromise(Right(x * x))
Promise.successful(x * x)
}
}
@ -47,7 +47,7 @@ class TypedActorPoolSpec extends AkkaSpec with DefaultTimeout {
val results = for (i 1 to 100) yield (i, pool.sq(i, 0))
for ((i, r) results)
r.get must equal(i * i)
Await.result(r, timeout.duration) must equal(i * i)
ta.stop(pool)
}
@ -97,9 +97,9 @@ class ActorPoolSpec extends AkkaSpec with DefaultTimeout {
count.get must be(2)
(pool ? ActorPool.Stat).as[ActorPool.Stats].get.size must be(2)
Await.result((pool ? ActorPool.Stat).mapTo[ActorPool.Stats], timeout.duration).size must be(2)
pool.stop()
system.stop(pool)
}
"pass ticket #705" in {
@ -125,11 +125,11 @@ class ActorPoolSpec extends AkkaSpec with DefaultTimeout {
}).withFaultHandler(faultHandler))
try {
(for (count 1 to 500) yield pool.?("Test", 20000)) foreach {
_.await.resultOrException.get must be("Response")
(for (count 1 to 500) yield pool.?("Test", 20 seconds)) foreach {
Await.result(_, 20 seconds) must be("Response")
}
} finally {
pool.stop()
system.stop(pool)
}
}
@ -163,7 +163,7 @@ class ActorPoolSpec extends AkkaSpec with DefaultTimeout {
pool ! 1
(pool ? ActorPool.Stat).as[ActorPool.Stats].get.size must be(2)
Await.result((pool ? ActorPool.Stat).mapTo[ActorPool.Stats], timeout.duration).size must be(2)
var loops = 0
def loop(t: Int) = {
@ -183,7 +183,7 @@ class ActorPoolSpec extends AkkaSpec with DefaultTimeout {
latch.await
count.get must be(loops)
(pool ? ActorPool.Stat).as[ActorPool.Stats].get.size must be(2)
Await.result((pool ? ActorPool.Stat).mapTo[ActorPool.Stats], timeout.duration).size must be(2)
// a whole bunch should max it out
@ -192,9 +192,9 @@ class ActorPoolSpec extends AkkaSpec with DefaultTimeout {
latch.await
count.get must be(loops)
(pool ? ActorPool.Stat).as[ActorPool.Stats].get.size must be(4)
Await.result((pool ? ActorPool.Stat).mapTo[ActorPool.Stats], timeout.duration).size must be(4)
pool.stop()
system.stop(pool)
}
"grow as needed under mailbox pressure" in {
@ -239,7 +239,7 @@ class ActorPoolSpec extends AkkaSpec with DefaultTimeout {
latch.await
count.get must be(loops)
(pool ? ActorPool.Stat).as[ActorPool.Stats].get.size must be(2)
Await.result((pool ? ActorPool.Stat).mapTo[ActorPool.Stats], timeout.duration).size must be(2)
// send a bunch over the threshold and observe an increment
loops = 15
@ -248,9 +248,9 @@ class ActorPoolSpec extends AkkaSpec with DefaultTimeout {
latch.await(10 seconds)
count.get must be(loops)
(pool ? ActorPool.Stat).as[ActorPool.Stats].get.size must be >= (3)
Await.result((pool ? ActorPool.Stat).mapTo[ActorPool.Stats], timeout.duration).size must be >= (3)
pool.stop()
system.stop(pool)
}
"round robin" in {
@ -281,7 +281,7 @@ class ActorPoolSpec extends AkkaSpec with DefaultTimeout {
latch1.await
delegates.size must be(1)
pool1.stop()
system.stop(pool1)
val latch2 = TestLatch(2)
delegates.clear()
@ -309,7 +309,7 @@ class ActorPoolSpec extends AkkaSpec with DefaultTimeout {
latch2.await
delegates.size must be(2)
pool2.stop()
system.stop(pool2)
}
"backoff" in {
@ -342,7 +342,7 @@ class ActorPoolSpec extends AkkaSpec with DefaultTimeout {
(5 millis).dilated.sleep
val z = (pool ? ActorPool.Stat).as[ActorPool.Stats].get.size
val z = Await.result((pool ? ActorPool.Stat).mapTo[ActorPool.Stats], timeout.duration).size
z must be >= (2)
@ -353,9 +353,9 @@ class ActorPoolSpec extends AkkaSpec with DefaultTimeout {
(500 millis).dilated.sleep
}
(pool ? ActorPool.Stat).as[ActorPool.Stats].get.size must be <= (z)
Await.result((pool ? ActorPool.Stat).mapTo[ActorPool.Stats], timeout.duration).size must be <= (z)
pool.stop()
system.stop(pool)
}
}
}

View file

@ -6,6 +6,7 @@ import java.util.concurrent.atomic.AtomicInteger
import java.util.concurrent.{ CountDownLatch, TimeUnit }
import akka.testkit._
import akka.util.duration._
import akka.dispatch.Await
@org.junit.runner.RunWith(classOf[org.scalatest.junit.JUnitRunner])
class ConfiguredLocalRoutingSpec extends AkkaSpec with DefaultTimeout with ImplicitSender {
@ -49,7 +50,7 @@ class ConfiguredLocalRoutingSpec extends AkkaSpec with DefaultTimeout with Impli
actor ! "hello"
helloLatch.await(5, TimeUnit.SECONDS) must be(true)
actor.stop()
system.stop(actor)
stopLatch.await(5, TimeUnit.SECONDS) must be(true)
}
@ -74,7 +75,7 @@ class ConfiguredLocalRoutingSpec extends AkkaSpec with DefaultTimeout with Impli
for (i 0 until iterationCount) {
for (k 0 until connectionCount) {
val id = (actor ? "hit").as[Int].getOrElse(fail("No id returned by actor"))
val id = Await.result((actor ? "hit").mapTo[Int], timeout.duration)
replies = replies + (id -> (replies(id) + 1))
}
}
@ -104,7 +105,7 @@ class ConfiguredLocalRoutingSpec extends AkkaSpec with DefaultTimeout with Impli
actor ! Broadcast("hello")
helloLatch.await(5, TimeUnit.SECONDS) must be(true)
actor.stop()
system.stop(actor)
stopLatch.await(5, TimeUnit.SECONDS) must be(true)
}
}
@ -134,7 +135,7 @@ class ConfiguredLocalRoutingSpec extends AkkaSpec with DefaultTimeout with Impli
for (i 1 to 5) expectMsg("world")
}
actor.stop()
system.stop(actor)
stopLatch.await(5, TimeUnit.SECONDS) must be(true)
}
@ -159,7 +160,7 @@ class ConfiguredLocalRoutingSpec extends AkkaSpec with DefaultTimeout with Impli
for (i 0 until iterationCount) {
for (k 0 until connectionCount) {
val id = (actor ? "hit").as[Int].getOrElse(fail("No id returned by actor"))
val id = Await.result((actor ? "hit").mapTo[Int], timeout.duration)
replies = replies + (id -> (replies(id) + 1))
}
}
@ -190,7 +191,7 @@ class ConfiguredLocalRoutingSpec extends AkkaSpec with DefaultTimeout with Impli
actor ! Broadcast("hello")
helloLatch.await(5, TimeUnit.SECONDS) must be(true)
actor.stop()
system.stop(actor)
stopLatch.await(5, TimeUnit.SECONDS) must be(true)
}
}

View file

@ -9,6 +9,7 @@ import collection.mutable.LinkedList
import java.util.concurrent.{ CountDownLatch, TimeUnit }
import akka.testkit._
import akka.util.duration._
import akka.dispatch.Await
object RoutingSpec {
@ -43,7 +44,7 @@ class RoutingSpec extends AkkaSpec with DefaultTimeout with ImplicitSender {
val c1, c2 = expectMsgType[ActorRef]
watch(router)
watch(c2)
c2.stop()
system.stop(c2)
expectMsg(Terminated(c2))
// it might take a while until the Router has actually processed the Terminated message
awaitCond {
@ -54,7 +55,7 @@ class RoutingSpec extends AkkaSpec with DefaultTimeout with ImplicitSender {
}
res == Seq(c1, c1)
}
c1.stop()
system.stop(c1)
expectMsg(Terminated(router))
}
@ -317,15 +318,15 @@ class RoutingSpec extends AkkaSpec with DefaultTimeout with ImplicitSender {
routedActor ! Broadcast(Stop(Some(1)))
shutdownLatch.await
(routedActor ? Broadcast(0)).as[Int].get must be(22)
Await.result(routedActor ? Broadcast(0), timeout.duration) must be(22)
}
case class Stop(id: Option[Int] = None)
def newActor(id: Int, shudownLatch: Option[TestLatch] = None) = system.actorOf(Props(new Actor {
def receive = {
case Stop(None) self.stop()
case Stop(Some(_id)) if (_id == id) self.stop()
case Stop(None) context.stop(self)
case Stop(Some(_id)) if (_id == id) context.stop(self)
case _id: Int if (_id == id)
case x {
Thread sleep 100 * id

View file

@ -106,7 +106,7 @@ class SerializeSpec extends AkkaSpec(SerializeSpec.serializationConf) {
}))
a ! new ObjectOutputStream(new ByteArrayOutputStream())
expectMsg("pass")
a.stop()
system.stop(a)
}
"serialize DeadLetterActorRef" in {
@ -124,7 +124,7 @@ class SerializeSpec extends AkkaSpec(SerializeSpec.serializationConf) {
(deadLetters eq a.deadLetters) must be(true)
}
} finally {
a.stop()
a.shutdown()
}
}
}

View file

@ -3,6 +3,8 @@ package akka.ticket
import akka.actor._
import akka.routing._
import akka.testkit.AkkaSpec
import akka.dispatch.Await
import akka.util.duration._
@org.junit.runner.RunWith(classOf[org.scalatest.junit.JUnitRunner])
class Ticket703Spec extends AkkaSpec {
@ -26,7 +28,7 @@ class Ticket703Spec extends AkkaSpec {
}
}))
}).withFaultHandler(OneForOneStrategy(List(classOf[Exception]), 5, 1000)))
(actorPool.?("Ping", 10000)).await.result must be === Some("Response")
Await.result(actorPool.?("Ping", 10000), 10 seconds) must be === "Response"
}
}
}

View file

@ -4,7 +4,7 @@
package akka.util
import org.scalatest.matchers.MustMatchers
import akka.dispatch.Future
import akka.dispatch.{ Future, Await }
import akka.testkit.AkkaSpec
import scala.util.Random
import akka.testkit.DefaultTimeout
@ -125,8 +125,7 @@ class IndexSpec extends AkkaSpec with MustMatchers with DefaultTimeout {
val tasks = List.fill(nrOfTasks)(executeRandomTask)
tasks.foreach(_.await)
tasks.foreach(_.exception.map(throw _))
tasks.foreach(Await.result(_, timeout.duration))
}
}
}

View file

@ -21,7 +21,7 @@ import java.util.Set;
* is a key in a JSON object; it's just a string that's the key in a map. A
* "path" is a parseable expression with a syntax and it refers to a series of
* keys. Path expressions are described in the <a
* href="https://github.com/havocp/config/blob/master/HOCON.md">spec for
* href="https://github.com/typesafehub/config/blob/master/HOCON.md">spec for
* Human-Optimized Config Object Notation</a>. In brief, a path is
* period-separated so "a.b.c" looks for key c in object b in object a in the
* root object. Sometimes double quotes are needed around special characters in
@ -97,7 +97,7 @@ public interface Config extends ConfigMergeable {
/**
* Returns a replacement config with all substitutions (the
* <code>${foo.bar}</code> syntax, see <a
* href="https://github.com/havocp/config/blob/master/HOCON.md">the
* href="https://github.com/typesafehub/config/blob/master/HOCON.md">the
* spec</a>) resolved. Substitutions are looked up using this
* <code>Config</code> as the root object, that is, a substitution
* <code>${foo.bar}</code> will be replaced with the result of
@ -395,7 +395,8 @@ public interface Config extends ConfigMergeable {
* Gets a value as a size in bytes (parses special strings like "128M"). If
* the value is already a number, then it's left alone; if it's a string,
* it's parsed understanding unit suffixes such as "128K", as documented in
* the <a href="https://github.com/havocp/config/blob/master/HOCON.md">the
* the <a
* href="https://github.com/typesafehub/config/blob/master/HOCON.md">the
* spec</a>.
*
* @param path
@ -414,7 +415,7 @@ public interface Config extends ConfigMergeable {
* Get value as a duration in milliseconds. If the value is already a
* number, then it's left alone; if it's a string, it's parsed understanding
* units suffixes like "10m" or "5ns" as documented in the <a
* href="https://github.com/havocp/config/blob/master/HOCON.md">the
* href="https://github.com/typesafehub/config/blob/master/HOCON.md">the
* spec</a>.
*
* @param path

View file

@ -5,7 +5,8 @@ package com.typesafe.config;
/**
* All exceptions thrown by the library are subclasses of ConfigException.
* All exceptions thrown by the library are subclasses of
* <code>ConfigException</code>.
*/
public abstract class ConfigException extends RuntimeException {
private static final long serialVersionUID = 1L;
@ -338,6 +339,9 @@ public abstract class ConfigException extends RuntimeException {
sb.append(p.problem());
sb.append(", ");
}
if (sb.length() == 0)
throw new ConfigException.BugOrBroken(
"ValidationFailed must have a non-empty list of problems");
sb.setLength(sb.length() - 2); // chop comma and space
return sb.toString();

View file

@ -295,7 +295,7 @@ public final class ConfigFactory {
/**
* Converts a Java {@link java.util.Properties} object to a
* {@link ConfigObject} using the rules documented in the <a
* href="https://github.com/havocp/config/blob/master/HOCON.md">HOCON
* href="https://github.com/typesafehub/config/blob/master/HOCON.md">HOCON
* spec</a>. The keys in the <code>Properties</code> object are split on the
* period character '.' and treated as paths. The values will all end up as
* string values. If you have both "a=foo" and "a.b=bar" in your properties

View file

@ -27,8 +27,8 @@ public interface ConfigMergeable {
*
* <p>
* The semantics of merging are described in the <a
* href="https://github.com/havocp/config/blob/master/HOCON.md">spec for
* HOCON</a>.
* href="https://github.com/typesafehub/config/blob/master/HOCON.md">spec
* for HOCON</a>.
*
* <p>
* Note that objects do not merge "across" non-objects; if you write

View file

@ -34,7 +34,7 @@ import java.util.Map;
* The API for a {@code ConfigObject} is in terms of keys, while the API for a
* {@link Config} is in terms of path expressions. Conceptually,
* {@code ConfigObject} is a tree of maps from keys to values, while a
* {@code ConfigObject} is a one-level map from paths to values.
* {@code Config} is a one-level map from paths to values.
*
* <p>
* Use {@link ConfigUtil#joinPath} and {@link ConfigUtil#splitPath} to convert

View file

@ -4,6 +4,7 @@
package com.typesafe.config;
import java.net.URL;
import java.util.List;
/**
@ -66,4 +67,16 @@ public interface ConfigOrigin {
* @return line number or -1 if none is available
*/
public int lineNumber();
/**
* Returns any comments that appeared to "go with" this place in the file.
* Often an empty list, but never null. The details of this are subject to
* change, but at the moment comments that are immediately before an array
* element or object field, with no blank line after the comment, "go with"
* that element or field.
*
* @return any comments that seemed to "go with" this origin, empty list if
* none
*/
public List<String> comments();
}

View file

@ -6,11 +6,13 @@ package com.typesafe.config;
/**
* A set of options related to resolving substitutions. Substitutions use the
* <code>${foo.bar}</code> syntax and are documented in the <a
* href="https://github.com/havocp/config/blob/master/HOCON.md">HOCON</a> spec.
* href="https://github.com/typesafehub/config/blob/master/HOCON.md">HOCON</a>
* spec.
* <p>
* This object is immutable, so the "setters" return a new object.
* <p>
* Here is an example of creating a custom {@code ConfigResolveOptions}:
*
* <pre>
* ConfigResolveOptions options = ConfigResolveOptions.defaults()
* .setUseSystemEnvironment(false)

View file

@ -5,8 +5,8 @@ package com.typesafe.config;
/**
* The syntax of a character stream, <a href="http://json.org">JSON</a>, <a
* href="https://github.com/havocp/config/blob/master/HOCON.md">HOCON</a> aka
* ".conf", or <a href=
* href="https://github.com/typesafehub/config/blob/master/HOCON.md">HOCON</a>
* aka ".conf", or <a href=
* "http://download.oracle.com/javase/7/docs/api/java/util/Properties.html#load%28java.io.Reader%29"
* >Java properties</a>.
*
@ -19,8 +19,8 @@ public enum ConfigSyntax {
JSON,
/**
* The JSON-superset <a
* href="https://github.com/havocp/config/blob/master/HOCON.md">HOCON</a>
* format.
* href="https://github.com/typesafehub/config/blob/master/HOCON.md"
* >HOCON</a> format.
*/
CONF,
/**

View file

@ -4,6 +4,10 @@ import java.util.List;
import com.typesafe.config.impl.ConfigImplUtil;
/**
* Contains static utility methods.
*
*/
public final class ConfigUtil {
private ConfigUtil() {

View file

@ -8,9 +8,9 @@ import java.util.Map;
import com.typesafe.config.impl.ConfigImpl;
/**
* This class holds some static factory methods for building ConfigValue. See
* also ConfigFactory which has methods for parsing files and certain in-memory
* data structures.
* This class holds some static factory methods for building {@link ConfigValue}
* instances. See also {@link ConfigFactory} which has methods for parsing files
* and certain in-memory data structures.
*/
public final class ConfigValueFactory {
private ConfigValueFactory() {

View file

@ -111,12 +111,12 @@ abstract class AbstractConfigObject extends AbstractConfigValue implements
return ConfigValueType.OBJECT;
}
protected abstract AbstractConfigObject newCopy(ResolveStatus status,
boolean ignoresFallbacks);
protected abstract AbstractConfigObject newCopy(ResolveStatus status, boolean ignoresFallbacks,
ConfigOrigin origin);
@Override
protected AbstractConfigObject newCopy(boolean ignoresFallbacks) {
return newCopy(resolveStatus(), ignoresFallbacks);
protected AbstractConfigObject newCopy(boolean ignoresFallbacks, ConfigOrigin origin) {
return newCopy(resolveStatus(), ignoresFallbacks, origin);
}
@Override
@ -173,7 +173,7 @@ abstract class AbstractConfigObject extends AbstractConfigValue implements
return new SimpleConfigObject(mergeOrigins(this, fallback), merged, newResolveStatus,
newIgnoresFallbacks);
else if (newResolveStatus != resolveStatus() || newIgnoresFallbacks != ignoresFallbacks())
return newCopy(newResolveStatus, newIgnoresFallbacks);
return newCopy(newResolveStatus, newIgnoresFallbacks, origin());
else
return this;
}
@ -234,7 +234,7 @@ abstract class AbstractConfigObject extends AbstractConfigValue implements
}
}
if (changes == null) {
return newCopy(newResolveStatus, ignoresFallbacks());
return newCopy(newResolveStatus, ignoresFallbacks(), origin());
} else {
Map<String, AbstractConfigValue> modified = new HashMap<String, AbstractConfigValue>();
for (String k : keySet()) {
@ -306,6 +306,12 @@ abstract class AbstractConfigObject extends AbstractConfigValue implements
sb.append("# ");
sb.append(v.origin().description());
sb.append("\n");
for (String comment : v.origin().comments()) {
indent(sb, indent + 1);
sb.append("# ");
sb.append(comment);
sb.append("\n");
}
indent(sb, indent + 1);
}
v.render(sb, indent + 1, k, formatted);

View file

@ -18,14 +18,14 @@ import com.typesafe.config.ConfigValue;
*/
abstract class AbstractConfigValue implements ConfigValue, MergeableValue {
final private ConfigOrigin origin;
final private SimpleConfigOrigin origin;
AbstractConfigValue(ConfigOrigin origin) {
this.origin = origin;
this.origin = (SimpleConfigOrigin) origin;
}
@Override
public ConfigOrigin origin() {
public SimpleConfigOrigin origin() {
return this.origin;
}
@ -76,9 +76,7 @@ abstract class AbstractConfigValue implements ConfigValue, MergeableValue {
return this;
}
protected AbstractConfigValue newCopy(boolean ignoresFallbacks) {
return this;
}
protected abstract AbstractConfigValue newCopy(boolean ignoresFallbacks, ConfigOrigin origin);
// this is virtualized rather than a field because only some subclasses
// really need to store the boolean, and they may be able to pack it
@ -105,6 +103,13 @@ abstract class AbstractConfigValue implements ConfigValue, MergeableValue {
throw badMergeException();
}
public AbstractConfigValue withOrigin(ConfigOrigin origin) {
if (this.origin == origin)
return this;
else
return newCopy(ignoresFallbacks(), origin);
}
@Override
public AbstractConfigValue withFallback(ConfigMergeable mergeable) {
if (ignoresFallbacks()) {
@ -118,7 +123,7 @@ abstract class AbstractConfigValue implements ConfigValue, MergeableValue {
AbstractConfigObject fallback = (AbstractConfigObject) other;
if (fallback.resolveStatus() == ResolveStatus.RESOLVED && fallback.isEmpty()) {
if (fallback.ignoresFallbacks())
return newCopy(true /* ignoresFallbacks */);
return newCopy(true /* ignoresFallbacks */, origin);
else
return this;
} else {
@ -128,7 +133,7 @@ abstract class AbstractConfigValue implements ConfigValue, MergeableValue {
// falling back to a non-object doesn't merge anything, and also
// prohibits merging any objects that we fall back to later.
// so we have to switch to ignoresFallbacks mode.
return newCopy(true /* ignoresFallbacks */);
return newCopy(true /* ignoresFallbacks */, origin);
}
}
}

View file

@ -29,4 +29,9 @@ final class ConfigBoolean extends AbstractConfigValue {
String transformToString() {
return value ? "true" : "false";
}
@Override
protected ConfigBoolean newCopy(boolean ignoresFallbacks, ConfigOrigin origin) {
return new ConfigBoolean(origin, value);
}
}

View file

@ -107,6 +107,11 @@ final class ConfigDelayedMerge extends AbstractConfigValue implements
return ignoresFallbacks;
}
@Override
protected AbstractConfigValue newCopy(boolean newIgnoresFallbacks, ConfigOrigin newOrigin) {
return new ConfigDelayedMerge(newOrigin, stack, newIgnoresFallbacks);
}
@Override
protected final ConfigDelayedMerge mergedWithTheUnmergeable(Unmergeable fallback) {
if (ignoresFallbacks)
@ -196,6 +201,12 @@ final class ConfigDelayedMerge extends AbstractConfigValue implements
i += 1;
sb.append(v.origin().description());
sb.append("\n");
for (String comment : v.origin().comments()) {
indent(sb, indent);
sb.append("# ");
sb.append(comment);
sb.append("\n");
}
indent(sb, indent);
}

View file

@ -49,12 +49,12 @@ class ConfigDelayedMergeObject extends AbstractConfigObject implements
}
@Override
protected ConfigDelayedMergeObject newCopy(ResolveStatus status,
boolean ignoresFallbacks) {
protected ConfigDelayedMergeObject newCopy(ResolveStatus status, boolean ignoresFallbacks,
ConfigOrigin origin) {
if (status != resolveStatus())
throw new ConfigException.BugOrBroken(
"attempt to create resolved ConfigDelayedMergeObject");
return new ConfigDelayedMergeObject(origin(), stack, ignoresFallbacks);
return new ConfigDelayedMergeObject(origin, stack, ignoresFallbacks);
}
@Override

View file

@ -43,4 +43,9 @@ final class ConfigDouble extends ConfigNumber {
protected double doubleValue() {
return value;
}
@Override
protected ConfigDouble newCopy(boolean ignoresFallbacks, ConfigOrigin origin) {
return new ConfigDouble(origin, value, originalText);
}
}

View file

@ -43,4 +43,9 @@ final class ConfigInt extends ConfigNumber {
protected double doubleValue() {
return value;
}
@Override
protected ConfigInt newCopy(boolean ignoresFallbacks, ConfigOrigin origin) {
return new ConfigInt(origin, value, originalText);
}
}

View file

@ -43,4 +43,9 @@ final class ConfigLong extends ConfigNumber {
protected double doubleValue() {
return value;
}
@Override
protected ConfigLong newCopy(boolean ignoresFallbacks, ConfigOrigin origin) {
return new ConfigLong(origin, value, originalText);
}
}

View file

@ -39,4 +39,9 @@ final class ConfigNull extends AbstractConfigValue {
protected void render(StringBuilder sb, int indent, boolean formatted) {
sb.append("null");
}
@Override
protected ConfigNull newCopy(boolean ignoresFallbacks, ConfigOrigin origin) {
return new ConfigNull(origin);
}
}

View file

@ -11,7 +11,7 @@ abstract class ConfigNumber extends AbstractConfigValue {
// a sentence) we always have it exactly as the person typed it into the
// config file. It's purely cosmetic; equals/hashCode don't consider this
// for example.
final private String originalText;
final protected String originalText;
protected ConfigNumber(ConfigOrigin origin, String originalText) {
super(origin);

View file

@ -34,4 +34,9 @@ final class ConfigString extends AbstractConfigValue {
protected void render(StringBuilder sb, int indent, boolean formatted) {
sb.append(ConfigImplUtil.renderJsonString(value));
}
@Override
protected ConfigString newCopy(boolean ignoresFallbacks, ConfigOrigin origin) {
return new ConfigString(origin, value);
}
}

View file

@ -61,8 +61,8 @@ final class ConfigSubstitution extends AbstractConfigValue implements
}
@Override
protected ConfigSubstitution newCopy(boolean ignoresFallbacks) {
return new ConfigSubstitution(origin(), pieces, prefixLength, ignoresFallbacks);
protected ConfigSubstitution newCopy(boolean ignoresFallbacks, ConfigOrigin newOrigin) {
return new ConfigSubstitution(newOrigin, pieces, prefixLength, ignoresFallbacks);
}
@Override

View file

@ -32,9 +32,53 @@ final class Parser {
return context.parse();
}
static private final class TokenWithComments {
final Token token;
final List<Token> comments;
TokenWithComments(Token token, List<Token> comments) {
this.token = token;
this.comments = comments;
}
TokenWithComments(Token token) {
this(token, Collections.<Token> emptyList());
}
TokenWithComments prepend(List<Token> earlier) {
if (this.comments.isEmpty()) {
return new TokenWithComments(token, earlier);
} else {
List<Token> merged = new ArrayList<Token>();
merged.addAll(earlier);
merged.addAll(comments);
return new TokenWithComments(token, merged);
}
}
SimpleConfigOrigin setComments(SimpleConfigOrigin origin) {
if (comments.isEmpty()) {
return origin;
} else {
List<String> newComments = new ArrayList<String>();
for (Token c : comments) {
newComments.add(Tokens.getCommentText(c));
}
return origin.setComments(newComments);
}
}
@Override
public String toString() {
// this ends up in user-visible error messages, so we don't want the
// comments
return token.toString();
}
}
static private final class ParseContext {
private int lineNumber;
final private Stack<Token> buffer;
final private Stack<TokenWithComments> buffer;
final private Iterator<Token> tokens;
final private ConfigIncluder includer;
final private ConfigIncludeContext includeContext;
@ -50,7 +94,7 @@ final class Parser {
Iterator<Token> tokens, ConfigIncluder includer,
ConfigIncludeContext includeContext) {
lineNumber = 1;
buffer = new Stack<Token>();
buffer = new Stack<TokenWithComments>();
this.tokens = tokens;
this.flavor = flavor;
this.baseOrigin = origin;
@ -60,13 +104,66 @@ final class Parser {
this.equalsCount = 0;
}
private Token nextToken() {
Token t = null;
if (buffer.isEmpty()) {
t = tokens.next();
} else {
t = buffer.pop();
private void consolidateCommentBlock(Token commentToken) {
// a comment block "goes with" the following token
// unless it's separated from it by a blank line.
// we want to build a list of newline tokens followed
// by a non-newline non-comment token; with all comments
// associated with that final non-newline non-comment token.
List<Token> newlines = new ArrayList<Token>();
List<Token> comments = new ArrayList<Token>();
Token previous = null;
Token next = commentToken;
while (true) {
if (Tokens.isNewline(next)) {
if (previous != null && Tokens.isNewline(previous)) {
// blank line; drop all comments to this point and
// start a new comment block
comments.clear();
}
newlines.add(next);
} else if (Tokens.isComment(next)) {
comments.add(next);
} else {
// a non-newline non-comment token
break;
}
previous = next;
next = tokens.next();
}
// put our concluding token in the queue with all the comments
// attached
buffer.push(new TokenWithComments(next, comments));
// now put all the newlines back in front of it
ListIterator<Token> li = newlines.listIterator(newlines.size());
while (li.hasPrevious()) {
buffer.push(new TokenWithComments(li.previous()));
}
}
private TokenWithComments popToken() {
if (buffer.isEmpty()) {
Token t = tokens.next();
if (Tokens.isComment(t)) {
consolidateCommentBlock(t);
return buffer.pop();
} else {
return new TokenWithComments(t);
}
} else {
return buffer.pop();
}
}
private TokenWithComments nextToken() {
TokenWithComments withComments = null;
withComments = popToken();
Token t = withComments.token;
if (Tokens.isProblem(t)) {
ConfigOrigin origin = t.origin();
@ -79,8 +176,7 @@ final class Parser {
message = addKeyName(message);
}
throw new ConfigException.Parse(origin, message, cause);
}
} else {
if (flavor == ConfigSyntax.JSON) {
if (Tokens.isUnquotedText(t)) {
throw parseError(addKeyName("Token not allowed in valid JSON: '"
@ -90,21 +186,25 @@ final class Parser {
}
}
return t;
return withComments;
}
}
private void putBack(Token token) {
private void putBack(TokenWithComments token) {
buffer.push(token);
}
private Token nextTokenIgnoringNewline() {
Token t = nextToken();
while (Tokens.isNewline(t)) {
private TokenWithComments nextTokenIgnoringNewline() {
TokenWithComments t = nextToken();
while (Tokens.isNewline(t.token)) {
// line number tokens have the line that was _ended_ by the
// newline, so we have to add one.
lineNumber = t.lineNumber() + 1;
lineNumber = t.token.lineNumber() + 1;
t = nextToken();
}
return t;
}
@ -116,8 +216,8 @@ final class Parser {
// is left just after the comma or the newline.
private boolean checkElementSeparator() {
if (flavor == ConfigSyntax.JSON) {
Token t = nextTokenIgnoringNewline();
if (t == Tokens.COMMA) {
TokenWithComments t = nextTokenIgnoringNewline();
if (t.token == Tokens.COMMA) {
return true;
} else {
putBack(t);
@ -125,15 +225,16 @@ final class Parser {
}
} else {
boolean sawSeparatorOrNewline = false;
Token t = nextToken();
TokenWithComments t = nextToken();
while (true) {
if (Tokens.isNewline(t)) {
if (Tokens.isNewline(t.token)) {
// newline number is the line just ended, so add one
lineNumber = t.lineNumber() + 1;
lineNumber = t.token.lineNumber() + 1;
sawSeparatorOrNewline = true;
// we want to continue to also eat
// a comma if there is one.
} else if (t == Tokens.COMMA) {
} else if (t.token == Tokens.COMMA) {
return true;
} else {
// non-newline-or-comma
@ -154,12 +255,17 @@ final class Parser {
return;
List<Token> values = null; // create only if we have value tokens
Token t = nextTokenIgnoringNewline(); // ignore a newline up front
while (Tokens.isValue(t) || Tokens.isUnquotedText(t)
|| Tokens.isSubstitution(t)) {
if (values == null)
TokenWithComments firstValueWithComments = null;
TokenWithComments t = nextTokenIgnoringNewline(); // ignore a
// newline up
// front
while (Tokens.isValue(t.token) || Tokens.isUnquotedText(t.token)
|| Tokens.isSubstitution(t.token)) {
if (values == null) {
values = new ArrayList<Token>();
values.add(t);
firstValueWithComments = t;
}
values.add(t.token);
t = nextToken(); // but don't consolidate across a newline
}
// the last one wasn't a value token
@ -168,9 +274,9 @@ final class Parser {
if (values == null)
return;
if (values.size() == 1 && Tokens.isValue(values.get(0))) {
if (values.size() == 1 && Tokens.isValue(firstValueWithComments.token)) {
// a single value token requires no consolidation
putBack(values.get(0));
putBack(firstValueWithComments);
return;
}
@ -235,7 +341,7 @@ final class Parser {
firstOrigin, minimized));
}
putBack(consolidated);
putBack(new TokenWithComments(consolidated, firstValueWithComments.comments));
}
private ConfigOrigin lineOrigin() {
@ -309,17 +415,23 @@ final class Parser {
return part + ")";
}
private AbstractConfigValue parseValue(Token token) {
if (Tokens.isValue(token)) {
return Tokens.getValue(token);
} else if (token == Tokens.OPEN_CURLY) {
return parseObject(true);
} else if (token == Tokens.OPEN_SQUARE) {
return parseArray();
private AbstractConfigValue parseValue(TokenWithComments t) {
AbstractConfigValue v;
if (Tokens.isValue(t.token)) {
v = Tokens.getValue(t.token);
} else if (t.token == Tokens.OPEN_CURLY) {
v = parseObject(true);
} else if (t.token == Tokens.OPEN_SQUARE) {
v = parseArray();
} else {
throw parseError(addQuoteSuggestion(token.toString(),
"Expecting a value but got wrong token: " + token));
throw parseError(addQuoteSuggestion(t.token.toString(),
"Expecting a value but got wrong token: " + t.token));
}
v = v.withOrigin(t.setComments(v.origin()));
return v;
}
private static AbstractConfigObject createValueUnderPath(Path path,
@ -339,24 +451,29 @@ final class Parser {
remaining = remaining.remainder();
}
}
// the setComments(null) is to ensure comments are only
// on the exact leaf node they apply to.
// a comment before "foo.bar" applies to the full setting
// "foo.bar" not also to "foo"
ListIterator<String> i = keys.listIterator(keys.size());
String deepest = i.previous();
AbstractConfigObject o = new SimpleConfigObject(value.origin(),
AbstractConfigObject o = new SimpleConfigObject(value.origin().setComments(null),
Collections.<String, AbstractConfigValue> singletonMap(
deepest, value));
while (i.hasPrevious()) {
Map<String, AbstractConfigValue> m = Collections.<String, AbstractConfigValue> singletonMap(
i.previous(), o);
o = new SimpleConfigObject(value.origin(), m);
o = new SimpleConfigObject(value.origin().setComments(null), m);
}
return o;
}
private Path parseKey(Token token) {
private Path parseKey(TokenWithComments token) {
if (flavor == ConfigSyntax.JSON) {
if (Tokens.isValueWithType(token, ConfigValueType.STRING)) {
String key = (String) Tokens.getValue(token).unwrapped();
if (Tokens.isValueWithType(token.token, ConfigValueType.STRING)) {
String key = (String) Tokens.getValue(token.token).unwrapped();
return Path.newKey(key);
} else {
throw parseError(addKeyName("Expecting close brace } or a field name here, got "
@ -364,9 +481,9 @@ final class Parser {
}
} else {
List<Token> expression = new ArrayList<Token>();
Token t = token;
while (Tokens.isValue(t) || Tokens.isUnquotedText(t)) {
expression.add(t);
TokenWithComments t = token;
while (Tokens.isValue(t.token) || Tokens.isUnquotedText(t.token)) {
expression.add(t.token);
t = nextToken(); // note: don't cross a newline
}
@ -400,13 +517,13 @@ final class Parser {
}
private void parseInclude(Map<String, AbstractConfigValue> values) {
Token t = nextTokenIgnoringNewline();
while (isUnquotedWhitespace(t)) {
TokenWithComments t = nextTokenIgnoringNewline();
while (isUnquotedWhitespace(t.token)) {
t = nextTokenIgnoringNewline();
}
if (Tokens.isValueWithType(t, ConfigValueType.STRING)) {
String name = (String) Tokens.getValue(t).unwrapped();
if (Tokens.isValueWithType(t.token, ConfigValueType.STRING)) {
String name = (String) Tokens.getValue(t.token).unwrapped();
AbstractConfigObject obj = (AbstractConfigObject) includer
.include(includeContext, name);
@ -448,8 +565,8 @@ final class Parser {
boolean lastInsideEquals = false;
while (true) {
Token t = nextTokenIgnoringNewline();
if (t == Tokens.CLOSE_CURLY) {
TokenWithComments t = nextTokenIgnoringNewline();
if (t.token == Tokens.CLOSE_CURLY) {
if (flavor == ConfigSyntax.JSON && afterComma) {
throw parseError(addQuoteSuggestion(t.toString(),
"expecting a field name after a comma, got a close brace } instead"));
@ -458,45 +575,45 @@ final class Parser {
"unbalanced close brace '}' with no open brace"));
}
break;
} else if (t == Tokens.END && !hadOpenCurly) {
} else if (t.token == Tokens.END && !hadOpenCurly) {
putBack(t);
break;
} else if (flavor != ConfigSyntax.JSON && isIncludeKeyword(t)) {
} else if (flavor != ConfigSyntax.JSON && isIncludeKeyword(t.token)) {
parseInclude(values);
afterComma = false;
} else {
Path path = parseKey(t);
Token afterKey = nextTokenIgnoringNewline();
TokenWithComments keyToken = t;
Path path = parseKey(keyToken);
TokenWithComments afterKey = nextTokenIgnoringNewline();
boolean insideEquals = false;
// path must be on-stack while we parse the value
pathStack.push(path);
Token valueToken;
TokenWithComments valueToken;
AbstractConfigValue newValue;
if (flavor == ConfigSyntax.CONF
&& afterKey == Tokens.OPEN_CURLY) {
if (flavor == ConfigSyntax.CONF && afterKey.token == Tokens.OPEN_CURLY) {
// can omit the ':' or '=' before an object value
valueToken = afterKey;
newValue = parseObject(true);
} else {
if (!isKeyValueSeparatorToken(afterKey)) {
if (!isKeyValueSeparatorToken(afterKey.token)) {
throw parseError(addQuoteSuggestion(afterKey.toString(),
"Key '" + path.render() + "' may not be followed by token: "
+ afterKey));
}
if (afterKey == Tokens.EQUALS) {
if (afterKey.token == Tokens.EQUALS) {
insideEquals = true;
equalsCount += 1;
}
consolidateValueTokens();
valueToken = nextTokenIgnoringNewline();
newValue = parseValue(valueToken);
}
newValue = parseValue(valueToken.prepend(keyToken.comments));
lastPath = pathStack.pop();
if (insideEquals) {
equalsCount -= 1;
@ -547,7 +664,7 @@ final class Parser {
afterComma = true;
} else {
t = nextTokenIgnoringNewline();
if (t == Tokens.CLOSE_CURLY) {
if (t.token == Tokens.CLOSE_CURLY) {
if (!hadOpenCurly) {
throw parseError(addQuoteSuggestion(lastPath, lastInsideEquals,
t.toString(), "unbalanced close brace '}' with no open brace"));
@ -557,7 +674,7 @@ final class Parser {
throw parseError(addQuoteSuggestion(lastPath, lastInsideEquals,
t.toString(), "Expecting close brace } or a comma, got " + t));
} else {
if (t == Tokens.END) {
if (t.token == Tokens.END) {
putBack(t);
break;
} else {
@ -567,6 +684,7 @@ final class Parser {
}
}
}
return new SimpleConfigObject(objectOrigin, values);
}
@ -577,18 +695,15 @@ final class Parser {
consolidateValueTokens();
Token t = nextTokenIgnoringNewline();
TokenWithComments t = nextTokenIgnoringNewline();
// special-case the first element
if (t == Tokens.CLOSE_SQUARE) {
if (t.token == Tokens.CLOSE_SQUARE) {
return new SimpleConfigList(arrayOrigin,
Collections.<AbstractConfigValue> emptyList());
} else if (Tokens.isValue(t)) {
} else if (Tokens.isValue(t.token) || t.token == Tokens.OPEN_CURLY
|| t.token == Tokens.OPEN_SQUARE) {
values.add(parseValue(t));
} else if (t == Tokens.OPEN_CURLY) {
values.add(parseObject(true));
} else if (t == Tokens.OPEN_SQUARE) {
values.add(parseArray());
} else {
throw parseError(addKeyName("List should have ] or a first element after the open [, instead had token: "
+ t
@ -604,7 +719,7 @@ final class Parser {
// comma (or newline equivalent) consumed
} else {
t = nextTokenIgnoringNewline();
if (t == Tokens.CLOSE_SQUARE) {
if (t.token == Tokens.CLOSE_SQUARE) {
return new SimpleConfigList(arrayOrigin, values);
} else {
throw parseError(addKeyName("List should have ended with ] or had a comma, instead had token: "
@ -619,14 +734,10 @@ final class Parser {
consolidateValueTokens();
t = nextTokenIgnoringNewline();
if (Tokens.isValue(t)) {
if (Tokens.isValue(t.token) || t.token == Tokens.OPEN_CURLY
|| t.token == Tokens.OPEN_SQUARE) {
values.add(parseValue(t));
} else if (t == Tokens.OPEN_CURLY) {
values.add(parseObject(true));
} else if (t == Tokens.OPEN_SQUARE) {
values.add(parseArray());
} else if (flavor != ConfigSyntax.JSON
&& t == Tokens.CLOSE_SQUARE) {
} else if (flavor != ConfigSyntax.JSON && t.token == Tokens.CLOSE_SQUARE) {
// we allow one trailing comma
putBack(t);
} else {
@ -640,8 +751,8 @@ final class Parser {
}
AbstractConfigValue parse() {
Token t = nextTokenIgnoringNewline();
if (t == Tokens.START) {
TokenWithComments t = nextTokenIgnoringNewline();
if (t.token == Tokens.START) {
// OK
} else {
throw new ConfigException.BugOrBroken(
@ -650,13 +761,11 @@ final class Parser {
t = nextTokenIgnoringNewline();
AbstractConfigValue result = null;
if (t == Tokens.OPEN_CURLY) {
result = parseObject(true);
} else if (t == Tokens.OPEN_SQUARE) {
result = parseArray();
if (t.token == Tokens.OPEN_CURLY || t.token == Tokens.OPEN_SQUARE) {
result = parseValue(t);
} else {
if (flavor == ConfigSyntax.JSON) {
if (t == Tokens.END) {
if (t.token == Tokens.END) {
throw parseError("Empty document");
} else {
throw parseError("Document must have an object or array at root, unexpected token: "
@ -668,11 +777,14 @@ final class Parser {
// of it, so put it back.
putBack(t);
result = parseObject(false);
// in this case we don't try to use commentsStack comments
// since they would all presumably apply to fields not the
// root object
}
}
t = nextTokenIgnoringNewline();
if (t == Tokens.END) {
if (t.token == Tokens.END) {
return result;
} else {
throw parseError("Document has trailing tokens after first object or array: "

View file

@ -145,6 +145,14 @@ final class SimpleConfigList extends AbstractConfigValue implements ConfigList {
sb.append("# ");
sb.append(v.origin().description());
sb.append("\n");
for (String comment : v.origin().comments()) {
indent(sb, indent + 1);
sb.append("# ");
sb.append(comment);
sb.append("\n");
}
indent(sb, indent + 1);
}
v.render(sb, indent + 1, formatted);
@ -353,4 +361,9 @@ final class SimpleConfigList extends AbstractConfigValue implements ConfigList {
public ConfigValue set(int index, ConfigValue element) {
throw weAreImmutable("set");
}
@Override
protected SimpleConfigList newCopy(boolean ignoresFallbacks, ConfigOrigin newOrigin) {
return new SimpleConfigList(newOrigin, value);
}
}

View file

@ -45,8 +45,9 @@ final class SimpleConfigObject extends AbstractConfigObject {
}
@Override
protected SimpleConfigObject newCopy(ResolveStatus newStatus, boolean newIgnoresFallbacks) {
return new SimpleConfigObject(origin(), value, newStatus, newIgnoresFallbacks);
protected SimpleConfigObject newCopy(ResolveStatus newStatus, boolean newIgnoresFallbacks,
ConfigOrigin newOrigin) {
return new SimpleConfigObject(newOrigin, value, newStatus, newIgnoresFallbacks);
}
@Override

View file

@ -8,6 +8,7 @@ import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
@ -22,19 +23,21 @@ final class SimpleConfigOrigin implements ConfigOrigin {
final private int endLineNumber;
final private OriginType originType;
final private String urlOrNull;
final private List<String> commentsOrNull;
protected SimpleConfigOrigin(String description, int lineNumber, int endLineNumber,
OriginType originType,
String urlOrNull) {
String urlOrNull, List<String> commentsOrNull) {
this.description = description;
this.lineNumber = lineNumber;
this.endLineNumber = endLineNumber;
this.originType = originType;
this.urlOrNull = urlOrNull;
this.commentsOrNull = commentsOrNull;
}
static SimpleConfigOrigin newSimple(String description) {
return new SimpleConfigOrigin(description, -1, -1, OriginType.GENERIC, null);
return new SimpleConfigOrigin(description, -1, -1, OriginType.GENERIC, null, null);
}
static SimpleConfigOrigin newFile(String filename) {
@ -44,17 +47,17 @@ final class SimpleConfigOrigin implements ConfigOrigin {
} catch (MalformedURLException e) {
url = null;
}
return new SimpleConfigOrigin(filename, -1, -1, OriginType.FILE, url);
return new SimpleConfigOrigin(filename, -1, -1, OriginType.FILE, url, null);
}
static SimpleConfigOrigin newURL(URL url) {
String u = url.toExternalForm();
return new SimpleConfigOrigin(u, -1, -1, OriginType.URL, u);
return new SimpleConfigOrigin(u, -1, -1, OriginType.URL, u, null);
}
static SimpleConfigOrigin newResource(String resource, URL url) {
return new SimpleConfigOrigin(resource, -1, -1, OriginType.RESOURCE,
url != null ? url.toExternalForm() : null);
url != null ? url.toExternalForm() : null, null);
}
static SimpleConfigOrigin newResource(String resource) {
@ -66,13 +69,22 @@ final class SimpleConfigOrigin implements ConfigOrigin {
return this;
} else {
return new SimpleConfigOrigin(this.description, lineNumber, lineNumber,
this.originType, this.urlOrNull);
this.originType, this.urlOrNull, this.commentsOrNull);
}
}
SimpleConfigOrigin addURL(URL url) {
return new SimpleConfigOrigin(this.description, this.lineNumber, this.endLineNumber, this.originType,
url != null ? url.toExternalForm() : null);
return new SimpleConfigOrigin(this.description, this.lineNumber, this.endLineNumber,
this.originType, url != null ? url.toExternalForm() : null, this.commentsOrNull);
}
SimpleConfigOrigin setComments(List<String> comments) {
if (ConfigImplUtil.equalsHandlingNull(comments, this.commentsOrNull)) {
return this;
} else {
return new SimpleConfigOrigin(this.description, this.lineNumber, this.endLineNumber,
this.originType, this.urlOrNull, comments);
}
}
@Override
@ -172,12 +184,22 @@ final class SimpleConfigOrigin implements ConfigOrigin {
return lineNumber;
}
@Override
public List<String> comments() {
if (commentsOrNull != null) {
return commentsOrNull;
} else {
return Collections.emptyList();
}
}
static final String MERGE_OF_PREFIX = "merge of ";
private static SimpleConfigOrigin mergeTwo(SimpleConfigOrigin a, SimpleConfigOrigin b) {
String mergedDesc;
int mergedStartLine;
int mergedEndLine;
List<String> mergedComments;
OriginType mergedType;
if (a.originType == b.originType) {
@ -233,8 +255,18 @@ final class SimpleConfigOrigin implements ConfigOrigin {
mergedURL = null;
}
if (ConfigImplUtil.equalsHandlingNull(a.commentsOrNull, b.commentsOrNull)) {
mergedComments = a.commentsOrNull;
} else {
mergedComments = new ArrayList<String>();
if (a.commentsOrNull != null)
mergedComments.addAll(a.commentsOrNull);
if (b.commentsOrNull != null)
mergedComments.addAll(b.commentsOrNull);
}
return new SimpleConfigOrigin(mergedDesc, mergedStartLine, mergedEndLine, mergedType,
mergedURL);
mergedURL, mergedComments);
}
private static int similarity(SimpleConfigOrigin a, SimpleConfigOrigin b) {

View file

@ -17,5 +17,6 @@ enum TokenType {
NEWLINE,
UNQUOTED_TEXT,
SUBSTITUTION,
PROBLEM;
PROBLEM,
COMMENT;
}

View file

@ -168,40 +168,27 @@ final class Tokenizer {
return c != '\n' && ConfigImplUtil.isWhitespace(c);
}
private int slurpComment() {
for (;;) {
int c = nextCharRaw();
if (c == -1 || c == '\n') {
return c;
}
}
}
// get next char, skipping comments
private int nextCharSkippingComments() {
for (;;) {
int c = nextCharRaw();
private boolean startOfComment(int c) {
if (c == -1) {
return -1;
return false;
} else {
if (allowComments) {
if (c == '#') {
return slurpComment();
return true;
} else if (c == '/') {
int maybeSecondSlash = nextCharRaw();
if (maybeSecondSlash == '/') {
return slurpComment();
} else {
// we want to predictably NOT consume any chars
putBack(maybeSecondSlash);
return c;
if (maybeSecondSlash == '/') {
return true;
} else {
return false;
}
} else {
return c;
return false;
}
} else {
return c;
}
return false;
}
}
}
@ -209,7 +196,7 @@ final class Tokenizer {
// get next char, skipping non-newline whitespace
private int nextCharAfterWhitespace(WhitespaceSaver saver) {
for (;;) {
int c = nextCharSkippingComments();
int c = nextCharRaw();
if (c == -1) {
return -1;
@ -269,6 +256,27 @@ final class Tokenizer {
return ((SimpleConfigOrigin) baseOrigin).setLineNumber(lineNumber);
}
// ONE char has always been consumed, either the # or the first /, but
// not both slashes
private Token pullComment(int firstChar) {
if (firstChar == '/') {
int discard = nextCharRaw();
if (discard != '/')
throw new ConfigException.BugOrBroken("called pullComment but // not seen");
}
StringBuilder sb = new StringBuilder();
for (;;) {
int c = nextCharRaw();
if (c == -1 || c == '\n') {
putBack(c);
return Tokens.newComment(lineOrigin, sb.toString());
} else {
sb.appendCodePoint(c);
}
}
}
// chars JSON allows a number to start with
static final String firstNumberChars = "0123456789-";
// chars JSON allows to be part of a number
@ -283,7 +291,7 @@ final class Tokenizer {
private Token pullUnquotedText() {
ConfigOrigin origin = lineOrigin;
StringBuilder sb = new StringBuilder();
int c = nextCharSkippingComments();
int c = nextCharRaw();
while (true) {
if (c == -1) {
break;
@ -291,6 +299,8 @@ final class Tokenizer {
break;
} else if (isWhitespace(c)) {
break;
} else if (startOfComment(c)) {
break;
} else {
sb.appendCodePoint(c);
}
@ -310,7 +320,7 @@ final class Tokenizer {
return Tokens.newBoolean(origin, false);
}
c = nextCharSkippingComments();
c = nextCharRaw();
}
// put back the char that ended the unquoted text
@ -324,12 +334,12 @@ final class Tokenizer {
StringBuilder sb = new StringBuilder();
sb.appendCodePoint(firstChar);
boolean containedDecimalOrE = false;
int c = nextCharSkippingComments();
int c = nextCharRaw();
while (c != -1 && numberChars.indexOf(c) >= 0) {
if (c == '.' || c == 'e' || c == 'E')
containedDecimalOrE = true;
sb.appendCodePoint(c);
c = nextCharSkippingComments();
c = nextCharRaw();
}
// the last character we looked at wasn't part of the number, put it
// back
@ -382,7 +392,7 @@ final class Tokenizer {
// kind of absurdly slow, but screw it for now
char[] a = new char[4];
for (int i = 0; i < 4; ++i) {
int c = nextCharSkippingComments();
int c = nextCharRaw();
if (c == -1)
throw problem("End of input but expecting 4 hex digits for \\uXXXX escape");
a[i] = (char) c;
@ -431,14 +441,14 @@ final class Tokenizer {
private Token pullSubstitution() throws ProblemException {
// the initial '$' has already been consumed
ConfigOrigin origin = lineOrigin;
int c = nextCharSkippingComments();
int c = nextCharRaw();
if (c != '{') {
throw problem(asString(c), "'$' not followed by {, '" + asString(c)
+ "' not allowed after '$'", true /* suggestQuotes */);
}
boolean optional = false;
c = nextCharSkippingComments();
c = nextCharRaw();
if (c == '?') {
optional = true;
} else {
@ -484,6 +494,9 @@ final class Tokenizer {
return line;
} else {
Token t = null;
if (startOfComment(c)) {
t = pullComment(c);
} else {
switch (c) {
case '"':
t = pullQuotedString();
@ -525,6 +538,7 @@ final class Tokenizer {
t = pullUnquotedText();
}
}
}
if (t == null)
throw new ConfigException.BugOrBroken(
@ -548,6 +562,7 @@ final class Tokenizer {
Token whitespace = whitespaceSaver.check(t, origin, lineNumber);
if (whitespace != null)
tokens.add(whitespace);
tokens.add(t);
}

View file

@ -52,7 +52,7 @@ final class Tokens {
@Override
public String toString() {
return "'\n'@" + lineNumber();
return "'\\n'@" + lineNumber();
}
@Override
@ -167,6 +167,45 @@ final class Tokens {
}
}
static private class Comment extends Token {
final private String text;
Comment(ConfigOrigin origin, String text) {
super(TokenType.COMMENT, origin);
this.text = text;
}
String text() {
return text;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("'#");
sb.append(text);
sb.append("' (COMMENT)");
return sb.toString();
}
@Override
protected boolean canEqual(Object other) {
return other instanceof Comment;
}
@Override
public boolean equals(Object other) {
return super.equals(other) && ((Comment) other).text.equals(text);
}
@Override
public int hashCode() {
int h = 41 * (41 + super.hashCode());
h = 41 * (h + text.hashCode());
return h;
}
}
// This is not a Value, because it requires special processing
static private class Substitution extends Token {
final private boolean optional;
@ -262,6 +301,18 @@ final class Tokens {
}
}
static boolean isComment(Token token) {
return token instanceof Comment;
}
static String getCommentText(Token token) {
if (token instanceof Comment) {
return ((Comment) token).text();
} else {
throw new ConfigException.BugOrBroken("tried to get comment text from " + token);
}
}
static boolean isUnquotedText(Token token) {
return token instanceof UnquotedText;
}
@ -316,6 +367,10 @@ final class Tokens {
return new Problem(origin, what, message, suggestQuotes, cause);
}
static Token newComment(ConfigOrigin origin, String text) {
return new Comment(origin, text);
}
static Token newUnquotedText(ConfigOrigin origin, String s) {
return new UnquotedText(origin, s);
}

View file

@ -3,27 +3,37 @@
##############################
# This the reference config file has all the default settings.
# Make your edits/overrides in your akka.conf.
# Make your edits/overrides in your application.conf.
akka {
version = "2.0-SNAPSHOT" # Akka version, checked against the runtime version of Akka.
# Akka version, checked against the runtime version of Akka.
version = "2.0-SNAPSHOT"
home = "" # Home directory of Akka, modules in the deploy directory will be loaded
# Home directory of Akka, modules in the deploy directory will be loaded
home = ""
enabled-modules = [] # Comma separated list of the enabled modules. Options: ["cluster", "camel", "http"]
# Comma separated list of the enabled modules. Options: ["cluster", "camel", "http"]
enabled-modules = []
event-handlers = ["akka.event.Logging$DefaultLogger"] # Event handlers to register at boot time (Logging$DefaultLogger logs to STDOUT)
loglevel = "INFO" # Options: ERROR, WARNING, INFO, DEBUG
# this level is used by the configured loggers (see "event-handlers") as soon
# Event handlers to register at boot time (Logging$DefaultLogger logs to STDOUT)
event-handlers = ["akka.event.Logging$DefaultLogger"]
# Log level used by the configured loggers (see "event-handlers") as soon
# as they have been started; before that, see "stdout-loglevel"
stdout-loglevel = "WARNING" # Loglevel for the very basic logger activated during AkkaApplication startup
# FIXME: Is there any sensible reason why we have 2 different log levels?
# Options: ERROR, WARNING, INFO, DEBUG
loglevel = "INFO"
logConfigOnStart = off # Log the complete configuration at INFO level when the actor system is started.
# Log level for the very basic logger activated during AkkaApplication startup
# Options: ERROR, WARNING, INFO, DEBUG
stdout-loglevel = "WARNING"
# Log the complete configuration at INFO level when the actor system is started.
# This is useful when you are uncertain of what configuration is used.
logConfigOnStart = off
extensions = [] # List FQCN of extensions which shall be loaded at actor system startup.
# List FQCN of extensions which shall be loaded at actor system startup.
# FIXME: clarify "extensions" here, "Akka Extensions (<link to docs>)"
extensions = []
# These boot classes are loaded (and created) automatically when the Akka Microkernel boots up
# Can be used to bootstrap your application(s)
@ -35,20 +45,34 @@ akka {
boot = []
actor {
provider = "akka.actor.LocalActorRefProvider"
creation-timeout = 20s # Timeout for ActorSystem.actorOf
timeout = 5s # Default timeout for Future based invocations
# Timeout for ActorSystem.actorOf
creation-timeout = 20s
# frequency with which stopping actors are prodded in case they had to be removed from their parents
reaper-interval = 5s
# Default timeout for Future based invocations
# - Actor: ask && ?
# - UntypedActor: ask
# - TypedActor: methods with non-void return type
serialize-messages = off # Does a deep clone of (non-primitive) messages to ensure immutability
dispatcher-shutdown-timeout = 1s # How long dispatchers by default will wait for new actors until they shut down
timeout = 5s
# Does a deep clone of (non-primitive) messages to ensure immutability
serialize-messages = off
# How long dispatchers by default will wait for new actors until they shut down
dispatcher-shutdown-timeout = 1s
deployment {
default { # deployment id pattern, e.g. /app/service-ping
# deployment id pattern, e.g. /user/service-ping
default {
router = "direct" # routing (load-balance) scheme to use
# routing (load-balance) scheme to use
# available: "direct", "round-robin", "random", "scatter-gather"
# or: fully qualified class name of the router class
# default is "direct";
@ -58,65 +82,113 @@ akka {
# supplied in the source code (overridable using create-as below)
# - target.paths: will look the paths up using actorFor and route to
# them, i.e. will not create children
router = "direct"
nr-of-instances = 1 # number of children to create in case of a non-direct router; this setting
# number of children to create in case of a non-direct router; this setting
# is ignored if target.paths is given
nr-of-instances = 1
create-as { # FIXME document 'create-as'
class = "" # fully qualified class name of recipe implementation
# FIXME document 'create-as', ticket 1511
create-as {
# fully qualified class name of recipe implementation
class = ""
}
target {
paths = [] # Alternatively to giving nr-of-instances you can specify the full paths of
# Alternatively to giving nr-of-instances you can specify the full paths of
# those actors which should be routed to. This setting takes precedence over
# nr-of-instances
paths = []
}
}
}
default-dispatcher {
type = "Dispatcher" # Must be one of the following
# Must be one of the following
# Dispatcher, (BalancingDispatcher, only valid when all actors using it are of the same type),
# A FQCN to a class inheriting MessageDispatcherConfigurator with a no-arg visible constructor
name = "DefaultDispatcher" # Name used in log messages and thread names.
daemonic = off # Toggles whether the threads created by this dispatcher should be daemons or not
keep-alive-time = 60s # Keep alive time for threads
core-pool-size-min = 8 # minimum number of threads to cap factor-based core number to
core-pool-size-factor = 8.0 # No of core threads ... ceil(available processors * factor)
core-pool-size-max = 4096 # maximum number of threads to cap factor-based number to
type = "Dispatcher"
# Name used in log messages and thread names.
name = "DefaultDispatcher"
# Toggles whether the threads created by this dispatcher should be daemons or not
daemonic = off
# Keep alive time for threads
keep-alive-time = 60s
# minimum number of threads to cap factor-based core number to
core-pool-size-min = 8
# No of core threads ... ceil(available processors * factor)
core-pool-size-factor = 8.0
# maximum number of threads to cap factor-based number to
core-pool-size-max = 4096
# Hint: max-pool-size is only used for bounded task queues
max-pool-size-min = 8 # minimum number of threads to cap factor-based max number to
max-pool-size-factor = 8.0 # Max no of threads ... ceil(available processors * factor)
max-pool-size-max = 4096 # maximum number of threads to cap factor-based max number to
task-queue-size = -1 # Specifies the bounded capacity of the task queue (< 1 == unbounded)
task-queue-type = "linked" # Specifies which type of task queue will be used, can be "array" or "linked" (default)
allow-core-timeout = on # Allow core threads to time out
throughput = 5 # Throughput defines the number of messages that are processed in a batch before the
# minimum number of threads to cap factor-based max number to
max-pool-size-min = 8
# Max no of threads ... ceil(available processors * factor)
max-pool-size-factor = 8.0
# maximum number of threads to cap factor-based max number to
max-pool-size-max = 4096
# Specifies the bounded capacity of the task queue (< 1 == unbounded)
task-queue-size = -1
# Specifies which type of task queue will be used, can be "array" or "linked" (default)
task-queue-type = "linked"
# Allow core threads to time out
allow-core-timeout = on
# Throughput defines the number of messages that are processed in a batch before the
# thread is returned to the pool. Set to 1 for as fair as possible.
throughput-deadline-time = 0ms # Throughput deadline for Dispatcher, set to 0 or negative for no deadline
mailbox-capacity = -1 # If negative (or zero) then an unbounded mailbox is used (default)
throughput = 5
# Throughput deadline for Dispatcher, set to 0 or negative for no deadline
throughput-deadline-time = 0ms
# If negative (or zero) then an unbounded mailbox is used (default)
# If positive then a bounded mailbox is used and the capacity is set using the property
# NOTE: setting a mailbox to 'blocking' can be a bit dangerous, could lead to deadlock, use with care
# The following are only used for Dispatcher and only if mailbox-capacity > 0
mailbox-push-timeout-time = 10s # Specifies the timeout to add a new message to a mailbox that is full - negative number means infinite timeout
mailbox-capacity = -1
# Specifies the timeout to add a new message to a mailbox that is full -
# negative number means infinite timeout
mailbox-push-timeout-time = 10s
}
debug {
receive = off # enable function of Actor.loggable(), which is to log any received message at DEBUG level
autoreceive = off # enable DEBUG logging of all AutoReceiveMessages (Kill, PoisonPill and the like)
lifecycle = off # enable DEBUG logging of actor lifecycle changes
fsm = off # enable DEBUG logging of all LoggingFSMs for events, transitions and timers
event-stream = off # enable DEBUG logging of subscription changes on the eventStream
# enable function of Actor.loggable(), which is to log any received message at DEBUG level
receive = off
# enable DEBUG logging of all AutoReceiveMessages (Kill, PoisonPill and the like)
autoreceive = off
# enable DEBUG logging of actor lifecycle changes
lifecycle = off
# enable DEBUG logging of all LoggingFSMs for events, transitions and timers
fsm = off
# enable DEBUG logging of subscription changes on the eventStream
event-stream = off
}
# Entries for pluggable serializers and their bindings. If a binding for a specific class is not found,
# then the default serializer (Java serialization) is used.
#
serializers {
# java = "akka.serialization.JavaSerializer"
# proto = "akka.testing.ProtobufSerializer"
# sjson = "akka.testing.SJSONSerializer"
default = "akka.serialization.JavaSerializer"
}
@ -137,7 +209,6 @@ akka {
#
scheduler {
# The HashedWheelTimer (HWT) implementation from Netty is used as the default scheduler in the system.
#
# HWT does not execute the scheduled tasks on exact time.
# It will, on every tick, check if there are any tasks behind the schedule and execute them.
# You can increase or decrease the accuracy of the execution timing by specifying smaller or larger tick duration.

View file

@ -156,15 +156,44 @@ object Actor {
/**
* Actor base trait that should be extended by or mixed to create an Actor with the semantics of the 'Actor Model':
* <a href="http://en.wikipedia.org/wiki/Actor_model">http://en.wikipedia.org/wiki/Actor_model</a>
* <p/>
* An actor has a well-defined (non-cyclic) life-cycle.
* <pre>
* => RUNNING (created and started actor) - can receive messages
* => SHUTDOWN (when 'stop' or 'exit' is invoked) - can't do anything
* </pre>
*
* <p/>
* The Actor's own ActorRef is available in the 'self' member variable.
* An actor has a well-defined (non-cyclic) life-cycle.
* - ''RUNNING'' (created and started actor) - can receive messages
* - ''SHUTDOWN'' (when 'stop' or 'exit' is invoked) - can't do anything
*
* The Actor's own [[akka.actor.ActorRef]] is available as `self`, the current
* messages sender as `sender` and the [[akka.actor.ActorContext]] as
* `context`. The only abstract method is `receive` which shall return the
* initial behavior of the actor as a partial function (behavior can be changed
* using `context.become` and `context.unbecome`).
*
* {{{
* class ExampleActor extends Actor {
* def receive = {
* // directly calculated reply
* case Request(r) => sender ! calculate(r)
*
* // just to demonstrate how to stop yourself
* case Shutdown => context.stop(self)
*
* // error kernel with child replying directly to customer
* case Dangerous(r) => context.actorOf(Props[ReplyToOriginWorker]).tell(PerformWork(r), sender)
*
* // error kernel with reply going through us
* case OtherJob(r) => context.actorOf(Props[ReplyToMeWorker]) ! JobRequest(r, sender)
* case JobReply(result, orig_s) => orig_s ! result
* }
* }
* }}}
*
* The last line demonstrates the essence of the error kernel design: spawn
* one-off actors which terminate after doing their job, pass on `sender` to
* allow direct reply if that is what makes sense, or round-trip the sender
* as shown with the fictitious JobRequest/JobReply message pair.
*
* If you dont like writing `context` you can always `import context._` to get
* direct access to `actorOf`, `stop` etc. This is not default in order to keep
* the name-space clean.
*/
trait Actor {
@ -218,25 +247,8 @@ trait Actor {
final def sender: ActorRef = context.sender
/**
* User overridable callback/setting.
* <p/>
* Partial function implementing the actor logic.
* To be implemented by concrete actor class.
* <p/>
* Example code:
* <pre>
* def receive = {
* case Ping =&gt;
* println("got a 'Ping' message")
* sender ! "pong"
*
* case OneWay =&gt;
* println("got a 'OneWay' message")
*
* case unknown =&gt;
* println("unknown message: " + unknown)
* }
* </pre>
* This defines the initial actor behavior, it must return a partial function
* with the actor logic.
*/
protected def receive: Receive
@ -258,19 +270,20 @@ trait Actor {
def postStop() {}
/**
* User overridable callback.
* User overridable callback: '''By default it disposes of all children and then calls `postStop()`.'''
* <p/>
* Is called on a crashed Actor right BEFORE it is restarted to allow clean
* up of resources before Actor is terminated.
* By default it calls postStop()
*/
def preRestart(reason: Throwable, message: Option[Any]) { postStop() }
def preRestart(reason: Throwable, message: Option[Any]) {
context.children foreach (context.stop(_))
postStop()
}
/**
* User overridable callback.
* User overridable callback: By default it calls `preStart()`.
* <p/>
* Is called right AFTER restart on the newly created Actor to allow reinitialization after an Actor crash.
* By default it calls preStart()
*/
def postRestart(reason: Throwable) { preStart() }
@ -278,7 +291,9 @@ trait Actor {
* User overridable callback.
* <p/>
* Is called when a message isn't handled by the current behavior of the actor
* by default it does: EventHandler.warning(self, message)
* by default it fails with either a [[akka.actor.DeathPactException]] (in
* case of an unhandled [[akka.actor.Terminated]] message) or a
* [[akka.actor.UnhandledMessageException]].
*/
def unhandled(message: Any) {
message match {

View file

@ -185,7 +185,7 @@ private[akka] class ActorCell(
val system: ActorSystemImpl,
val self: InternalActorRef,
val props: Props,
val parent: InternalActorRef,
@volatile var parent: InternalActorRef,
/*no member*/ _receiveTimeout: Option[Duration],
var hotswap: Stack[PartialFunction[Any, Unit]]) extends UntypedActorContext {
@ -242,6 +242,16 @@ private[akka] class ActorCell(
_actorOf(props, name)
}
final def stop(actor: ActorRef): Unit = {
val a = actor.asInstanceOf[InternalActorRef]
if (childrenRefs contains actor.path.name) {
system.locker ! a
childrenRefs -= actor.path.name
handleChildTerminated(actor)
}
a.stop()
}
final var currentMessage: Envelope = null
final var actor: Actor = _
@ -405,7 +415,8 @@ private[akka] class ActorCell(
// do not process normal messages while waiting for all children to terminate
dispatcher suspend this
if (system.settings.DebugLifecycle) system.eventStream.publish(Debug(self.path.toString, "stopping"))
for (child c) child.stop()
// do not use stop(child) because that would dissociate the children from us, but we still want to wait for them
for (child c) child.asInstanceOf[InternalActorRef].stop()
stopping = true
}
}
@ -550,15 +561,17 @@ private[akka] class ActorCell(
}
final def handleFailure(child: ActorRef, cause: Throwable): Unit = childrenRefs.get(child.path.name) match {
case Some(stats) if stats.child == child if (!props.faultHandler.handleFailure(child, cause, stats, childrenRefs.values)) throw cause
case Some(stats) if stats.child == child if (!props.faultHandler.handleFailure(this, child, cause, stats, childrenRefs.values)) throw cause
case Some(stats) system.eventStream.publish(Warning(self.path.toString, "dropping Failed(" + cause + ") from unknown child " + child + " matching names but not the same, was: " + stats.child))
case None system.eventStream.publish(Warning(self.path.toString, "dropping Failed(" + cause + ") from unknown child " + child))
}
final def handleChildTerminated(child: ActorRef): Unit = {
if (childrenRefs contains child.path.name) {
childrenRefs -= child.path.name
props.faultHandler.handleChildTerminated(child, children)
props.faultHandler.handleChildTerminated(this, child, children)
if (stopping && childrenRefs.isEmpty) doTerminate()
} else system.locker ! ChildTerminated(child)
}
// ➡➡➡ NEVER SEND THE SAME SYSTEM MESSAGE OBJECT TO TWO ACTORS ⬅⬅⬅

View file

@ -15,6 +15,7 @@ import akka.event.DeathWatch
import scala.annotation.tailrec
import java.util.concurrent.ConcurrentHashMap
import akka.event.LoggingAdapter
import java.util.concurrent.atomic.AtomicBoolean
/**
* ActorRef is an immutable and serializable handle to an Actor.
@ -110,11 +111,6 @@ abstract class ActorRef extends java.lang.Comparable[ActorRef] with Serializable
*/
def forward(message: Any)(implicit context: ActorContext) = tell(message, context.sender)
/**
* Shuts down the actor its dispatcher and message queue.
*/
def stop(): Unit
/**
* Is the actor shut down?
*/
@ -192,6 +188,7 @@ private[akka] abstract class InternalActorRef extends ActorRef with ScalaActorRe
def resume(): Unit
def suspend(): Unit
def restart(cause: Throwable): Unit
def stop(): Unit
def sendSystemMessage(message: SystemMessage): Unit
def getParent: InternalActorRef
/**
@ -325,7 +322,7 @@ private[akka] class LocalActorRef private[akka] (
a.result
case None
this.!(message)(null)
new DefaultPromise[Any](0)(actorCell.system.dispatcher)
Promise[Any]()(actorCell.system.dispatcher)
}
}
@ -411,7 +408,7 @@ class DeadLetterActorRef(val eventStream: EventStream) extends MinimalActorRef {
private[akka] def init(dispatcher: MessageDispatcher, rootPath: ActorPath) {
_path = rootPath / "deadLetters"
brokenPromise = new KeptPromise[Any](Left(new ActorKilledException("In DeadLetterActorRef - promises are always broken.")))(dispatcher)
brokenPromise = Promise.failed(new ActorKilledException("In DeadLetterActorRef - promises are always broken."))(dispatcher)
}
override def isTerminated(): Boolean = true
@ -470,24 +467,16 @@ class VirtualPathContainer(val path: ActorPath, override val getParent: Internal
class AskActorRef(
val path: ActorPath,
override val getParent: InternalActorRef,
deathWatch: DeathWatch,
timeout: Timeout,
val dispatcher: MessageDispatcher) extends MinimalActorRef {
val dispatcher: MessageDispatcher,
val deathWatch: DeathWatch) extends MinimalActorRef {
final val result = new DefaultPromise[Any](timeout)(dispatcher)
final val running = new AtomicBoolean(true)
final val result = Promise[Any]()(dispatcher)
{
val callback: Future[Any] Unit = { _ deathWatch.publish(Terminated(AskActorRef.this)); whenDone() }
result onComplete callback
result onTimeout callback
}
protected def whenDone(): Unit = ()
override def !(message: Any)(implicit sender: ActorRef = null): Unit = message match {
case Status.Success(r) result.completeWithResult(r)
case Status.Failure(f) result.completeWithException(f)
case other result.completeWithResult(other)
override def !(message: Any)(implicit sender: ActorRef = null): Unit = if (running.get) message match {
case Status.Success(r) result.success(r)
case Status.Failure(f) result.failure(f)
case other result.success(other)
}
override def sendSystemMessage(message: SystemMessage): Unit = message match {
@ -496,11 +485,13 @@ class AskActorRef(
}
override def ?(message: Any)(implicit timeout: Timeout): Future[Any] =
new KeptPromise[Any](Left(new UnsupportedOperationException("Ask/? is not supported for [%s]".format(getClass.getName))))(dispatcher)
Promise.failed(new UnsupportedOperationException("Ask/? is not supported for %s".format(getClass.getName)))(dispatcher)
override def isTerminated = result.isCompleted || result.isExpired
override def isTerminated = result.isCompleted
override def stop(): Unit = if (!isTerminated) result.completeWithException(new ActorKilledException("Stopped"))
override def stop(): Unit = if (running.getAndSet(false)) {
deathWatch.publish(Terminated(this))
}
@throws(classOf[java.io.ObjectStreamException])
private def writeReplace(): AnyRef = SerializedActorRef(path.toString)

View file

@ -234,6 +234,18 @@ trait ActorRefFactory {
* replies in order to resolve the matching set of actors.
*/
def actorSelection(path: String): ActorSelection = ActorSelection(lookupRoot, path)
/**
* Stop the actor pointed to by the given [[akka.actor.ActorRef]]; this is
* an asynchronous operation, i.e. involves a message send, but if invoked
* on an [[akka.actor.ActorContext]] if operating on a child of that
* context it will free up the name for immediate reuse.
*
* When invoked on [[akka.actor.ActorSystem]] for a top-level actor, this
* method sends a message to the guardian actor and blocks waiting for a reply,
* see `akka.actor.creation-timeout` in the `reference.conf`.
*/
def stop(actor: ActorRef): Unit
}
class ActorRefProviderException(message: String) extends AkkaException(message)
@ -248,6 +260,11 @@ private[akka] case class CreateChild(props: Props, name: String)
*/
private[akka] case class CreateRandomNameChild(props: Props)
/**
* Internal Akka use only, used in implementation of system.stop(child).
*/
private[akka] case class StopChild(child: ActorRef)
/**
* Local ActorRef provider.
*/
@ -309,7 +326,7 @@ class LocalActorRefProvider(
override def isTerminated = stopped.isOn
override def !(message: Any)(implicit sender: ActorRef = null): Unit = stopped.ifOff(message match {
case Failed(ex) if sender ne null causeOfTermination = Some(ex); sender.stop()
case Failed(ex) if sender ne null causeOfTermination = Some(ex); sender.asInstanceOf[InternalActorRef].stop()
case _ log.error(this + " received unexpected message [" + message + "]")
})
@ -329,9 +346,10 @@ class LocalActorRefProvider(
*/
private class Guardian extends Actor {
def receive = {
case Terminated(_) context.self.stop()
case Terminated(_) context.stop(self)
case CreateChild(child, name) sender ! (try context.actorOf(child, name) catch { case e: Exception e })
case CreateRandomNameChild(child) sender ! (try context.actorOf(child) catch { case e: Exception e })
case StopChild(child) context.stop(child); sender ! "ok"
case m deadLetters ! DeadLetter(m, sender, self)
}
}
@ -345,9 +363,10 @@ class LocalActorRefProvider(
def receive = {
case Terminated(_)
eventStream.stopDefaultLoggers()
context.self.stop()
context.stop(self)
case CreateChild(child, name) sender ! (try context.actorOf(child, name) catch { case e: Exception e })
case CreateRandomNameChild(child) sender ! (try context.actorOf(child) catch { case e: Exception e })
case StopChild(child) context.stop(child); sender ! "ok"
case m deadLetters ! DeadLetter(m, sender, self)
}
}
@ -374,7 +393,7 @@ class LocalActorRefProvider(
def dispatcher: MessageDispatcher = system.dispatcher
lazy val terminationFuture: DefaultPromise[Unit] = new DefaultPromise[Unit](Timeout.never)(dispatcher)
lazy val terminationFuture: Promise[Unit] = Promise[Unit]()(dispatcher)
@volatile
private var extraNames: Map[String, InternalActorRef] = Map()
@ -412,7 +431,7 @@ class LocalActorRefProvider(
lazy val tempContainer = new VirtualPathContainer(tempNode, rootGuardian, log)
val deathWatch = new LocalDeathWatch
val deathWatch = new LocalDeathWatch(1024) //TODO make configrable
def init(_system: ActorSystemImpl) {
system = _system
@ -461,20 +480,20 @@ class LocalActorRefProvider(
case t
val path = tempPath()
val name = path.name
val a = new AskActorRef(path, tempContainer, deathWatch, t, dispatcher) {
override def whenDone() {
tempContainer.removeChild(name)
}
}
val a = new AskActorRef(path, tempContainer, dispatcher, deathWatch)
tempContainer.addChild(name, a)
val f = dispatcher.prerequisites.scheduler.scheduleOnce(t.duration) { tempContainer.removeChild(name); a.stop() }
a.result onComplete { _
try { a.stop(); f.cancel() }
finally { tempContainer.removeChild(name) }
}
Some(a)
}
}
}
class LocalDeathWatch extends DeathWatch with ActorClassification {
def mapSize = 1024
class LocalDeathWatch(val mapSize: Int) extends DeathWatch with ActorClassification {
override def publish(event: Event): Unit = {
val monitors = dissociate(classify(event))
@ -508,6 +527,9 @@ class DefaultScheduler(hashedWheelTimer: HashedWheelTimer, log: LoggingAdapter,
def schedule(initialDelay: Duration, delay: Duration)(f: Unit): Cancellable =
new DefaultCancellable(hashedWheelTimer.newTimeout(createContinuousTask(delay, f), initialDelay))
def schedule(initialDelay: Duration, delay: Duration, runnable: Runnable): Cancellable =
new DefaultCancellable(hashedWheelTimer.newTimeout(createContinuousTask(delay, runnable), initialDelay))
def scheduleOnce(delay: Duration, runnable: Runnable): Cancellable =
new DefaultCancellable(hashedWheelTimer.newTimeout(createSingleTask(runnable), delay))
@ -565,6 +587,17 @@ class DefaultScheduler(hashedWheelTimer: HashedWheelTimer, log: LoggingAdapter,
}
}
private def createContinuousTask(delay: Duration, runnable: Runnable): TimerTask = {
new TimerTask {
def run(timeout: org.jboss.netty.akka.util.Timeout) {
dispatcher.dispatchTask(() runnable.run())
try timeout.getTimer.newTimeout(this, delay) catch {
case _: IllegalStateException // stop recurring if timer is stopped
}
}
}
}
private def execDirectly(t: HWTimeout): Unit = {
try t.getTask.run(t) catch {
case e: InterruptedException throw e

View file

@ -73,6 +73,7 @@ object ActorSystem {
val ProviderClass = getString("akka.actor.provider")
val CreationTimeout = Timeout(Duration(getMilliseconds("akka.actor.creation-timeout"), MILLISECONDS))
val ReaperInterval = Duration(getMilliseconds("akka.actor.reaper-interval"), MILLISECONDS)
val ActorTimeout = Timeout(Duration(getMilliseconds("akka.actor.timeout"), MILLISECONDS))
val SerializeAllMessages = getBoolean("akka.actor.serialize-messages")
@ -300,7 +301,7 @@ abstract class ActorSystem extends ActorRefFactory {
* (below which the logging actors reside) and the execute all registered
* termination handlers (see [[ActorSystem.registerOnTermination]]).
*/
def stop()
def shutdown()
/**
* Registers the provided extension and creates its payload, if this extension isn't already registered
@ -339,7 +340,7 @@ class ActorSystemImpl(val name: String, applicationConfig: Config) extends Actor
private[akka] def systemActorOf(props: Props, name: String): ActorRef = {
implicit val timeout = settings.CreationTimeout
(systemGuardian ? CreateChild(props, name)).get match {
Await.result(systemGuardian ? CreateChild(props, name), timeout.duration) match {
case ref: ActorRef ref
case ex: Exception throw ex
}
@ -347,7 +348,7 @@ class ActorSystemImpl(val name: String, applicationConfig: Config) extends Actor
def actorOf(props: Props, name: String): ActorRef = {
implicit val timeout = settings.CreationTimeout
(guardian ? CreateChild(props, name)).get match {
Await.result(guardian ? CreateChild(props, name), timeout.duration) match {
case ref: ActorRef ref
case ex: Exception throw ex
}
@ -355,12 +356,24 @@ class ActorSystemImpl(val name: String, applicationConfig: Config) extends Actor
def actorOf(props: Props): ActorRef = {
implicit val timeout = settings.CreationTimeout
(guardian ? CreateRandomNameChild(props)).get match {
Await.result(guardian ? CreateRandomNameChild(props), timeout.duration) match {
case ref: ActorRef ref
case ex: Exception throw ex
}
}
def stop(actor: ActorRef): Unit = {
implicit val timeout = settings.CreationTimeout
val path = actor.path
val guard = guardian.path
val sys = systemGuardian.path
path.parent match {
case `guard` Await.result(guardian ? StopChild(actor), timeout.duration)
case `sys` Await.result(systemGuardian ? StopChild(actor), timeout.duration)
case _ actor.asInstanceOf[InternalActorRef].stop()
}
}
import settings._
// this provides basic logging (to stdout) until .start() is called below
@ -423,18 +436,23 @@ class ActorSystemImpl(val name: String, applicationConfig: Config) extends Actor
deadLetters.init(dispatcher, provider.rootPath)
// this starts the reaper actor and the user-configured logging subscribers, which are also actors
registerOnTermination(stopScheduler())
_locker = new Locker(scheduler, ReaperInterval, lookupRoot.path / "locker", deathWatch)
loadExtensions()
if (LogConfigOnStart) logConfiguration()
this
}
@volatile
private var _locker: Locker = _ // initialized in start()
def locker = _locker
def start() = _start
def registerOnTermination[T](code: T) { terminationFuture onComplete (_ code) }
def registerOnTermination(code: Runnable) { terminationFuture onComplete (_ code.run) }
def stop() {
guardian.stop()
def shutdown() {
stop(guardian)
}
/**

View file

@ -511,7 +511,7 @@ trait FSM[S, D] extends ListenerManagement {
case _
nextState.replies.reverse foreach { r sender ! r }
terminate(nextState)
self.stop()
context.stop(self)
}
}

View file

@ -119,12 +119,12 @@ abstract class FaultHandlingStrategy {
/**
* This method is called after the child has been removed from the set of children.
*/
def handleChildTerminated(child: ActorRef, children: Iterable[ActorRef]): Unit
def handleChildTerminated(context: ActorContext, child: ActorRef, children: Iterable[ActorRef]): Unit
/**
* This method is called to act on the failure of a child: restart if the flag is true, stop otherwise.
*/
def processFailure(restart: Boolean, child: ActorRef, cause: Throwable, stats: ChildRestartStats, children: Iterable[ChildRestartStats]): Unit
def processFailure(context: ActorContext, restart: Boolean, child: ActorRef, cause: Throwable, stats: ChildRestartStats, children: Iterable[ChildRestartStats]): Unit
def handleSupervisorFailing(supervisor: ActorRef, children: Iterable[ActorRef]): Unit = {
if (children.nonEmpty)
@ -139,12 +139,12 @@ abstract class FaultHandlingStrategy {
/**
* Returns whether it processed the failure or not
*/
def handleFailure(child: ActorRef, cause: Throwable, stats: ChildRestartStats, children: Iterable[ChildRestartStats]): Boolean = {
def handleFailure(context: ActorContext, child: ActorRef, cause: Throwable, stats: ChildRestartStats, children: Iterable[ChildRestartStats]): Boolean = {
val action = if (decider.isDefinedAt(cause)) decider(cause) else Escalate
action match {
case Resume child.asInstanceOf[InternalActorRef].resume(); true
case Restart processFailure(true, child, cause, stats, children); true
case Stop processFailure(false, child, cause, stats, children); true
case Restart processFailure(context, true, child, cause, stats, children); true
case Stop processFailure(context, false, child, cause, stats, children); true
case Escalate false
}
}
@ -192,17 +192,17 @@ case class AllForOneStrategy(decider: FaultHandlingStrategy.Decider,
*/
val retriesWindow = (maxNrOfRetries, withinTimeRange)
def handleChildTerminated(child: ActorRef, children: Iterable[ActorRef]): Unit = {
children foreach (_.stop())
def handleChildTerminated(context: ActorContext, child: ActorRef, children: Iterable[ActorRef]): Unit = {
children foreach (context.stop(_))
//TODO optimization to drop all children here already?
}
def processFailure(restart: Boolean, child: ActorRef, cause: Throwable, stats: ChildRestartStats, children: Iterable[ChildRestartStats]): Unit = {
def processFailure(context: ActorContext, restart: Boolean, child: ActorRef, cause: Throwable, stats: ChildRestartStats, children: Iterable[ChildRestartStats]): Unit = {
if (children.nonEmpty) {
if (restart && children.forall(_.requestRestartPermission(retriesWindow)))
children.foreach(_.child.asInstanceOf[InternalActorRef].restart(cause))
else
children.foreach(_.child.stop())
for (c children) context.stop(c.child)
}
}
}
@ -249,13 +249,13 @@ case class OneForOneStrategy(decider: FaultHandlingStrategy.Decider,
*/
val retriesWindow = (maxNrOfRetries, withinTimeRange)
def handleChildTerminated(child: ActorRef, children: Iterable[ActorRef]): Unit = {}
def handleChildTerminated(context: ActorContext, child: ActorRef, children: Iterable[ActorRef]): Unit = {}
def processFailure(restart: Boolean, child: ActorRef, cause: Throwable, stats: ChildRestartStats, children: Iterable[ChildRestartStats]): Unit = {
def processFailure(context: ActorContext, restart: Boolean, child: ActorRef, cause: Throwable, stats: ChildRestartStats, children: Iterable[ChildRestartStats]): Unit = {
if (restart && stats.requestRestartPermission(retriesWindow))
child.asInstanceOf[InternalActorRef].restart(cause)
else
child.stop() //TODO optimization to drop child here already?
context.stop(child) //TODO optimization to drop child here already?
}
}

View file

@ -0,0 +1,50 @@
/**
* Copyright (C) 2009-2011 Typesafe Inc. <http://www.typesafe.com>
*/
package akka.actor
import akka.dispatch._
import akka.util.Duration
import akka.util.duration._
import java.util.concurrent.ConcurrentHashMap
import akka.event.DeathWatch
class Locker(scheduler: Scheduler, period: Duration, val path: ActorPath, val deathWatch: DeathWatch) extends MinimalActorRef {
class DavyJones extends Runnable {
def run = {
val iter = heap.entrySet.iterator
while (iter.hasNext) {
val soul = iter.next()
deathWatch.subscribe(Locker.this, soul.getKey) // in case Terminated got lost somewhere
soul.getKey match {
case _: LocalActorRef // nothing to do, they know what they signed up for
case nonlocal nonlocal.stop() // try again in case it was due to a communications failure
}
}
}
}
private val heap = new ConcurrentHashMap[InternalActorRef, Long]
scheduler.schedule(period, period, new DavyJones)
override def sendSystemMessage(msg: SystemMessage): Unit = this.!(msg)
override def !(msg: Any)(implicit sender: ActorRef = null): Unit = msg match {
case Terminated(soul) heap.remove(soul)
case ChildTerminated(soul) heap.remove(soul)
case soul: InternalActorRef
heap.put(soul, 0l) // wanted to put System.nanoTime and do something intelligent, but forgot what that was
deathWatch.subscribe(this, soul)
// now re-bind the soul so that it does not drown its parent
soul match {
case local: LocalActorRef
val cell = local.underlying
cell.parent = this
case _
}
case _ // ignore
}
}

View file

@ -42,6 +42,15 @@ trait Scheduler {
*/
def schedule(initialDelay: Duration, frequency: Duration)(f: Unit): Cancellable
/**
* Schedules a function to be run repeatedly with an initial delay and a frequency.
* E.g. if you would like the function to be run after 2 seconds and thereafter every 100ms you would set
* delay = Duration(2, TimeUnit.SECONDS) and frequency = Duration(100, TimeUnit.MILLISECONDS)
*
* Java API
*/
def schedule(initialDelay: Duration, frequency: Duration, runnable: Runnable): Cancellable
/**
* Schedules a Runnable to be run once with a delay, i.e. a time period that has to pass before the runnable is executed.
*

View file

@ -11,6 +11,7 @@ import java.util.concurrent.atomic.{ AtomicReference ⇒ AtomVar }
import akka.serialization.{ Serializer, Serialization }
import akka.dispatch._
import akka.serialization.SerializationExtension
import java.util.concurrent.TimeoutException
trait TypedActorFactory {
@ -24,7 +25,7 @@ trait TypedActorFactory {
*/
def stop(proxy: AnyRef): Boolean = getActorRefFor(proxy) match {
case null false
case ref ref.stop; true
case ref ref.asInstanceOf[InternalActorRef].stop; true
}
/**
@ -338,11 +339,9 @@ object TypedActor extends ExtensionId[TypedActorExtension] with ExtensionIdProvi
if (m.returnsFuture_?) {
val s = sender
m(me).asInstanceOf[Future[Any]] onComplete {
_.value.get match {
case Left(f) s ! Status.Failure(f)
case Right(r) s ! r
}
}
} else {
sender ! m(me)
}
@ -418,12 +417,12 @@ object TypedActor extends ExtensionId[TypedActorExtension] with ExtensionIdProvi
case m if m.returnsFuture_? actor.?(m, timeout)
case m if m.returnsJOption_? || m.returnsOption_?
val f = actor.?(m, timeout)
(try { f.await.value } catch { case _: FutureTimeoutException None }) match {
(try { Await.ready(f, timeout.duration).value } catch { case _: TimeoutException None }) match {
case None | Some(Right(null)) if (m.returnsJOption_?) JOption.none[Any] else None
case Some(Right(joption: AnyRef)) joption
case Some(Left(ex)) throw ex
}
case m (actor.?(m, timeout)).get.asInstanceOf[AnyRef]
case m Await.result(actor.?(m, timeout), timeout.duration).asInstanceOf[AnyRef]
}
}
}

View file

@ -8,46 +8,67 @@ import akka.japi.{ Creator, Procedure }
import akka.dispatch.{ MessageDispatcher, Promise }
/**
* Actor base trait that should be extended by or mixed to create an Actor with the semantics of the 'Actor Model':
* <a href="http://en.wikipedia.org/wiki/Actor_model">http://en.wikipedia.org/wiki/Actor_model</a>
*
* This class is the Java cousin to the [[akka.actor.Actor]] Scala interface.
* Subclass this abstract class to create a MDB-style untyped actor.
* <p/>
* This class is meant to be used from Java.
* <p/>
*
* An actor has a well-defined (non-cyclic) life-cycle.
* - ''RUNNING'' (created and started actor) - can receive messages
* - ''SHUTDOWN'' (when 'stop' or 'exit' is invoked) - can't do anything
*
* The Actor's own [[akka.actor.ActorRef]] is available as `getSelf()`, the current
* messages sender as `getSender()` and the [[akka.actor.UntypedActorContext]] as
* `getContext()`. The only abstract method is `onReceive()` which is invoked for
* each processed message unless dynamically overridden using `getContext().become()`.
*
* Here is an example on how to create and use an UntypedActor:
* <pre>
*
* {{{
* public class SampleUntypedActor extends UntypedActor {
*
* public class Reply {
* final public ActorRef sender;
* final public Result result;
* Reply(ActorRef sender, Result result) {
* this.sender = sender;
* this.result = result;
* }
* }
*
* public void onReceive(Object message) throws Exception {
* if (message instanceof String) {
* String msg = (String)message;
*
* if (msg.equals("UseReply")) {
* // Reply to original sender of message using the 'reply' method
* getContext().getSender().tell(msg + ":" + getSelf().getAddress());
*
* } else if (msg.equals("UseSender") && getSender().isDefined()) {
* // Reply to original sender of message using the sender reference
* // also passing along my own reference (the self)
* getSender().get().tell(msg, getSelf());
* if (msg.equals("UseSender")) {
* // Reply to original sender of message
* getSender().tell(msg + ":" + getSelf());
*
* } else if (msg.equals("SendToSelf")) {
* // Send message to the actor itself recursively
* getSelf().tell(msg)
* getSelf().tell("SomeOtherMessage");
*
* } else if (msg.equals("ForwardMessage")) {
* // Retreive an actor from the ActorRegistry by ID and get an ActorRef back
* ActorRef actorRef = Actor.registry.local.actorsFor("some-actor-id").head();
* } else if (msg.equals("ErrorKernelWithDirectReply")) {
* // Send work to one-off child which will reply directly to original sender
* getContext().actorOf(new Props(Worker.class)).tell("DoSomeDangerousWork", getSender());
*
* } else if (msg.equals("ErrorKernelWithReplyHere")) {
* // Send work to one-off child and collect the answer, reply handled further down
* getContext().actorOf(new Props(Worker.class)).tell("DoWorkAndReplyToMe");
*
* } else throw new IllegalArgumentException("Unknown message: " + message);
*
* } else if (message instanceof Reply) {
*
* final Reply reply = (Reply) message;
* // might want to do some processing/book-keeping here
* reply.sender.tell(reply.result);
*
* } else throw new IllegalArgumentException("Unknown message: " + message);
* }
*
* public static void main(String[] args) {
* ActorSystem system = ActorSystem.create("Sample");
* ActorRef actor = system.actorOf(SampleUntypedActor.class);
* actor.tell("SendToSelf");
* actor.stop();
* }
* }
* </pre>
* }}}
*/
abstract class UntypedActor extends Actor {
@ -65,8 +86,9 @@ abstract class UntypedActor extends Actor {
def getSelf(): ActorRef = self
/**
* The reference sender Actor of the last received message.
* Is defined if the message was sent from another Actor, else None.
* The reference sender Actor of the currently processed message. This is
* always a legal destination to send to, even if there is no logical recipient
* for the reply, in which case it will be sent to the dead letter mailbox.
*/
def getSender(): ActorRef = sender
@ -77,7 +99,7 @@ abstract class UntypedActor extends Actor {
* Actor are automatically started asynchronously when created.
* Empty default implementation.
*/
override def preStart() {}
override def preStart(): Unit = super.preStart()
/**
* User overridable callback.
@ -85,24 +107,22 @@ abstract class UntypedActor extends Actor {
* Is called asynchronously after 'actor.stop()' is invoked.
* Empty default implementation.
*/
override def postStop() {}
override def postStop(): Unit = super.postStop()
/**
* User overridable callback.
* User overridable callback: '''By default it disposes of all children and then calls `postStop()`.'''
* <p/>
* Is called on a crashed Actor right BEFORE it is restarted to allow clean
* up of resources before Actor is terminated.
* By default it calls postStop()
*/
override def preRestart(reason: Throwable, message: Option[Any]) { postStop() }
override def preRestart(reason: Throwable, message: Option[Any]): Unit = super.preRestart(reason, message)
/**
* User overridable callback.
* User overridable callback: By default it calls `preStart()`.
* <p/>
* Is called right AFTER restart on the newly created Actor to allow reinitialization after an Actor crash.
* By default it calls preStart()
*/
override def postRestart(reason: Throwable) { preStart() }
override def postRestart(reason: Throwable): Unit = super.postRestart(reason)
/**
* User overridable callback.

View file

@ -30,8 +30,10 @@ package object actor {
implicit def future2actor[T](f: akka.dispatch.Future[T]) = new {
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) }
if (f.isCompleted) send(f) else f onComplete send
f onComplete {
case Right(r) actor ! r
case Left(f) actor ! Status.Failure(f)
}
this
}
}

File diff suppressed because it is too large Load diff

View file

@ -166,7 +166,7 @@ class PromiseStream[A](implicit val dispatcher: MessageDispatcher, val timeout:
} else enqueue(elem)
} else {
if (_pendOut.compareAndSet(po, po.tail)) {
po.head completeWithResult elem
po.head success elem
if (!po.head.isCompleted) enqueue(elem)
} else enqueue(elem)
}
@ -183,11 +183,11 @@ class PromiseStream[A](implicit val dispatcher: MessageDispatcher, val timeout:
if (eo eq null) dequeue()
else {
if (eo.nonEmpty) {
if (_elemOut.compareAndSet(eo, eo.tail)) new KeptPromise(Right(eo.head))
if (_elemOut.compareAndSet(eo, eo.tail)) Promise.successful(eo.head)
else dequeue()
} else dequeue(Promise[A](timeout))
} else dequeue(Promise[A])
}
} else dequeue(Promise[A](timeout))
} else dequeue(Promise[A])
@tailrec
final def dequeue(promise: Promise[A]): Future[A] = _state.get match {
@ -227,7 +227,7 @@ class PromiseStream[A](implicit val dispatcher: MessageDispatcher, val timeout:
} else dequeue(promise)
} else {
if (_elemOut.compareAndSet(eo, eo.tail)) {
promise completeWithResult eo.head
promise success eo.head
} else dequeue(promise)
}
}

View file

@ -3,27 +3,52 @@
*/
package akka.dispatch.japi
import akka.japi.{ Procedure, Function JFunc, Option JOption }
import akka.actor.Timeout
import akka.japi.{ Procedure2, Procedure, Function JFunc, Option JOption }
/* Java API */
trait Future[+T] { self: akka.dispatch.Future[T]
private[japi] final def onTimeout[A >: T](proc: Procedure[akka.dispatch.Future[A]]): this.type = self.onTimeout(proc(_))
private[japi] final def onResult[A >: T](proc: Procedure[A]): this.type = self.onResult({ case r proc(r.asInstanceOf[A]) }: PartialFunction[T, Unit])
private[japi] final def onException(proc: Procedure[Throwable]): this.type = self.onException({ 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(_))
private[japi] final def map[A >: T, B](f: JFunc[A, B], timeout: Timeout): akka.dispatch.Future[B] = {
implicit val t = timeout
self.map(f(_))
}
private[japi] final def flatMap[A >: T, B](f: JFunc[A, akka.dispatch.Future[B]], timeout: Timeout): akka.dispatch.Future[B] = {
implicit val t = timeout
self.flatMap(f(_))
}
/**
* 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])
/**
* 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])
/**
* 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(_))
/**
* 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(_))
/**
* 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 filter[A >: T](p: JFunc[A, java.lang.Boolean], timeout: Timeout): akka.dispatch.Future[A] = {
implicit val t = timeout
/**
* 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] =
self.filter((a: Any) p(a.asInstanceOf[A])).asInstanceOf[akka.dispatch.Future[A]]
}
}

View file

@ -11,10 +11,11 @@ import akka.config.ConfigurationException
import akka.util.ReentrantGuard
import akka.util.duration._
import akka.actor.Timeout
import akka.dispatch.FutureTimeoutException
import java.util.concurrent.atomic.AtomicInteger
import akka.actor.ActorRefProvider
import scala.util.control.NoStackTrace
import java.util.concurrent.TimeoutException
import akka.dispatch.Await
object LoggingBus {
implicit def fromActorSystem(system: ActorSystem): LoggingBus = system.eventStream
@ -137,7 +138,10 @@ trait LoggingBus extends ActorEventBus {
} {
// this is very necessary, else you get infinite loop with DeadLetter
unsubscribe(logger)
logger.stop()
logger match {
case ref: InternalActorRef ref.stop()
case _
}
}
publish(Debug(simpleName(this), "all default loggers stopped"))
}
@ -146,8 +150,8 @@ trait LoggingBus extends ActorEventBus {
val name = "log" + Extension(system).id() + "-" + simpleName(clazz)
val actor = system.systemActorOf(Props(clazz), name)
implicit val timeout = Timeout(3 seconds)
val response = try actor ? InitializeLogger(this) get catch {
case _: FutureTimeoutException
val response = try Await.result(actor ? InitializeLogger(this), timeout.duration) catch {
case _: TimeoutException
publish(Warning(simpleName(this), "Logger " + name + " did not respond within " + timeout + " to InitializeLogger(bus)"))
}
if (response != LoggerInitialized)

Some files were not shown because too many files have changed in this diff Show more