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:
commit
e456213e31
179 changed files with 2334 additions and 2138 deletions
|
|
@ -20,7 +20,7 @@ public class JavaAPI {
|
|||
|
||||
@AfterClass
|
||||
public static void afterAll() {
|
||||
system.stop();
|
||||
system.shutdown();
|
||||
system = null;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ public class JavaExtension {
|
|||
|
||||
@AfterClass
|
||||
public static void afterAll() {
|
||||
system.stop();
|
||||
system.shutdown();
|
||||
system = null;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ object ConsistencySpec {
|
|||
}
|
||||
|
||||
lastStep = step
|
||||
case "done" ⇒ sender ! "done"; self.stop()
|
||||
case "done" ⇒ sender ! "done"; context.stop(self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ class DeployerSpec extends AkkaSpec(DeployerSpec.deployerConf) {
|
|||
}
|
||||
""", ConfigParseOptions.defaults).withFallback(AkkaSpec.testConf)
|
||||
|
||||
ActorSystem("invalid", invalidDeployerConf).stop()
|
||||
ActorSystem("invalid", invalidDeployerConf).shutdown()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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]) {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 }
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 = ()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"))
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ class TellLatencyPerformanceSpec extends PerformanceSpec {
|
|||
ok must be(true)
|
||||
logMeasurement(numberOfClients, durationNs, stat)
|
||||
}
|
||||
clients.foreach(_.stop())
|
||||
clients.foreach(system.stop(_))
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(_))
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(_))
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(_))
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(_))
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ class TradingLatencyPerformanceSpec extends PerformanceSpec {
|
|||
}
|
||||
logMeasurement(numberOfClients, durationNs, stat)
|
||||
}
|
||||
clients.foreach(_.stop())
|
||||
clients.foreach(system.stop(_))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ class TradingThroughputPerformanceSpec extends PerformanceSpec {
|
|||
}
|
||||
logMeasurement(numberOfClients, durationNs, totalNumberOfOrders)
|
||||
}
|
||||
clients.foreach(_.stop())
|
||||
clients.foreach(system.stop(_))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -4,6 +4,10 @@ import java.util.List;
|
|||
|
||||
import com.typesafe.config.impl.ConfigImplUtil;
|
||||
|
||||
/**
|
||||
* Contains static utility methods.
|
||||
*
|
||||
*/
|
||||
public final class ConfigUtil {
|
||||
private ConfigUtil() {
|
||||
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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: "
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -17,5 +17,6 @@ enum TokenType {
|
|||
NEWLINE,
|
||||
UNQUOTED_TEXT,
|
||||
SUBSTITUTION,
|
||||
PROBLEM;
|
||||
PROBLEM,
|
||||
COMMENT;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
* message’s 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 don’t 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 =>
|
||||
* println("got a 'Ping' message")
|
||||
* sender ! "pong"
|
||||
*
|
||||
* case OneWay =>
|
||||
* println("got a 'OneWay' message")
|
||||
*
|
||||
* case unknown =>
|
||||
* 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 {
|
||||
|
|
|
|||
|
|
@ -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 ⬅⬅⬅
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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?
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
50
akka-actor/src/main/scala/akka/actor/Locker.scala
Normal file
50
akka-actor/src/main/scala/akka/actor/Locker.scala
Normal 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
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
* message’s 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.
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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]]
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
Loading…
Add table
Add a link
Reference in a new issue