diff --git a/akka-actor-tests/src/test/scala/akka/actor/ActorConfigurationVerificationSpec.scala b/akka-actor-tests/src/test/scala/akka/actor/ActorConfigurationVerificationSpec.scala new file mode 100644 index 0000000000..bedf51f083 --- /dev/null +++ b/akka-actor-tests/src/test/scala/akka/actor/ActorConfigurationVerificationSpec.scala @@ -0,0 +1,77 @@ +/** + * Copyright (C) 2009-2012 Typesafe Inc. + */ +package akka.actor + +import akka.testkit._ +import akka.testkit.DefaultTimeout +import akka.testkit.TestEvent._ +import akka.util.duration._ +import akka.routing._ +import org.scalatest.BeforeAndAfterEach +import akka.ConfigurationException + +object ActorConfigurationVerificationSpec { + + class TestActor extends Actor { + def receive: Receive = { + case _ ⇒ + } + } + + val config = """ + balancing-dispatcher { + type = BalancingDispatcher + throughput = 1 + } + pinned-dispatcher { + executor = "thread-pool-executor" + type = PinnedDispatcher + } + """ +} + +@org.junit.runner.RunWith(classOf[org.scalatest.junit.JUnitRunner]) +class ActorConfigurationVerificationSpec extends AkkaSpec(ActorConfigurationVerificationSpec.config) with DefaultTimeout with BeforeAndAfterEach { + import ActorConfigurationVerificationSpec._ + + override def atStartup { + system.eventStream.publish(Mute(EventFilter[ConfigurationException](""))) + } + + "An Actor configured with a BalancingDispatcher" must { + "fail verification with a ConfigurationException if also configured with a RoundRobinRouter" in { + intercept[ConfigurationException] { + system.actorOf(Props[TestActor].withDispatcher("balancing-dispatcher").withRouter(RoundRobinRouter(2))) + } + } + "fail verification with a ConfigurationException if also configured with a BroadcastRouter" in { + intercept[ConfigurationException] { + system.actorOf(Props[TestActor].withDispatcher("balancing-dispatcher").withRouter(BroadcastRouter(2))) + } + } + "fail verification with a ConfigurationException if also configured with a RandomRouter" in { + intercept[ConfigurationException] { + system.actorOf(Props[TestActor].withDispatcher("balancing-dispatcher").withRouter(RandomRouter(2))) + } + } + "fail verification with a ConfigurationException if also configured with a SmallestMailboxRouter" in { + intercept[ConfigurationException] { + system.actorOf(Props[TestActor].withDispatcher("balancing-dispatcher").withRouter(SmallestMailboxRouter(2))) + } + } + "fail verification with a ConfigurationException if also configured with a ScatterGatherFirstCompletedRouter" in { + intercept[ConfigurationException] { + system.actorOf(Props[TestActor].withDispatcher("balancing-dispatcher").withRouter(ScatterGatherFirstCompletedRouter(nrOfInstances = 2, within = 2 seconds))) + } + } + "not fail verification with a ConfigurationException also not configured with a Router" in { + system.actorOf(Props[TestActor].withDispatcher("balancing-dispatcher")) + } + } + "An Actor configured with a non-balancing dispatcher" must { + "not fail verification with a ConfigurationException if also configured with a Router" in { + system.actorOf(Props[TestActor].withDispatcher("pinned-dispatcher").withRouter(RoundRobinRouter(2))) + } + } +} diff --git a/akka-actor-tests/src/test/scala/akka/actor/ActorLifeCycleSpec.scala b/akka-actor-tests/src/test/scala/akka/actor/ActorLifeCycleSpec.scala index 16b4055d0e..d87aaaaee6 100644 --- a/akka-actor-tests/src/test/scala/akka/actor/ActorLifeCycleSpec.scala +++ b/akka-actor-tests/src/test/scala/akka/actor/ActorLifeCycleSpec.scala @@ -13,6 +13,7 @@ import akka.util.duration._ import java.util.concurrent.atomic._ import akka.dispatch.Await import akka.pattern.ask +import java.util.UUID.{ randomUUID ⇒ newUuid } object ActorLifeCycleSpec { @@ -35,7 +36,7 @@ class ActorLifeCycleSpec extends AkkaSpec with BeforeAndAfterEach with ImplicitS "invoke preRestart, preStart, postRestart when using OneForOneStrategy" in { filterException[ActorKilledException] { - val id = newUuid().toString + val id = newUuid.toString val supervisor = system.actorOf(Props(new Supervisor( OneForOneStrategy(maxNrOfRetries = 3)(List(classOf[Exception]))))) val gen = new AtomicInteger(0) diff --git a/akka-actor-tests/src/test/scala/akka/actor/ActorRefSpec.scala b/akka-actor-tests/src/test/scala/akka/actor/ActorRefSpec.scala index e8c667bc7e..bec066d97a 100644 --- a/akka-actor-tests/src/test/scala/akka/actor/ActorRefSpec.scala +++ b/akka-actor-tests/src/test/scala/akka/actor/ActorRefSpec.scala @@ -393,7 +393,7 @@ class ActorRefSpec extends AkkaSpec with DefaultTimeout { override def postRestart(reason: Throwable) = latch.countDown() })) - protected def receive = { case "sendKill" ⇒ ref ! Kill } + def receive = { case "sendKill" ⇒ ref ! Kill } })) boss ! "sendKill" diff --git a/akka-actor-tests/src/test/scala/akka/actor/ActorWithStashSpec.scala b/akka-actor-tests/src/test/scala/akka/actor/ActorWithStashSpec.scala index c516a17a42..524913b01d 100644 --- a/akka-actor-tests/src/test/scala/akka/actor/ActorWithStashSpec.scala +++ b/akka-actor-tests/src/test/scala/akka/actor/ActorWithStashSpec.scala @@ -131,7 +131,7 @@ class ActorWithStashSpec extends AkkaSpec(ActorWithStashSpec.testConf) with Defa val hasMsgLatch = new TestLatch val slaveProps = myProps(new Actor with Stash { - protected def receive = { + def receive = { case "crash" ⇒ throw new Exception("Crashing...") diff --git a/akka-actor-tests/src/test/scala/akka/actor/FSMActorSpec.scala b/akka-actor-tests/src/test/scala/akka/actor/FSMActorSpec.scala index ef49cbc18d..cc98a23f1f 100644 --- a/akka-actor-tests/src/test/scala/akka/actor/FSMActorSpec.scala +++ b/akka-actor-tests/src/test/scala/akka/actor/FSMActorSpec.scala @@ -147,7 +147,7 @@ class FSMActorSpec extends AkkaSpec(Map("akka.actor.debug.fsm" -> true)) with Im object Hello object Bye val tester = system.actorOf(Props(new Actor { - protected def receive = { + def receive = { case Hello ⇒ lock ! "hello" case "world" ⇒ answerLatch.open case Bye ⇒ lock ! "bye" diff --git a/akka-actor-tests/src/test/scala/akka/actor/HotSwapSpec.scala b/akka-actor-tests/src/test/scala/akka/actor/HotSwapSpec.scala index 236d3bd014..120caa3e93 100644 --- a/akka-actor-tests/src/test/scala/akka/actor/HotSwapSpec.scala +++ b/akka-actor-tests/src/test/scala/akka/actor/HotSwapSpec.scala @@ -6,10 +6,60 @@ package akka.actor import akka.testkit._ +object HotSwapSpec { + abstract class Becomer extends Actor { + + } +} + @org.junit.runner.RunWith(classOf[org.scalatest.junit.JUnitRunner]) class HotSwapSpec extends AkkaSpec with ImplicitSender { + import HotSwapSpec.Becomer "An Actor" must { + "be able to become in its constructor" in { + val a = system.actorOf(Props(new Becomer { + context.become { case always ⇒ sender ! always } + def receive = { case always ⇒ sender ! "FAILURE" } + })) + a ! "pigdog" + expectMsg("pigdog") + } + + "be able to become multiple times in its constructor" in { + val a = system.actorOf(Props(new Becomer { + for (i ← 1 to 4) context.become({ case always ⇒ sender ! i + ":" + always }) + def receive = { case always ⇒ sender ! "FAILURE" } + })) + a ! "pigdog" + expectMsg("4:pigdog") + } + + "be able to become with stacking in its constructor" in { + val a = system.actorOf(Props(new Becomer { + context.become({ case always ⇒ sender ! "pigdog:" + always; context.unbecome() }, false) + def receive = { case always ⇒ sender ! "badass:" + always } + })) + a ! "pigdog" + expectMsg("pigdog:pigdog") + a ! "badass" + expectMsg("badass:badass") + } + + "be able to become, with stacking, multiple times in its constructor" in { + val a = system.actorOf(Props(new Becomer { + for (i ← 1 to 4) context.become({ case always ⇒ sender ! i + ":" + always; context.unbecome() }, false) + def receive = { case always ⇒ sender ! "FAILURE" } + })) + a ! "pigdog" + a ! "pigdog" + a ! "pigdog" + a ! "pigdog" + expectMsg("4:pigdog") + expectMsg("3:pigdog") + expectMsg("2:pigdog") + expectMsg("1:pigdog") + } "be able to hotswap its behavior with become(..)" in { val a = system.actorOf(Props(new Actor { @@ -30,13 +80,10 @@ class HotSwapSpec extends AkkaSpec with ImplicitSender { val a = system.actorOf(Props(new Actor { def receive = { case "init" ⇒ sender ! "init" - case "swap" ⇒ - context.become({ - case "swapped" ⇒ - sender ! "swapped" - case "revert" ⇒ - context.unbecome() - }) + case "swap" ⇒ context.become({ + case "swapped" ⇒ sender ! "swapped" + case "revert" ⇒ context.unbecome() + }) } })) diff --git a/akka-actor-tests/src/test/scala/akka/actor/ReceiveTimeoutSpec.scala b/akka-actor-tests/src/test/scala/akka/actor/ReceiveTimeoutSpec.scala index dc08df1c98..09fe9c103f 100644 --- a/akka-actor-tests/src/test/scala/akka/actor/ReceiveTimeoutSpec.scala +++ b/akka-actor-tests/src/test/scala/akka/actor/ReceiveTimeoutSpec.scala @@ -22,7 +22,7 @@ class ReceiveTimeoutSpec extends AkkaSpec { val timeoutActor = system.actorOf(Props(new Actor { context.setReceiveTimeout(500 milliseconds) - protected def receive = { + def receive = { case ReceiveTimeout ⇒ timeoutLatch.open } })) @@ -38,7 +38,7 @@ class ReceiveTimeoutSpec extends AkkaSpec { val timeoutActor = system.actorOf(Props(new Actor { context.setReceiveTimeout(500 milliseconds) - protected def receive = { + def receive = { case Tick ⇒ () case ReceiveTimeout ⇒ timeoutLatch.open } @@ -58,7 +58,7 @@ class ReceiveTimeoutSpec extends AkkaSpec { val timeoutActor = system.actorOf(Props(new Actor { context.setReceiveTimeout(500 milliseconds) - protected def receive = { + def receive = { case Tick ⇒ () case ReceiveTimeout ⇒ count.incrementAndGet @@ -78,7 +78,7 @@ class ReceiveTimeoutSpec extends AkkaSpec { val timeoutLatch = TestLatch() val timeoutActor = system.actorOf(Props(new Actor { - protected def receive = { + def receive = { case ReceiveTimeout ⇒ timeoutLatch.open } })) diff --git a/akka-actor-tests/src/test/scala/akka/actor/RestartStrategySpec.scala b/akka-actor-tests/src/test/scala/akka/actor/RestartStrategySpec.scala index 829ab081e0..8d114bc396 100644 --- a/akka-actor-tests/src/test/scala/akka/actor/RestartStrategySpec.scala +++ b/akka-actor-tests/src/test/scala/akka/actor/RestartStrategySpec.scala @@ -40,7 +40,7 @@ class RestartStrategySpec extends AkkaSpec with DefaultTimeout { val slaveProps = Props(new Actor { - protected def receive = { + def receive = { case Ping ⇒ countDownLatch.countDown() case Crash ⇒ throw new Exception("Crashing...") } @@ -83,7 +83,7 @@ class RestartStrategySpec extends AkkaSpec with DefaultTimeout { val slaveProps = Props(new Actor { - protected def receive = { + def receive = { case Crash ⇒ throw new Exception("Crashing...") } @@ -110,7 +110,7 @@ class RestartStrategySpec extends AkkaSpec with DefaultTimeout { val slaveProps = Props(new Actor { - protected def receive = { + def receive = { case Ping ⇒ if (!pingLatch.isOpen) pingLatch.open else secondPingLatch.open case Crash ⇒ throw new Exception("Crashing...") @@ -166,7 +166,7 @@ class RestartStrategySpec extends AkkaSpec with DefaultTimeout { val slaveProps = Props(new Actor { - protected def receive = { + def receive = { case Ping ⇒ countDownLatch.countDown() case Crash ⇒ throw new Exception("Crashing...") } @@ -221,7 +221,7 @@ class RestartStrategySpec extends AkkaSpec with DefaultTimeout { val slaveProps = Props(new Actor { - protected def receive = { + def receive = { case Ping ⇒ countDownLatch.countDown() case Crash ⇒ throw new Exception("Crashing...") } diff --git a/akka-actor-tests/src/test/scala/akka/actor/SchedulerSpec.scala b/akka-actor-tests/src/test/scala/akka/actor/SchedulerSpec.scala index 3b87af2aad..beeb2a4c3b 100644 --- a/akka-actor-tests/src/test/scala/akka/actor/SchedulerSpec.scala +++ b/akka-actor-tests/src/test/scala/akka/actor/SchedulerSpec.scala @@ -18,7 +18,12 @@ class SchedulerSpec extends AkkaSpec with BeforeAndAfterEach with DefaultTimeout } override def afterEach { - while (cancellables.peek() ne null) { Option(cancellables.poll()).foreach(_.cancel()) } + while (cancellables.peek() ne null) { + for (c ← Option(cancellables.poll())) { + c.cancel() + c.isCancelled must be === true + } + } } "A Scheduler" must { diff --git a/akka-actor-tests/src/test/scala/akka/actor/SupervisorHierarchySpec.scala b/akka-actor-tests/src/test/scala/akka/actor/SupervisorHierarchySpec.scala index a04e83f39b..62752d8052 100644 --- a/akka-actor-tests/src/test/scala/akka/actor/SupervisorHierarchySpec.scala +++ b/akka-actor-tests/src/test/scala/akka/actor/SupervisorHierarchySpec.scala @@ -20,7 +20,7 @@ object SupervisorHierarchySpec { */ class CountDownActor(countDown: CountDownLatch, override val supervisorStrategy: SupervisorStrategy) extends Actor { - protected def receive = { + def receive = { case p: Props ⇒ sender ! context.actorOf(p) } // test relies on keeping children around during restart @@ -67,7 +67,7 @@ class SupervisorHierarchySpec extends AkkaSpec with DefaultTimeout { val crasher = context.watch(context.actorOf(Props(new CountDownActor(countDownMessages, SupervisorStrategy.defaultStrategy)))) - protected def receive = { + def receive = { case "killCrasher" ⇒ crasher ! Kill case Terminated(_) ⇒ countDownMax.countDown() } diff --git a/akka-actor-tests/src/test/scala/akka/actor/SupervisorMiscSpec.scala b/akka-actor-tests/src/test/scala/akka/actor/SupervisorMiscSpec.scala index 92af540a9a..197e749d2e 100644 --- a/akka-actor-tests/src/test/scala/akka/actor/SupervisorMiscSpec.scala +++ b/akka-actor-tests/src/test/scala/akka/actor/SupervisorMiscSpec.scala @@ -37,7 +37,7 @@ class SupervisorMiscSpec extends AkkaSpec(SupervisorMiscSpec.config) with Defaul val workerProps = Props(new Actor { override def postRestart(cause: Throwable) { countDownLatch.countDown() } - protected def receive = { + def receive = { case "status" ⇒ this.sender ! "OK" case _ ⇒ this.context.stop(self) } diff --git a/akka-actor-tests/src/test/scala/akka/actor/dispatch/ActorModelSpec.scala b/akka-actor-tests/src/test/scala/akka/actor/dispatch/ActorModelSpec.scala index 88358e9f16..acc416f04f 100644 --- a/akka-actor-tests/src/test/scala/akka/actor/dispatch/ActorModelSpec.scala +++ b/akka-actor-tests/src/test/scala/akka/actor/dispatch/ActorModelSpec.scala @@ -400,17 +400,17 @@ abstract class ActorModelSpec(config: String) extends AkkaSpec(config) with Defa val a = newTestActor(dispatcher.id) val f1 = a ? Reply("foo") val f2 = a ? Reply("bar") - val f3 = try { a ? Interrupt } catch { case ie: InterruptedException ⇒ Promise.failed(ActorInterruptedException(ie)) } + val f3 = try { a ? Interrupt } catch { case ie: InterruptedException ⇒ Promise.failed(new ActorInterruptedException(ie)) } val f4 = a ? Reply("foo2") - val f5 = try { a ? Interrupt } catch { case ie: InterruptedException ⇒ Promise.failed(ActorInterruptedException(ie)) } + val f5 = try { a ? Interrupt } catch { case ie: InterruptedException ⇒ Promise.failed(new ActorInterruptedException(ie)) } val f6 = a ? Reply("bar2") 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(intercept[ActorInterruptedException](Await.result(f3, timeout.duration)).getCause.getMessage === "Ping!") assert(Await.result(f6, timeout.duration) === "bar2") - assert(intercept[ActorInterruptedException](Await.result(f5, timeout.duration)).getMessage === "Ping!") + assert(intercept[ActorInterruptedException](Await.result(f5, timeout.duration)).getCause.getMessage === "Ping!") } } diff --git a/akka-actor-tests/src/test/scala/akka/event/EventStreamSpec.scala b/akka-actor-tests/src/test/scala/akka/event/EventStreamSpec.scala index d2497c4a69..a8cd32f5d3 100644 --- a/akka-actor-tests/src/test/scala/akka/event/EventStreamSpec.scala +++ b/akka-actor-tests/src/test/scala/akka/event/EventStreamSpec.scala @@ -19,7 +19,7 @@ object EventStreamSpec { loglevel = INFO event-handlers = ["akka.event.EventStreamSpec$MyLog", "%s"] } - """.format(Logging.StandardOutLoggerName)) + """.format(Logging.StandardOutLogger.getClass.getName)) val configUnhandled = ConfigFactory.parseString(""" akka { diff --git a/akka-actor-tests/src/test/scala/akka/pattern/PatternSpec.scala b/akka-actor-tests/src/test/scala/akka/pattern/PatternSpec.scala index 2776beabce..68e6d40824 100644 --- a/akka-actor-tests/src/test/scala/akka/pattern/PatternSpec.scala +++ b/akka-actor-tests/src/test/scala/akka/pattern/PatternSpec.scala @@ -7,11 +7,9 @@ package akka.pattern import akka.testkit.AkkaSpec import akka.actor.Props import akka.actor.Actor -import akka.actor.ActorTimeoutException import akka.util.Duration import akka.util.duration._ import akka.dispatch.{ Future, Promise, Await } -import java.lang.IllegalStateException object PatternSpec { case class Work(duration: Duration) @@ -41,13 +39,10 @@ class PatternSpec extends AkkaSpec { Await.ready(gracefulStop(target, 1 millis), 1 second) } - "complete Future with ActorTimeoutException when actor not terminated within timeout" in { + "complete Future with AskTimeoutException when actor not terminated within timeout" in { val target = system.actorOf(Props[TargetActor]) target ! Work(250 millis) - val result = gracefulStop(target, 10 millis) - intercept[ActorTimeoutException] { - Await.result(result, 200 millis) - } + intercept[AskTimeoutException] { Await.result(gracefulStop(target, 10 millis), 200 millis) } } } diff --git a/akka-actor-tests/src/test/scala/akka/performance/workbench/PerformanceSpec.scala b/akka-actor-tests/src/test/scala/akka/performance/workbench/PerformanceSpec.scala index ca6e42d67f..ca23dd5a33 100644 --- a/akka-actor-tests/src/test/scala/akka/performance/workbench/PerformanceSpec.scala +++ b/akka-actor-tests/src/test/scala/akka/performance/workbench/PerformanceSpec.scala @@ -3,12 +3,11 @@ package akka.performance.workbench import scala.collection.immutable.TreeMap import org.apache.commons.math.stat.descriptive.DescriptiveStatistics import org.scalatest.BeforeAndAfterEach -import akka.actor.simpleName import akka.testkit.AkkaSpec -import akka.actor.ActorSystem import akka.util.Duration import com.typesafe.config.Config import java.util.concurrent.TimeUnit +import akka.event.Logging abstract class PerformanceSpec(cfg: Config = BenchmarkConfig.config) extends AkkaSpec(cfg) with BeforeAndAfterEach { @@ -36,7 +35,7 @@ abstract class PerformanceSpec(cfg: Config = BenchmarkConfig.config) extends Akk } def logMeasurement(numberOfClients: Int, durationNs: Long, n: Long) { - val name = simpleName(this) + val name = Logging.simpleName(this) val durationS = durationNs.toDouble / 1000000000.0 val stats = Stats( @@ -51,7 +50,7 @@ abstract class PerformanceSpec(cfg: Config = BenchmarkConfig.config) extends Akk } def logMeasurement(numberOfClients: Int, durationNs: Long, stat: DescriptiveStatistics) { - val name = simpleName(this) + val name = Logging.simpleName(this) val durationS = durationNs.toDouble / 1000000000.0 val percentiles = TreeMap[Int, Long]( diff --git a/akka-actor-tests/src/test/scala/akka/routing/ConfiguredLocalRoutingSpec.scala b/akka-actor-tests/src/test/scala/akka/routing/ConfiguredLocalRoutingSpec.scala index d01f1cda04..5bedc8fc33 100644 --- a/akka-actor-tests/src/test/scala/akka/routing/ConfiguredLocalRoutingSpec.scala +++ b/akka-actor-tests/src/test/scala/akka/routing/ConfiguredLocalRoutingSpec.scala @@ -8,7 +8,7 @@ import java.util.concurrent.atomic.AtomicInteger import org.junit.runner.RunWith import akka.actor.{ Props, LocalActorRef, Deploy, Actor, ActorRef } -import akka.config.ConfigurationException +import akka.ConfigurationException import akka.dispatch.Await import akka.pattern.{ ask, gracefulStop } import akka.testkit.{ TestLatch, ImplicitSender, DefaultTimeout, AkkaSpec } diff --git a/akka-actor-tests/src/test/scala/akka/routing/ResizerSpec.scala b/akka-actor-tests/src/test/scala/akka/routing/ResizerSpec.scala index 457c4ab411..ede4a69d7c 100644 --- a/akka-actor-tests/src/test/scala/akka/routing/ResizerSpec.scala +++ b/akka-actor-tests/src/test/scala/akka/routing/ResizerSpec.scala @@ -128,35 +128,6 @@ class ResizerSpec extends AkkaSpec(ResizerSpec.config) with DefaultTimeout with current.routees.size must be(2) } - "resize when busy" in { - - val busy = new TestLatch(1) - - val resizer = DefaultResizer( - lowerBound = 1, - upperBound = 3, - pressureThreshold = 0, - messagesPerResize = 1) - - val router = system.actorOf(Props[BusyActor].withRouter(RoundRobinRouter(resizer = Some(resizer))).withDispatcher("bal-disp")) - - val latch1 = new TestLatch(1) - router ! (latch1, busy) - Await.ready(latch1, 2 seconds) - - val latch2 = new TestLatch(1) - router ! (latch2, busy) - Await.ready(latch2, 2 seconds) - - val latch3 = new TestLatch(1) - router ! (latch3, busy) - Await.ready(latch3, 2 seconds) - - Await.result(router ? CurrentRoutees, 5 seconds).asInstanceOf[RouterRoutees].routees.size must be(3) - - busy.countDown() - } - "grow as needed under pressure" in { // make sure the pool starts at the expected lower limit and grows to the upper as needed // as influenced by the backlog of blocking pooled actors diff --git a/akka-actor-tests/src/test/scala/akka/routing/RoutingSpec.scala b/akka-actor-tests/src/test/scala/akka/routing/RoutingSpec.scala index 2ae32cfcf5..5ad6da271f 100644 --- a/akka-actor-tests/src/test/scala/akka/routing/RoutingSpec.scala +++ b/akka-actor-tests/src/test/scala/akka/routing/RoutingSpec.scala @@ -10,7 +10,7 @@ import akka.testkit._ import akka.util.duration._ import akka.dispatch.Await import akka.util.Duration -import akka.config.ConfigurationException +import akka.ConfigurationException import com.typesafe.config.ConfigFactory import akka.pattern.ask import java.util.concurrent.ConcurrentHashMap diff --git a/akka-actor/src/main/java/org/jboss/netty/akka/util/internal/ConcurrentIdentityHashMap.java b/akka-actor/src/main/java/akka/util/internal/ConcurrentIdentityHashMap.java similarity index 99% rename from akka-actor/src/main/java/org/jboss/netty/akka/util/internal/ConcurrentIdentityHashMap.java rename to akka-actor/src/main/java/akka/util/internal/ConcurrentIdentityHashMap.java index ff8a568d02..eb83c98f35 100644 --- a/akka-actor/src/main/java/org/jboss/netty/akka/util/internal/ConcurrentIdentityHashMap.java +++ b/akka-actor/src/main/java/akka/util/internal/ConcurrentIdentityHashMap.java @@ -18,7 +18,7 @@ * Expert Group and released to the public domain, as explained at * http://creativecommons.org/licenses/publicdomain */ -package org.jboss.netty.akka.util.internal; +package akka.util.internal; import java.util.AbstractCollection; import java.util.AbstractMap; diff --git a/akka-actor/src/main/java/org/jboss/netty/akka/util/HashedWheelTimer.java b/akka-actor/src/main/java/akka/util/internal/HashedWheelTimer.java similarity index 96% rename from akka-actor/src/main/java/org/jboss/netty/akka/util/HashedWheelTimer.java rename to akka-actor/src/main/java/akka/util/internal/HashedWheelTimer.java index 6e54fa2233..25841861c5 100644 --- a/akka-actor/src/main/java/org/jboss/netty/akka/util/HashedWheelTimer.java +++ b/akka-actor/src/main/java/akka/util/internal/HashedWheelTimer.java @@ -13,12 +13,10 @@ * License for the specific language governing permissions and limitations * under the License. */ -package org.jboss.netty.akka.util; +package akka.util.internal; import akka.event.LoggingAdapter; import akka.util.Duration; -import org.jboss.netty.akka.util.internal.ConcurrentIdentityHashMap; -import org.jboss.netty.akka.util.internal.ReusableIterator; import java.util.*; import java.util.concurrent.ThreadFactory; @@ -34,7 +32,7 @@ import java.util.concurrent.locks.ReentrantReadWriteLock; *

Tick Duration

* * As described with 'approximated', this timer does not execute the scheduled - * {@link TimerTask} on time. {@link org.jboss.netty.akka.util.HashedWheelTimer}, on every tick, will + * {@link TimerTask} on time. {@link HashedWheelTimer}, on every tick, will * check if there are any {@link TimerTask}s behind the schedule and execute * them. *

@@ -46,7 +44,7 @@ import java.util.concurrent.locks.ReentrantReadWriteLock; * *

Ticks per Wheel (Wheel Size)

* - * {@link org.jboss.netty.akka.util.HashedWheelTimer} maintains a data structure called 'wheel'. + * {@link HashedWheelTimer} maintains a data structure called 'wheel'. * To put simply, a wheel is a hash table of {@link TimerTask}s whose hash * function is 'dead line of the task'. The default number of ticks per wheel * (i.e. the size of the wheel) is 512. You could specify a larger value @@ -54,7 +52,7 @@ import java.util.concurrent.locks.ReentrantReadWriteLock; * *

Do not create many instances.

* - * {@link org.jboss.netty.akka.util.HashedWheelTimer} creates a new thread whenever it is instantiated and + * {@link HashedWheelTimer} creates a new thread whenever it is instantiated and * started. Therefore, you should make sure to create only one instance and * share it across your application. One of the common mistakes, that makes * your application unresponsive, is to create a new instance in @@ -63,7 +61,7 @@ import java.util.concurrent.locks.ReentrantReadWriteLock; * *

Implementation Details

* - * {@link org.jboss.netty.akka.util.HashedWheelTimer} is based on + * {@link HashedWheelTimer} is based on * George Varghese and * Tony Lauck's paper, * 'Hashed @@ -155,7 +153,7 @@ public class HashedWheelTimer implements Timer { ticksPerWheel = normalizeTicksPerWheel(ticksPerWheel); Set[] wheel = new Set[ticksPerWheel]; for (int i = 0; i < wheel.length; i ++) { - wheel[i] = new MapBackedSet(new ConcurrentIdentityHashMap(16, 0.95f, 4)); + wheel[i] = Collections.newSetFromMap(new ConcurrentIdentityHashMap(16, 0.95f, 4)); } return wheel; } diff --git a/akka-actor/src/main/java/org/jboss/netty/akka/util/internal/ReusableIterator.java b/akka-actor/src/main/java/akka/util/internal/ReusableIterator.java similarity index 95% rename from akka-actor/src/main/java/org/jboss/netty/akka/util/internal/ReusableIterator.java rename to akka-actor/src/main/java/akka/util/internal/ReusableIterator.java index 210edbe65d..8c8e5e50e5 100644 --- a/akka-actor/src/main/java/org/jboss/netty/akka/util/internal/ReusableIterator.java +++ b/akka-actor/src/main/java/akka/util/internal/ReusableIterator.java @@ -13,7 +13,7 @@ * License for the specific language governing permissions and limitations * under the License. */ -package org.jboss.netty.akka.util.internal; +package akka.util.internal; import java.util.Iterator; diff --git a/akka-actor/src/main/java/org/jboss/netty/akka/util/internal/SystemPropertyUtil.java b/akka-actor/src/main/java/akka/util/internal/SystemPropertyUtil.java similarity index 98% rename from akka-actor/src/main/java/org/jboss/netty/akka/util/internal/SystemPropertyUtil.java rename to akka-actor/src/main/java/akka/util/internal/SystemPropertyUtil.java index bf3e2ac571..affef54bfc 100644 --- a/akka-actor/src/main/java/org/jboss/netty/akka/util/internal/SystemPropertyUtil.java +++ b/akka-actor/src/main/java/akka/util/internal/SystemPropertyUtil.java @@ -13,7 +13,7 @@ * License for the specific language governing permissions and limitations * under the License. */ -package org.jboss.netty.akka.util.internal; +package akka.util.internal; import java.util.regex.Pattern; diff --git a/akka-actor/src/main/java/org/jboss/netty/akka/util/Timeout.java b/akka-actor/src/main/java/akka/util/internal/Timeout.java similarity index 97% rename from akka-actor/src/main/java/org/jboss/netty/akka/util/Timeout.java rename to akka-actor/src/main/java/akka/util/internal/Timeout.java index dbda2110d3..a03534bb8d 100644 --- a/akka-actor/src/main/java/org/jboss/netty/akka/util/Timeout.java +++ b/akka-actor/src/main/java/akka/util/internal/Timeout.java @@ -13,7 +13,7 @@ * License for the specific language governing permissions and limitations * under the License. */ -package org.jboss.netty.akka.util; +package akka.util.internal; /** * A handle associated with a {@link TimerTask} that is returned by a diff --git a/akka-actor/src/main/java/org/jboss/netty/akka/util/Timer.java b/akka-actor/src/main/java/akka/util/internal/Timer.java similarity index 92% rename from akka-actor/src/main/java/org/jboss/netty/akka/util/Timer.java rename to akka-actor/src/main/java/akka/util/internal/Timer.java index b5bd8c6a7c..9cb02794de 100644 --- a/akka-actor/src/main/java/org/jboss/netty/akka/util/Timer.java +++ b/akka-actor/src/main/java/akka/util/internal/Timer.java @@ -13,7 +13,7 @@ * License for the specific language governing permissions and limitations * under the License. */ -package org.jboss.netty.akka.util; +package akka.util.internal; import akka.util.Duration; import java.util.Set; @@ -45,7 +45,7 @@ public interface Timer { Timeout newTimeout(TimerTask task, Duration delay); /** - * Releases all resources acquired by this {@link org.jboss.netty.akka.util.Timer} and cancels all + * Releases all resources acquired by this {@link Timer} and cancels all * tasks which were scheduled but not executed yet. * * @return the handles associated with the tasks which were canceled by diff --git a/akka-actor/src/main/java/org/jboss/netty/akka/util/TimerTask.java b/akka-actor/src/main/java/akka/util/internal/TimerTask.java similarity index 82% rename from akka-actor/src/main/java/org/jboss/netty/akka/util/TimerTask.java rename to akka-actor/src/main/java/akka/util/internal/TimerTask.java index 3d0190d8f5..673dde67c7 100644 --- a/akka-actor/src/main/java/org/jboss/netty/akka/util/TimerTask.java +++ b/akka-actor/src/main/java/akka/util/internal/TimerTask.java @@ -13,11 +13,11 @@ * License for the specific language governing permissions and limitations * under the License. */ -package org.jboss.netty.akka.util; +package akka.util.internal; /** * A task which is executed after the delay specified with - * {@link Timer#newTimeout(org.jboss.netty.akka.util.TimerTask, long, java.util.concurrent.TimeUnit)} + * {@link Timer#newTimeout(TimerTask, long, java.util.concurrent.TimeUnit)} * . * * @author The Netty Project @@ -28,7 +28,7 @@ public interface TimerTask { /** * Executed after the delay specified with - * {@link Timer#newTimeout(org.jboss.netty.akka.util.TimerTask, long, java.util.concurrent.TimeUnit)} + * {@link Timer#newTimeout(TimerTask, long, java.util.concurrent.TimeUnit)} * . * * @param timeout diff --git a/akka-actor/src/main/java/com/eaio/util/lang/Hex.java b/akka-actor/src/main/java/com/eaio/util/lang/Hex.java deleted file mode 100644 index 7794059517..0000000000 --- a/akka-actor/src/main/java/com/eaio/util/lang/Hex.java +++ /dev/null @@ -1,215 +0,0 @@ -/* - * Hex.java - * - * Created 04.07.2003. - * - * eaio: UUID - an implementation of the UUID specification Copyright (c) 2003-2009 Johann Burkard (jb@eaio.com) - * http://eaio.com. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE - * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ -package com.eaio.util.lang; - -import java.io.IOException; - -/** - * Number-to-hexadecimal and hexadecimal-to-number conversions. - * - * @see UUID - * @author Johann Burkard - * @version $Id: Hex.java 1888 2009-03-15 12:43:24Z johann $ - */ -public final class Hex { - - /** - * No instances needed. - */ - private Hex() { - super(); - } - - private static final char[] DIGITS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', - 'f' }; - - /** - * Turns a short into hex octets. - * - * @param a the {@link Appendable}, may not be null - * @param in the integer - * @return {@link Appendable} - */ - public static Appendable append(Appendable a, short in) { - return append(a, (long) in, 4); - } - - /** - * Turns a short into hex octets. - * - * @param a the {@link Appendable}, may not be null - * @param in the integer - * @param length the number of octets to produce - * @return {@link Appendable} - */ - public static Appendable append(Appendable a, short in, int length) { - return append(a, (long) in, length); - } - - /** - * Turns an int into hex octets. - * - * @param a the {@link Appendable}, may not be null - * @param in the integer - * @return {@link Appendable} - */ - public static Appendable append(Appendable a, int in) { - return append(a, (long) in, 8); - } - - /** - * Turns an int into hex octets. - * - * @param a the {@link Appendable}, may not be null - * @param in the integer - * @param length the number of octets to produce - * @return {@link Appendable} - */ - public static Appendable append(Appendable a, int in, int length) { - return append(a, (long) in, length); - } - - /** - * Turns a long into hex octets. - * - * @param a the {@link Appendable}, may not be null - * @param in the long - * @return {@link Appendable} - */ - public static Appendable append(Appendable a, long in) { - return append(a, in, 16); - } - - /** - * Turns a long into hex octets. - * - * @param a the {@link Appendable}, may not be null - * @param in the long - * @param length the number of octets to produce - * @return {@link Appendable} - */ - public static Appendable append(Appendable a, long in, int length) { - try { - int lim = (length << 2) - 4; - while (lim >= 0) { - a.append(DIGITS[(byte) (in >> lim) & 0x0f]); - lim -= 4; - } - } - catch (IOException ex) { - // Bla - } - return a; - } - - /** - * Turns a byte array into hex octets. - * - * @param a the {@link Appendable}, may not be null - * @param bytes the byte array - * @return {@link Appendable} - */ - public static Appendable append(Appendable a, byte[] bytes) { - try { - for (byte b : bytes) { - a.append(DIGITS[(byte) ((b & 0xF0) >> 4)]); - a.append(DIGITS[(byte) (b & 0x0F)]); - } - } - catch (IOException ex) { - // Bla - } - return a; - } - - /** - * Parses a long from a hex encoded number. This method will skip all characters that are not 0-9, - * A-F and a-f. - *

- * Returns 0 if the {@link CharSequence} does not contain any interesting characters. - * - * @param s the {@link CharSequence} to extract a long from, may not be null - * @return a long - * @throws NullPointerException if the {@link CharSequence} is null - */ - public static long parseLong(CharSequence s) { - long out = 0; - byte shifts = 0; - char c; - for (int i = 0; i < s.length() && shifts < 16; i++) { - c = s.charAt(i); - if ((c > 47) && (c < 58)) { - ++shifts; - out <<= 4; - out |= c - 48; - } - else if ((c > 64) && (c < 71)) { - ++shifts; - out <<= 4; - out |= c - 55; - } - else if ((c > 96) && (c < 103)) { - ++shifts; - out <<= 4; - out |= c - 87; - } - } - return out; - } - - /** - * Parses a short from a hex encoded number. This method will skip all characters that are not 0-9, - * A-F and a-f. - *

- * Returns 0 if the {@link CharSequence} does not contain any interesting characters. - * - * @param s the {@link CharSequence} to extract a short from, may not be null - * @return a short - * @throws NullPointerException if the {@link CharSequence} is null - */ - public static short parseShort(String s) { - short out = 0; - byte shifts = 0; - char c; - for (int i = 0; i < s.length() && shifts < 4; i++) { - c = s.charAt(i); - if ((c > 47) && (c < 58)) { - ++shifts; - out <<= 4; - out |= c - 48; - } - else if ((c > 64) && (c < 71)) { - ++shifts; - out <<= 4; - out |= c - 55; - } - else if ((c > 96) && (c < 103)) { - ++shifts; - out <<= 4; - out |= c - 87; - } - } - return out; - } - -} diff --git a/akka-actor/src/main/java/com/eaio/uuid/MACAddressParser.java b/akka-actor/src/main/java/com/eaio/uuid/MACAddressParser.java deleted file mode 100644 index c077147470..0000000000 --- a/akka-actor/src/main/java/com/eaio/uuid/MACAddressParser.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * MACAddressParserTest.java - * - * Created 30.01.2006. - * - * eaio: UUID - an implementation of the UUID specification - * Copyright (c) 2003-2009 Johann Burkard (jb@eaio.com) http://eaio.com. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN - * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE - * USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ -package com.eaio.uuid; - -/** - * The MAC address parser attempts to find the following patterns: - *

- * - * @see UUID - * @author Johann Burkard - * @version $Id: MACAddressParser.java 1888 2009-03-15 12:43:24Z johann $ - */ -class MACAddressParser { - - /** - * No instances needed. - */ - private MACAddressParser() { - super(); - } - - /** - * Attempts to find a pattern in the given String. - * - * @param in the String, may not be null - * @return the substring that matches this pattern or null - */ - static String parse(String in) { - - String out = in; - - // lanscan - - int hexStart = out.indexOf("0x"); - if (hexStart != -1 && out.indexOf("ETHER") != -1) { - int hexEnd = out.indexOf(' ', hexStart); - if (hexEnd > hexStart + 2) { - out = out.substring(hexStart, hexEnd); - } - } - - else { - - int octets = 0; - int lastIndex, old, end; - - if (out.indexOf('-') > -1) { - out = out.replace('-', ':'); - } - - lastIndex = out.lastIndexOf(':'); - - if (lastIndex > out.length() - 2) { - out = null; - } - else { - - end = Math.min(out.length(), lastIndex + 3); - - ++octets; - old = lastIndex; - while (octets != 5 && lastIndex != -1 && lastIndex > 1) { - lastIndex = out.lastIndexOf(':', --lastIndex); - if (old - lastIndex == 3 || old - lastIndex == 2) { - ++octets; - old = lastIndex; - } - } - - if (octets == 5 && lastIndex > 1) { - out = out.substring(lastIndex - 2, end).trim(); - } - else { - out = null; - } - - } - - } - - if (out != null && out.startsWith("0x")) { - out = out.substring(2); - } - - return out; - } - -} diff --git a/akka-actor/src/main/java/com/eaio/uuid/UUID.java b/akka-actor/src/main/java/com/eaio/uuid/UUID.java deleted file mode 100644 index a578a68c6d..0000000000 --- a/akka-actor/src/main/java/com/eaio/uuid/UUID.java +++ /dev/null @@ -1,308 +0,0 @@ -/* - * UUID.java - * - * Created 07.02.2003 - * - * eaio: UUID - an implementation of the UUID specification - * Copyright (c) 2003-2009 Johann Burkard (jb@eaio.com) http://eaio.com. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN - * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE - * USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ -package com.eaio.uuid; - -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.io.Serializable; - -import com.eaio.util.lang.Hex; - -/** - * Creates UUIDs according to the DCE Universal Token Identifier specification. - *

- * All you need to know: - *

- * UUID u = new UUID();
- * 
- * - * @see - * http://www.opengroup.org/onlinepubs/9629399/apdxa.htm - * - * @see - * http://www.uddi.org/pubs/draft-leach-uuids-guids-01.txt - * - * @see UUID - * @author Johann Burkard - * @version $Id: UUID.java 1888 2009-03-15 12:43:24Z johann $ - */ -public class UUID implements Comparable, Serializable, Cloneable { - - /** - * Hasn't ever changed between versions. - */ - static final long serialVersionUID = 7435962790062944603L; - - /** - * The time field of the UUID. - * - * @serial - */ - public long time; - - /** - * The clock sequence and node field of the UUID. - * - * @serial - */ - public long clockSeqAndNode; - - /** - * Constructor for UUID. Constructs a new, unique UUID. - * - * @see UUIDGen#newTime() - * @see UUIDGen#getClockSeqAndNode() - */ - public UUID() { - this(UUIDGen.newTime(), UUIDGen.getClockSeqAndNode()); - } - - /** - * Constructor for UUID. Constructs a UUID from two long values. - * - * @param time the upper 64 bits - * @param clockSeqAndNode the lower 64 bits - */ - public UUID(long time, long clockSeqAndNode) { - this.time = time; - this.clockSeqAndNode = clockSeqAndNode; - } - - /** - * Copy constructor for UUID. Values of the given UUID are copied. - * - * @param u the UUID, may not be null - */ - public UUID(UUID u) { - this(u.time, u.clockSeqAndNode); - } - - /** - * Parses a textual representation of a UUID. - *

- * No validation is performed. If the {@link CharSequence} is shorter than 36 characters, - * {@link ArrayIndexOutOfBoundsException}s will be thrown. - * - * @param s the {@link CharSequence}, may not be null - */ - public UUID(CharSequence s) { - this(Hex.parseLong(s.subSequence(0, 18)), Hex.parseLong(s.subSequence( - 19, 36))); - } - - /** - * Compares this UUID to another Object. Throws a {@link ClassCastException} if - * the other Object is not an instance of the UUID class. Returns a value - * smaller than zero if the other UUID is "larger" than this UUID and a value - * larger than zero if the other UUID is "smaller" than this UUID. - * - * @param t the other UUID, may not be null - * @return a value < 0, 0 or a value > 0 - * @see java.lang.Comparable#compareTo(java.lang.Object) - * @throws ClassCastException - */ - public int compareTo(UUID t) { - if (this == t) { - return 0; - } - if (time > t.time) { - return 1; - } - if (time < t.time) { - return -1; - } - if (clockSeqAndNode > t.clockSeqAndNode) { - return 1; - } - if (clockSeqAndNode < t.clockSeqAndNode) { - return -1; - } - return 0; - } - - /** - * Tweaked Serialization routine. - * - * @param out the ObjectOutputStream - * @throws IOException - */ - private void writeObject(ObjectOutputStream out) throws IOException { - out.writeLong(time); - out.writeLong(clockSeqAndNode); - } - - /** - * Tweaked Serialization routine. - * - * @param in the ObjectInputStream - * @throws IOException - */ - private void readObject(ObjectInputStream in) throws IOException { - time = in.readLong(); - clockSeqAndNode = in.readLong(); - } - - /** - * Returns this UUID as a String. - * - * @return a String, never null - * @see java.lang.Object#toString() - * @see #toAppendable(Appendable) - */ - @Override - public final String toString() { - return toAppendable(null).toString(); - } - - /** - * Appends a String representation of this to the given {@link StringBuffer} or - * creates a new one if none is given. - * - * @param in the StringBuffer to append to, may be null - * @return a StringBuffer, never null - * @see #toAppendable(Appendable) - */ - public StringBuffer toStringBuffer(StringBuffer in) { - StringBuffer out = in; - if (out == null) { - out = new StringBuffer(36); - } - else { - out.ensureCapacity(out.length() + 36); - } - return (StringBuffer) toAppendable(out); - } - - /** - * Appends a String representation of this object to the given {@link Appendable} object. - *

- * For reasons I'll probably never understand, Sun has decided to have a number of I/O classes implement - * Appendable which forced them to destroy an otherwise nice and simple interface with {@link IOException}s. - *

- * I decided to ignore any possible IOExceptions in this method. - * - * @param a the Appendable object, may be null - * @return an Appendable object, defaults to a {@link StringBuilder} if a is null - */ - public Appendable toAppendable(Appendable a) { - Appendable out = a; - if (out == null) { - out = new StringBuilder(36); - } - try { - Hex.append(out, (int) (time >> 32)).append('-'); - Hex.append(out, (short) (time >> 16)).append('-'); - Hex.append(out, (short) time).append('-'); - Hex.append(out, (short) (clockSeqAndNode >> 48)).append('-'); - Hex.append(out, clockSeqAndNode, 12); - } - catch (IOException ex) { - // What were they thinking? - } - return out; - } - - /** - * Returns a hash code of this UUID. The hash code is calculated by XOR'ing the - * upper 32 bits of the time and clockSeqAndNode fields and the lower 32 bits of - * the time and clockSeqAndNode fields. - * - * @return an int representing the hash code - * @see java.lang.Object#hashCode() - */ - @Override - public int hashCode() { - return (int) ((time >> 32) ^ time ^ (clockSeqAndNode >> 32) ^ clockSeqAndNode); - } - - /** - * Clones this UUID. - * - * @return a new UUID with identical values, never null - */ - @Override - public Object clone() { - try { - return super.clone(); - } - catch (CloneNotSupportedException ex) { - // One of Sun's most epic fails. - return null; - } - } - - /** - * Returns the time field of the UUID (upper 64 bits). - * - * @return the time field - */ - public final long getTime() { - return time; - } - - /** - * Returns the clock and node field of the UUID (lower 64 bits). - * - * @return the clockSeqAndNode field - */ - public final long getClockSeqAndNode() { - return clockSeqAndNode; - } - - /** - * Compares two Objects for equality. - * - * @see java.lang.Object#equals(Object) - * @param obj the Object to compare this UUID with, may be null - * @return true if the other Object is equal to this UUID, - * false if not - */ - @Override - public boolean equals(Object obj) { - if (!(obj instanceof UUID)) { - return false; - } - return compareTo((UUID) obj) == 0; - } - - /** - * Returns the nil UUID (a UUID whose values are both set to zero). - *

- * Starting with version 2.0, this method does return a new UUID instance every - * time it is called. Earlier versions returned one instance. This has now been - * changed because this UUID has public, non-final instance fields. Returning a - * new instance is therefore more safe. - * - * @return a nil UUID, never null - */ - public static UUID nilUUID() { - return new UUID(0, 0); - } - -} diff --git a/akka-actor/src/main/java/com/eaio/uuid/UUIDGen.java b/akka-actor/src/main/java/com/eaio/uuid/UUIDGen.java deleted file mode 100644 index fb60e1727a..0000000000 --- a/akka-actor/src/main/java/com/eaio/uuid/UUIDGen.java +++ /dev/null @@ -1,368 +0,0 @@ -/* - * UUIDGen.java - * - * Created on 09.08.2003. - * - * eaio: UUID - an implementation of the UUID specification - * Copyright (c) 2003-2009 Johann Burkard (jb@eaio.com) http://eaio.com. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN - * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE - * USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ -package com.eaio.uuid; - -import java.io.BufferedReader; -import java.io.File; -import java.io.IOException; -import java.io.InputStreamReader; -import java.net.InetAddress; -import java.net.InterfaceAddress; -import java.net.NetworkInterface; -import java.net.SocketException; -import java.net.UnknownHostException; -import java.util.Enumeration; -import java.util.concurrent.atomic.AtomicLong; - -import com.eaio.util.lang.Hex; - -/** - * This class contains methods to generate UUID fields. These methods have been - * refactored out of {@link com.eaio.uuid.UUID}. - *

- * Starting with version 2, this implementation tries to obtain the MAC address - * of the network card. Under Microsoft Windows, the ifconfig - * command is used which may pop up a command window in Java Virtual Machines - * prior to 1.4 once this class is initialized. The command window is closed - * automatically. - *

- * The MAC address code has been tested extensively in Microsoft Windows, - * Linux, Solaris 8, HP-UX 11, but should work in MacOS X and BSDs, too. - *

- * If you use JDK 6 or later, the code in {@link InterfaceAddress} will be used. - * - * @see UUID - * @author Johann Burkard - * @version $Id: UUIDGen.java 2914 2010-04-23 11:35:00Z johann $ - * @see com.eaio.uuid.UUID - */ -public final class UUIDGen { - - /** - * No instances needed. - */ - private UUIDGen() { - super(); - } - - /** - * The last time value. Used to remove duplicate UUIDs. - */ - private final static AtomicLong lastTime = new AtomicLong(Long.MIN_VALUE); - - /** - * The cached MAC address. - */ - private static String macAddress = null; - - /** - * The current clock and node value. - */ - private static long clockSeqAndNode = 0x8000000000000000L; - - static { - - try { - Class.forName("java.net.InterfaceAddress"); - macAddress = Class.forName( - "com.eaio.uuid.UUIDGen$HardwareAddressLookup").newInstance().toString(); - } - catch (ExceptionInInitializerError err) { - // Ignored. - } - catch (ClassNotFoundException ex) { - // Ignored. - } - catch (LinkageError err) { - // Ignored. - } - catch (IllegalAccessException ex) { - // Ignored. - } - catch (InstantiationException ex) { - // Ignored. - } - catch (SecurityException ex) { - // Ignored. - } - - if (macAddress == null) { - - Process p = null; - BufferedReader in = null; - - try { - String osname = System.getProperty("os.name", ""); - - if (osname.startsWith("Windows")) { - p = Runtime.getRuntime().exec( - new String[] { "ipconfig", "/all" }, null); - } - // Solaris code must appear before the generic code - else if (osname.startsWith("Solaris") - || osname.startsWith("SunOS")) { - String hostName = getFirstLineOfCommand( - "uname", "-n" ); - if (hostName != null) { - p = Runtime.getRuntime().exec( - new String[] { "/usr/sbin/arp", hostName }, - null); - } - } - else if (new File("/usr/sbin/lanscan").exists()) { - p = Runtime.getRuntime().exec( - new String[] { "/usr/sbin/lanscan" }, null); - } - else if (new File("/sbin/ifconfig").exists()) { - p = Runtime.getRuntime().exec( - new String[] { "/sbin/ifconfig", "-a" }, null); - } - - if (p != null) { - in = new BufferedReader(new InputStreamReader( - p.getInputStream()), 128); - String l = null; - while ((l = in.readLine()) != null) { - macAddress = MACAddressParser.parse(l); - if (macAddress != null - && Hex.parseShort(macAddress) != 0xff) { - break; - } - } - } - - } - catch (SecurityException ex) { - // Ignore it. - } - catch (IOException ex) { - // Ignore it. - } - finally { - if (p != null) { - if (in != null) { - try { - in.close(); - } - catch (IOException ex) { - // Ignore it. - } - } - try { - p.getErrorStream().close(); - } - catch (IOException ex) { - // Ignore it. - } - try { - p.getOutputStream().close(); - } - catch (IOException ex) { - // Ignore it. - } - p.destroy(); - } - } - - } - - if (macAddress != null) { - clockSeqAndNode |= Hex.parseLong(macAddress); - } - else { - try { - byte[] local = InetAddress.getLocalHost().getAddress(); - clockSeqAndNode |= (local[0] << 24) & 0xFF000000L; - clockSeqAndNode |= (local[1] << 16) & 0xFF0000; - clockSeqAndNode |= (local[2] << 8) & 0xFF00; - clockSeqAndNode |= local[3] & 0xFF; - } - catch (UnknownHostException ex) { - clockSeqAndNode |= (long) (Math.random() * 0x7FFFFFFF); - } - } - - // Skip the clock sequence generation process and use random instead. - - clockSeqAndNode |= (long) (Math.random() * 0x3FFF) << 48; - - } - - /** - * Returns the current clockSeqAndNode value. - * - * @return the clockSeqAndNode value - * @see UUID#getClockSeqAndNode() - */ - public static long getClockSeqAndNode() { - return clockSeqAndNode; - } - - /** - * Generates a new time field. Each time field is unique and larger than the - * previously generated time field. - * - * @return a new time value - * @see UUID#getTime() - */ - public static long newTime() { - return createTime(System.currentTimeMillis()); - } - - /** - * Creates a new time field from the given timestamp. Note that even identical - * values of currentTimeMillis will produce different time fields. - * - * @param currentTimeMillis the timestamp - * @return a new time value - * @see UUID#getTime() - */ - public static long createTime(long currentTimeMillis) { - - long time; - - // UTC time - - long timeMillis = (currentTimeMillis * 10000) + 0x01B21DD213814000L; - - // Make sure our time is unique - - for(;;) { - final long c = lastTime.get(); - if (timeMillis <= c) { - timeMillis = lastTime.incrementAndGet(); - break; - } else if(lastTime.compareAndSet(c, timeMillis)) break; - } - - // time low - - time = timeMillis << 32; - - // time mid - - time |= (timeMillis & 0xFFFF00000000L) >> 16; - - // time hi and version - - time |= 0x1000 | ((timeMillis >> 48) & 0x0FFF); // version 1 - - return time; - - } - - /** - * Returns the MAC address. Not guaranteed to return anything. - * - * @return the MAC address, may be null - */ - public static String getMACAddress() { - return macAddress; - } - - /** - * Returns the first line of the shell command. - * - * @param commands the commands to run - * @return the first line of the command - * @throws IOException - */ - static String getFirstLineOfCommand(String... commands) throws IOException { - - Process p = null; - BufferedReader reader = null; - - try { - p = Runtime.getRuntime().exec(commands); - reader = new BufferedReader(new InputStreamReader( - p.getInputStream()), 128); - - return reader.readLine(); - } - finally { - if (p != null) { - if (reader != null) { - try { - reader.close(); - } - catch (IOException ex) { - // Ignore it. - } - } - try { - p.getErrorStream().close(); - } - catch (IOException ex) { - // Ignore it. - } - try { - p.getOutputStream().close(); - } - catch (IOException ex) { - // Ignore it. - } - p.destroy(); - } - } - - } - - /** - * Scans MAC addresses for good ones. - */ - static class HardwareAddressLookup { - - /** - * @see java.lang.Object#toString() - */ - @Override - public String toString() { - String out = null; - try { - Enumeration ifs = NetworkInterface.getNetworkInterfaces(); - if (ifs != null) { - while (ifs.hasMoreElements()) { - NetworkInterface iface = ifs.nextElement(); - byte[] hardware = iface.getHardwareAddress(); - if (hardware != null && hardware.length == 6 - && hardware[1] != (byte) 0xff) { - out = Hex.append(new StringBuilder(36), hardware).toString(); - break; - } - } - } - } - catch (SocketException ex) { - // Ignore it. - } - return out; - } - - } - -} diff --git a/akka-actor/src/main/java/org/jboss/netty/akka/util/MapBackedSet.java b/akka-actor/src/main/java/org/jboss/netty/akka/util/MapBackedSet.java deleted file mode 100644 index 2bc1bc25e0..0000000000 --- a/akka-actor/src/main/java/org/jboss/netty/akka/util/MapBackedSet.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2009 Red Hat, Inc. - * - * Red Hat licenses this file to you under the Apache License, version 2.0 - * (the "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - */ -package org.jboss.netty.akka.util; - -import java.io.Serializable; -import java.util.AbstractSet; -import java.util.Iterator; -import java.util.Map; - -/** - * A {@link java.util.Map}-backed {@link java.util.Set}. - * - * @author The Netty Project - * @author Trustin Lee - * - * @version $Rev: 2080 $, $Date: 2010-01-26 18:04:19 +0900 (Tue, 26 Jan 2010) $ - */ -final class MapBackedSet extends AbstractSet implements Serializable { - - private static final long serialVersionUID = -6761513279741915432L; - - private final Map map; - - /** - * Creates a new instance which wraps the specified {@code map}. - */ - MapBackedSet(Map map) { - this.map = map; - } - - @Override - public int size() { - return map.size(); - } - - @Override - public boolean contains(Object o) { - return map.containsKey(o); - } - - @Override - public boolean add(E o) { - return map.put(o, Boolean.TRUE) == null; - } - - @Override - public boolean remove(Object o) { - return map.remove(o) != null; - } - - @Override - public void clear() { - map.clear(); - } - - @Override - public Iterator iterator() { - return map.keySet().iterator(); - } -} diff --git a/akka-actor/src/main/scala/akka/AkkaException.scala b/akka-actor/src/main/scala/akka/AkkaException.scala index 85de2504d3..04e820419f 100644 --- a/akka-actor/src/main/scala/akka/AkkaException.scala +++ b/akka-actor/src/main/scala/akka/AkkaException.scala @@ -4,26 +4,6 @@ package akka -import akka.actor.newUuid - -object AkkaException { - - def toStringWithStackTrace(throwable: Throwable): String = throwable match { - case null ⇒ "Unknown Throwable: was 'null'" - case ae: AkkaException ⇒ ae.toLongString - case e ⇒ "%s:%s\n%s" format (e.getClass.getName, e.getMessage, stackTraceToString(e)) - } - - def stackTraceToString(throwable: Throwable): String = { - val trace = throwable.getStackTrace - val sb = new StringBuilder - for (i ← 0 until trace.length) - sb.append("\tat %s\n" format trace(i)) - sb.toString - } - -} - /** * Akka base Exception. Each Exception gets: *

*/ //TODO add @SerialVersionUID(1L) when SI-4804 is fixed -class AkkaException(message: String = "", cause: Throwable = null) extends RuntimeException(message, cause) with Serializable { - lazy val uuid = newUuid.toString +class AkkaException(message: String, cause: Throwable) extends RuntimeException(message, cause) with Serializable { + def this(msg: String) = this(msg, null) - override lazy val toString = - "%s:%s\n[%s]".format(getClass.getName, message, uuid) + lazy val uuid: String = java.util.UUID.randomUUID().toString - lazy val toLongString = - "%s:%s\n[%s]\n%s".format(getClass.getName, message, uuid, stackTraceToString) - - def this(msg: String) = this(msg, null); - - def stackTraceToString = AkkaException.stackTraceToString(this) + override def toString(): String = uuid + super.toString() +} + +/** + * This exception is thrown when Akka detects a problem with the provided configuration + */ +class ConfigurationException(message: String, cause: Throwable) extends AkkaException(message, cause) { + def this(msg: String) = this(msg, null) } diff --git a/akka-actor/src/main/scala/akka/actor/Actor.scala b/akka-actor/src/main/scala/akka/actor/Actor.scala index 2499d42f10..3d93e52a54 100644 --- a/akka-actor/src/main/scala/akka/actor/Actor.scala +++ b/akka-actor/src/main/scala/akka/actor/Actor.scala @@ -12,8 +12,9 @@ import java.util.regex.Pattern /** * Marker trait to show which Messages are automatically handled by Akka + * Internal use only */ -trait AutoReceivedMessage extends Serializable +private[akka] trait AutoReceivedMessage extends Serializable /** * Marker trait to indicate that a message might be potentially harmful, @@ -26,9 +27,16 @@ trait PossiblyHarmful */ trait NoSerializationVerificationNeeded -case class Failed(cause: Throwable) extends AutoReceivedMessage with PossiblyHarmful +/** + * Internal use only + */ +private[akka] case class Failed(cause: Throwable) extends AutoReceivedMessage with PossiblyHarmful abstract class PoisonPill extends AutoReceivedMessage with PossiblyHarmful + +/** + * A message all Actors will understand, that when processed will terminate the Actor permanently. + */ case object PoisonPill extends PoisonPill { /** * Java API: get the singleton instance @@ -37,6 +45,10 @@ case object PoisonPill extends PoisonPill { } abstract class Kill extends AutoReceivedMessage with PossiblyHarmful +/** + * A message all Actors will understand, that when processed will make the Actor throw an ActorKilledException, + * which will trigger supervision. + */ case object Kill extends Kill { /** * Java API: get the singleton instance @@ -44,9 +56,17 @@ case object Kill extends Kill { def getInstance = this } +/** + * When Death Watch is used, the watcher will receive a Terminated(watched) message when watched is terminated. + */ case class Terminated(@BeanProperty actor: ActorRef) extends PossiblyHarmful abstract class ReceiveTimeout extends PossiblyHarmful + +/** + * When using ActorContext.setReceiveTimeout, the singleton instance of ReceiveTimeout will be sent + * to the Actor when there hasn't been any message for that long. + */ case object ReceiveTimeout extends ReceiveTimeout { /** * Java API: get the singleton instance @@ -60,49 +80,79 @@ case object ReceiveTimeout extends ReceiveTimeout { * message is delivered by active routing of the various actors involved. */ sealed trait SelectionPath extends AutoReceivedMessage -case class SelectChildName(name: String, next: Any) extends SelectionPath -case class SelectChildPattern(pattern: Pattern, next: Any) extends SelectionPath -case class SelectParent(next: Any) extends SelectionPath -// Exceptions for Actors +/** + * Internal use only + */ +private[akka] case class SelectChildName(name: String, next: Any) extends SelectionPath + +/** + * Internal use only + */ +private[akka] case class SelectChildPattern(pattern: Pattern, next: Any) extends SelectionPath + +/** + * Internal use only + */ +private[akka] case class SelectParent(next: Any) extends SelectionPath + +/** + * IllegalActorStateException is thrown when a core invariant in the Actor implementation has been violated. + * For instance, if you try to create an Actor that doesn't extend Actor. + */ class IllegalActorStateException private[akka] (message: String, cause: Throwable = null) extends AkkaException(message, cause) { - def this(msg: String) = this(msg, null); + def this(msg: String) = this(msg, null) } +/** + * ActorKilledException is thrown when an Actor receives the akka.actor.Kill message + */ class ActorKilledException private[akka] (message: String, cause: Throwable) extends AkkaException(message, cause) with NoStackTrace { - def this(msg: String) = this(msg, null); + def this(msg: String) = this(msg, null) } -case class InvalidActorNameException(message: String) extends AkkaException(message) +/** + * An InvalidActorNameException is thrown when you try to convert something, usually a String, to an Actor name + * which doesn't validate. + */ +class InvalidActorNameException(message: String) extends AkkaException(message) -case class ActorInitializationException private[akka] (actor: ActorRef, message: String, cause: Throwable = null) - extends AkkaException(message, cause) - with NoStackTrace { - def this(msg: String) = this(null, msg, null); -} - -class ActorTimeoutException private[akka] (message: String, cause: Throwable = null) - extends AkkaException(message, cause) { - def this(msg: String) = this(msg, null); +/** + * An ActorInitializationException is thrown when the the initialization logic for an Actor fails. + */ +class ActorInitializationException private[akka] (actor: ActorRef, message: String, cause: Throwable) + extends AkkaException(message, cause) /*with NoStackTrace*/ { + def this(msg: String) = this(null, msg, null) + def this(actor: ActorRef, msg: String) = this(actor, msg, null) } +/** + * InvalidMessageException is thrown when an invalid message is sent to an Actor. + * Technically it's only "null" which is an InvalidMessageException but who knows, + * there might be more of them in the future, or not. + */ class InvalidMessageException private[akka] (message: String, cause: Throwable = null) extends AkkaException(message, cause) with NoStackTrace { - def this(msg: String) = this(msg, null); + def this(msg: String) = this(msg, null) } +/** + * A DeathPactException is thrown by an Actor that receives a Terminated(someActor) message + * that it doesn't handle itself, effectively crashing the Actor and escalating to the supervisor. + */ case class DeathPactException private[akka] (dead: ActorRef) extends AkkaException("Monitored actor [" + dead + "] terminated") with NoStackTrace -// must not pass InterruptedException to other threads -case class ActorInterruptedException private[akka] (cause: Throwable) - extends AkkaException(cause.getMessage, cause) - with NoStackTrace +/** + * When an InterruptedException is thrown inside an Actor, it is wrapped as an ActorInterruptedException as to + * avoid cascading interrupts to other threads than the originally interrupted one. + */ +class ActorInterruptedException private[akka] (cause: Throwable) extends AkkaException(cause.getMessage, cause) with NoStackTrace /** * This message is published to the EventStream whenever an Actor receives a message it doesn't understand @@ -115,18 +165,43 @@ case class UnhandledMessage(@BeanProperty message: Any, @BeanProperty sender: Ac */ object Status { sealed trait Status extends Serializable + + /** + * This class/message type is preferably used to indicate success of some operation performed. + */ case class Success(status: AnyRef) extends Status + + /** + * This class/message type is preferably used to indicate failure of some operation performed. + * As an example, it is used to signal failure with AskSupport is used (ask/?). + */ case class Failure(cause: Throwable) extends Status } +/** + * Mix in ActorLogging into your Actor to easily obtain a reference to a logger, which is available under the name "log". + * + * {{{ + * class MyActor extends Actor with ActorLogging { + * def receive = { + * case "pigdog" => log.info("We've got yet another pigdog on our hands") + * } + * } + * }}} + */ trait ActorLogging { this: Actor ⇒ val log = akka.event.Logging(context.system, this) } object Actor { - + /** + * Type alias representing a Receive-expression for Akka Actors. + */ type Receive = PartialFunction[Any, Unit] + /** + * emptyBehavior is a Receive-expression that matches no messages at all, ever. + */ object emptyBehavior extends Receive { def isDefinedAt(x: Any) = false def apply(x: Any) = throw new UnsupportedOperationException("Empty behavior apply()") @@ -243,7 +318,7 @@ trait Actor { * This defines the initial actor behavior, it must return a partial function * with the actor logic. */ - protected def receive: Receive + def receive: Receive /** * User overridable definition the strategy to use for supervising @@ -303,42 +378,5 @@ trait Actor { case _ ⇒ context.system.eventStream.publish(UnhandledMessage(message, sender, self)) } } - - // ========================================= - // ==== INTERNAL IMPLEMENTATION DETAILS ==== - // ========================================= - - /** - * For Akka internal use only. - */ - private[akka] final def apply(msg: Any) = { - // TODO would it be more efficient to assume that most messages are matched and catch MatchError instead of using isDefinedAt? - val head = behaviorStack.head - if (head.isDefinedAt(msg)) head.apply(msg) else unhandled(msg) - } - - /** - * For Akka internal use only. - */ - private[akka] def pushBehavior(behavior: Receive): Unit = { - behaviorStack = behaviorStack.push(behavior) - } - - /** - * For Akka internal use only. - */ - private[akka] def popBehavior(): Unit = { - val original = behaviorStack - val popped = original.pop - behaviorStack = if (popped.isEmpty) original else popped - } - - /** - * For Akka internal use only. - */ - private[akka] def clearBehaviorStack(): Unit = - behaviorStack = Stack.empty[Receive].push(behaviorStack.last) - - private var behaviorStack: Stack[Receive] = Stack.empty[Receive].push(receive) } diff --git a/akka-actor/src/main/scala/akka/actor/ActorCell.scala b/akka-actor/src/main/scala/akka/actor/ActorCell.scala index 68c9097d83..0955595640 100644 --- a/akka-actor/src/main/scala/akka/actor/ActorCell.scala +++ b/akka-actor/src/main/scala/akka/actor/ActorCell.scala @@ -134,10 +134,17 @@ trait ActorContext extends ActorRefFactory { */ def unwatch(subject: ActorRef): ActorRef + /** + * ActorContexts shouldn't be Serializable + */ final protected def writeObject(o: ObjectOutputStream): Unit = throw new NotSerializableException("ActorContext is not serializable!") } +/** + * UntypedActorContext is the UntypedActor equivalent of ActorContext, + * containing the Java API + */ trait UntypedActorContext extends ActorContext { /** @@ -178,7 +185,9 @@ private[akka] object ActorCell { final val emptyReceiveTimeoutData: (Long, Cancellable) = (-1, emptyCancellable) - trait SuspendReason + final val behaviorStackPlaceHolder: Stack[Actor.Receive] = Stack.empty.push(Actor.emptyBehavior) + + sealed trait SuspendReason case object UserRequest extends SuspendReason case class Recreation(cause: Throwable) extends SuspendReason case object Termination extends SuspendReason @@ -402,6 +411,8 @@ private[akka] class ActorCell( var actor: Actor = _ + private var behaviorStack: Stack[Actor.Receive] = Stack.empty + @volatile //This must be volatile since it isn't protected by the mailbox status var mailbox: Mailbox = _ @@ -482,14 +493,20 @@ private[akka] class ActorCell( //This method is in charge of setting up the contextStack and create a new instance of the Actor protected def newActor(): Actor = { - val stackBefore = contextStack.get - contextStack.set(stackBefore.push(this)) + contextStack.set(contextStack.get.push(this)) try { - val instance = props.creator() + import ActorCell.behaviorStackPlaceHolder + + behaviorStack = behaviorStackPlaceHolder + val instance = props.creator.apply() if (instance eq null) - throw ActorInitializationException(self, "Actor instance passed to actorOf can't be 'null'") + throw new ActorInitializationException(self, "Actor instance passed to actorOf can't be 'null'") + behaviorStack = behaviorStack match { + case `behaviorStackPlaceHolder` ⇒ Stack.empty.push(instance.receive) + case newBehaviors ⇒ Stack.empty.push(instance.receive).pushAll(newBehaviors.reverse.drop(1)) + } instance } finally { val stackAfter = contextStack.get @@ -510,13 +527,12 @@ private[akka] class ActorCell( if (system.settings.DebugLifecycle) system.eventStream.publish(Debug(self.path.toString, clazz(created), "started (" + created + ")")) } catch { case NonFatal(i: InstantiationException) ⇒ - throw ActorInitializationException(self, + throw new ActorInitializationException(self, """exception during creation, this problem is likely to occur because the class of the Actor you tried to create is either, a non-static inner class (in which case make it a static inner class or use Props(new ...) or Props( new UntypedActorFactory ... ) or is missing an appropriate, reachable no-args constructor. """, i.getCause) - case NonFatal(e) ⇒ - throw ActorInitializationException(self, "exception during creation", e) + case NonFatal(e) ⇒ throw new ActorInitializationException(self, "exception during creation", e) } } @@ -540,7 +556,10 @@ private[akka] class ActorCell( doRecreate(cause, failedActor) } } catch { - case NonFatal(e) ⇒ throw ActorInitializationException(self, "exception during creation", e) + case NonFatal(e) ⇒ throw new ActorInitializationException(self, "exception during creation", e match { + case i: InstantiationException ⇒ i.getCause + case other ⇒ other + }) } } @@ -605,7 +624,7 @@ private[akka] class ActorCell( cancelReceiveTimeout() // FIXME: leave this here??? messageHandle.message match { case msg: AutoReceivedMessage ⇒ autoReceiveMessage(messageHandle) - case msg ⇒ actor(msg) + case msg ⇒ receiveMessage(msg) } currentMessage = null // reset current message after successful invocation } catch { @@ -621,14 +640,14 @@ private[akka] class ActorCell( if (actor ne null) actor.supervisorStrategy.handleSupervisorFailing(self, children) } finally { t match { // Wrap InterruptedExceptions and rethrow - case _: InterruptedException ⇒ parent.tell(Failed(ActorInterruptedException(t)), self); throw t + case _: InterruptedException ⇒ parent.tell(Failed(new ActorInterruptedException(t)), self); throw t case _ ⇒ parent.tell(Failed(t), self) } } def become(behavior: Actor.Receive, discardOld: Boolean = true): Unit = { if (discardOld) unbecome() - actor.pushBehavior(behavior) + behaviorStack = behaviorStack.push(behavior) } /** @@ -639,14 +658,16 @@ private[akka] class ActorCell( /* * UntypedActorContext impl */ - def become(behavior: Procedure[Any], discardOld: Boolean): Unit = { - def newReceive: Actor.Receive = { case msg ⇒ behavior.apply(msg) } - become(newReceive, discardOld) + def become(behavior: Procedure[Any], discardOld: Boolean): Unit = + become({ case msg ⇒ behavior.apply(msg) }: Actor.Receive, discardOld) + + def unbecome(): Unit = { + val original = behaviorStack + val popped = original.pop + behaviorStack = if (popped.isEmpty) original else popped } - def unbecome(): Unit = actor.popBehavior() - - def autoReceiveMessage(msg: Envelope) { + def autoReceiveMessage(msg: Envelope): Unit = { if (system.settings.DebugAutoReceive) system.eventStream.publish(Debug(self.path.toString, clazz(actor), "received AutoReceiveMessage " + msg)) @@ -660,6 +681,12 @@ private[akka] class ActorCell( } } + final def receiveMessage(msg: Any): Unit = { + //FIXME replace with behaviorStack.head.applyOrElse(msg, unhandled) + "-optimize" + val head = behaviorStack.head + if (head.isDefinedAt(msg)) head.apply(msg) else actor.unhandled(msg) + } + private def doTerminate() { val a = actor try { @@ -675,7 +702,7 @@ private[akka] class ActorCell( if (system.settings.DebugLifecycle) system.eventStream.publish(Debug(self.path.toString, clazz(actor), "stopped")) } finally { - if (a ne null) a.clearBehaviorStack() + behaviorStack = ActorCell.behaviorStackPlaceHolder clearActorFields(a) actor = null } @@ -685,7 +712,6 @@ private[akka] class ActorCell( private def doRecreate(cause: Throwable, failedActor: Actor): Unit = try { // after all killed children have terminated, recreate the rest, then go on to start the new instance actor.supervisorStrategy.handleSupervisorRestarted(cause, self, children) - val freshActor = newActor() actor = freshActor // this must happen before postRestart has a chance to fail if (freshActor eq failedActor) setActorFields(freshActor, this, self) // If the creator returns the same instance, we need to restore our nulled out fields. @@ -702,7 +728,7 @@ private[akka] class ActorCell( actor.supervisorStrategy.handleSupervisorFailing(self, children) clearActorFields(actor) // If this fails, we need to ensure that preRestart isn't called. } finally { - parent.tell(Failed(ActorInitializationException(self, "exception during re-creation", e)), self) + parent.tell(Failed(new ActorInitializationException(self, "exception during re-creation", e)), self) } } @@ -749,13 +775,11 @@ private[akka] class ActorCell( } - final def cancelReceiveTimeout() { - //Only cancel if + final def cancelReceiveTimeout(): Unit = if (receiveTimeoutData._2 ne emptyCancellable) { receiveTimeoutData._2.cancel() receiveTimeoutData = (receiveTimeoutData._1, emptyCancellable) } - } final def clearActorFields(actorInstance: Actor): Unit = { setActorFields(actorInstance, context = null, self = system.deadLetters) diff --git a/akka-actor/src/main/scala/akka/actor/ActorPath.scala b/akka-actor/src/main/scala/akka/actor/ActorPath.scala index 4ebcec0dbb..aa93dbcc47 100644 --- a/akka-actor/src/main/scala/akka/actor/ActorPath.scala +++ b/akka-actor/src/main/scala/akka/actor/ActorPath.scala @@ -6,17 +6,6 @@ import scala.annotation.tailrec import java.net.MalformedURLException object ActorPath { - def split(s: String): List[String] = { - @tailrec - def rec(pos: Int, acc: List[String]): List[String] = { - val from = s.lastIndexOf('/', pos - 1) - val sub = s.substring(from + 1, pos) - val l = sub :: acc - if (from == -1) l else rec(from, l) - } - rec(s.length, Nil) - } - /** * Parse string as actor path; throws java.net.MalformedURLException if unable to do so. */ @@ -25,6 +14,11 @@ object ActorPath { case _ ⇒ throw new MalformedURLException("cannot parse as ActorPath: " + s) } + /** + * This Regular Expression is used to validate a path element (Actor Name). + * Since Actors form a tree, it is addressable using an URL, therefor an Actor Name has to conform to: + * http://www.ietf.org/rfc/rfc2396.txt + */ val ElementRegex = """[-\w:@&=+,.!~*'_;][-\w:@&=+,.!~*'$_;]*""".r } @@ -112,21 +106,21 @@ sealed trait ActorPath extends Comparable[ActorPath] with Serializable { //TODO add @SerialVersionUID(1L) when SI-4804 is fixed final case class RootActorPath(address: Address, name: String = "/") extends ActorPath { - def parent: ActorPath = this + override def parent: ActorPath = this - def root: RootActorPath = this + override def root: RootActorPath = this - def /(child: String): ActorPath = new ChildActorPath(this, child) + override def /(child: String): ActorPath = new ChildActorPath(this, child) - val elements: Iterable[String] = List("") + override val elements: Iterable[String] = List("") - override val toString = address + name + override val toString: String = address + name - def toStringWithAddress(addr: Address): String = + override def toStringWithAddress(addr: Address): String = if (address.host.isDefined) address + name else addr + name - def compareTo(other: ActorPath) = other match { + override def compareTo(other: ActorPath): Int = other match { case r: RootActorPath ⇒ toString compareTo r.toString case c: ChildActorPath ⇒ 1 } @@ -136,11 +130,11 @@ final case class RootActorPath(address: Address, name: String = "/") extends Act final class ChildActorPath(val parent: ActorPath, val name: String) extends ActorPath { if (name.indexOf('/') != -1) throw new IllegalArgumentException("/ is a path separator and is not legal in ActorPath names: [%s]" format name) - def address: Address = root.address + override def address: Address = root.address - def /(child: String): ActorPath = new ChildActorPath(this, child) + override def /(child: String): ActorPath = new ChildActorPath(this, child) - def elements: Iterable[String] = { + override def elements: Iterable[String] = { @tailrec def rec(p: ActorPath, acc: List[String]): Iterable[String] = p match { case r: RootActorPath ⇒ acc @@ -149,7 +143,7 @@ final class ChildActorPath(val parent: ActorPath, val name: String) extends Acto rec(this, Nil) } - def root = { + override def root: RootActorPath = { @tailrec def rec(p: ActorPath): RootActorPath = p match { case r: RootActorPath ⇒ r @@ -209,7 +203,7 @@ final class ChildActorPath(val parent: ActorPath, val name: String) extends Acto finalizeHash(rec(this, startHash(42), startMagicA, startMagicB)) } - def compareTo(other: ActorPath) = { + override def compareTo(other: ActorPath): Int = { @tailrec def rec(left: ActorPath, right: ActorPath): Int = if (left eq right) 0 diff --git a/akka-actor/src/main/scala/akka/actor/ActorRef.scala b/akka-actor/src/main/scala/akka/actor/ActorRef.scala index b3d4ad19d1..460bd02076 100644 --- a/akka-actor/src/main/scala/akka/actor/ActorRef.scala +++ b/akka-actor/src/main/scala/akka/actor/ActorRef.scala @@ -6,7 +6,6 @@ package akka.actor import akka.dispatch._ import akka.util._ -import scala.collection.immutable.Stack import java.lang.{ UnsupportedOperationException, IllegalStateException } import akka.serialization.{ Serialization, JavaSerializer } import akka.event.EventStream @@ -160,11 +159,11 @@ trait ScalaActorRef { ref: ActorRef ⇒ * often necessary to distinguish between local and non-local references, this * is the only method provided on the scope. */ -trait ActorRefScope { +private[akka] trait ActorRefScope { def isLocal: Boolean } -trait LocalRef extends ActorRefScope { +private[akka] trait LocalRef extends ActorRefScope { final def isLocal = true } @@ -215,18 +214,20 @@ private[akka] abstract class InternalActorRef extends ActorRef with ScalaActorRe * This is an internal look-up failure token, not useful for anything else. */ private[akka] case object Nobody extends MinimalActorRef { - val path = new RootActorPath(Address("akka", "all-systems"), "/Nobody") - def provider = throw new UnsupportedOperationException("Nobody does not provide") + override val path: RootActorPath = new RootActorPath(Address("akka", "all-systems"), "/Nobody") + override def provider = throw new UnsupportedOperationException("Nobody does not provide") } /** * Local (serializable) ActorRef that is used when referencing the Actor on its "home" node. + * + * INTERNAL API */ private[akka] class LocalActorRef private[akka] ( _system: ActorSystemImpl, _props: Props, _supervisor: InternalActorRef, - val path: ActorPath, + override val path: ActorPath, val systemService: Boolean = false, _receiveTimeout: Option[Duration] = None) extends InternalActorRef with LocalRef { @@ -268,21 +269,21 @@ private[akka] class LocalActorRef private[akka] ( * message sends done from the same thread after calling this method will not * be processed until resumed. */ - def suspend(): Unit = actorCell.suspend() + override def suspend(): Unit = actorCell.suspend() /** * Resumes a suspended actor. */ - def resume(): Unit = actorCell.resume() + override def resume(): Unit = actorCell.resume() /** * Shuts down the actor and its message queue */ - def stop(): Unit = actorCell.stop() + override def stop(): Unit = actorCell.stop() - def getParent: InternalActorRef = actorCell.parent + override def getParent: InternalActorRef = actorCell.parent - def provider = actorCell.provider + override def provider: ActorRefProvider = actorCell.provider /** * Method for looking up a single child beneath this actor. Override in order @@ -294,7 +295,7 @@ private[akka] class LocalActorRef private[akka] ( case None ⇒ Nobody } - def getChild(names: Iterator[String]): InternalActorRef = { + override def getChild(names: Iterator[String]): InternalActorRef = { /* * The idea is to recursively descend as far as possible with LocalActor * Refs and hand over to that “foreign” child when we encounter it. @@ -303,16 +304,16 @@ private[akka] class LocalActorRef private[akka] ( def rec(ref: InternalActorRef, name: Iterator[String]): InternalActorRef = ref match { case l: LocalActorRef ⇒ - val n = name.next() - val next = n match { + val next = name.next() match { case ".." ⇒ l.getParent case "" ⇒ l - case _ ⇒ l.getSingleChild(n) + case any ⇒ l.getSingleChild(any) } if (next == Nobody || name.isEmpty) next else rec(next, name) case _ ⇒ ref.getChild(name) } + if (names.isEmpty) this else rec(this, names) } @@ -321,11 +322,11 @@ private[akka] class LocalActorRef private[akka] ( protected[akka] def underlying: ActorCell = actorCell - def sendSystemMessage(message: SystemMessage) { underlying.dispatcher.systemDispatch(underlying, message) } + override def sendSystemMessage(message: SystemMessage): Unit = underlying.dispatcher.systemDispatch(underlying, message) - def !(message: Any)(implicit sender: ActorRef = null): Unit = actorCell.tell(message, sender) + override def !(message: Any)(implicit sender: ActorRef = null): Unit = actorCell.tell(message, sender) - def restart(cause: Throwable): Unit = actorCell.restart(cause) + override def restart(cause: Throwable): Unit = actorCell.restart(cause) @throws(classOf[java.io.ObjectStreamException]) protected def writeReplace(): AnyRef = SerializedActorRef(path) @@ -333,9 +334,10 @@ private[akka] class LocalActorRef private[akka] ( /** * Memento pattern for serializing ActorRefs transparently + * INTERNAL API */ //TODO add @SerialVersionUID(1L) when SI-4804 is fixed -case class SerializedActorRef private (path: String) { +private[akka] case class SerializedActorRef private (path: String) { import akka.serialization.JavaSerializer.currentSystem @throws(classOf[java.io.ObjectStreamException]) @@ -349,7 +351,10 @@ case class SerializedActorRef private (path: String) { } } -object SerializedActorRef { +/** + * INTERNAL API + */ +private[akka] object SerializedActorRef { def apply(path: ActorPath): SerializedActorRef = { Serialization.currentTransportAddress.value match { case null ⇒ new SerializedActorRef(path.toString) @@ -360,33 +365,32 @@ object SerializedActorRef { /** * Trait for ActorRef implementations where all methods contain default stubs. + * + * INTERNAL API */ private[akka] trait MinimalActorRef extends InternalActorRef with LocalRef { - def getParent: InternalActorRef = Nobody + override def getParent: InternalActorRef = Nobody + override def getChild(names: Iterator[String]): InternalActorRef = if (names.forall(_.isEmpty)) this else Nobody - def getChild(names: Iterator[String]): InternalActorRef = { - val dropped = names.dropWhile(_.isEmpty) - if (dropped.isEmpty) this - else Nobody - } + override def suspend(): Unit = () + override def resume(): Unit = () + override def stop(): Unit = () + override def isTerminated = false - def suspend(): Unit = () - def resume(): Unit = () + override def !(message: Any)(implicit sender: ActorRef = null): Unit = () - def stop(): Unit = () - - def isTerminated = false - - def !(message: Any)(implicit sender: ActorRef = null): Unit = () - - def sendSystemMessage(message: SystemMessage): Unit = () - def restart(cause: Throwable): Unit = () + override def sendSystemMessage(message: SystemMessage): Unit = () + override def restart(cause: Throwable): Unit = () @throws(classOf[java.io.ObjectStreamException]) protected def writeReplace(): AnyRef = SerializedActorRef(path) } +/** + * When a message is sent to an Actor that is terminated before receiving the message, it will be sent as a DeadLetter + * to the ActorSystem's EventStream + */ case class DeadLetter(message: Any, sender: ActorRef, recipient: ActorRef) private[akka] object DeadLetterActorRef { @@ -402,10 +406,12 @@ private[akka] object DeadLetterActorRef { /** * This special dead letter reference has a name: it is that which is returned * by a local look-up which is unsuccessful. + * + * INTERNAL API */ private[akka] class EmptyLocalActorRef( - val provider: ActorRefProvider, - val path: ActorPath, + override val provider: ActorRefProvider, + override val path: ActorPath, val eventStream: EventStream) extends MinimalActorRef { override def isTerminated(): Boolean = true @@ -419,6 +425,8 @@ private[akka] class EmptyLocalActorRef( /** * Internal implementation of the dead letter destination: will publish any * received message to the eventStream, wrapped as [[akka.actor.DeadLetter]]. + * + * INTERNAL API */ private[akka] class DeadLetterActorRef(_provider: ActorRefProvider, _path: ActorPath, _eventStream: EventStream) extends EmptyLocalActorRef(_provider, _path, _eventStream) { @@ -434,10 +442,12 @@ private[akka] class DeadLetterActorRef(_provider: ActorRefProvider, _path: Actor /** * Internal implementation detail used for paths like “/temp” + * + * INTERNAL API */ private[akka] class VirtualPathContainer( - val provider: ActorRefProvider, - val path: ActorPath, + override val provider: ActorRefProvider, + override val path: ActorPath, override val getParent: InternalActorRef, val log: LoggingAdapter) extends MinimalActorRef { @@ -450,12 +460,8 @@ private[akka] class VirtualPathContainer( } } - def removeChild(name: String): Unit = { - children.remove(name) match { - case null ⇒ log.warning("{} trying to remove non-child {}", path, name) - case _ ⇒ //okay - } - } + def removeChild(name: String): Unit = + if (children.remove(name) eq null) log.warning("{} trying to remove non-child {}", path, name) def getChild(name: String): InternalActorRef = children.get(name) diff --git a/akka-actor/src/main/scala/akka/actor/ActorRefProvider.scala b/akka-actor/src/main/scala/akka/actor/ActorRefProvider.scala index 536136934a..41473e7f7c 100644 --- a/akka-actor/src/main/scala/akka/actor/ActorRefProvider.scala +++ b/akka-actor/src/main/scala/akka/actor/ActorRefProvider.scala @@ -49,8 +49,12 @@ trait ActorRefProvider { */ def rootPath: ActorPath + /** + * The Settings associated with this ActorRefProvider + */ def settings: ActorSystem.Settings + //FIXME WHY IS THIS HERE? def dispatcher: MessageDispatcher /** @@ -61,8 +65,12 @@ trait ActorRefProvider { */ def init(system: ActorSystemImpl): Unit + /** + * The Deployer associated with this ActorRefProvider + */ def deployer: Deployer + //FIXME WHY IS THIS HERE? def scheduler: Scheduler /** @@ -131,6 +139,7 @@ trait ActorRefProvider { */ def terminationFuture: Future[Unit] + //FIXME I PROPOSE TO REMOVE THIS IN 2.1 - √ /** * Obtain the address which is to be used within sender references when * sending to the given other address or none if the other address cannot be @@ -141,22 +150,33 @@ trait ActorRefProvider { } /** - * Interface implemented by ActorSystem and AkkaContext, the only two places + * Interface implemented by ActorSystem and ActorContext, the only two places * from which you can get fresh actors. */ trait ActorRefFactory { - + /** + * INTERNAL USE ONLY + */ protected def systemImpl: ActorSystemImpl - + /** + * INTERNAL USE ONLY + */ protected def provider: ActorRefProvider - + /** + * INTERNAL USE ONLY + */ protected def dispatcher: MessageDispatcher /** * Father of all children created by this interface. + * + * INTERNAL USE ONLY */ protected def guardian: InternalActorRef + /** + * INTERNAL USE ONLY + */ protected def lookupRoot: InternalActorRef /** @@ -276,8 +296,6 @@ trait ActorRefFactory { def stop(actor: ActorRef): Unit } -class ActorRefProviderException(message: String) extends AkkaException(message) - /** * Internal Akka use only, used in implementation of system.actorOf. */ @@ -298,10 +316,10 @@ private[akka] case class StopChild(child: ActorRef) */ class LocalActorRefProvider( _systemName: String, - val settings: ActorSystem.Settings, + override val settings: ActorSystem.Settings, val eventStream: EventStream, - val scheduler: Scheduler, - val deployer: Deployer) extends ActorRefProvider { + override val scheduler: Scheduler, + override val deployer: Deployer) extends ActorRefProvider { // this is the constructor needed for reflectively instantiating the provider def this(_systemName: String, @@ -315,13 +333,13 @@ class LocalActorRefProvider( scheduler, new Deployer(settings, dynamicAccess)) - val rootPath: ActorPath = RootActorPath(Address("akka", _systemName)) + override val rootPath: ActorPath = RootActorPath(Address("akka", _systemName)) - val log = Logging(eventStream, "LocalActorRefProvider(" + rootPath.address + ")") + private[akka] val log: LoggingAdapter = Logging(eventStream, "LocalActorRefProvider(" + rootPath.address + ")") - val deadLetters = new DeadLetterActorRef(this, rootPath / "deadLetters", eventStream) + override val deadLetters: InternalActorRef = new DeadLetterActorRef(this, rootPath / "deadLetters", eventStream) - val deathWatch = new LocalDeathWatch(1024) //TODO make configrable + override val deathWatch: DeathWatch = new LocalDeathWatch(1024) //TODO make configrable /* * generate name for temporary actor refs @@ -332,7 +350,7 @@ class LocalActorRefProvider( private val tempNode = rootPath / "temp" - def tempPath() = tempNode / tempName() + override def tempPath(): ActorPath = tempNode / tempName() /** * Top-level anchor for the supervision hierarchy of this actor system. Will @@ -348,11 +366,11 @@ class LocalActorRefProvider( def provider: ActorRefProvider = LocalActorRefProvider.this - override def stop() = stopped switchOn { + override def stop(): Unit = stopped switchOn { terminationFuture.complete(causeOfTermination.toLeft(())) } - override def isTerminated = stopped.isOn + override def isTerminated: Boolean = 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.asInstanceOf[InternalActorRef].stop() @@ -371,7 +389,7 @@ class LocalActorRefProvider( /** * Overridable supervision strategy to be used by the “/user” guardian. */ - protected def guardianSupervisionStrategy = { + protected def guardianSupervisionStrategy: SupervisorStrategy = { import akka.actor.SupervisorStrategy._ OneForOneStrategy() { case _: ActorKilledException ⇒ Stop @@ -387,12 +405,12 @@ class LocalActorRefProvider( */ private class Guardian extends Actor { - override val supervisorStrategy = guardianSupervisionStrategy + override val supervisorStrategy: SupervisorStrategy = guardianSupervisionStrategy def receive = { 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 CreateChild(child, name) ⇒ sender ! (try context.actorOf(child, name) catch { case e: Exception ⇒ e }) // FIXME shouldn't this use NonFatal & Status.Failure? + case CreateRandomNameChild(child) ⇒ sender ! (try context.actorOf(child) catch { case e: Exception ⇒ e }) // FIXME shouldn't this use NonFatal & Status.Failure? case StopChild(child) ⇒ context.stop(child); sender ! "ok" case m ⇒ deadLetters ! DeadLetter(m, sender, self) } @@ -404,12 +422,11 @@ class LocalActorRefProvider( /** * Overridable supervision strategy to be used by the “/system” guardian. */ - protected def systemGuardianSupervisionStrategy = { + protected def systemGuardianSupervisionStrategy: SupervisorStrategy = { import akka.actor.SupervisorStrategy._ OneForOneStrategy() { - case _: ActorKilledException ⇒ Stop - case _: ActorInitializationException ⇒ Stop - case _: Exception ⇒ Restart + case _: ActorKilledException | _: ActorInitializationException ⇒ Stop + case _: Exception ⇒ Restart } } @@ -420,14 +437,12 @@ class LocalActorRefProvider( */ private class SystemGuardian extends Actor { - override val supervisorStrategy = systemGuardianSupervisionStrategy + override val supervisorStrategy: SupervisorStrategy = systemGuardianSupervisionStrategy def receive = { - case Terminated(_) ⇒ - eventStream.stopDefaultLoggers() - 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 Terminated(_) ⇒ eventStream.stopDefaultLoggers(); context.stop(self) + case CreateChild(child, name) ⇒ sender ! (try context.actorOf(child, name) catch { case e: Exception ⇒ e }) // FIXME shouldn't this use NonFatal & Status.Failure? + case CreateRandomNameChild(child) ⇒ sender ! (try context.actorOf(child) catch { case e: Exception ⇒ e }) // FIXME shouldn't this use NonFatal & Status.Failure? case StopChild(child) ⇒ context.stop(child); sender ! "ok" case m ⇒ deadLetters ! DeadLetter(m, sender, self) } diff --git a/akka-actor/src/main/scala/akka/actor/ActorSelection.scala b/akka-actor/src/main/scala/akka/actor/ActorSelection.scala index b407868270..93a26c6289 100644 --- a/akka-actor/src/main/scala/akka/actor/ActorSelection.scala +++ b/akka-actor/src/main/scala/akka/actor/ActorSelection.scala @@ -5,6 +5,10 @@ package akka.actor import java.util.regex.Pattern import akka.util.Helpers +/** + * An ActorSelection is a logical view of a section of an ActorSystem's tree of Actors, + * allowing for broadcasting of messages to that section. + */ abstract class ActorSelection { this: ScalaActorSelection ⇒ @@ -12,11 +16,11 @@ abstract class ActorSelection { protected def path: Array[AnyRef] - def tell(msg: Any) { target ! toMessage(msg, path) } + def tell(msg: Any): Unit = target ! toMessage(msg, path) - def tell(msg: Any, sender: ActorRef) { target.tell(toMessage(msg, path), sender) } + def tell(msg: Any, sender: ActorRef): Unit = target.tell(toMessage(msg, path), sender) - // this may want to be fast ... + // FIXME make this so that "next" instead is the remaining path private def toMessage(msg: Any, path: Array[AnyRef]): Any = { var acc = msg var index = path.length - 1 @@ -32,7 +36,12 @@ abstract class ActorSelection { } } +/** + * An ActorSelection is a logical view of a section of an ActorSystem's tree of Actors, + * allowing for broadcasting of messages to that section. + */ object ActorSelection { + //This cast is safe because the self-type of ActorSelection requires that it mixes in ScalaActorSelection implicit def toScala(sel: ActorSelection): ScalaActorSelection = sel.asInstanceOf[ScalaActorSelection] /** @@ -43,7 +52,7 @@ object ActorSelection { */ def apply(anchor: ActorRef, path: String): ActorSelection = { val elems = path.split("/+").dropWhile(_.isEmpty) - val compiled: Array[AnyRef] = elems map (x ⇒ if (x.contains("?") || x.contains("*")) Helpers.makePattern(x) else x) + val compiled: Array[AnyRef] = elems map (x ⇒ if ((x.indexOf('?') != -1) || (x.indexOf('*') != -1)) Helpers.makePattern(x) else x) new ActorSelection with ScalaActorSelection { def target = anchor def path = compiled @@ -51,6 +60,10 @@ object ActorSelection { } } +/** + * Contains the Scala API (!-method) for ActorSelections) which provides automatic tracking of the sender, + * as per the usual implicit ActorRef pattern. + */ trait ScalaActorSelection { this: ActorSelection ⇒ diff --git a/akka-actor/src/main/scala/akka/actor/ActorSystem.scala b/akka-actor/src/main/scala/akka/actor/ActorSystem.scala index 20ba0f696e..c5595212c2 100644 --- a/akka-actor/src/main/scala/akka/actor/ActorSystem.scala +++ b/akka-actor/src/main/scala/akka/actor/ActorSystem.scala @@ -4,38 +4,34 @@ package akka.actor -import akka.config.ConfigurationException import akka.event._ import akka.dispatch._ import akka.pattern.ask -import org.jboss.netty.akka.util.HashedWheelTimer -import java.util.concurrent.TimeUnit.MILLISECONDS -import com.typesafe.config.Config -import com.typesafe.config.ConfigFactory +import com.typesafe.config.{ Config, ConfigFactory } import scala.annotation.tailrec -import org.jboss.netty.akka.util.internal.ConcurrentIdentityHashMap import java.io.Closeable -import akka.dispatch.Await.Awaitable -import akka.dispatch.Await.CanAwait +import akka.dispatch.Await.{ Awaitable, CanAwait } import akka.util._ +import akka.util.internal.{ HashedWheelTimer, ConcurrentIdentityHashMap } import collection.immutable.Stack import java.util.concurrent.{ ThreadFactory, CountDownLatch, TimeoutException, RejectedExecutionException } +import java.util.concurrent.TimeUnit.MILLISECONDS object ActorSystem { - val Version = "2.1-SNAPSHOT" + val Version: String = "2.1-SNAPSHOT" - val EnvHome = System.getenv("AKKA_HOME") match { + val EnvHome: Option[String] = System.getenv("AKKA_HOME") match { case null | "" | "." ⇒ None case value ⇒ Some(value) } - val SystemHome = System.getProperty("akka.home") match { + val SystemHome: Option[String] = System.getProperty("akka.home") match { case null | "" ⇒ None case value ⇒ Some(value) } - val GlobalHome = SystemHome orElse EnvHome + val GlobalHome: Option[String] = SystemHome orElse EnvHome /** * Creates a new ActorSystem with the name "default", @@ -102,8 +98,16 @@ object ActorSystem { */ def apply(name: String, config: Config, classLoader: ClassLoader): ActorSystem = new ActorSystemImpl(name, config, classLoader).start() + /** + * Settings are the overall ActorSystem Settings which also provides a convenient access to the Config object. + * + * For more detailed information about the different possible configuration options, look in the Akka Documentation under "Configuration" + */ class Settings(classLoader: ClassLoader, cfg: Config, final val name: String) { + /** + * The backing Config of this ActorSystem's Settings + */ final val config: Config = { val config = cfg.withFallback(ConfigFactory.defaultReference(classLoader)) config.checkValid(ConfigFactory.defaultReference(classLoader), "akka") @@ -114,11 +118,9 @@ object ActorSystem { import config._ final val ConfigVersion = getString("akka.version") - final val ProviderClass = getString("akka.actor.provider") - final val CreationTimeout = Timeout(Duration(getMilliseconds("akka.actor.creation-timeout"), MILLISECONDS)) - final val ReaperInterval = Duration(getMilliseconds("akka.actor.reaper-interval"), MILLISECONDS) + final val SerializeAllMessages = getBoolean("akka.actor.serialize-messages") final val SerializeAllCreators = getBoolean("akka.actor.serialize-creators") @@ -146,13 +148,16 @@ object ActorSystem { final val JvmExitOnFatalError = getBoolean("akka.jvm-exit-on-fatal-error") if (ConfigVersion != Version) - throw new ConfigurationException("Akka JAR version [" + Version + "] does not match the provided config version [" + ConfigVersion + "]") + throw new akka.ConfigurationException("Akka JAR version [" + Version + "] does not match the provided config version [" + ConfigVersion + "]") + /** + * Returns the String representation of the Config that this Settings is backed by + */ override def toString: String = config.root.render } /** - * INTERNAL + * INTERNAL USE ONLY */ private[akka] def findClassLoader(): ClassLoader = { def findCaller(get: Int ⇒ Class[_]): ClassLoader = @@ -423,7 +428,7 @@ abstract class ExtendedActorSystem extends ActorSystem { def dynamicAccess: DynamicAccess } -class ActorSystemImpl protected[akka] (val name: String, applicationConfig: Config, classLoader: ClassLoader) extends ExtendedActorSystem { +private[akka] class ActorSystemImpl(val name: String, applicationConfig: Config, classLoader: ClassLoader) extends ExtendedActorSystem { if (!name.matches("""^[a-zA-Z0-9][a-zA-Z0-9-]*$""")) throw new IllegalArgumentException( @@ -476,7 +481,7 @@ class ActorSystemImpl protected[akka] (val name: String, applicationConfig: Conf def logConfiguration(): Unit = log.info(settings.toString) - protected def systemImpl = this + protected def systemImpl: ActorSystemImpl = this private[akka] def systemActorOf(props: Props, name: String): ActorRef = { implicit val timeout = settings.CreationTimeout @@ -540,6 +545,7 @@ class ActorSystemImpl protected[akka] (val name: String, applicationConfig: Conf def deadLetters: ActorRef = provider.deadLetters + //FIXME Why do we need this at all? val deadLetterQueue: MessageQueue = new MessageQueue { def enqueue(receiver: ActorRef, envelope: Envelope) { deadLetters ! DeadLetter(envelope.message, envelope.sender, receiver) } def dequeue() = null @@ -547,7 +553,7 @@ class ActorSystemImpl protected[akka] (val name: String, applicationConfig: Conf def numberOfMessages = 0 def cleanUp(owner: ActorContext, deadLetters: MessageQueue): Unit = () } - + //FIXME Why do we need this at all? val deadLetterMailbox: Mailbox = new Mailbox(null, deadLetterQueue) { becomeClosed() def systemEnqueue(receiver: ActorRef, handle: SystemMessage): Unit = deadLetters ! DeadLetter(handle, receiver, receiver) diff --git a/akka-actor/src/main/scala/akka/actor/Address.scala b/akka-actor/src/main/scala/akka/actor/Address.scala index 651d970885..44c12eed35 100644 --- a/akka-actor/src/main/scala/akka/actor/Address.scala +++ b/akka-actor/src/main/scala/akka/actor/Address.scala @@ -5,6 +5,7 @@ package akka.actor import java.net.URI import java.net.URISyntaxException import java.net.MalformedURLException +import annotation.tailrec /** * The address specifies the physical location under which an Actor can be @@ -20,36 +21,62 @@ final case class Address private (protocol: String, system: String, host: Option def this(protocol: String, system: String) = this(protocol, system, None, None) def this(protocol: String, system: String, host: String, port: Int) = this(protocol, system, Option(host), Some(port)) + /** + * Returns the canonical String representation of this Address formatted as: + * + * ://@: + */ @transient override lazy val toString: String = { - val sb = new StringBuilder(protocol) - sb.append("://") - sb.append(system) - if (host.isDefined) { - sb.append('@') - sb.append(host.get) - } - if (port.isDefined) { - sb.append(':') - sb.append(port.get) - } + val sb = (new StringBuilder(protocol)).append("://").append(system) + + if (host.isDefined) sb.append('@').append(host.get) + if (port.isDefined) sb.append(':').append(port.get) + sb.toString } - def hostPort: String = toString.substring(protocol.length() + 3) + /** + * Returns a String representation formatted as: + * + * @: + */ + def hostPort: String = toString.substring(protocol.length + 3) } object Address { + /** + * Constructs a new Address with the specified protocol and system name + */ def apply(protocol: String, system: String) = new Address(protocol, system) + + /** + * Constructs a new Address with the specified protocol, system name, host and port + */ def apply(protocol: String, system: String, host: String, port: Int) = new Address(protocol, system, Some(host), Some(port)) } -object RelativeActorPath { +private[akka] trait PathUtils { + protected def split(s: String): List[String] = { + @tailrec + def rec(pos: Int, acc: List[String]): List[String] = { + val from = s.lastIndexOf('/', pos - 1) + val sub = s.substring(from + 1, pos) + val l = sub :: acc + if (from == -1) l else rec(from, l) + } + rec(s.length, Nil) + } +} + +object RelativeActorPath extends PathUtils { def unapply(addr: String): Option[Iterable[String]] = { try { val uri = new URI(addr) if (uri.isAbsolute) None - else Some(ActorPath.split(uri.getPath)) + else Some(split(uri.getPath)) + } catch { + case _: URISyntaxException ⇒ None } } } @@ -58,13 +85,7 @@ object RelativeActorPath { * This object serves as extractor for Scala and as address parser for Java. */ object AddressFromURIString { - def unapply(addr: String): Option[Address] = - try { - val uri = new URI(addr) - unapply(uri) - } catch { - case _: URISyntaxException ⇒ None - } + def unapply(addr: String): Option[Address] = try unapply(new URI(addr)) catch { case _: URISyntaxException ⇒ None } def unapply(uri: URI): Option[Address] = if (uri eq null) None @@ -84,7 +105,7 @@ object AddressFromURIString { */ def apply(addr: String): Address = addr match { case AddressFromURIString(address) ⇒ address - case _ ⇒ throw new MalformedURLException + case _ ⇒ throw new MalformedURLException(addr) } /** @@ -93,14 +114,17 @@ object AddressFromURIString { def parse(addr: String): Address = apply(addr) } -object ActorPathExtractor { +/** + * Given an ActorPath it returns the Address and the path elements if the path is well-formed + */ +object ActorPathExtractor extends PathUtils { def unapply(addr: String): Option[(Address, Iterable[String])] = try { val uri = new URI(addr) if (uri.getPath == null) None else AddressFromURIString.unapply(uri) match { case None ⇒ None - case Some(addr) ⇒ Some((addr, ActorPath.split(uri.getPath).drop(1))) + case Some(addr) ⇒ Some((addr, split(uri.getPath).drop(1))) } } catch { case _: URISyntaxException ⇒ None diff --git a/akka-actor/src/main/scala/akka/actor/Deployer.scala b/akka-actor/src/main/scala/akka/actor/Deployer.scala index 2fd9538d77..30118ae03a 100644 --- a/akka-actor/src/main/scala/akka/actor/Deployer.scala +++ b/akka-actor/src/main/scala/akka/actor/Deployer.scala @@ -34,8 +34,19 @@ final case class Deploy( routerConfig: RouterConfig = NoRouter, scope: Scope = NoScopeGiven) { + /** + * Java API to create a Deploy with the given RouterConfig + */ def this(routing: RouterConfig) = this("", ConfigFactory.empty, routing) + + /** + * Java API to create a Deploy with the given RouterConfig with Scope + */ def this(routing: RouterConfig, scope: Scope) = this("", ConfigFactory.empty, routing, scope) + + /** + * Java API to create a Deploy with the given Scope + */ def this(scope: Scope) = this("", ConfigFactory.empty, NoRouter, scope) /** @@ -67,13 +78,9 @@ trait Scope { //TODO add @SerialVersionUID(1L) when SI-4804 is fixed abstract class LocalScope extends Scope -case object LocalScope extends LocalScope { - /** - * Java API - */ - @deprecated("use instance() method instead", "2.0.1") - def scope: Scope = this +//FIXME docs +case object LocalScope extends LocalScope { /** * Java API: get the singleton instance */ @@ -128,7 +135,7 @@ private[akka] class Deployer(val settings: ActorSystem.Settings, val dynamicAcce add(d.path.split("/").drop(1), d) } - protected def parseConfig(key: String, config: Config): Option[Deploy] = { + def parseConfig(key: String, config: Config): Option[Deploy] = { val deployment = config.withFallback(default) @@ -162,5 +169,4 @@ private[akka] class Deployer(val settings: ActorSystem.Settings, val dynamicAcce Some(Deploy(key, deployment, router, NoScopeGiven)) } - } diff --git a/akka-actor/src/main/scala/akka/actor/DynamicAccess.scala b/akka-actor/src/main/scala/akka/actor/DynamicAccess.scala index 8d3ac68852..72ffbbe76e 100644 --- a/akka-actor/src/main/scala/akka/actor/DynamicAccess.scala +++ b/akka-actor/src/main/scala/akka/actor/DynamicAccess.scala @@ -14,7 +14,7 @@ import java.lang.reflect.InvocationTargetException * This is an internal facility and users are not expected to encounter it * unless they are extending Akka in ways which go beyond simple Extensions. */ -trait DynamicAccess { +abstract class DynamicAccess { /** * Convenience method which given a `Class[_]` object and a constructor description @@ -88,7 +88,7 @@ trait DynamicAccess { * by default. */ class ReflectiveDynamicAccess(val classLoader: ClassLoader) extends DynamicAccess { - + //FIXME switch to Scala Reflection for 2.10 override def getClassFor[T: ClassManifest](fqcn: String): Either[Throwable, Class[_ <: T]] = try { val c = classLoader.loadClass(fqcn).asInstanceOf[Class[_ <: T]] diff --git a/akka-actor/src/main/scala/akka/actor/FSM.scala b/akka-actor/src/main/scala/akka/actor/FSM.scala index 3d1f8930c4..50c769e156 100644 --- a/akka-actor/src/main/scala/akka/actor/FSM.scala +++ b/akka-actor/src/main/scala/akka/actor/FSM.scala @@ -6,30 +6,86 @@ package akka.actor import akka.util._ import scala.collection.mutable -import akka.event.Logging import akka.routing.{ Deafen, Listen, Listeners } object FSM { + /** + * A partial function value which does not match anything and can be used to + * “reset” `whenUnhandled` and `onTermination` handlers. + * + * {{{ + * onTermination(FSM.NullFunction) + * }}} + */ object NullFunction extends PartialFunction[Any, Nothing] { def isDefinedAt(o: Any) = false def apply(o: Any) = sys.error("undefined") } + /** + * Message type which is sent directly to the subscribed actor in + * [[akka.actor.FSM.SubscribeTransitionCallback]] before sending any + * [[akka.actor.FSM.Transition]] messages. + */ case class CurrentState[S](fsmRef: ActorRef, state: S) + + /** + * Message type which is used to communicate transitions between states to + * all subscribed listeners (use [[akka.actor.FSM.SubscribeTransitionCallback]]). + */ case class Transition[S](fsmRef: ActorRef, from: S, to: S) + + /** + * Send this to an [[akka.actor.FSM]] to request first the [[akka.actor.CurrentState]] + * and then a series of [[akka.actor.Transition]] updates. Cancel the subscription + * using [[akka.actor.FSM.UnsubscribeTransitionCallback]]. + */ case class SubscribeTransitionCallBack(actorRef: ActorRef) + + /** + * Unsubscribe from [[akka.actor.FSM.Transition]] notifications which was + * effected by sending the corresponding [[akka.actor.FSM.SubscribeTransitionCallback]]. + */ case class UnsubscribeTransitionCallBack(actorRef: ActorRef) + /** + * Reason why this [[akka.actor.FSM]] is shutting down. + */ sealed trait Reason + + /** + * Default reason if calling `stop()`. + */ case object Normal extends Reason + + /** + * Reason given when someone was calling `system.stop(fsm)` from outside; + * also applies to `Stop` supervision directive. + */ case object Shutdown extends Reason + + /** + * Signifies that the [[akka.actor.FSM]] is shutting itself down because of + * an error, e.g. if the state to transition into does not exist. You can use + * this to communicate a more precise cause to the [[akka.actor.FSM$onTermination]] block. + */ case class Failure(cause: Any) extends Reason + /** + * This case object is received in case of a state timeout. + */ case object StateTimeout - case class TimeoutMarker(generation: Long) - case class Timer(name: String, msg: Any, repeat: Boolean, generation: Int)(implicit system: ActorSystem) { + /** + * Internal API + */ + private case class TimeoutMarker(generation: Long) + + /** + * Internal API + */ + private[akka] case class Timer(name: String, msg: Any, repeat: Boolean, generation: Int)(implicit system: ActorSystem) { private var ref: Option[Cancellable] = _ def schedule(actor: ActorRef, timeout: Duration) { @@ -56,8 +112,16 @@ object FSM { def unapply[S](in: (S, S)) = Some(in) } + /** + * Log Entry of the [[akka.actor.LoggingFSM]], can be obtained by calling `getLog`. + */ case class LogEntry[S, D](stateName: S, stateData: D, event: Any) + /** + * This captures all of the managed state of the [[akka.actor.FSM]]: the state + * name, the state data, possibly custom timeout, stop reason and replies + * accumulated while processing the last message. + */ case class State[S, D](stateName: S, stateData: D, timeout: Option[Duration] = None, stopReason: Option[Reason] = None, replies: List[Any] = Nil) { /** @@ -86,6 +150,9 @@ object FSM { copy(stateData = nextStateDate) } + /** + * Internal API. + */ private[akka] def withStopReason(reason: Reason): State[S, D] = { copy(stopReason = Some(reason)) } @@ -182,8 +249,19 @@ trait FSM[S, D] extends Listeners with ActorLogging { type Timeout = Option[Duration] type TransitionHandler = PartialFunction[(S, S), Unit] - // “import” so that it is visible without an import + /* + * “import” so that these are visible without an import + */ + + /** + * This extractor is just convenience for matching a (S, S) pair, including a + * reminder what the new state is. + */ val -> = FSM.-> + + /** + * This case object is received in case of a state timeout. + */ val StateTimeout = FSM.StateTimeout /** @@ -202,13 +280,9 @@ trait FSM[S, D] extends Listeners with ActorLogging { * @param stateTimeout default state timeout for this state * @param stateFunction partial function describing response to input */ - protected final def when(stateName: S, stateTimeout: Duration = null)(stateFunction: StateFunction): Unit = + final def when(stateName: S, stateTimeout: Duration = null)(stateFunction: StateFunction): Unit = register(stateName, stateFunction, Option(stateTimeout)) - @deprecated("use the more import-friendly variant taking a Duration", "2.0") - protected final def when(stateName: S, stateTimeout: Timeout)(stateFunction: StateFunction): Unit = - register(stateName, stateFunction, stateTimeout) - /** * Set initial state. Call this method from the constructor before the #initialize method. * @@ -216,9 +290,7 @@ trait FSM[S, D] extends Listeners with ActorLogging { * @param stateData initial state data * @param timeout state timeout for the initial state, overriding the default timeout for that state */ - protected final def startWith(stateName: S, - stateData: D, - timeout: Timeout = None): Unit = + final def startWith(stateName: S, stateData: D, timeout: Timeout = None): Unit = currentState = FSM.State(stateName, stateData, timeout) /** @@ -228,7 +300,7 @@ trait FSM[S, D] extends Listeners with ActorLogging { * @param nextStateName state designator for the next state * @return state transition descriptor */ - protected final def goto(nextStateName: S): State = FSM.State(nextStateName, currentState.stateData) + final def goto(nextStateName: S): State = FSM.State(nextStateName, currentState.stateData) /** * Produce "empty" transition descriptor. Return this from a state function @@ -236,29 +308,29 @@ trait FSM[S, D] extends Listeners with ActorLogging { * * @return descriptor for staying in current state */ - protected final def stay(): State = goto(currentState.stateName) // cannot directly use currentState because of the timeout field + final def stay(): State = goto(currentState.stateName) // cannot directly use currentState because of the timeout field /** * Produce change descriptor to stop this FSM actor with reason "Normal". */ - protected final def stop(): State = stop(Normal) + final def stop(): State = stop(Normal) /** * Produce change descriptor to stop this FSM actor including specified reason. */ - protected final def stop(reason: Reason): State = stop(reason, currentState.stateData) + final def stop(reason: Reason): State = stop(reason, currentState.stateData) /** * Produce change descriptor to stop this FSM actor including specified reason. */ - protected final def stop(reason: Reason, stateData: D): State = stay using stateData withStopReason (reason) + final def stop(reason: Reason, stateData: D): State = stay using stateData withStopReason (reason) - protected final class TransformHelper(func: StateFunction) { + final class TransformHelper(func: StateFunction) { def using(andThen: PartialFunction[State, State]): StateFunction = func andThen (andThen orElse { case x ⇒ x }) } - protected final def transform(func: StateFunction): TransformHelper = new TransformHelper(func) + final def transform(func: StateFunction): TransformHelper = new TransformHelper(func) /** * Schedule named timer to deliver message after given delay, possibly repeating. @@ -268,7 +340,9 @@ trait FSM[S, D] extends Listeners with ActorLogging { * @param repeat send once if false, scheduleAtFixedRate if true * @return current state descriptor */ - protected[akka] def setTimer(name: String, msg: Any, timeout: Duration, repeat: Boolean): State = { + final def setTimer(name: String, msg: Any, timeout: Duration, repeat: Boolean): State = { + if (debugEvent) + log.debug("setting " + (if (repeat) "repeating " else "") + "timer '" + name + "'/" + timeout + ": " + msg) if (timers contains name) { timers(name).cancel } @@ -282,24 +356,27 @@ trait FSM[S, D] extends Listeners with ActorLogging { * Cancel named timer, ensuring that the message is not subsequently delivered (no race). * @param name of the timer to cancel */ - protected[akka] def cancelTimer(name: String): Unit = + final def cancelTimer(name: String): Unit = { + if (debugEvent) + log.debug("canceling timer '" + name + "'") if (timers contains name) { timers(name).cancel timers -= name } + } /** * Inquire whether the named timer is still active. Returns true unless the * timer does not exist, has previously been canceled or if it was a * single-shot timer whose message was already received. */ - protected[akka] final def timerActive_?(name: String) = timers contains name + final def timerActive_?(name: String) = timers contains name /** * Set state timeout explicitly. This method can safely be used from within a * state handler. */ - protected final def setStateTimeout(state: S, timeout: Timeout): Unit = stateTimeouts(state) = timeout + final def setStateTimeout(state: S, timeout: Timeout): Unit = stateTimeouts(state) = timeout /** * Set handler which is called upon each state transition, i.e. not when @@ -326,50 +403,52 @@ trait FSM[S, D] extends Listeners with ActorLogging { * Multiple handlers may be installed, and every one of them will be * called, not only the first one matching. */ - protected final def onTransition(transitionHandler: TransitionHandler): Unit = transitionEvent :+= transitionHandler + final def onTransition(transitionHandler: TransitionHandler): Unit = transitionEvent :+= transitionHandler /** * Convenience wrapper for using a total function instead of a partial * function literal. To be used with onTransition. */ - implicit protected final def total2pf(transitionHandler: (S, S) ⇒ Unit): TransitionHandler = + implicit final def total2pf(transitionHandler: (S, S) ⇒ Unit): TransitionHandler = new TransitionHandler { def isDefinedAt(in: (S, S)) = true def apply(in: (S, S)) { transitionHandler(in._1, in._2) } } /** - * Set handler which is called upon termination of this FSM actor. + * Set handler which is called upon termination of this FSM actor. Calling + * this method again will overwrite the previous contents. */ - protected final def onTermination(terminationHandler: PartialFunction[StopEvent, Unit]): Unit = + final def onTermination(terminationHandler: PartialFunction[StopEvent, Unit]): Unit = terminateEvent = terminationHandler /** - * Set handler which is called upon reception of unhandled messages. + * Set handler which is called upon reception of unhandled messages. Calling + * this method again will overwrite the previous contents. */ - protected final def whenUnhandled(stateFunction: StateFunction): Unit = + final def whenUnhandled(stateFunction: StateFunction): Unit = handleEvent = stateFunction orElse handleEventDefault /** * Verify existence of initial state and setup timers. This should be the * last call within the constructor. */ - protected final def initialize: Unit = makeTransition(currentState) + final def initialize: Unit = makeTransition(currentState) /** * Return current state name (i.e. object of type S) */ - protected[akka] def stateName: S = currentState.stateName + final def stateName: S = currentState.stateName /** * Return current state data (i.e. object of type D) */ - protected[akka] def stateData: D = currentState.stateData + final def stateData: D = currentState.stateData /** * Return next state data (available in onTransition handlers) */ - protected[akka] def nextStateData = nextState.stateData + final def nextStateData = nextState.stateData /* * **************************************************************** @@ -377,6 +456,8 @@ trait FSM[S, D] extends Listeners with ActorLogging { * **************************************************************** */ + private[akka] def debugEvent: Boolean = false + /* * FSM State data and current timeout handling */ @@ -436,7 +517,7 @@ trait FSM[S, D] extends Listeners with ActorLogging { * Main actor receive() method * ******************************************* */ - override final protected def receive: Receive = { + override final def receive: Receive = { case TimeoutMarker(gen) ⇒ if (generation == gen) { processMsg(StateTimeout, "state timeout") @@ -524,7 +605,21 @@ trait FSM[S, D] extends Listeners with ActorLogging { } } - override def postStop(): Unit = { terminate(stay withStopReason Shutdown) } + /** + * Call `onTermination` hook; if you want to retain this behavior when + * overriding make sure to call `super.postStop()`. + * + * Please note that this method is called by default from `preRestart()`, + * so override that one if `onTermination` shall not be called during + * restart. + */ + override def postStop(): Unit = { + /* + * setting this instance’s state to terminated does no harm during restart + * since the new instance will initialize fresh using startWith() + */ + terminate(stay withStopReason Shutdown) + } private def terminate(nextState: State): Unit = { if (!currentState.stopReason.isDefined) { @@ -541,13 +636,22 @@ trait FSM[S, D] extends Listeners with ActorLogging { } } + /** + * All messages sent to the [[akka.actor.FSM]] will be wrapped inside an + * `Event`, which allows pattern matching to extract both state and data. + */ case class Event(event: Any, stateData: D) + /** + * Case class representing the state of the [[akka.actor.FSM]] whithin the + * `onTermination` block. + */ case class StopEvent(reason: Reason, currentState: S, stateData: D) } /** - * Stackable trait for FSM which adds a rolling event log. + * Stackable trait for [[akka.actor.FSM]] which adds a rolling event log and + * debug logging capabilities (analogous to [[akka.event.LoggingReceive]]). * * @since 1.2 */ @@ -557,7 +661,7 @@ trait LoggingFSM[S, D] extends FSM[S, D] { this: Actor ⇒ def logDepth: Int = 0 - private val debugEvent = context.system.settings.FsmDebugEvent + private[akka] override val debugEvent = context.system.settings.FsmDebugEvent private val events = new Array[Event](logDepth) private val states = new Array[AnyRef](logDepth) @@ -574,18 +678,6 @@ trait LoggingFSM[S, D] extends FSM[S, D] { this: Actor ⇒ } } - protected[akka] abstract override def setTimer(name: String, msg: Any, timeout: Duration, repeat: Boolean): State = { - if (debugEvent) - log.debug("setting " + (if (repeat) "repeating " else "") + "timer '" + name + "'/" + timeout + ": " + msg) - super.setTimer(name, msg, timeout, repeat) - } - - protected[akka] abstract override def cancelTimer(name: String): Unit = { - if (debugEvent) - log.debug("canceling timer '" + name + "'") - super.cancelTimer(name) - } - private[akka] abstract override def processEvent(event: Event, source: AnyRef): Unit = { if (debugEvent) { val srcstr = source match { @@ -614,6 +706,7 @@ trait LoggingFSM[S, D] extends FSM[S, D] { this: Actor ⇒ /** * Retrieve current rolling log in oldest-first order. The log is filled with * each incoming event before processing by the user supplied state handler. + * The log entries are lost when this actor is restarted. */ protected def getLog: IndexedSeq[LogEntry[S, D]] = { val log = events zip states filter (_._1 ne null) map (x ⇒ LogEntry(x._2.asInstanceOf[S], x._1.stateData, x._1.event)) diff --git a/akka-actor/src/main/scala/akka/actor/FaultHandling.scala b/akka-actor/src/main/scala/akka/actor/FaultHandling.scala index 70246bab30..27a9f346db 100644 --- a/akka-actor/src/main/scala/akka/actor/FaultHandling.scala +++ b/akka-actor/src/main/scala/akka/actor/FaultHandling.scala @@ -9,8 +9,13 @@ import scala.collection.JavaConversions._ import java.lang.{ Iterable ⇒ JIterable } import akka.util.Duration +/** + * ChildRestartStats is the statistics kept by every parent Actor for every child Actor + * and is used for SupervisorStrategies to know how to deal with problems that occur for the children. + */ case class ChildRestartStats(val child: ActorRef, var maxNrOfRetriesCount: Int = 0, var restartTimeWindowStartNanos: Long = 0L) { + //FIXME How about making ChildRestartStats immutable and then move these methods into the actual supervisor strategies? def requestRestartPermission(retriesWindow: (Option[Int], Option[Int])): Boolean = retriesWindow match { case (Some(retries), _) if retries < 1 ⇒ false @@ -160,20 +165,21 @@ object SupervisorStrategy extends SupervisorStrategyLowPriorityImplicits { def makeDecider(flat: Iterable[CauseDirective]): Decider = { val directives = sort(flat) - { - case x ⇒ directives find (_._1 isInstance x) map (_._2) getOrElse Escalate - } + { case x ⇒ directives collectFirst { case (c, d) if c isInstance x ⇒ d } getOrElse Escalate } } - def makeDecider(func: JDecider): Decider = { - case x ⇒ func(x) - } + /** + * Converts a Java Decider into a Scala Decider + */ + def makeDecider(func: JDecider): Decider = { case x ⇒ func(x) } /** * Sort so that subtypes always precede their supertypes, but without * obeying any order between unrelated subtypes (insert sort). + * + * INTERNAL API */ - def sort(in: Iterable[CauseDirective]): Seq[CauseDirective] = + private[akka] def sort(in: Iterable[CauseDirective]): Seq[CauseDirective] = (new ArrayBuffer[CauseDirective](in.size) /: in) { (buf, ca) ⇒ buf.indexWhere(_._1 isAssignableFrom ca._1) match { case -1 ⇒ buf append ca @@ -184,14 +190,21 @@ object SupervisorStrategy extends SupervisorStrategyLowPriorityImplicits { private[akka] def withinTimeRangeOption(withinTimeRange: Duration): Option[Duration] = if (withinTimeRange.isFinite && withinTimeRange >= Duration.Zero) Some(withinTimeRange) else None + private[akka] def maxNrOfRetriesOption(maxNrOfRetries: Int): Option[Int] = if (maxNrOfRetries < 0) None else Some(maxNrOfRetries) } +/** + * An Akka SupervisorStrategy is the policy to apply for crashing children + */ abstract class SupervisorStrategy { import SupervisorStrategy._ + /** + * Returns the Decider that is associated with this SupervisorStrategy + */ def decider: Decider /** @@ -204,21 +217,19 @@ abstract class SupervisorStrategy { */ 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) - children.foreach(_.asInstanceOf[InternalActorRef].suspend()) - } + //FIXME docs + def handleSupervisorFailing(supervisor: ActorRef, children: Iterable[ActorRef]): Unit = + if (children.nonEmpty) children.foreach(_.asInstanceOf[InternalActorRef].suspend()) - def handleSupervisorRestarted(cause: Throwable, supervisor: ActorRef, children: Iterable[ActorRef]): Unit = { - if (children.nonEmpty) - children.foreach(_.asInstanceOf[InternalActorRef].restart(cause)) - } + //FIXME docs + def handleSupervisorRestarted(cause: Throwable, supervisor: ActorRef, children: Iterable[ActorRef]): Unit = + if (children.nonEmpty) children.foreach(_.asInstanceOf[InternalActorRef].restart(cause)) /** * Returns whether it processed the failure or not */ def handleFailure(context: ActorContext, child: ActorRef, cause: Throwable, stats: ChildRestartStats, children: Iterable[ChildRestartStats]): Boolean = { - val directive = if (decider.isDefinedAt(cause)) decider(cause) else Escalate + val directive = if (decider.isDefinedAt(cause)) decider(cause) else Escalate //FIXME applyOrElse in Scala 2.10 directive match { case Resume ⇒ child.asInstanceOf[InternalActorRef].resume(); true case Restart ⇒ processFailure(context, true, child, cause, stats, children); true @@ -242,6 +253,8 @@ abstract class SupervisorStrategy { case class AllForOneStrategy(maxNrOfRetries: Int = -1, withinTimeRange: Duration = Duration.Inf)(val decider: SupervisorStrategy.Decider) extends SupervisorStrategy { + import SupervisorStrategy._ + def this(maxNrOfRetries: Int, withinTimeRange: Duration, decider: SupervisorStrategy.JDecider) = this(maxNrOfRetries, withinTimeRange)(SupervisorStrategy.makeDecider(decider)) @@ -256,9 +269,7 @@ case class AllForOneStrategy(maxNrOfRetries: Int = -1, withinTimeRange: Duration * every call to requestRestartPermission, assuming that strategies are shared * across actors and thus this field does not take up much space */ - private val retriesWindow = ( - SupervisorStrategy.maxNrOfRetriesOption(maxNrOfRetries), - SupervisorStrategy.withinTimeRangeOption(withinTimeRange).map(_.toMillis.toInt)) + private val retriesWindow = (maxNrOfRetriesOption(maxNrOfRetries), withinTimeRangeOption(withinTimeRange).map(_.toMillis.toInt)) def handleChildTerminated(context: ActorContext, child: ActorRef, children: Iterable[ActorRef]): Unit = {} diff --git a/akka-actor/src/main/scala/akka/actor/IO.scala b/akka-actor/src/main/scala/akka/actor/IO.scala index a90dd6f579..07af4213fc 100644 --- a/akka-actor/src/main/scala/akka/actor/IO.scala +++ b/akka-actor/src/main/scala/akka/actor/IO.scala @@ -21,8 +21,7 @@ import java.nio.channels.{ import scala.collection.mutable import scala.annotation.tailrec import scala.collection.generic.CanBuildFrom -import com.eaio.uuid.UUID - +import java.util.UUID /** * IO messages and iteratees. * @@ -31,7 +30,7 @@ import com.eaio.uuid.UUID */ object IO { - final class DivergentIterateeException extends Exception("Iteratees should not return a continuation when receiving EOF") + final class DivergentIterateeException extends IllegalStateException("Iteratees should not return a continuation when receiving EOF") /** * An immutable handle to a Java NIO Channel. Contains a reference to the @@ -65,14 +64,14 @@ object IO { * A [[akka.actor.IO.Handle]] to a ReadableByteChannel. */ sealed trait ReadHandle extends Handle with Product { - override def asReadable = this + override def asReadable: ReadHandle = this } /** * A [[akka.actor.IO.Handle]] to a WritableByteChannel. */ sealed trait WriteHandle extends Handle with Product { - override def asWritable = this + override def asWritable: WriteHandle = this /** * Sends a request to the [[akka.actor.IOManager]] to write to the @@ -89,16 +88,16 @@ object IO { * created by [[akka.actor.IOManager]].connect() and * [[akka.actor.IO.ServerHandle]].accept(). */ - case class SocketHandle(owner: ActorRef, ioManager: ActorRef, uuid: UUID = new UUID()) extends ReadHandle with WriteHandle { - override def asSocket = this + case class SocketHandle(owner: ActorRef, ioManager: ActorRef, uuid: UUID = UUID.randomUUID()) extends ReadHandle with WriteHandle { + override def asSocket: SocketHandle = this } /** * A [[akka.actor.IO.Handle]] to a ServerSocketChannel. Instances are * normally created by [[akka.actor.IOManager]].listen(). */ - case class ServerHandle(owner: ActorRef, ioManager: ActorRef, uuid: UUID = new UUID()) extends Handle { - override def asServer = this + case class ServerHandle(owner: ActorRef, ioManager: ActorRef, uuid: UUID = UUID.randomUUID()) extends Handle { + override def asServer: ServerHandle = this /** * Sends a request to the [[akka.actor.IOManager]] to accept an incoming @@ -321,16 +320,18 @@ object IO { } object Chunk { - val empty = Chunk(ByteString.empty) + val empty: Chunk = new Chunk(ByteString.empty) } /** * Part of an [[akka.actor.IO.Input]] stream that contains a chunk of bytes. */ case class Chunk(bytes: ByteString) extends Input { - def ++(that: Input) = that match { - case Chunk(more) ⇒ Chunk(bytes ++ more) - case _: EOF ⇒ that + final override def ++(that: Input): Input = that match { + case Chunk(more) if more.isEmpty ⇒ this + case c: Chunk if bytes.isEmpty ⇒ c + case Chunk(more) ⇒ Chunk(bytes ++ more) + case _: EOF ⇒ that } } @@ -343,7 +344,7 @@ object IO { * Iteratee.recover() in order to handle it properly. */ case class EOF(cause: Option[Exception]) extends Input { - def ++(that: Input) = that + final override def ++(that: Input): Input = that } object Iteratee { @@ -353,7 +354,15 @@ object IO { * inferred as an Iteratee and not as a Done. */ def apply[A](value: A): Iteratee[A] = Done(value) + + /** + * Returns Iteratee.unit + */ def apply(): Iteratee[Unit] = unit + + /** + * The single value representing Done(()) + */ val unit: Iteratee[Unit] = Done(()) } @@ -446,6 +455,7 @@ object IO { */ final case class Cont[+A](f: Input ⇒ (Iteratee[A], Input), error: Option[Exception] = None) extends Iteratee[A] + //FIXME general description of what an IterateeRef is and how it is used, potentially with link to docs object IterateeRef { /** @@ -478,13 +488,14 @@ object IO { * 'refFactory' is used to provide the default value for new keys. */ class Map[K, V] private (refFactory: ⇒ IterateeRef[V], underlying: mutable.Map[K, IterateeRef[V]] = mutable.Map.empty[K, IterateeRef[V]]) extends mutable.Map[K, IterateeRef[V]] { - def get(key: K) = Some(underlying.getOrElseUpdate(key, refFactory)) - def iterator = underlying.iterator - def +=(kv: (K, IterateeRef[V])) = { underlying += kv; this } - def -=(key: K) = { underlying -= key; this } + override def get(key: K) = Some(underlying.getOrElseUpdate(key, refFactory)) + override def iterator = underlying.iterator + override def +=(kv: (K, IterateeRef[V])) = { underlying += kv; this } + override def -=(key: K) = { underlying -= key; this } override def empty = new Map[K, V](refFactory) } + //FIXME general description of what an Map is and how it is used, potentially with link to docs object Map { /** * Uses a factory to create the initial IterateeRef for each new key. @@ -501,7 +512,6 @@ object IO { */ def async[K]()(implicit executor: ExecutionContext): IterateeRef.Map[K, Unit] = new Map(IterateeRef.async()) } - } /** @@ -511,8 +521,11 @@ object IO { * for details. */ trait IterateeRef[A] { + //FIXME Add docs def flatMap(f: A ⇒ Iteratee[A]): Unit + //FIXME Add docs def map(f: A ⇒ A): Unit + //FIXME Add docs def apply(input: Input): Unit } @@ -529,12 +542,16 @@ object IO { */ final class IterateeRefSync[A](initial: Iteratee[A]) extends IterateeRef[A] { private var _value: (Iteratee[A], Input) = (initial, Chunk.empty) - def flatMap(f: A ⇒ Iteratee[A]): Unit = _value = _value match { + override def flatMap(f: A ⇒ Iteratee[A]): Unit = _value = _value match { case (iter, chunk @ Chunk(bytes)) if bytes.nonEmpty ⇒ (iter flatMap f)(chunk) case (iter, input) ⇒ (iter flatMap f, input) } - def map(f: A ⇒ A): Unit = _value = (_value._1 map f, _value._2) - def apply(input: Input): Unit = _value = _value._1(_value._2 ++ input) + override def map(f: A ⇒ A): Unit = _value = (_value._1 map f, _value._2) + override def apply(input: Input): Unit = _value = _value._1(_value._2 ++ input) + + /** + * Returns the current value of this IterateeRefSync + */ def value: (Iteratee[A], Input) = _value } @@ -554,12 +571,16 @@ object IO { */ final class IterateeRefAsync[A](initial: Iteratee[A])(implicit executor: ExecutionContext) extends IterateeRef[A] { private var _value: Future[(Iteratee[A], Input)] = Future((initial, Chunk.empty)) - def flatMap(f: A ⇒ Iteratee[A]): Unit = _value = _value map { + override def flatMap(f: A ⇒ Iteratee[A]): Unit = _value = _value map { case (iter, chunk @ Chunk(bytes)) if bytes.nonEmpty ⇒ (iter flatMap f)(chunk) case (iter, input) ⇒ (iter flatMap f, input) } - def map(f: A ⇒ A): Unit = _value = _value map (v ⇒ (v._1 map f, v._2)) - def apply(input: Input): Unit = _value = _value map (v ⇒ v._1(v._2 ++ input)) + override def map(f: A ⇒ A): Unit = _value = _value map (v ⇒ (v._1 map f, v._2)) + override def apply(input: Input): Unit = _value = _value map (v ⇒ v._1(v._2 ++ input)) + + /** + * Returns a Future which will hold the future value of this IterateeRefAsync + */ def future: Future[(Iteratee[A], Input)] = _value } @@ -703,10 +724,9 @@ object IO { /** * An Iteratee that continually repeats an Iteratee. * - * TODO: Should terminate on EOF + * FIXME TODO: Should terminate on EOF */ - def repeat(iter: Iteratee[Unit]): Iteratee[Unit] = - iter flatMap (_ ⇒ repeat(iter)) + def repeat(iter: Iteratee[Unit]): Iteratee[Unit] = iter flatMap (_ ⇒ repeat(iter)) /** * An Iteratee that applies an Iteratee to each element of a Traversable @@ -781,7 +801,7 @@ object IO { * An IOManager does not need to be manually stopped when not in use as it will * automatically enter an idle state when it has no channels to manage. */ -final class IOManager private (system: ActorSystem) extends Extension { +final class IOManager private (system: ActorSystem) extends Extension { //FIXME how about taking an ActorContext /** * A reference to the [[akka.actor.IOManagerActor]] that performs the actual * IO. It communicates with other actors using subclasses of @@ -862,9 +882,10 @@ final class IOManager private (system: ActorSystem) extends Extension { } +//FIXME add docs object IOManager extends ExtensionId[IOManager] with ExtensionIdProvider { - override def lookup = this - override def createExtension(system: ExtendedActorSystem) = new IOManager(system) + override def lookup: IOManager.type = this + override def createExtension(system: ExtendedActorSystem): IOManager = new IOManager(system) } /** @@ -875,7 +896,7 @@ object IOManager extends ExtensionId[IOManager] with ExtensionIdProvider { final class IOManagerActor extends Actor with ActorLogging { import SelectionKey.{ OP_READ, OP_WRITE, OP_ACCEPT, OP_CONNECT } - private val bufferSize = 8192 // TODO: make buffer size configurable + private val bufferSize = 8192 // FIXME TODO: make configurable private type ReadChannel = ReadableByteChannel with SelectableChannel private type WriteChannel = WritableByteChannel with SelectableChannel @@ -898,7 +919,7 @@ final class IOManagerActor extends Actor with ActorLogging { private var lastSelect = 0 /** force a select when lastSelect reaches this amount */ - private val selectAt = 100 + private val selectAt = 100 // FIXME TODO: make configurable /** true while the selector is open and channels.nonEmpty */ private var running = false @@ -948,9 +969,7 @@ final class IOManagerActor extends Actor with ActorLogging { lastSelect = 0 } - private def forwardFailure(f: ⇒ Unit): Unit = { - try { f } catch { case NonFatal(e) ⇒ sender ! Status.Failure(e) } - } + private def forwardFailure(f: ⇒ Unit): Unit = try f catch { case NonFatal(e) ⇒ sender ! Status.Failure(e) } private def setSocketOptions(socket: java.net.Socket, options: Seq[IO.SocketOption]) { options foreach { @@ -968,7 +987,7 @@ final class IOManagerActor extends Actor with ActorLogging { } } - protected def receive = { + def receive = { case Select ⇒ select() if (running) self ! Select @@ -986,7 +1005,7 @@ final class IOManagerActor extends Actor with ActorLogging { forwardFailure(sock.setPerformancePreferences(connTime, latency, bandwidth)) } - channel.socket bind (address, 1000) // TODO: make backlog configurable + channel.socket bind (address, 1000) // FIXME TODO: make backlog configurable channels update (server, channel) channel register (selector, OP_ACCEPT, server) server.owner ! IO.Listening(server, channel.socket.getLocalSocketAddress()) @@ -1049,29 +1068,13 @@ final class IOManagerActor extends Actor with ActorLogging { private def process(key: SelectionKey) { val handle = key.attachment.asInstanceOf[IO.Handle] try { - if (key.isConnectable) key.channel match { - case channel: SocketChannel ⇒ connect(handle.asSocket, channel) - } - if (key.isAcceptable) key.channel match { - case channel: ServerSocketChannel ⇒ accept(handle.asServer, channel) - } - if (key.isReadable) key.channel match { - case channel: ReadChannel ⇒ read(handle.asReadable, channel) - } - if (key.isWritable) key.channel match { - case channel: WriteChannel ⇒ - try { - write(handle.asWritable, channel) - } catch { - case e: IOException ⇒ - // ignore, let it fail on read to ensure nothing left in read buffer. - } - } + if (key.isConnectable) key.channel match { case channel: SocketChannel ⇒ connect(handle.asSocket, channel) } + if (key.isAcceptable) key.channel match { case channel: ServerSocketChannel ⇒ accept(handle.asServer, channel) } + if (key.isReadable) key.channel match { case channel: ReadChannel ⇒ read(handle.asReadable, channel) } + if (key.isWritable) key.channel match { case channel: WriteChannel ⇒ try write(handle.asWritable, channel) catch { case e: IOException ⇒ } } // ignore, let it fail on read to ensure nothing left in read buffer. } catch { - case e: ClassCastException ⇒ cleanup(handle, Some(e)) - case e: CancelledKeyException ⇒ cleanup(handle, Some(e)) - case e: IOException ⇒ cleanup(handle, Some(e)) - case e: ActorInitializationException ⇒ cleanup(handle, Some(e)) + case e @ (_: ClassCastException | _: CancelledKeyException | _: IOException | _: ActorInitializationException) ⇒ + cleanup(handle, Some(e.asInstanceOf[Exception])) //Scala patmat is broken } } @@ -1090,9 +1093,6 @@ final class IOManagerActor extends Actor with ActorLogging { } } - private def setOps(handle: IO.Handle, ops: Int): Unit = - channels(handle) keyFor selector interestOps ops - private def addOps(handle: IO.Handle, ops: Int) { val key = channels(handle) keyFor selector val cur = key.interestOps @@ -1158,9 +1158,9 @@ final class IOManagerActor extends Actor with ActorLogging { } } } - } +//FIXME is this public API? final class WriteBuffer(bufferSize: Int) { private val _queue = new java.util.ArrayDeque[ByteString] private val _buffer = ByteBuffer.allocate(bufferSize) @@ -1182,9 +1182,9 @@ final class WriteBuffer(bufferSize: Int) { this } - def length = _length + def length: Int = _length - def isEmpty = _length == 0 + def isEmpty: Boolean = _length == 0 def write(channel: WritableByteChannel with SelectableChannel): Int = { @tailrec diff --git a/akka-actor/src/main/scala/akka/actor/Props.scala b/akka-actor/src/main/scala/akka/actor/Props.scala index d66fb6653c..292a437dab 100644 --- a/akka-actor/src/main/scala/akka/actor/Props.scala +++ b/akka-actor/src/main/scala/akka/actor/Props.scala @@ -18,12 +18,24 @@ import akka.routing._ */ object Props { + /** + * The defaultCreator, simply throws an UnsupportedOperationException when applied, which is used when creating a Props + */ final val defaultCreator: () ⇒ Actor = () ⇒ throw new UnsupportedOperationException("No actor creator specified!") + /** + * The defaultRoutedProps is NoRouter which is used when creating a Props + */ final val defaultRoutedProps: RouterConfig = NoRouter + /** + * The default Deploy instance which is used when creating a Props + */ final val defaultDeploy = Deploy() + /** + * A Props instance whose creator will create an actor that doesn't respond to any message + */ final val empty = new Props(() ⇒ new Actor { def receive = Actor.emptyBehavior }) /** @@ -49,8 +61,7 @@ object Props { * Returns a Props that has default values except for "creator" which will be a function that creates an instance * of the supplied class using the default constructor. */ - def apply(actorClass: Class[_ <: Actor]): Props = - default.withCreator(actorClass) + def apply(actorClass: Class[_ <: Actor]): Props = default.withCreator(actorClass) /** * Returns a Props that has default values except for "creator" which will be a function that creates an instance @@ -58,18 +69,18 @@ object Props { * * Scala API. */ - def apply(creator: ⇒ Actor): Props = - default.withCreator(creator) + def apply(creator: ⇒ Actor): Props = default.withCreator(creator) /** * Returns a Props that has default values except for "creator" which will be a function that creates an instance * using the supplied thunk. */ - def apply(creator: Creator[_ <: Actor]): Props = - default.withCreator(creator.create) + def apply(creator: Creator[_ <: Actor]): Props = default.withCreator(creator.create) - def apply(behavior: ActorContext ⇒ Actor.Receive): Props = - apply(new Actor { def receive = behavior(context) }) + /** + * Returns a new Props whose creator will instantiate an Actor that has the behavior specified + */ + def apply(behavior: ActorContext ⇒ Actor.Receive): Props = apply(new Actor { def receive = behavior(context) }) } /** @@ -175,4 +186,4 @@ case class Props( */ private[akka] case class FromClassCreator(clazz: Class[_ <: Actor]) extends Function0[Actor] { def apply(): Actor = clazz.newInstance -} \ No newline at end of file +} diff --git a/akka-actor/src/main/scala/akka/actor/Scheduler.scala b/akka-actor/src/main/scala/akka/actor/Scheduler.scala index 8b02734cc8..e1d36ab95d 100644 --- a/akka-actor/src/main/scala/akka/actor/Scheduler.scala +++ b/akka-actor/src/main/scala/akka/actor/Scheduler.scala @@ -5,10 +5,13 @@ package akka.actor import akka.util.Duration -import org.jboss.netty.akka.util.{ TimerTask, HashedWheelTimer, Timeout ⇒ HWTimeout } +import akka.util.internal.{ TimerTask, HashedWheelTimer, Timeout ⇒ HWTimeout, Timer } import akka.event.LoggingAdapter import akka.dispatch.MessageDispatcher import java.io.Closeable +import java.util.concurrent.atomic.AtomicReference +import scala.annotation.tailrec +import akka.util.internal._ //#scheduler /** @@ -119,7 +122,7 @@ class DefaultScheduler(hashedWheelTimer: HashedWheelTimer, log: LoggingAdapter, dispatcher: ⇒ MessageDispatcher) extends Scheduler with Closeable { - def schedule(initialDelay: Duration, delay: Duration, receiver: ActorRef, message: Any): Cancellable = { + override def schedule(initialDelay: Duration, delay: Duration, receiver: ActorRef, message: Any): Cancellable = { val continuousCancellable = new ContinuousCancellable continuousCancellable.init( hashedWheelTimer.newTimeout( @@ -134,7 +137,7 @@ class DefaultScheduler(hashedWheelTimer: HashedWheelTimer, initialDelay)) } - def schedule(initialDelay: Duration, delay: Duration)(f: ⇒ Unit): Cancellable = { + override def schedule(initialDelay: Duration, delay: Duration)(f: ⇒ Unit): Cancellable = { val continuousCancellable = new ContinuousCancellable continuousCancellable.init( hashedWheelTimer.newTimeout( @@ -148,7 +151,7 @@ class DefaultScheduler(hashedWheelTimer: HashedWheelTimer, initialDelay)) } - def schedule(initialDelay: Duration, delay: Duration, runnable: Runnable): Cancellable = { + override def schedule(initialDelay: Duration, delay: Duration, runnable: Runnable): Cancellable = { val continuousCancellable = new ContinuousCancellable continuousCancellable.init( hashedWheelTimer.newTimeout( @@ -161,7 +164,7 @@ class DefaultScheduler(hashedWheelTimer: HashedWheelTimer, initialDelay)) } - def scheduleOnce(delay: Duration, runnable: Runnable): Cancellable = + override def scheduleOnce(delay: Duration, runnable: Runnable): Cancellable = new DefaultCancellable( hashedWheelTimer.newTimeout( new TimerTask() { @@ -169,7 +172,7 @@ class DefaultScheduler(hashedWheelTimer: HashedWheelTimer, }, delay)) - def scheduleOnce(delay: Duration, receiver: ActorRef, message: Any): Cancellable = + override def scheduleOnce(delay: Duration, receiver: ActorRef, message: Any): Cancellable = new DefaultCancellable( hashedWheelTimer.newTimeout( new TimerTask { @@ -177,7 +180,7 @@ class DefaultScheduler(hashedWheelTimer: HashedWheelTimer, }, delay)) - def scheduleOnce(delay: Duration)(f: ⇒ Unit): Cancellable = + override def scheduleOnce(delay: Duration)(f: ⇒ Unit): Cancellable = new DefaultCancellable( hashedWheelTimer.newTimeout( new TimerTask with Runnable { @@ -188,11 +191,7 @@ class DefaultScheduler(hashedWheelTimer: HashedWheelTimer, private trait ContinuousScheduling { this: TimerTask ⇒ def scheduleNext(timeout: HWTimeout, delay: Duration, delegator: ContinuousCancellable) { - try { - delegator.swap(timeout.getTimer.newTimeout(this, delay)) - } catch { - case _: IllegalStateException ⇒ // stop recurring if timer is stopped - } + try delegator.swap(timeout.getTimer.newTimeout(this, delay)) catch { case _: IllegalStateException ⇒ } // stop recurring if timer is stopped } } @@ -203,54 +202,50 @@ class DefaultScheduler(hashedWheelTimer: HashedWheelTimer, } } - def close() = { + override def close(): Unit = { import scala.collection.JavaConverters._ hashedWheelTimer.stop().asScala foreach execDirectly } } +private[akka] object ContinuousCancellable { + val initial: HWTimeout = new HWTimeout { + override def getTimer: Timer = null + override def getTask: TimerTask = null + override def isExpired: Boolean = false + override def isCancelled: Boolean = false + override def cancel: Unit = () + } + + val cancelled: HWTimeout = new HWTimeout { + override def getTimer: Timer = null + override def getTask: TimerTask = null + override def isExpired: Boolean = false + override def isCancelled: Boolean = true + override def cancel: Unit = () + } +} /** * Wrapper of a [[org.jboss.netty.akka.util.Timeout]] that delegates all * methods. Needed to be able to cancel continuous tasks, * since they create new Timeout for each tick. */ -private[akka] class ContinuousCancellable extends Cancellable { - @volatile - private var delegate: HWTimeout = _ - @volatile - private var cancelled = false - +private[akka] class ContinuousCancellable extends AtomicReference[HWTimeout](ContinuousCancellable.initial) with Cancellable { private[akka] def init(initialTimeout: HWTimeout): this.type = { - delegate = initialTimeout + compareAndSet(ContinuousCancellable.initial, initialTimeout) this } - private[akka] def swap(newTimeout: HWTimeout): Unit = { - val wasCancelled = isCancelled - delegate = newTimeout - if (wasCancelled || isCancelled) cancel() + @tailrec private[akka] final def swap(newTimeout: HWTimeout): Unit = get match { + case some if some.isCancelled ⇒ try cancel() finally newTimeout.cancel() + case some ⇒ if (!compareAndSet(some, newTimeout)) swap(newTimeout) } - def isCancelled(): Boolean = { - // delegate is initially null, but this object will not be exposed to the world until after init - cancelled || delegate.isCancelled() - } - - def cancel(): Unit = { - // the underlying Timeout will not become cancelled once the task has been started to run, - // therefore we keep a flag here to make sure that rescheduling doesn't occur when cancelled - cancelled = true - // delegate is initially null, but this object will not be exposed to the world until after init - delegate.cancel() - } + def isCancelled(): Boolean = get().isCancelled() + def cancel(): Unit = getAndSet(ContinuousCancellable.cancelled).cancel() } -class DefaultCancellable(val timeout: HWTimeout) extends Cancellable { - def cancel() { - timeout.cancel() - } - - def isCancelled: Boolean = { - timeout.isCancelled - } +private[akka] class DefaultCancellable(timeout: HWTimeout) extends AtomicReference[HWTimeout](timeout) with Cancellable { + override def cancel(): Unit = getAndSet(ContinuousCancellable.cancelled).cancel() + override def isCancelled: Boolean = get().isCancelled } diff --git a/akka-actor/src/main/scala/akka/actor/Stash.scala b/akka-actor/src/main/scala/akka/actor/Stash.scala index 6672945522..386bc0f070 100644 --- a/akka-actor/src/main/scala/akka/actor/Stash.scala +++ b/akka-actor/src/main/scala/akka/actor/Stash.scala @@ -56,7 +56,7 @@ trait Stash { /* The capacity of the stash. Configured in the actor's dispatcher config. */ - private val capacity = { + private val capacity: Int = { val dispatcher = context.system.settings.config.getConfig(context.props.dispatcher) val config = dispatcher.withFallback(context.system.settings.config.getConfig("akka.actor.default-dispatcher")) config.getInt("stash-capacity") @@ -125,4 +125,7 @@ An (unbounded) deque-based mailbox can be configured as follows: } +/** + * Is thrown when the size of the Stash exceeds the capacity of the Stash + */ class StashOverflowException(message: String, cause: Throwable = null) extends AkkaException(message, cause) diff --git a/akka-actor/src/main/scala/akka/actor/TypedActor.scala b/akka-actor/src/main/scala/akka/actor/TypedActor.scala index 4d85542d36..9bb560417b 100644 --- a/akka-actor/src/main/scala/akka/actor/TypedActor.scala +++ b/akka-actor/src/main/scala/akka/actor/TypedActor.scala @@ -6,21 +6,28 @@ package akka.actor import akka.japi.{ Creator, Option ⇒ JOption } import java.lang.reflect.{ InvocationTargetException, Method, InvocationHandler, Proxy } -import akka.util.{ Timeout, NonFatal } +import akka.util.{ Timeout, NonFatal, Duration } import java.util.concurrent.atomic.{ AtomicReference ⇒ AtomVar } import akka.dispatch._ import java.util.concurrent.TimeoutException import java.util.concurrent.TimeUnit.MILLISECONDS -import java.lang.IllegalStateException -import akka.util.Duration import akka.actor.TypedActor.TypedActorInvocationHandler -import akka.serialization.{ JavaSerializer, Serialization, SerializationExtension } +import akka.serialization.{ JavaSerializer, SerializationExtension } import java.io.ObjectStreamException +/** + * A TypedActorFactory is something that can created TypedActor instances. + */ trait TypedActorFactory { + /** + * Underlying dependency is to be able to create normal Actors + */ protected def actorFactory: ActorRefFactory + /** + * Underlying dependency to a TypedActorExtension, which can either be contextual or ActorSystem "global" + */ protected def typedActor: TypedActorExtension /** @@ -80,6 +87,9 @@ trait TypedActorFactory { } +/** + * This represents the TypedActor Akka Extension, access to the functionality is done through a given ActorSystem. + */ object TypedActor extends ExtensionId[TypedActorExtension] with ExtensionIdProvider { override def get(system: ActorSystem): TypedActorExtension = super.get(system) @@ -145,8 +155,10 @@ object TypedActor extends ExtensionId[TypedActorExtension] with ExtensionIdProvi /** * Represents the serialized form of a MethodCall, uses readResolve and writeReplace to marshall the call + * + * INTERNAL USE ONLY */ - case class SerializedMethodCall(ownerType: Class[_], methodName: String, parameterTypes: Array[Class[_]], serializedParameters: Array[(Int, Class[_], Array[Byte])]) { + private[akka] case class SerializedMethodCall(ownerType: Class[_], methodName: String, parameterTypes: Array[Class[_]], serializedParameters: Array[(Int, Class[_], Array[Byte])]) { //TODO implement writeObject and readObject to serialize //TODO Possible optimization is to special encode the parameter-types to conserve space @@ -213,6 +225,8 @@ object TypedActor extends ExtensionId[TypedActorExtension] with ExtensionIdProvi /** * Implementation of TypedActor as an Actor + * + * INTERNAL USE ONLY */ private[akka] class TypedActor[R <: AnyRef, T <: R](val proxyVar: AtomVar[R], createInstance: ⇒ T) extends Actor { val me = try { @@ -371,6 +385,9 @@ object TypedActor extends ExtensionId[TypedActorExtension] with ExtensionIdProvi def postRestart(reason: Throwable): Unit } + /** + * INTERNAL USE ONLY + */ private[akka] class TypedActorInvocationHandler(@transient val extension: TypedActorExtension, @transient val actorVar: AtomVar[ActorRef], @transient val timeout: Timeout) extends InvocationHandler with Serializable { def actor = actorVar.get @throws(classOf[Throwable]) @@ -396,6 +413,9 @@ object TypedActor extends ExtensionId[TypedActorExtension] with ExtensionIdProvi @throws(classOf[ObjectStreamException]) private def writeReplace(): AnyRef = SerializedTypedActorInvocationHandler(actor, timeout.duration) } + /** + * INTERNAL USE ONLY + */ private[akka] case class SerializedTypedActorInvocationHandler(val actor: ActorRef, val timeout: Duration) { @throws(classOf[ObjectStreamException]) private def readResolve(): AnyRef = JavaSerializer.currentSystem.value match { case null ⇒ throw new IllegalStateException("SerializedTypedActorInvocationHandler.readResolve requires that JavaSerializer.currentSystem.value is set to a non-null value") @@ -569,12 +589,16 @@ case class TypedProps[T <: AnyRef] protected[TypedProps] ( def withoutInterface(interface: Class[_ >: T]): TypedProps[T] = this.copy(interfaces = interfaces diff TypedProps.extractInterfaces(interface)) - import akka.actor.{ Props ⇒ ActorProps } - def actorProps(): ActorProps = - if (dispatcher == ActorProps().dispatcher) ActorProps() - else ActorProps(dispatcher = dispatcher) + /** + * Returns the akka.actor.Props representation of this TypedProps + */ + def actorProps(): Props = if (dispatcher == Props().dispatcher) Props() else Props(dispatcher = dispatcher) } +/** + * ContextualTypedActorFactory allows TypedActors to create children, effectively forming the same Actor Supervision Hierarchies + * as normal Actors can. + */ case class ContextualTypedActorFactory(typedActor: TypedActorExtension, actorFactory: ActorContext) extends TypedActorFactory { override def getActorRefFor(proxy: AnyRef): ActorRef = typedActor.getActorRefFor(proxy) override def isTypedActor(proxyOrNot: AnyRef): Boolean = typedActor.isTypedActor(proxyOrNot) @@ -607,7 +631,9 @@ class TypedActorExtension(system: ExtendedActorSystem) extends TypedActorFactory def isTypedActor(proxyOrNot: AnyRef): Boolean = invocationHandlerFor(proxyOrNot) ne null // Private API - + /** + * INTERNAL USE ONLY + */ private[akka] def createActorRefProxy[R <: AnyRef, T <: R](props: TypedProps[T], proxyVar: AtomVar[R], actorRef: ⇒ ActorRef): R = { //Warning, do not change order of the following statements, it's some elaborate chicken-n-egg handling val actorVar = new AtomVar[ActorRef](null) @@ -631,6 +657,9 @@ class TypedActorExtension(system: ExtendedActorSystem) extends TypedActorFactory } } + /** + * INTERNAL USE ONLY + */ private[akka] def invocationHandlerFor(typedActor_? : AnyRef): TypedActorInvocationHandler = if ((typedActor_? ne null) && Proxy.isProxyClass(typedActor_?.getClass)) typedActor_? match { case null ⇒ null diff --git a/akka-actor/src/main/scala/akka/actor/UntypedActor.scala b/akka-actor/src/main/scala/akka/actor/UntypedActor.scala index a5ebeb851c..9420ab84cc 100644 --- a/akka-actor/src/main/scala/akka/actor/UntypedActor.scala +++ b/akka-actor/src/main/scala/akka/actor/UntypedActor.scala @@ -93,11 +93,17 @@ import akka.japi.{ Creator } abstract class UntypedActor extends Actor { /** - * To be implemented by concrete UntypedActor. Defines the message handler. + * To be implemented by concrete UntypedActor, this defines the behavior of the + * UntypedActor. */ @throws(classOf[Exception]) def onReceive(message: Any): Unit + /** + * Returns this UntypedActor's UntypedActorContext + * The UntypedActorContext is not thread safe so do not expose it outside of the + * UntypedActor. + */ def getContext(): UntypedActorContext = context.asInstanceOf[UntypedActorContext] /** @@ -150,9 +156,7 @@ abstract class UntypedActor extends Actor { */ override def postRestart(reason: Throwable): Unit = super.postRestart(reason) - final protected def receive = { - case msg ⇒ onReceive(msg) - } + final def receive = { case msg ⇒ onReceive(msg) } } /** diff --git a/akka-actor/src/main/scala/akka/actor/package.scala b/akka-actor/src/main/scala/akka/actor/package.scala index 9ec5348fee..3bf56b8bc4 100644 --- a/akka-actor/src/main/scala/akka/actor/package.scala +++ b/akka-actor/src/main/scala/akka/actor/package.scala @@ -7,24 +7,4 @@ package akka package object actor { implicit def actorRef2Scala(ref: ActorRef): ScalaActorRef = ref.asInstanceOf[ScalaActorRef] implicit def scala2ActorRef(ref: ScalaActorRef): ActorRef = ref.asInstanceOf[ActorRef] - - type Uuid = com.eaio.uuid.UUID - - def newUuid(): Uuid = new Uuid() - - def uuidFrom(time: Long, clockSeqAndNode: Long): Uuid = new Uuid(time, clockSeqAndNode) - - def uuidFrom(uuid: String): Uuid = new Uuid(uuid) - - def simpleName(obj: AnyRef): String = { - val n = obj.getClass.getName - val i = n.lastIndexOf('.') - n.substring(i + 1) - } - - def simpleName(clazz: Class[_]): String = { - val n = clazz.getName - val i = n.lastIndexOf('.') - n.substring(i + 1) - } } diff --git a/akka-actor/src/main/scala/akka/config/ConfigurationException.scala b/akka-actor/src/main/scala/akka/config/ConfigurationException.scala deleted file mode 100644 index ba0a3a2234..0000000000 --- a/akka-actor/src/main/scala/akka/config/ConfigurationException.scala +++ /dev/null @@ -1,15 +0,0 @@ -/** - * Copyright (C) 2009-2012 Typesafe Inc. - */ - -package akka.config - -import akka.AkkaException - -class ConfigurationException(message: String, cause: Throwable = null) extends AkkaException(message, cause) { - def this(msg: String) = this(msg, null); -} - -class ModuleNotAvailableException(message: String, cause: Throwable = null) extends AkkaException(message, cause) { - def this(msg: String) = this(msg, null); -} diff --git a/akka-actor/src/main/scala/akka/dispatch/AbstractDispatcher.scala b/akka-actor/src/main/scala/akka/dispatch/AbstractDispatcher.scala index db5c71167b..682e6ba4bf 100644 --- a/akka-actor/src/main/scala/akka/dispatch/AbstractDispatcher.scala +++ b/akka-actor/src/main/scala/akka/dispatch/AbstractDispatcher.scala @@ -33,7 +33,10 @@ final case class Envelope(val message: Any, val sender: ActorRef)(system: ActorS } } -object SystemMessage { +/** + * INTERNAL API + */ +private[akka] object SystemMessage { @tailrec final def size(list: SystemMessage, acc: Int = 0): Int = { if (list eq null) acc else size(list.next, acc + 1) @@ -59,33 +62,57 @@ object SystemMessage { * system messages is handled in a single thread only and not ever passed around, * hence no further synchronization is needed. * + * INTERNAL API + * * ➡➡➡ NEVER SEND THE SAME SYSTEM MESSAGE OBJECT TO TWO ACTORS ⬅⬅⬅ */ -sealed trait SystemMessage extends PossiblyHarmful { +private[akka] sealed trait SystemMessage extends PossiblyHarmful { @transient var next: SystemMessage = _ } -case class Create() extends SystemMessage // send to self from Dispatcher.register -case class Recreate(cause: Throwable) extends SystemMessage // sent to self from ActorCell.restart -case class Suspend() extends SystemMessage // sent to self from ActorCell.suspend -case class Resume() extends SystemMessage // sent to self from ActorCell.resume -case class Terminate() extends SystemMessage // sent to self from ActorCell.stop -case class Supervise(child: ActorRef) extends SystemMessage // sent to supervisor ActorRef from ActorCell.start -case class ChildTerminated(child: ActorRef) extends SystemMessage // sent to supervisor from ActorCell.doTerminate -case class Link(subject: ActorRef) extends SystemMessage // sent to self from ActorCell.watch -case class Unlink(subject: ActorRef) extends SystemMessage // sent to self from ActorCell.unwatch + +/** + * INTERNAL API + */ +private[akka] case class Create() extends SystemMessage // send to self from Dispatcher.register +/** + * INTERNAL API + */ +private[akka] case class Recreate(cause: Throwable) extends SystemMessage // sent to self from ActorCell.restart +/** + * INTERNAL API + */ +private[akka] case class Suspend() extends SystemMessage // sent to self from ActorCell.suspend +/** + * INTERNAL API + */ +private[akka] case class Resume() extends SystemMessage // sent to self from ActorCell.resume +/** + * INTERNAL API + */ +private[akka] case class Terminate() extends SystemMessage // sent to self from ActorCell.stop +/** + * INTERNAL API + */ +private[akka] case class Supervise(child: ActorRef) extends SystemMessage // sent to supervisor ActorRef from ActorCell.start +/** + * INTERNAL API + */ +private[akka] case class ChildTerminated(child: ActorRef) extends SystemMessage // sent to supervisor from ActorCell.doTerminate +/** + * INTERNAL API + */ +private[akka] case class Link(subject: ActorRef) extends SystemMessage // sent to self from ActorCell.watch +/** + * INTERNAL API + */ +private[akka] case class Unlink(subject: ActorRef) extends SystemMessage // sent to self from ActorCell.unwatch final case class TaskInvocation(eventStream: EventStream, runnable: Runnable, cleanup: () ⇒ Unit) extends Runnable { - def run() { - try { - runnable.run() - } catch { - case NonFatal(e) ⇒ - eventStream.publish(Error(e, "TaskInvocation", this.getClass, e.getMessage)) - } finally { - cleanup() - } - } + def run(): Unit = + try runnable.run() catch { + case NonFatal(e) ⇒ eventStream.publish(Error(e, "TaskInvocation", this.getClass, e.getMessage)) + } finally cleanup() } /** @@ -170,10 +197,16 @@ trait ExecutionContext { def reportFailure(t: Throwable): Unit } +/** + * INTERNAL API + */ private[akka] trait LoadMetrics { self: Executor ⇒ def atFullThrottle(): Boolean } +/** + * INTERNAL API + */ private[akka] object MessageDispatcher { val UNSCHEDULED = 0 //WARNING DO NOT CHANGE THE VALUE OF THIS: It relies on the faster init of 0 in AbstractMessageDispatcher val SCHEDULED = 1 @@ -181,7 +214,7 @@ private[akka] object MessageDispatcher { // dispatcher debugging helper using println (see below) // since this is a compile-time constant, scalac will elide code behind if (MessageDispatcher.debug) (RK checked with 2.9.1) - final val debug = false + final val debug = false // Deliberately without type ascription to make it a compile-time constant lazy val actors = new Index[MessageDispatcher, ActorRef](16, _ compareTo _) def printActors: Unit = if (debug) { for { @@ -228,7 +261,7 @@ abstract class MessageDispatcher(val prerequisites: DispatcherPrerequisites) ext /** * Creates and returns a mailbox for the given actor. */ - protected[akka] def createMailbox(actor: ActorCell): Mailbox + protected[akka] def createMailbox(actor: ActorCell): Mailbox //FIXME should this really be private[akka]? /** * Identifier of this dispatcher, corresponds to the full key @@ -255,7 +288,7 @@ abstract class MessageDispatcher(val prerequisites: DispatcherPrerequisites) ext ifSensibleToDoSoThenScheduleShutdown() } - final def execute(runnable: Runnable) { + final def execute(runnable: Runnable): Unit = { val invocation = TaskInvocation(eventStream, runnable, taskCleanup) addInhabitants(+1) try { @@ -300,6 +333,8 @@ abstract class MessageDispatcher(val prerequisites: DispatcherPrerequisites) ext /** * If you override it, you must call it. But only ever once. See "attach" for only invocation. + * + * INTERNAL API */ protected[akka] def register(actor: ActorCell) { if (debug) actors.put(this, actor.self) @@ -308,6 +343,8 @@ abstract class MessageDispatcher(val prerequisites: DispatcherPrerequisites) ext /** * If you override it, you must call it. But only ever once. See "detach" for the only invocation + * + * INTERNAL API */ protected[akka] def unregister(actor: ActorCell) { if (debug) actors.remove(this, actor.self) @@ -340,6 +377,8 @@ abstract class MessageDispatcher(val prerequisites: DispatcherPrerequisites) ext * When the dispatcher no longer has any actors registered, how long will it wait until it shuts itself down, * defaulting to your akka configs "akka.actor.default-dispatcher.shutdown-timeout" or default specified in * reference.conf + * + * INTERNAL API */ protected[akka] def shutdownTimeout: Duration @@ -362,36 +401,59 @@ abstract class MessageDispatcher(val prerequisites: DispatcherPrerequisites) ext } /** - * Will be called when the dispatcher is to queue an invocation for execution + * Will be called when the dispatcher is to queue an invocation for execution + * + * INTERNAL API */ protected[akka] def systemDispatch(receiver: ActorCell, invocation: SystemMessage) /** - * Will be called when the dispatcher is to queue an invocation for execution + * Will be called when the dispatcher is to queue an invocation for execution + * + * INTERNAL API */ protected[akka] def dispatch(receiver: ActorCell, invocation: Envelope) /** * Suggest to register the provided mailbox for execution + * + * INTERNAL API */ protected[akka] def registerForExecution(mbox: Mailbox, hasMessageHint: Boolean, hasSystemMessageHint: Boolean): Boolean // TODO check whether this should not actually be a property of the mailbox + /** + * INTERNAL API + */ protected[akka] def throughput: Int + + /** + * INTERNAL API + */ protected[akka] def throughputDeadlineTime: Duration - @inline - protected[akka] final val isThroughputDeadlineTimeDefined = throughputDeadlineTime.toMillis > 0 + /** + * INTERNAL API + */ + @inline protected[akka] final val isThroughputDeadlineTimeDefined = throughputDeadlineTime.toMillis > 0 + /** + * INTERNAL API + */ protected[akka] def executeTask(invocation: TaskInvocation) /** * Called one time every time an actor is detached from this dispatcher and this dispatcher has no actors left attached * Must be idempotent + * + * INTERNAL API */ protected[akka] def shutdown(): Unit } +/** + * An ExecutorServiceConfigurator is a class that given some prerequisites and a configuration can create instances of ExecutorService + */ abstract class ExecutorServiceConfigurator(config: Config, prerequisites: DispatcherPrerequisites) extends ExecutorServiceFactoryProvider /** diff --git a/akka-actor/src/main/scala/akka/dispatch/BalancingDispatcher.scala b/akka-actor/src/main/scala/akka/dispatch/BalancingDispatcher.scala index e95f54b88b..43e8944105 100644 --- a/akka-actor/src/main/scala/akka/dispatch/BalancingDispatcher.scala +++ b/akka-actor/src/main/scala/akka/dispatch/BalancingDispatcher.scala @@ -35,12 +35,35 @@ class BalancingDispatcher( attemptTeamWork: Boolean) extends Dispatcher(_prerequisites, _id, throughput, throughputDeadlineTime, mailboxType, _executorServiceFactoryProvider, _shutdownTimeout) { - val team = new ConcurrentSkipListSet[ActorCell]( + /** + * INTERNAL USE ONLY + */ + private[akka] val team = new ConcurrentSkipListSet[ActorCell]( Helpers.identityHashComparator(new Comparator[ActorCell] { def compare(l: ActorCell, r: ActorCell) = l.self.path compareTo r.self.path })) - val messageQueue: MessageQueue = mailboxType.create(None) + /** + * INTERNAL USE ONLY + */ + private[akka] val messageQueue: MessageQueue = mailboxType.create(None) + + private class SharingMailbox(_actor: ActorCell, _messageQueue: MessageQueue) extends Mailbox(_actor, _messageQueue) with DefaultSystemMessageQueue { + override def cleanUp(): Unit = { + //Don't call the original implementation of this since it scraps all messages, and we don't want to do that + if (hasSystemMessages) { + val dlq = actor.systemImpl.deadLetterMailbox + var message = systemDrain() + while (message ne null) { + // message must be “virgin” before being able to systemEnqueue again + val next = message.next + message.next = null + dlq.systemEnqueue(actor.self, message) + message = next + } + } + } + } protected[akka] override def createMailbox(actor: ActorCell): Mailbox = new SharingMailbox(actor, messageQueue) @@ -64,7 +87,7 @@ class BalancingDispatcher( @tailrec def scheduleOne(i: Iterator[ActorCell] = team.iterator): Unit = if (messageQueue.hasMessages && i.hasNext - && (executorService.get().executor match { + && (executorService.executor match { case lm: LoadMetrics ⇒ lm.atFullThrottle == false case other ⇒ true }) @@ -74,22 +97,3 @@ class BalancingDispatcher( scheduleOne() } } - -class SharingMailbox(_actor: ActorCell, _messageQueue: MessageQueue) - extends Mailbox(_actor, _messageQueue) with DefaultSystemMessageQueue { - - override def cleanUp(): Unit = { - //Don't call the original implementation of this since it scraps all messages, and we don't want to do that - if (hasSystemMessages) { - val dlq = actor.systemImpl.deadLetterMailbox - var message = systemDrain() - while (message ne null) { - // message must be “virgin” before being able to systemEnqueue again - val next = message.next - message.next = null - dlq.systemEnqueue(actor.self, message) - message = next - } - } - } -} diff --git a/akka-actor/src/main/scala/akka/dispatch/Dispatcher.scala b/akka-actor/src/main/scala/akka/dispatch/Dispatcher.scala index fbffd08d7e..3c17ab8db4 100644 --- a/akka-actor/src/main/scala/akka/dispatch/Dispatcher.scala +++ b/akka-actor/src/main/scala/akka/dispatch/Dispatcher.scala @@ -9,6 +9,7 @@ import java.util.concurrent.atomic.AtomicReference import akka.actor.ActorCell import akka.util.Duration import java.util.concurrent._ +import akka.event.Logging /** * The event-based ``Dispatcher`` binds a set of Actors to a thread pool backed up by a @@ -32,31 +33,44 @@ class Dispatcher( val shutdownTimeout: Duration) extends MessageDispatcher(_prerequisites) { - protected val executorServiceFactory: ExecutorServiceFactory = - executorServiceFactoryProvider.createExecutorServiceFactory(id, prerequisites.threadFactory) + private class LazyExecutorServiceDelegate(factory: ExecutorServiceFactory) extends ExecutorServiceDelegate { + lazy val executor: ExecutorService = factory.createExecutorService + def copy(): LazyExecutorServiceDelegate = new LazyExecutorServiceDelegate(factory) + } - protected val executorService = new AtomicReference[ExecutorServiceDelegate]( - new ExecutorServiceDelegate { lazy val executor = executorServiceFactory.createExecutorService }) + @volatile private var executorServiceDelegate: LazyExecutorServiceDelegate = + new LazyExecutorServiceDelegate(executorServiceFactoryProvider.createExecutorServiceFactory(id, prerequisites.threadFactory)) - protected[akka] def dispatch(receiver: ActorCell, invocation: Envelope) = { + protected final def executorService: ExecutorServiceDelegate = executorServiceDelegate + + /** + * INTERNAL USE ONLY + */ + protected[akka] def dispatch(receiver: ActorCell, invocation: Envelope): Unit = { val mbox = receiver.mailbox mbox.enqueue(receiver.self, invocation) registerForExecution(mbox, true, false) } - protected[akka] def systemDispatch(receiver: ActorCell, invocation: SystemMessage) = { + /** + * INTERNAL USE ONLY + */ + protected[akka] def systemDispatch(receiver: ActorCell, invocation: SystemMessage): Unit = { val mbox = receiver.mailbox mbox.systemEnqueue(receiver.self, invocation) registerForExecution(mbox, false, true) } + /** + * INTERNAL USE ONLY + */ protected[akka] def executeTask(invocation: TaskInvocation) { try { - executorService.get() execute invocation + executorService execute invocation } catch { case e: RejectedExecutionException ⇒ try { - executorService.get() execute invocation + executorService execute invocation } catch { case e2: RejectedExecutionException ⇒ prerequisites.eventStream.publish(Error(e, getClass.getName, getClass, "executeTask was rejected twice!")) @@ -65,26 +79,39 @@ class Dispatcher( } } + /** + * INTERNAL USE ONLY + */ protected[akka] def createMailbox(actor: ActorCell): Mailbox = new Mailbox(actor, mailboxType.create(Some(actor))) with DefaultSystemMessageQueue - protected[akka] def shutdown: Unit = - Option(executorService.getAndSet(new ExecutorServiceDelegate { - lazy val executor = executorServiceFactory.createExecutorService - })) foreach { _.shutdown() } + /** + * INTERNAL USE ONLY + */ + protected[akka] def shutdown: Unit = { + val newDelegate = executorServiceDelegate.copy() // Doesn't matter which one we copy + val es = synchronized { // FIXME getAndSet using ARFU or Unsafe + val service = executorServiceDelegate + executorServiceDelegate = newDelegate // just a quick getAndSet + service + } + es.shutdown() + } /** * Returns if it was registered + * + * INTERNAL USE ONLY */ protected[akka] override def registerForExecution(mbox: Mailbox, hasMessageHint: Boolean, hasSystemMessageHint: Boolean): Boolean = { if (mbox.canBeScheduledForExecution(hasMessageHint, hasSystemMessageHint)) { //This needs to be here to ensure thread safety and no races if (mbox.setAsScheduled()) { try { - executorService.get() execute mbox + executorService execute mbox true } catch { case e: RejectedExecutionException ⇒ try { - executorService.get() execute mbox + executorService execute mbox true } catch { //Retry once case e: RejectedExecutionException ⇒ @@ -97,7 +124,7 @@ class Dispatcher( } else false } - override val toString = getClass.getSimpleName + "[" + id + "]" + override val toString: String = Logging.simpleName(this) + "[" + id + "]" } object PriorityGenerator { diff --git a/akka-actor/src/main/scala/akka/dispatch/Dispatchers.scala b/akka-actor/src/main/scala/akka/dispatch/Dispatchers.scala index 93d44e007d..e148129bce 100644 --- a/akka-actor/src/main/scala/akka/dispatch/Dispatchers.scala +++ b/akka-actor/src/main/scala/akka/dispatch/Dispatchers.scala @@ -5,17 +5,15 @@ package akka.dispatch import java.util.concurrent.{ ConcurrentHashMap, TimeUnit, ThreadFactory } - -import scala.collection.JavaConverters.mapAsJavaMapConverter - import com.typesafe.config.{ ConfigFactory, Config } - -import Dispatchers.DefaultDispatcherId import akka.actor.{ Scheduler, DynamicAccess, ActorSystem } import akka.event.Logging.Warning import akka.event.EventStream import akka.util.Duration +/** + * DispatcherPrerequisites represents useful contextual pieces when constructing a MessageDispatcher + */ trait DispatcherPrerequisites { def threadFactory: ThreadFactory def eventStream: EventStream @@ -25,7 +23,10 @@ trait DispatcherPrerequisites { def settings: ActorSystem.Settings } -case class DefaultDispatcherPrerequisites( +/** + * INTERNAL USE ONLY + */ +private[akka] case class DefaultDispatcherPrerequisites( val threadFactory: ThreadFactory, val eventStream: EventStream, val deadLetterMailbox: Mailbox, @@ -96,6 +97,7 @@ class Dispatchers(val settings: ActorSystem.Settings, val prerequisites: Dispatc } } + //INTERNAL API private def config(id: String): Config = { import scala.collection.JavaConverters._ def simpleName = id.substring(id.lastIndexOf('.') + 1) @@ -105,12 +107,13 @@ class Dispatchers(val settings: ActorSystem.Settings, val prerequisites: Dispatc .withFallback(defaultDispatcherConfig) } + //INTERNAL API private def idConfig(id: String): Config = { import scala.collection.JavaConverters._ ConfigFactory.parseMap(Map("id" -> id).asJava) } - /* + /** * Creates a dispatcher from a Config. Internal test purpose only. * * ex: from(config.getConfig(id)) @@ -119,18 +122,22 @@ class Dispatchers(val settings: ActorSystem.Settings, val prerequisites: Dispatc * * Throws: IllegalArgumentException if the value of "type" is not valid * IllegalArgumentException if it cannot create the MessageDispatcherConfigurator + * + * INTERNAL USE ONLY */ - private[akka] def from(cfg: Config): MessageDispatcher = { - configuratorFrom(cfg).dispatcher() - } + private[akka] def from(cfg: Config): MessageDispatcher = configuratorFrom(cfg).dispatcher() - /* + private[akka] def isBalancingDispatcher(id: String): Boolean = settings.config.hasPath(id) && config(id).getString("type") == "BalancingDispatcher" + + /** * Creates a MessageDispatcherConfigurator from a Config. * * The Config must also contain a `id` property, which is the identifier of the dispatcher. * * Throws: IllegalArgumentException if the value of "type" is not valid * IllegalArgumentException if it cannot create the MessageDispatcherConfigurator + * + * INTERNAL USE ONLY */ private def configuratorFrom(cfg: Config): MessageDispatcherConfigurator = { if (!cfg.hasPath("id")) throw new IllegalArgumentException("Missing dispatcher 'id' property in config: " + cfg.root.render) @@ -208,7 +215,7 @@ class BalancingDispatcherConfigurator(config: Config, prerequisites: DispatcherP class PinnedDispatcherConfigurator(config: Config, prerequisites: DispatcherPrerequisites) extends MessageDispatcherConfigurator(config, prerequisites) { - val threadPoolConfig: ThreadPoolConfig = configureExecutor() match { + private val threadPoolConfig: ThreadPoolConfig = configureExecutor() match { case e: ThreadPoolExecutorConfigurator ⇒ e.threadPoolConfig case other ⇒ prerequisites.eventStream.publish( diff --git a/akka-actor/src/main/scala/akka/dispatch/Mailbox.scala b/akka-actor/src/main/scala/akka/dispatch/Mailbox.scala index 2e3a98e8d9..35b1e35012 100644 --- a/akka-actor/src/main/scala/akka/dispatch/Mailbox.scala +++ b/akka-actor/src/main/scala/akka/dispatch/Mailbox.scala @@ -14,9 +14,15 @@ import akka.actor.ActorContext import com.typesafe.config.Config import akka.actor.ActorSystem +/** + * This exception normally is thrown when a bounded mailbox is over capacity + */ class MessageQueueAppendFailedException(message: String, cause: Throwable = null) extends AkkaException(message, cause) -object Mailbox { +/** + * INTERNAL API + */ +private[akka] object Mailbox { type Status = Int @@ -25,21 +31,22 @@ object Mailbox { */ // primary status: only first three - final val Open = 0 // _status is not initialized in AbstractMailbox, so default must be zero! - final val Suspended = 1 - final val Closed = 2 + final val Open = 0 // _status is not initialized in AbstractMailbox, so default must be zero! Deliberately without type ascription to make it a compile-time constant + final val Suspended = 1 // Deliberately without type ascription to make it a compile-time constant + final val Closed = 2 // Deliberately without type ascription to make it a compile-time constant // secondary status: Scheduled bit may be added to Open/Suspended - final val Scheduled = 4 + final val Scheduled = 4 // Deliberately without type ascription to make it a compile-time constant // mailbox debugging helper using println (see below) // since this is a compile-time constant, scalac will elide code behind if (Mailbox.debug) (RK checked with 2.9.1) - final val debug = false + final val debug = false // Deliberately without type ascription to make it a compile-time constant } /** * Mailbox and InternalMailbox is separated in two classes because ActorCell is needed for implementation, * but can't be exposed to user defined mailbox subclasses. * + * INTERNAL API */ private[akka] abstract class Mailbox(val actor: ActorCell, val messageQueue: MessageQueue) extends SystemMessageQueue with Runnable { @@ -244,6 +251,11 @@ private[akka] abstract class Mailbox(val actor: ActorCell, val messageQueue: Mes } } +/** + * A MessageQueue is one of the core components in forming an Akka Mailbox. + * The MessageQueue is where the normal messages that are sent to Actors will be enqueued (and subsequently dequeued) + * It needs to atleast support N producers and 1 consumer thread-safely. + */ trait MessageQueue { /** * Try to enqueue the message to this queue, or throw an exception. @@ -277,7 +289,7 @@ trait MessageQueue { } /** - * Internal mailbox implementation detail. + * INTERNAL USE ONLY */ private[akka] trait SystemMessageQueue { /** @@ -294,7 +306,7 @@ private[akka] trait SystemMessageQueue { } /** - * Internal mailbox implementation detail. + * INTERNAL USE ONLY */ private[akka] trait DefaultSystemMessageQueue { self: Mailbox ⇒ @@ -325,6 +337,9 @@ private[akka] trait DefaultSystemMessageQueue { self: Mailbox ⇒ def hasSystemMessages: Boolean = systemQueueGet ne null } +/** + * A QueueBasedMessageQueue is a MessageQueue backed by a java.util.Queue + */ trait QueueBasedMessageQueue extends MessageQueue { def queue: Queue[Envelope] def numberOfMessages = queue.size @@ -340,11 +355,19 @@ trait QueueBasedMessageQueue extends MessageQueue { } } +/** + * UnboundedMessageQueueSemantics adds unbounded semantics to a QueueBasedMessageQueue, + * i.e. a non-blocking enqueue and dequeue. + */ trait UnboundedMessageQueueSemantics extends QueueBasedMessageQueue { def enqueue(receiver: ActorRef, handle: Envelope): Unit = queue add handle def dequeue(): Envelope = queue.poll() } +/** + * BoundedMessageQueueSemantics adds bounded semantics to a QueueBasedMessageQueue, + * i.e. blocking enqueue with timeout + */ trait BoundedMessageQueueSemantics extends QueueBasedMessageQueue { def pushTimeOut: Duration override def queue: BlockingQueue[Envelope] @@ -360,17 +383,28 @@ trait BoundedMessageQueueSemantics extends QueueBasedMessageQueue { def dequeue(): Envelope = queue.poll() } +/** + * DequeBasedMessageQueue refines QueueBasedMessageQueue to be backed by a java.util.Deque + */ trait DequeBasedMessageQueue extends QueueBasedMessageQueue { def queue: Deque[Envelope] def enqueueFirst(receiver: ActorRef, handle: Envelope): Unit } +/** + * UnboundedDequeBasedMessageQueueSemantics adds unbounded semantics to a DequeBasedMessageQueue, + * i.e. a non-blocking enqueue and dequeue. + */ trait UnboundedDequeBasedMessageQueueSemantics extends DequeBasedMessageQueue { def enqueue(receiver: ActorRef, handle: Envelope): Unit = queue add handle def enqueueFirst(receiver: ActorRef, handle: Envelope): Unit = queue addFirst handle def dequeue(): Envelope = queue.poll() } +/** + * BoundedMessageQueueSemantics adds bounded semantics to a DequeBasedMessageQueue, + * i.e. blocking enqueue with timeout + */ trait BoundedDequeBasedMessageQueueSemantics extends DequeBasedMessageQueue { def pushTimeOut: Duration override def queue: BlockingDeque[Envelope] @@ -393,14 +427,14 @@ trait BoundedDequeBasedMessageQueueSemantics extends DequeBasedMessageQueue { } /** - * Mailbox configuration. + * MailboxType is a factory to create MessageQueues for an optionally provided ActorContext */ trait MailboxType { def create(owner: Option[ActorContext]): MessageQueue } /** - * It's a case class for Java (new UnboundedMailbox) + * UnboundedMailbox is the default unbounded MailboxType used by Akka Actors. */ case class UnboundedMailbox() extends MailboxType { @@ -412,6 +446,9 @@ case class UnboundedMailbox() extends MailboxType { } } +/** + * BoundedMailbox is the default bounded MailboxType used by Akka Actors. + */ case class BoundedMailbox( final val capacity: Int, final val pushTimeOut: Duration) extends MailboxType { def this(settings: ActorSystem.Settings, config: Config) = this(config.getInt("mailbox-capacity"), @@ -428,17 +465,20 @@ case class BoundedMailbox( final val capacity: Int, final val pushTimeOut: Durat } /** - * Extend me to provide the comparator + * UnboundedPriorityMailbox is an unbounded mailbox that allows for priorization of its contents. + * Extend this class and provide the Comparator in the constructor. */ -class UnboundedPriorityMailbox( final val cmp: Comparator[Envelope]) extends MailboxType { +class UnboundedPriorityMailbox( final val cmp: Comparator[Envelope], final val initialCapacity: Int) extends MailboxType { + def this(cmp: Comparator[Envelope]) = this(cmp, 11) final override def create(owner: Option[ActorContext]): MessageQueue = - new PriorityBlockingQueue[Envelope](11, cmp) with QueueBasedMessageQueue with UnboundedMessageQueueSemantics { + new PriorityBlockingQueue[Envelope](initialCapacity, cmp) with QueueBasedMessageQueue with UnboundedMessageQueueSemantics { final def queue: Queue[Envelope] = this } } /** - * Extend me to provide the comparator + * BoundedPriorityMailbox is a bounded mailbox that allows for priorization of its contents. + * Extend this class and provide the Comparator in the constructor. */ class BoundedPriorityMailbox( final val cmp: Comparator[Envelope], final val capacity: Int, final val pushTimeOut: Duration) extends MailboxType { @@ -452,6 +492,9 @@ class BoundedPriorityMailbox( final val cmp: Comparator[Envelope], final val cap } } +/** + * UnboundedDequeBasedMailbox is an unbounded MailboxType, backed by a Deque. + */ case class UnboundedDequeBasedMailbox() extends MailboxType { def this(settings: ActorSystem.Settings, config: Config) = this() @@ -462,6 +505,9 @@ case class UnboundedDequeBasedMailbox() extends MailboxType { } } +/** + * BoundedDequeBasedMailbox is an bounded MailboxType, backed by a Deque. + */ case class BoundedDequeBasedMailbox( final val capacity: Int, final val pushTimeOut: Duration) extends MailboxType { def this(settings: ActorSystem.Settings, config: Config) = this(config.getInt("mailbox-capacity"), diff --git a/akka-actor/src/main/scala/akka/event/DeathWatch.scala b/akka-actor/src/main/scala/akka/event/DeathWatch.scala index 7469f6609f..8bf6935619 100644 --- a/akka-actor/src/main/scala/akka/event/DeathWatch.scala +++ b/akka-actor/src/main/scala/akka/event/DeathWatch.scala @@ -12,7 +12,7 @@ import akka.actor._ * A failed subscribe should also only mean that the Classifier (ActorRef) that is listened to is already shut down * See LocalDeathWatch for semantics */ -trait DeathWatch extends ActorEventBus with ActorClassifier { +abstract class DeathWatch extends ActorEventBus with ActorClassifier { type Event = Terminated protected final def classify(event: Event): Classifier = event.actor diff --git a/akka-actor/src/main/scala/akka/event/EventBus.scala b/akka-actor/src/main/scala/akka/event/EventBus.scala index 2dd22b3b54..6a5cc67cc4 100644 --- a/akka-actor/src/main/scala/akka/event/EventBus.scala +++ b/akka-actor/src/main/scala/akka/event/EventBus.scala @@ -182,10 +182,9 @@ trait SubchannelClassification { this: EventBus ⇒ */ trait ScanningClassification { self: EventBus ⇒ protected final val subscribers = new ConcurrentSkipListSet[(Classifier, Subscriber)](new Comparator[(Classifier, Subscriber)] { - def compare(a: (Classifier, Subscriber), b: (Classifier, Subscriber)): Int = { - val cM = compareClassifiers(a._1, b._1) - if (cM != 0) cM - else compareSubscribers(a._2, b._2) + def compare(a: (Classifier, Subscriber), b: (Classifier, Subscriber)): Int = compareClassifiers(a._1, b._1) match { + case 0 ⇒ compareSubscribers(a._2, b._2) + case other ⇒ other } }) @@ -238,7 +237,7 @@ trait ActorClassification { this: ActorEventBus with ActorClassifier ⇒ import java.util.concurrent.ConcurrentHashMap import scala.annotation.tailrec private val empty = TreeSet.empty[ActorRef] - protected val mappings = new ConcurrentHashMap[ActorRef, TreeSet[ActorRef]](mapSize) + private val mappings = new ConcurrentHashMap[ActorRef, TreeSet[ActorRef]](mapSize) @tailrec protected final def associate(monitored: ActorRef, monitor: ActorRef): Boolean = { @@ -320,9 +319,9 @@ trait ActorClassification { this: ActorEventBus with ActorClassifier ⇒ */ protected def mapSize: Int - def publish(event: Event): Unit = { - val receivers = mappings.get(classify(event)) - if (receivers ne null) receivers foreach { _ ! event } + def publish(event: Event): Unit = mappings.get(classify(event)) match { + case null ⇒ () + case some ⇒ some foreach { _ ! event } } def subscribe(subscriber: Subscriber, to: Classifier): Boolean = associate(to, subscriber) diff --git a/akka-actor/src/main/scala/akka/event/EventStream.scala b/akka-actor/src/main/scala/akka/event/EventStream.scala index 27f0c71515..172cf052ca 100644 --- a/akka-actor/src/main/scala/akka/event/EventStream.scala +++ b/akka-actor/src/main/scala/akka/event/EventStream.scala @@ -3,7 +3,8 @@ */ package akka.event -import akka.actor.{ ActorRef, ActorSystem, simpleName } +import akka.actor.{ ActorRef, ActorSystem } +import akka.event.Logging.simpleName import akka.util.Subclassification object EventStream { diff --git a/akka-actor/src/main/scala/akka/event/Logging.scala b/akka-actor/src/main/scala/akka/event/Logging.scala index bf4fc7996d..6e6f92ad0d 100644 --- a/akka-actor/src/main/scala/akka/event/Logging.scala +++ b/akka-actor/src/main/scala/akka/event/Logging.scala @@ -4,12 +4,10 @@ package akka.event import akka.actor._ -import akka.AkkaException +import akka.{ ConfigurationException, AkkaException } import akka.actor.ActorSystem.Settings -import akka.config.ConfigurationException -import akka.util.ReentrantGuard +import akka.util.{ Timeout, ReentrantGuard } import akka.util.duration._ -import akka.util.Timeout import java.util.concurrent.atomic.AtomicInteger import scala.util.control.NoStackTrace import java.util.concurrent.TimeoutException @@ -31,7 +29,7 @@ trait LoggingBus extends ActorEventBus { import Logging._ - private val guard = new ReentrantGuard + private val guard = new ReentrantGuard //Switch to ReentrantReadWrite private var loggers = Seq.empty[ActorRef] private var _logLevel: LogLevel = _ @@ -99,7 +97,7 @@ trait LoggingBus extends ActorEventBus { val myloggers = for { loggerName ← defaultLoggers - if loggerName != StandardOutLoggerName + if loggerName != StandardOutLogger.getClass.getName } yield { try { system.dynamicAccess.getClassFor[Actor](loggerName) match { @@ -131,7 +129,7 @@ trait LoggingBus extends ActorEventBus { case _: InvalidActorNameException ⇒ // ignore if it is already running } publish(Debug(logName, this.getClass, "Default Loggers started")) - if (!(defaultLoggers contains StandardOutLoggerName)) { + if (!(defaultLoggers contains StandardOutLogger.getClass.getName)) { unsubscribe(StandardOutLogger) } } catch { @@ -165,6 +163,9 @@ trait LoggingBus extends ActorEventBus { publish(Debug(simpleName(this), this.getClass, "all default loggers stopped")) } + /** + * INTERNAL API + */ private def addLogger(system: ActorSystemImpl, clazz: Class[_ <: Actor], level: LogLevel, logName: String): ActorRef = { val name = "log" + Extension(system).id() + "-" + simpleName(clazz) val actor = system.systemActorOf(Props(clazz), name) @@ -275,9 +276,9 @@ object LogSource { // this one unfortunately does not work as implicit, because existential types have some weird behavior val fromClass: LogSource[Class[_]] = new LogSource[Class[_]] { - def genString(c: Class[_]) = simpleName(c) - override def genString(c: Class[_], system: ActorSystem) = simpleName(c) + "(" + system + ")" - override def getClazz(c: Class[_]) = c + def genString(c: Class[_]): String = Logging.simpleName(c) + override def genString(c: Class[_], system: ActorSystem): String = genString(c) + "(" + system + ")" + override def getClazz(c: Class[_]): Class[_] = c } implicit def fromAnyClass[T]: LogSource[Class[T]] = fromClass.asInstanceOf[LogSource[Class[T]]] @@ -310,7 +311,7 @@ object LogSource { case a: Actor ⇒ apply(a) case a: ActorRef ⇒ apply(a) case s: String ⇒ apply(s) - case x ⇒ (simpleName(x), x.getClass) + case x ⇒ (Logging.simpleName(x), x.getClass) } /** @@ -324,7 +325,7 @@ object LogSource { case a: Actor ⇒ apply(a) case a: ActorRef ⇒ apply(a) case s: String ⇒ apply(s) - case x ⇒ (simpleName(x) + "(" + system + ")", x.getClass) + case x ⇒ (Logging.simpleName(x) + "(" + system + ")", x.getClass) } } @@ -363,9 +364,33 @@ object LogSource { */ object Logging { - object Extension extends ExtensionKey[LogExt] + /** + * Returns a 'safe' getSimpleName for the provided object's Class + * @param obj + * @return the simple name of the given object's Class + */ + def simpleName(obj: AnyRef): String = simpleName(obj.getClass) - class LogExt(system: ExtendedActorSystem) extends Extension { + /** + * Returns a 'safe' getSimpleName for the provided Class + * @param obj + * @return the simple name of the given Class + */ + def simpleName(clazz: Class[_]): String = { + val n = clazz.getName + val i = n.lastIndexOf('.') + n.substring(i + 1) + } + + /** + * INTERNAL API + */ + private[akka] object Extension extends ExtensionKey[LogExt] + + /** + * INTERNAL API + */ + private[akka] class LogExt(system: ExtendedActorSystem) extends Extension { private val loggerId = new AtomicInteger def id() = loggerId.incrementAndGet() } @@ -425,12 +450,6 @@ object Logging { // these type ascriptions/casts are necessary to avoid CCEs during construction while retaining correct type val AllLogLevels = Seq(ErrorLevel: AnyRef, WarningLevel, InfoLevel, DebugLevel).asInstanceOf[Seq[LogLevel]] - val errorFormat = "[ERROR] [%s] [%s] [%s] %s\n%s".intern - val errorFormatWithoutCause = "[ERROR] [%s] [%s] [%s] %s".intern - val warningFormat = "[WARN] [%s] [%s] [%s] %s".intern - val infoFormat = "[INFO] [%s] [%s] [%s] %s".intern - val debugFormat = "[DEBUG] [%s] [%s] [%s] %s".intern - /** * Obtain LoggingAdapter for the given actor system and source object. This * will use the system’s event stream and include the system’s address in the @@ -511,7 +530,7 @@ object Logging { * Artificial exception injected into Error events if no Throwable is * supplied; used for getting a stack dump of error locations. */ - class EventHandlerException extends AkkaException + class EventHandlerException extends AkkaException("") /** * Exception that wraps a LogEvent. @@ -618,27 +637,34 @@ object Logging { // weird return type due to binary compatibility def loggerInitialized(): LoggerInitialized.type = LoggerInitialized + /** + * LoggerInitializationException is thrown to indicate that there was a problem initializing a logger + * @param msg + */ class LoggerInitializationException(msg: String) extends AkkaException(msg) trait StdOutLogger { import java.text.SimpleDateFormat import java.util.Date - val dateFormat = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss.S") + private val dateFormat = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss.SSS") + private val errorFormat = "[ERROR] [%s] [%s] [%s] %s\n%s".intern + private val errorFormatWithoutCause = "[ERROR] [%s] [%s] [%s] %s".intern + private val warningFormat = "[WARN] [%s] [%s] [%s] %s".intern + private val infoFormat = "[INFO] [%s] [%s] [%s] %s".intern + private val debugFormat = "[DEBUG] [%s] [%s] [%s] %s".intern - def timestamp = dateFormat.format(new Date) + def timestamp(): String = synchronized { dateFormat.format(new Date) } // SDF isn't threadsafe - def print(event: Any) { - event match { - case e: Error ⇒ error(e) - case e: Warning ⇒ warning(e) - case e: Info ⇒ info(e) - case e: Debug ⇒ debug(e) - case e ⇒ warning(Warning(simpleName(this), this.getClass, "received unexpected event of class " + e.getClass + ": " + e)) - } + def print(event: Any): Unit = event match { + case e: Error ⇒ error(e) + case e: Warning ⇒ warning(e) + case e: Info ⇒ info(e) + case e: Debug ⇒ debug(e) + case e ⇒ warning(Warning(simpleName(this), this.getClass, "received unexpected event of class " + e.getClass + ": " + e)) } - def error(event: Error) = { + def error(event: Error): Unit = { val f = if (event.cause == Error.NoCause) errorFormatWithoutCause else errorFormat println(f.format( timestamp, @@ -648,21 +674,21 @@ object Logging { stackTraceFor(event.cause))) } - def warning(event: Warning) = + def warning(event: Warning): Unit = println(warningFormat.format( timestamp, event.thread.getName, event.logSource, event.message)) - def info(event: Info) = + def info(event: Info): Unit = println(infoFormat.format( timestamp, event.thread.getName, event.logSource, event.message)) - def debug(event: Debug) = + def debug(event: Debug): Unit = println(debugFormat.format( timestamp, event.thread.getName, @@ -683,8 +709,8 @@ object Logging { override val toString = "StandardOutLogger" override def !(message: Any)(implicit sender: ActorRef = null): Unit = print(message) } + val StandardOutLogger = new StandardOutLogger - val StandardOutLoggerName = StandardOutLogger.getClass.getName /** * Actor wrapper around the standard output logger. If @@ -702,7 +728,7 @@ object Logging { * Returns the StackTrace for the given Throwable as a String */ def stackTraceFor(e: Throwable): String = e match { - case null | Error.NoCause ⇒ "" + case null | Error.NoCause | _: NoStackTrace ⇒ "" case other ⇒ val sw = new java.io.StringWriter val pw = new java.io.PrintWriter(sw) @@ -746,51 +772,51 @@ trait LoggingAdapter { * These actually implement the passing on of the messages to be logged. * Will not be called if is...Enabled returned false. */ - protected def notifyError(message: String) - protected def notifyError(cause: Throwable, message: String) - protected def notifyWarning(message: String) - protected def notifyInfo(message: String) - protected def notifyDebug(message: String) + protected def notifyError(message: String): Unit + protected def notifyError(cause: Throwable, message: String): Unit + protected def notifyWarning(message: String): Unit + protected def notifyInfo(message: String): Unit + protected def notifyDebug(message: String): Unit /* * The rest is just the widening of the API for the user's convenience. */ - def error(cause: Throwable, message: String) { if (isErrorEnabled) notifyError(cause, message) } - def error(cause: Throwable, template: String, arg1: Any) { if (isErrorEnabled) notifyError(cause, format1(template, arg1)) } - def error(cause: Throwable, template: String, arg1: Any, arg2: Any) { if (isErrorEnabled) notifyError(cause, format(template, arg1, arg2)) } - def error(cause: Throwable, template: String, arg1: Any, arg2: Any, arg3: Any) { if (isErrorEnabled) notifyError(cause, format(template, arg1, arg2, arg3)) } - def error(cause: Throwable, template: String, arg1: Any, arg2: Any, arg3: Any, arg4: Any) { if (isErrorEnabled) notifyError(cause, format(template, arg1, arg2, arg3, arg4)) } + def error(cause: Throwable, message: String): Unit = { if (isErrorEnabled) notifyError(cause, message) } + def error(cause: Throwable, template: String, arg1: Any): Unit = { if (isErrorEnabled) notifyError(cause, format1(template, arg1)) } + def error(cause: Throwable, template: String, arg1: Any, arg2: Any): Unit = { if (isErrorEnabled) notifyError(cause, format(template, arg1, arg2)) } + def error(cause: Throwable, template: String, arg1: Any, arg2: Any, arg3: Any): Unit = { if (isErrorEnabled) notifyError(cause, format(template, arg1, arg2, arg3)) } + def error(cause: Throwable, template: String, arg1: Any, arg2: Any, arg3: Any, arg4: Any): Unit = { if (isErrorEnabled) notifyError(cause, format(template, arg1, arg2, arg3, arg4)) } - def error(message: String) { if (isErrorEnabled) notifyError(message) } - def error(template: String, arg1: Any) { if (isErrorEnabled) notifyError(format1(template, arg1)) } - def error(template: String, arg1: Any, arg2: Any) { if (isErrorEnabled) notifyError(format(template, arg1, arg2)) } - def error(template: String, arg1: Any, arg2: Any, arg3: Any) { if (isErrorEnabled) notifyError(format(template, arg1, arg2, arg3)) } - def error(template: String, arg1: Any, arg2: Any, arg3: Any, arg4: Any) { if (isErrorEnabled) notifyError(format(template, arg1, arg2, arg3, arg4)) } + def error(message: String): Unit = { if (isErrorEnabled) notifyError(message) } + def error(template: String, arg1: Any): Unit = { if (isErrorEnabled) notifyError(format1(template, arg1)) } + def error(template: String, arg1: Any, arg2: Any): Unit = { if (isErrorEnabled) notifyError(format(template, arg1, arg2)) } + def error(template: String, arg1: Any, arg2: Any, arg3: Any): Unit = { if (isErrorEnabled) notifyError(format(template, arg1, arg2, arg3)) } + def error(template: String, arg1: Any, arg2: Any, arg3: Any, arg4: Any): Unit = { if (isErrorEnabled) notifyError(format(template, arg1, arg2, arg3, arg4)) } - def warning(message: String) { if (isWarningEnabled) notifyWarning(message) } - def warning(template: String, arg1: Any) { if (isWarningEnabled) notifyWarning(format1(template, arg1)) } - def warning(template: String, arg1: Any, arg2: Any) { if (isWarningEnabled) notifyWarning(format(template, arg1, arg2)) } - def warning(template: String, arg1: Any, arg2: Any, arg3: Any) { if (isWarningEnabled) notifyWarning(format(template, arg1, arg2, arg3)) } - def warning(template: String, arg1: Any, arg2: Any, arg3: Any, arg4: Any) { if (isWarningEnabled) notifyWarning(format(template, arg1, arg2, arg3, arg4)) } + def warning(message: String): Unit = { if (isWarningEnabled) notifyWarning(message) } + def warning(template: String, arg1: Any): Unit = { if (isWarningEnabled) notifyWarning(format1(template, arg1)) } + def warning(template: String, arg1: Any, arg2: Any): Unit = { if (isWarningEnabled) notifyWarning(format(template, arg1, arg2)) } + def warning(template: String, arg1: Any, arg2: Any, arg3: Any): Unit = { if (isWarningEnabled) notifyWarning(format(template, arg1, arg2, arg3)) } + def warning(template: String, arg1: Any, arg2: Any, arg3: Any, arg4: Any): Unit = { if (isWarningEnabled) notifyWarning(format(template, arg1, arg2, arg3, arg4)) } def info(message: String) { if (isInfoEnabled) notifyInfo(message) } - def info(template: String, arg1: Any) { if (isInfoEnabled) notifyInfo(format1(template, arg1)) } - def info(template: String, arg1: Any, arg2: Any) { if (isInfoEnabled) notifyInfo(format(template, arg1, arg2)) } - def info(template: String, arg1: Any, arg2: Any, arg3: Any) { if (isInfoEnabled) notifyInfo(format(template, arg1, arg2, arg3)) } - def info(template: String, arg1: Any, arg2: Any, arg3: Any, arg4: Any) { if (isInfoEnabled) notifyInfo(format(template, arg1, arg2, arg3, arg4)) } + def info(template: String, arg1: Any): Unit = { if (isInfoEnabled) notifyInfo(format1(template, arg1)) } + def info(template: String, arg1: Any, arg2: Any): Unit = { if (isInfoEnabled) notifyInfo(format(template, arg1, arg2)) } + def info(template: String, arg1: Any, arg2: Any, arg3: Any): Unit = { if (isInfoEnabled) notifyInfo(format(template, arg1, arg2, arg3)) } + def info(template: String, arg1: Any, arg2: Any, arg3: Any, arg4: Any): Unit = { if (isInfoEnabled) notifyInfo(format(template, arg1, arg2, arg3, arg4)) } def debug(message: String) { if (isDebugEnabled) notifyDebug(message) } - def debug(template: String, arg1: Any) { if (isDebugEnabled) notifyDebug(format1(template, arg1)) } - def debug(template: String, arg1: Any, arg2: Any) { if (isDebugEnabled) notifyDebug(format(template, arg1, arg2)) } - def debug(template: String, arg1: Any, arg2: Any, arg3: Any) { if (isDebugEnabled) notifyDebug(format(template, arg1, arg2, arg3)) } - def debug(template: String, arg1: Any, arg2: Any, arg3: Any, arg4: Any) { if (isDebugEnabled) notifyDebug(format(template, arg1, arg2, arg3, arg4)) } + def debug(template: String, arg1: Any): Unit = { if (isDebugEnabled) notifyDebug(format1(template, arg1)) } + def debug(template: String, arg1: Any, arg2: Any): Unit = { if (isDebugEnabled) notifyDebug(format(template, arg1, arg2)) } + def debug(template: String, arg1: Any, arg2: Any, arg3: Any): Unit = { if (isDebugEnabled) notifyDebug(format(template, arg1, arg2, arg3)) } + def debug(template: String, arg1: Any, arg2: Any, arg3: Any, arg4: Any): Unit = { if (isDebugEnabled) notifyDebug(format(template, arg1, arg2, arg3, arg4)) } def log(level: Logging.LogLevel, message: String) { if (isEnabled(level)) notifyLog(level, message) } - def log(level: Logging.LogLevel, template: String, arg1: Any) { if (isEnabled(level)) notifyLog(level, format1(template, arg1)) } - def log(level: Logging.LogLevel, template: String, arg1: Any, arg2: Any) { if (isEnabled(level)) notifyLog(level, format(template, arg1, arg2)) } - def log(level: Logging.LogLevel, template: String, arg1: Any, arg2: Any, arg3: Any) { if (isEnabled(level)) notifyLog(level, format(template, arg1, arg2, arg3)) } - def log(level: Logging.LogLevel, template: String, arg1: Any, arg2: Any, arg3: Any, arg4: Any) { if (isEnabled(level)) notifyLog(level, format(template, arg1, arg2, arg3, arg4)) } + def log(level: Logging.LogLevel, template: String, arg1: Any): Unit = { if (isEnabled(level)) notifyLog(level, format1(template, arg1)) } + def log(level: Logging.LogLevel, template: String, arg1: Any, arg2: Any): Unit = { if (isEnabled(level)) notifyLog(level, format(template, arg1, arg2)) } + def log(level: Logging.LogLevel, template: String, arg1: Any, arg2: Any, arg3: Any): Unit = { if (isEnabled(level)) notifyLog(level, format(template, arg1, arg2, arg3)) } + def log(level: Logging.LogLevel, template: String, arg1: Any, arg2: Any, arg3: Any, arg4: Any): Unit = { if (isEnabled(level)) notifyLog(level, format(template, arg1, arg2, arg3, arg4)) } final def isEnabled(level: Logging.LogLevel): Boolean = level match { case Logging.ErrorLevel ⇒ isErrorEnabled @@ -806,14 +832,14 @@ trait LoggingAdapter { case Logging.DebugLevel ⇒ if (isDebugEnabled) notifyDebug(message) } - private def format1(t: String, arg: Any) = arg match { + private def format1(t: String, arg: Any): String = arg match { case a: Array[_] if !a.getClass.getComponentType.isPrimitive ⇒ format(t, a: _*) case a: Array[_] ⇒ format(t, (a map (_.asInstanceOf[AnyRef]): _*)) case x ⇒ format(t, x) } - def format(t: String, arg: Any*) = { - val sb = new StringBuilder + def format(t: String, arg: Any*): String = { + val sb = new StringBuilder //FIXME add some decent size hint here var p = 0 var rest = t while (p < arg.length) { @@ -823,17 +849,15 @@ trait LoggingAdapter { rest = "" p = arg.length } else { - sb.append(rest.substring(0, index)) - sb.append(arg(p)) + sb.append(rest.substring(0, index)).append(arg(p)) rest = rest.substring(index + 2) p += 1 } } - sb.append(rest) - sb.toString + sb.append(rest).toString } } - +//FIXME DOCUMENT class BusLogging(val bus: LoggingBus, val logSource: String, val logClass: Class[_]) extends LoggingAdapter { import Logging._ @@ -843,14 +867,9 @@ class BusLogging(val bus: LoggingBus, val logSource: String, val logClass: Class def isInfoEnabled = bus.logLevel >= InfoLevel def isDebugEnabled = bus.logLevel >= DebugLevel - protected def notifyError(message: String) { bus.publish(Error(logSource, logClass, message)) } - - protected def notifyError(cause: Throwable, message: String) { bus.publish(Error(cause, logSource, logClass, message)) } - - protected def notifyWarning(message: String) { bus.publish(Warning(logSource, logClass, message)) } - - protected def notifyInfo(message: String) { bus.publish(Info(logSource, logClass, message)) } - - protected def notifyDebug(message: String) { bus.publish(Debug(logSource, logClass, message)) } - + protected def notifyError(message: String): Unit = bus.publish(Error(logSource, logClass, message)) + protected def notifyError(cause: Throwable, message: String): Unit = bus.publish(Error(cause, logSource, logClass, message)) + protected def notifyWarning(message: String): Unit = bus.publish(Warning(logSource, logClass, message)) + protected def notifyInfo(message: String): Unit = bus.publish(Info(logSource, logClass, message)) + protected def notifyDebug(message: String): Unit = bus.publish(Debug(logSource, logClass, message)) } diff --git a/akka-actor/src/main/scala/akka/event/LoggingReceive.scala b/akka-actor/src/main/scala/akka/event/LoggingReceive.scala index 452b2b6b19..337815eed1 100644 --- a/akka-actor/src/main/scala/akka/event/LoggingReceive.scala +++ b/akka-actor/src/main/scala/akka/event/LoggingReceive.scala @@ -26,9 +26,7 @@ object LoggingReceive { */ def apply(r: Receive)(implicit context: ActorContext): Receive = r match { case _: LoggingReceive ⇒ r - case _ ⇒ - if (context.system.settings.AddLoggingReceive) new LoggingReceive(None, r) - else r + case _ ⇒ if (context.system.settings.AddLoggingReceive) new LoggingReceive(None, r) else r } } @@ -37,7 +35,7 @@ object LoggingReceive { * @param source the log source, if not defined the actor of the context will be used */ class LoggingReceive(source: Option[AnyRef], r: Receive)(implicit context: ActorContext) extends Receive { - def isDefinedAt(o: Any) = { + def isDefinedAt(o: Any): Boolean = { val handled = r.isDefinedAt(o) val (str, clazz) = LogSource.fromAnyRef(source getOrElse context.asInstanceOf[ActorCell].actor) context.system.eventStream.publish(Debug(str, clazz, "received " + (if (handled) "handled" else "unhandled") + " message " + o)) diff --git a/akka-actor/src/main/scala/akka/experimental.scala b/akka-actor/src/main/scala/akka/experimental.scala deleted file mode 100644 index aef3cb5c85..0000000000 --- a/akka-actor/src/main/scala/akka/experimental.scala +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (C) 2009-2012 Typesafe Inc. - */ - -package akka - -import annotation.target._ - -/** - * This annotation marks a feature which is not yet considered stable and may - * change or be removed in a future release. - * - * @since 1.2 - */ -@getter -@setter -@beanGetter -@beanSetter -final class experimental(since: String) extends annotation.StaticAnnotation diff --git a/akka-actor/src/main/scala/akka/japi/JavaAPI.scala b/akka-actor/src/main/scala/akka/japi/JavaAPI.scala index 47ce667759..5bd38ad52a 100644 --- a/akka-actor/src/main/scala/akka/japi/JavaAPI.scala +++ b/akka-actor/src/main/scala/akka/japi/JavaAPI.scala @@ -24,28 +24,14 @@ trait Function2[T1, T2, R] { * A Procedure is like a Function, but it doesn't produce a return value. */ trait Procedure[T] { - def apply(param: T) -} - -/** - * A Procedure is like a Function, but it doesn't produce a return value. - */ -trait Procedure2[T1, T2] { - def apply(param: T1, param2: T2) -} - -/** - * An executable piece of code that takes no parameters and doesn't return any value. - */ -trait SideEffect { - def apply() + def apply(param: T): Unit } /** * An executable piece of code that takes no parameters and doesn't return any value. */ trait Effect { - def apply() + def apply(): Unit } /** @@ -67,9 +53,9 @@ sealed abstract class Option[A] extends java.lang.Iterable[A] { def get: A def isEmpty: Boolean - def isDefined = !isEmpty + def isDefined: Boolean = !isEmpty def asScala: scala.Option[A] - def iterator = if (isEmpty) Iterator.empty else Iterator.single(get) + def iterator: java.util.Iterator[A] = if (isEmpty) Iterator.empty else Iterator.single(get) } object Option { @@ -102,18 +88,18 @@ object Option { * A. */ final case class Some[A](v: A) extends Option[A] { - def get = v - def isEmpty = false - def asScala = scala.Some(v) + def get: A = v + def isEmpty: Boolean = false + def asScala: scala.Some[A] = scala.Some(v) } /** * This case object represents non-existent values. */ private case object None extends Option[Nothing] { - def get = throw new NoSuchElementException("None.get") - def isEmpty = true - def asScala = scala.None + def get: Nothing = throw new NoSuchElementException("None.get") + def isEmpty: Boolean = true + def asScala: scala.None.type = scala.None } implicit def java2ScalaOption[A](o: Option[A]): scala.Option[A] = o.asScala diff --git a/akka-actor/src/main/scala/akka/pattern/AskSupport.scala b/akka-actor/src/main/scala/akka/pattern/AskSupport.scala index ef4217039d..a20baaf533 100644 --- a/akka-actor/src/main/scala/akka/pattern/AskSupport.scala +++ b/akka-actor/src/main/scala/akka/pattern/AskSupport.scala @@ -46,7 +46,7 @@ trait AskSupport { * Sends a message asynchronously and returns a [[akka.dispatch.Future]] * holding the eventual reply message; this means that the target actor * needs to send the result to the `sender` reference provided. The Future - * will be completed with an [[akka.actor.AskTimeoutException]] after the + * will be completed with an [[akka.pattern.AskTimeoutException]] after the * given timeout has expired; this is independent from any timeout applied * while awaiting a result for this future (i.e. in * `Await.result(..., timeout)`). @@ -96,7 +96,7 @@ trait AskSupport { * Sends a message asynchronously and returns a [[akka.dispatch.Future]] * holding the eventual reply message; this means that the target actor * needs to send the result to the `sender` reference provided. The Future - * will be completed with an [[akka.actor.AskTimeoutException]] after the + * will be completed with an [[akka.pattern.AskTimeoutException]] after the * given timeout has expired; this is independent from any timeout applied * while awaiting a result for this future (i.e. in * `Await.result(..., timeout)`). @@ -126,7 +126,7 @@ trait AskSupport { * Sends a message asynchronously and returns a [[akka.dispatch.Future]] * holding the eventual reply message; this means that the target actor * needs to send the result to the `sender` reference provided. The Future - * will be completed with an [[akka.actor.AskTimeoutException]] after the + * will be completed with an [[akka.pattern.AskTimeoutException]] after the * given timeout has expired; this is independent from any timeout applied * while awaiting a result for this future (i.e. in * `Await.result(..., timeout)`). @@ -157,6 +157,8 @@ trait AskSupport { /** * Akka private optimized representation of the temporary actor spawned to * receive the reply to an "ask" operation. + * + * INTERNAL API */ private[akka] final class PromiseActorRef private (val provider: ActorRefProvider, val result: Promise[Any]) extends MinimalActorRef { @@ -182,14 +184,12 @@ private[akka] final class PromiseActorRef private (val provider: ActorRefProvide private def state: AnyRef = Unsafe.instance.getObjectVolatile(this, stateOffset) @inline - private def updateState(oldState: AnyRef, newState: AnyRef): Boolean = - Unsafe.instance.compareAndSwapObject(this, stateOffset, oldState, newState) + private def updateState(oldState: AnyRef, newState: AnyRef): Boolean = Unsafe.instance.compareAndSwapObject(this, stateOffset, oldState, newState) @inline - private def setState(newState: AnyRef): Unit = - Unsafe.instance.putObjectVolatile(this, stateOffset, newState) + private def setState(newState: AnyRef): Unit = Unsafe.instance.putObjectVolatile(this, stateOffset, newState) - override def getParent = provider.tempContainer + override def getParent: InternalActorRef = provider.tempContainer /** * Contract of this method: @@ -234,7 +234,7 @@ private[akka] final class PromiseActorRef private (val provider: ActorRefProvide case _ ⇒ } - override def isTerminated = state match { + override def isTerminated: Boolean = state match { case Stopped | _: StoppedWithPath ⇒ true case _ ⇒ false } @@ -263,6 +263,9 @@ private[akka] final class PromiseActorRef private (val provider: ActorRefProvide } } +/** + * INTERNAL API + */ private[akka] object PromiseActorRef { private case object Registering private case object Stopped @@ -272,9 +275,7 @@ private[akka] object PromiseActorRef { val result = Promise[Any]()(provider.dispatcher) val a = new PromiseActorRef(provider, result) val f = provider.scheduler.scheduleOnce(timeout.duration) { result.tryComplete(Left(new AskTimeoutException("Timed out"))) } - result onComplete { _ ⇒ - try a.stop() finally f.cancel() - } + result onComplete { _ ⇒ try a.stop() finally f.cancel() } a } } \ No newline at end of file diff --git a/akka-actor/src/main/scala/akka/pattern/GracefulStopSupport.scala b/akka-actor/src/main/scala/akka/pattern/GracefulStopSupport.scala index d6fbd31c1e..adcbe53f0b 100644 --- a/akka-actor/src/main/scala/akka/pattern/GracefulStopSupport.scala +++ b/akka-actor/src/main/scala/akka/pattern/GracefulStopSupport.scala @@ -4,9 +4,9 @@ package akka.pattern -import akka.actor.{ ActorRef, Actor, ActorSystem, Props, PoisonPill, Terminated, ReceiveTimeout, ActorTimeoutException } import akka.dispatch.{ Promise, Future } -import akka.util.Duration +import akka.actor._ +import akka.util.{ Timeout, Duration } trait GracefulStopSupport { /** @@ -14,34 +14,39 @@ trait GracefulStopSupport { * existing messages of the target actor has been processed and the actor has been * terminated. * - * Useful when you need to wait for termination or compose ordered termination of several actors. + * Useful when you need to wait for termination or compose ordered termination of several actors, + * which should only be done outside of the ActorSystem as blocking inside Actors is discouraged. + * + * IMPORTANT NOTICE: the actor being terminated and its supervisor + * being informed of the availability of the deceased actor’s name are two + * distinct operations, which do not obey any reliable ordering. Especially + * the following will NOT work: + * + * {{{ + * def receive = { + * case msg => + * Await.result(gracefulStop(someChild, timeout), timeout) + * context.actorOf(Props(...), "someChild") // assuming that that was someChild’s name, this will NOT work + * } + * }}} * * If the target actor isn't terminated within the timeout the [[akka.dispatch.Future]] - * is completed with failure [[akka.actor.ActorTimeoutException]]. + * is completed with failure [[akka.pattern.AskTimeoutException]]. */ def gracefulStop(target: ActorRef, timeout: Duration)(implicit system: ActorSystem): Future[Boolean] = { if (target.isTerminated) { Promise.successful(true) - } else { - val result = Promise[Boolean]() - system.actorOf(Props(new Actor { - // Terminated will be received when target has been stopped - context watch target + } else system match { + case e: ExtendedActorSystem ⇒ + val ref = PromiseActorRef(e.provider, Timeout(timeout)) + e.deathWatch.subscribe(ref, target) + ref.result onComplete { + case Right(Terminated(`target`)) ⇒ () // Ignore + case _ ⇒ e.deathWatch.unsubscribe(ref, target) + } // Just making sure we're not leaking here target ! PoisonPill - // ReceiveTimeout will be received if nothing else is received within the timeout - context setReceiveTimeout timeout - - def receive = { - case Terminated(a) if a == target ⇒ - result success true - context stop self - case ReceiveTimeout ⇒ - result failure new ActorTimeoutException( - "Failed to stop [%s] within [%s]".format(target.path, context.receiveTimeout)) - context stop self - } - })) - result + ref.result map { case Terminated(`target`) ⇒ true } + case s ⇒ throw new IllegalArgumentException("Unknown ActorSystem implementation: '" + s + "'") } } } \ No newline at end of file diff --git a/akka-actor/src/main/scala/akka/pattern/Patterns.scala b/akka-actor/src/main/scala/akka/pattern/Patterns.scala index b58e9a8fc1..853b46e318 100644 --- a/akka-actor/src/main/scala/akka/pattern/Patterns.scala +++ b/akka-actor/src/main/scala/akka/pattern/Patterns.scala @@ -18,7 +18,7 @@ object Patterns { * Sends a message asynchronously and returns a [[akka.dispatch.Future]] * holding the eventual reply message; this means that the target actor * needs to send the result to the `sender` reference provided. The Future - * will be completed with an [[akka.actor.AskTimeoutException]] after the + * will be completed with an [[akka.pattern.AskTimeoutException]] after the * given timeout has expired; this is independent from any timeout applied * while awaiting a result for this future (i.e. in * `Await.result(..., timeout)`). @@ -49,7 +49,7 @@ object Patterns { * Sends a message asynchronously and returns a [[akka.dispatch.Future]] * holding the eventual reply message; this means that the target actor * needs to send the result to the `sender` reference provided. The Future - * will be completed with an [[akka.actor.AskTimeoutException]] after the + * will be completed with an [[akka.pattern.AskTimeoutException]] after the * given timeout has expired; this is independent from any timeout applied * while awaiting a result for this future (i.e. in * `Await.result(..., timeout)`). @@ -100,7 +100,7 @@ object Patterns { * Useful when you need to wait for termination or compose ordered termination of several actors. * * If the target actor isn't terminated within the timeout the [[akka.dispatch.Future]] - * is completed with failure [[akka.actor.ActorTimeoutException]]. + * is completed with failure [[akka.pattern.AskTimeoutException]]. */ def gracefulStop(target: ActorRef, timeout: Duration, system: ActorSystem): Future[java.lang.Boolean] = scalaGracefulStop(target, timeout)(system).asInstanceOf[Future[java.lang.Boolean]] diff --git a/akka-actor/src/main/scala/akka/routing/ConnectionManager.scala b/akka-actor/src/main/scala/akka/routing/ConnectionManager.scala index 3136a2342d..9029c1f78b 100644 --- a/akka-actor/src/main/scala/akka/routing/ConnectionManager.scala +++ b/akka-actor/src/main/scala/akka/routing/ConnectionManager.scala @@ -10,10 +10,8 @@ import akka.actor._ * An Iterable that also contains a version. */ trait VersionedIterable[A] { - val version: Long - + def version: Long def iterable: Iterable[A] - def apply(): Iterable[A] = iterable } @@ -42,7 +40,7 @@ trait ConnectionManager { /** * Shuts the connection manager down, which stops all managed actors */ - def shutdown() + def shutdown(): Unit /** * Returns a VersionedIterator containing all connected ActorRefs at some moment in time. Since there is @@ -59,5 +57,5 @@ trait ConnectionManager { * * @param ref the dead */ - def remove(deadRef: ActorRef) + def remove(deadRef: ActorRef): Unit } diff --git a/akka-actor/src/main/scala/akka/routing/ConsistentHash.scala b/akka-actor/src/main/scala/akka/routing/ConsistentHash.scala index 130db2be3e..afa321d07d 100644 --- a/akka-actor/src/main/scala/akka/routing/ConsistentHash.scala +++ b/akka-actor/src/main/scala/akka/routing/ConsistentHash.scala @@ -23,7 +23,7 @@ class ConsistentHash[T](nodes: Seq[T], replicas: Int) { nodes.foreach(this += _) - def +=(node: T) { + def +=(node: T): Unit = { cluster += node (1 to replicas) foreach { replica ⇒ val key = hashFor((node + ":" + replica).getBytes("UTF-8")) @@ -32,7 +32,7 @@ class ConsistentHash[T](nodes: Seq[T], replicas: Int) { } } - def -=(node: T) { + def -=(node: T): Unit = { cluster -= node (1 to replicas) foreach { replica ⇒ val key = hashFor((node + ":" + replica).getBytes("UTF-8")) @@ -96,7 +96,7 @@ class MurmurHash[@specialized(Int, Long, Float, Double) T](seed: Int) extends (T private var hashvalue = h /** Begin a new hash using the same seed. */ - def reset() { + def reset(): Unit = { h = startHash(seed) c = hiddenMagicA k = hiddenMagicB @@ -104,7 +104,7 @@ class MurmurHash[@specialized(Int, Long, Float, Double) T](seed: Int) extends (T } /** Incorporate the hash value of one item. */ - def apply(t: T) { + def apply(t: T): Unit = { h = extendHash(h, t.##, c, k) c = nextMagicA(c) k = nextMagicB(k) @@ -112,7 +112,7 @@ class MurmurHash[@specialized(Int, Long, Float, Double) T](seed: Int) extends (T } /** Incorporate a known hash value. */ - def append(i: Int) { + def append(i: Int): Unit = { h = extendHash(h, i, c, k) c = nextMagicA(c) k = nextMagicB(k) @@ -120,14 +120,15 @@ class MurmurHash[@specialized(Int, Long, Float, Double) T](seed: Int) extends (T } /** Retrieve the hash value */ - def hash = { + def hash: Int = { if (!hashed) { hashvalue = finalizeHash(h) hashed = true } hashvalue } - override def hashCode = hash + + override def hashCode: Int = hash } /** @@ -143,35 +144,35 @@ class MurmurHash[@specialized(Int, Long, Float, Double) T](seed: Int) extends (T object MurmurHash { // Magic values used for MurmurHash's 32 bit hash. // Don't change these without consulting a hashing expert! - final private val visibleMagic = 0x971e137b - final private val hiddenMagicA = 0x95543787 - final private val hiddenMagicB = 0x2ad7eb25 - final private val visibleMixer = 0x52dce729 - final private val hiddenMixerA = 0x7b7d159c - final private val hiddenMixerB = 0x6bce6396 - final private val finalMixer1 = 0x85ebca6b - final private val finalMixer2 = 0xc2b2ae35 + final private val visibleMagic: Int = 0x971e137b + final private val hiddenMagicA: Int = 0x95543787 + final private val hiddenMagicB: Int = 0x2ad7eb25 + final private val visibleMixer: Int = 0x52dce729 + final private val hiddenMixerA: Int = 0x7b7d159c + final private val hiddenMixerB: Int = 0x6bce6396 + final private val finalMixer1: Int = 0x85ebca6b + final private val finalMixer2: Int = 0xc2b2ae35 // Arbitrary values used for hashing certain classes - final private val seedString = 0xf7ca7fd2 - final private val seedArray = 0x3c074a61 + final private val seedString: Int = 0xf7ca7fd2 + final private val seedArray: Int = 0x3c074a61 /** The first 23 magic integers from the first stream are stored here */ - val storedMagicA = + val storedMagicA: Array[Int] = Iterator.iterate(hiddenMagicA)(nextMagicA).take(23).toArray /** The first 23 magic integers from the second stream are stored here */ - val storedMagicB = + val storedMagicB: Array[Int] = Iterator.iterate(hiddenMagicB)(nextMagicB).take(23).toArray /** Begin a new hash with a seed value. */ - def startHash(seed: Int) = seed ^ visibleMagic + def startHash(seed: Int): Int = seed ^ visibleMagic /** The initial magic integers in the first stream. */ - def startMagicA = hiddenMagicA + def startMagicA: Int = hiddenMagicA /** The initial magic integer in the second stream. */ - def startMagicB = hiddenMagicB + def startMagicB: Int = hiddenMagicB /** * Incorporates a new value into an existing hash. @@ -182,18 +183,17 @@ object MurmurHash { * @param magicB a magic integer from a different stream * @return the updated hash value */ - def extendHash(hash: Int, value: Int, magicA: Int, magicB: Int) = { + def extendHash(hash: Int, value: Int, magicA: Int, magicB: Int): Int = (hash ^ rotl(value * magicA, 11) * magicB) * 3 + visibleMixer - } /** Given a magic integer from the first stream, compute the next */ - def nextMagicA(magicA: Int) = magicA * 5 + hiddenMixerA + def nextMagicA(magicA: Int): Int = magicA * 5 + hiddenMixerA /** Given a magic integer from the second stream, compute the next */ - def nextMagicB(magicB: Int) = magicB * 5 + hiddenMixerB + def nextMagicB(magicB: Int): Int = magicB * 5 + hiddenMixerB /** Once all hashes have been incorporated, this performs a final mixing */ - def finalizeHash(hash: Int) = { + def finalizeHash(hash: Int): Int = { var i = (hash ^ (hash >>> 16)) i *= finalMixer1 i ^= (i >>> 13) @@ -203,7 +203,7 @@ object MurmurHash { } /** Compute a high-quality hash of an array */ - def arrayHash[@specialized T](a: Array[T]) = { + def arrayHash[@specialized T](a: Array[T]): Int = { var h = startHash(a.length * seedArray) var c = hiddenMagicA var k = hiddenMagicB @@ -218,7 +218,7 @@ object MurmurHash { } /** Compute a high-quality hash of a string */ - def stringHash(s: String) = { + def stringHash(s: String): Int = { var h = startHash(s.length * seedString) var c = hiddenMagicA var k = hiddenMagicB @@ -239,7 +239,7 @@ object MurmurHash { * where the order of appearance of elements does not matter. * This is useful for hashing sets, for example. */ - def symmetricHash[T](xs: TraversableOnce[T], seed: Int) = { + def symmetricHash[T](xs: TraversableOnce[T], seed: Int): Int = { var a, b, n = 0 var c = 1 xs.foreach(i ⇒ { diff --git a/akka-actor/src/main/scala/akka/routing/Listeners.scala b/akka-actor/src/main/scala/akka/routing/Listeners.scala index 39fbf6355d..5ac02e2945 100644 --- a/akka-actor/src/main/scala/akka/routing/Listeners.scala +++ b/akka-actor/src/main/scala/akka/routing/Listeners.scala @@ -5,8 +5,7 @@ package akka.routing import akka.actor.{ Actor, ActorRef } -import java.util.concurrent.ConcurrentSkipListSet -import scala.collection.JavaConversions._ +import java.util.{ Set, TreeSet } sealed trait ListenerMessage case class Listen(listener: ActorRef) extends ListenerMessage @@ -25,13 +24,29 @@ case class WithListeners(f: (ActorRef) ⇒ Unit) extends ListenerMessage * Send WithListeners(fun) to traverse the current listeners. */ trait Listeners { self: Actor ⇒ - protected val listeners = new ConcurrentSkipListSet[ActorRef] + protected val listeners: Set[ActorRef] = new TreeSet[ActorRef] + /** + * Chain this into the receive function. + * + * {{ def receive = listenerManagement orElse … }} + */ protected def listenerManagement: Actor.Receive = { - case Listen(l) ⇒ listeners add l - case Deafen(l) ⇒ listeners remove l - case WithListeners(f) ⇒ listeners foreach f + case Listen(l) ⇒ listeners add l + case Deafen(l) ⇒ listeners remove l + case WithListeners(f) ⇒ + val i = listeners.iterator + while (i.hasNext) f(i.next) } - protected def gossip(msg: Any) = listeners foreach (_ ! msg) + /** + * Sends the supplied message to all current listeners using the provided sender as sender. + * + * @param msg + * @param sender + */ + protected def gossip(msg: Any)(implicit sender: ActorRef = null): Unit = { + val i = listeners.iterator + while (i.hasNext) i.next ! msg + } } diff --git a/akka-actor/src/main/scala/akka/routing/Routing.scala b/akka-actor/src/main/scala/akka/routing/Routing.scala index fdf14a5b96..94eed672f4 100644 --- a/akka-actor/src/main/scala/akka/routing/Routing.scala +++ b/akka-actor/src/main/scala/akka/routing/Routing.scala @@ -6,14 +6,12 @@ package akka.routing import akka.actor._ import akka.util.Duration import akka.util.duration._ -import akka.config.ConfigurationException +import akka.ConfigurationException import akka.pattern.pipe -import akka.pattern.AskSupport import com.typesafe.config.Config import scala.collection.JavaConversions.iterableAsScalaIterable import java.util.concurrent.atomic.{ AtomicLong, AtomicBoolean } import java.util.concurrent.TimeUnit -import java.util.concurrent.locks.ReentrantLock import akka.jsr166y.ThreadLocalRandom import akka.util.Unsafe import akka.dispatch.Dispatchers @@ -31,11 +29,17 @@ private[akka] class RoutedActorRef(_system: ActorSystemImpl, _props: Props, _sup _supervisor, _path) { + // verify that a BalancingDispatcher is not used with a Router + if (_system.dispatchers.isBalancingDispatcher(_props.dispatcher) && _props.routerConfig != NoRouter) + throw new ConfigurationException( + "Configuration for actor [" + _path.toString + + "] is invalid - you can not use a 'BalancingDispatcher' together with any type of 'Router'") + /* * CAUTION: RoutedActorRef is PROBLEMATIC * ====================================== - * - * We are constructing/assembling the children outside of the scope of the + * + * We are constructing/assembling the children outside of the scope of the * Router actor, inserting them in its childrenRef list, which is not at all * synchronized. This is done exactly once at start-up, all other accesses * are done from the Router actor. This means that the only thing which is @@ -49,12 +53,11 @@ private[akka] class RoutedActorRef(_system: ActorSystemImpl, _props: Props, _sup ref: InternalActorRef, props: Props, supervisor: InternalActorRef, - receiveTimeout: Option[Duration]): ActorCell = - { - val cell = super.newActorCell(system, ref, props, supervisor, receiveTimeout) - Unsafe.instance.monitorEnter(cell) - cell - } + receiveTimeout: Option[Duration]): ActorCell = { + val cell = super.newActorCell(system, ref, props, supervisor, receiveTimeout) + Unsafe.instance.monitorEnter(cell) + cell + } private[akka] val routerConfig = _props.routerConfig private[akka] val routeeProps = _props.copy(routerConfig = NoRouter) @@ -171,7 +174,7 @@ trait RouterConfig { def createRoute(routeeProps: Props, routeeProvider: RouteeProvider): Route - def createRouteeProvider(context: ActorContext) = new RouteeProvider(context, resizer) + def createRouteeProvider(context: ActorContext): RouteeProvider = new RouteeProvider(context, resizer) def createActor(): Router = new Router { override def supervisorStrategy: SupervisorStrategy = RouterConfig.this.supervisorStrategy @@ -192,7 +195,8 @@ trait RouterConfig { */ def withFallback(other: RouterConfig): RouterConfig = this - protected def toAll(sender: ActorRef, routees: Iterable[ActorRef]): Iterable[Destination] = routees.map(Destination(sender, _)) + protected def toAll(sender: ActorRef, routees: Iterable[ActorRef]): Iterable[Destination] = + routees.map(Destination(sender, _)) /** * Routers with dynamically resizable number of routees return the [[akka.routing.Resizer]] @@ -215,9 +219,7 @@ class RouteeProvider(val context: ActorContext, val resizer: Option[Resizer]) { * Not thread safe, but intended to be called from protected points, such as * `RouterConfig.createRoute` and `Resizer.resize`. */ - def registerRoutees(routees: IndexedSeq[ActorRef]): Unit = { - routedRef.addRoutees(routees) - } + def registerRoutees(routees: IndexedSeq[ActorRef]): Unit = routedRef.addRoutees(routees) /** * Adds the routees to the router. @@ -237,9 +239,7 @@ class RouteeProvider(val context: ActorContext, val resizer: Option[Resizer]) { * Not thread safe, but intended to be called from protected points, such as * `Resizer.resize`. */ - def unregisterRoutees(routees: IndexedSeq[ActorRef]): Unit = { - routedRef.removeRoutees(routees) - } + def unregisterRoutees(routees: IndexedSeq[ActorRef]): Unit = routedRef.removeRoutees(routees) def createRoutees(props: Props, nrOfInstances: Int, routees: Iterable[String]): IndexedSeq[ActorRef] = (nrOfInstances, routees) match { @@ -250,11 +250,8 @@ class RouteeProvider(val context: ActorContext, val resizer: Option[Resizer]) { case (_, xs) ⇒ xs.map(context.actorFor(_))(scala.collection.breakOut) } - def createAndRegisterRoutees(props: Props, nrOfInstances: Int, routees: Iterable[String]): Unit = { - if (resizer.isEmpty) { - registerRoutees(createRoutees(props, nrOfInstances, routees)) - } - } + def createAndRegisterRoutees(props: Props, nrOfInstances: Int, routees: Iterable[String]): Unit = + if (resizer.isEmpty) registerRoutees(createRoutees(props, nrOfInstances, routees)) /** * All routees of the router @@ -262,7 +259,6 @@ class RouteeProvider(val context: ActorContext, val resizer: Option[Resizer]) { def routees: IndexedSeq[ActorRef] = routedRef.routees private def routedRef = context.self.asInstanceOf[RoutedActorRef] - } /** @@ -305,8 +301,8 @@ trait Router extends Actor { final def receive = ({ case Router.Resize ⇒ - try ref.routerConfig.resizer foreach (_.resize(ref.routeeProps, ref.routeeProvider)) - finally assert(ref.resizeInProgress.getAndSet(false)) + val ab = ref.resizeInProgress + if (ab.get) try ref.routerConfig.resizer foreach (_.resize(ref.routeeProps, ref.routeeProvider)) finally ab.set(false) case Terminated(child) ⇒ ref.removeRoutees(IndexedSeq(child)) @@ -321,6 +317,9 @@ trait Router extends Actor { } } +/** + * INTERNAL API + */ private object Router { case object Resize @@ -374,9 +373,9 @@ case class Destination(sender: ActorRef, recipient: ActorRef) //TODO add @SerialVersionUID(1L) when SI-4804 is fixed abstract class NoRouter extends RouterConfig case object NoRouter extends NoRouter { - def createRoute(props: Props, routeeProvider: RouteeProvider): Route = null + def createRoute(props: Props, routeeProvider: RouteeProvider): Route = null // FIXME, null, really?? def routerDispatcher: String = "" - def supervisorStrategy = null + def supervisorStrategy = null // FIXME null, really?? override def withFallback(other: RouterConfig): RouterConfig = other /** @@ -406,9 +405,7 @@ case object FromConfig extends FromConfig { //TODO add @SerialVersionUID(1L) when SI-4804 is fixed class FromConfig(val routerDispatcher: String = Dispatchers.DefaultDispatcherId) extends RouterConfig - with Product - with Serializable - with Equals { + with Serializable { def this() = this(Dispatchers.DefaultDispatcherId) @@ -416,42 +413,14 @@ class FromConfig(val routerDispatcher: String = Dispatchers.DefaultDispatcherId) throw new ConfigurationException("router " + routeeProvider.context.self + " needs external configuration from file (e.g. application.conf)") def supervisorStrategy: SupervisorStrategy = Router.defaultSupervisorStrategy - - // open-coded case class to preserve binary compatibility, all deprecated for 2.1 - @deprecated("FromConfig does not make sense as case class", "2.0.1") - override def productPrefix = "FromConfig" - - @deprecated("FromConfig does not make sense as case class", "2.0.1") - def productArity = 1 - - @deprecated("FromConfig does not make sense as case class", "2.0.1") - def productElement(x: Int) = x match { - case 0 ⇒ routerDispatcher - case _ ⇒ throw new IndexOutOfBoundsException(x.toString) - } - - @deprecated("FromConfig does not make sense as case class", "2.0.1") - def copy(d: String = Dispatchers.DefaultDispatcherId): FromConfig = new FromConfig(d) - - @deprecated("FromConfig does not make sense as case class", "2.0.1") - def canEqual(o: Any) = o.isInstanceOf[FromConfig] - - @deprecated("FromConfig does not make sense as case class", "2.0.1") - override def hashCode = ScalaRunTime._hashCode(this) - - @deprecated("FromConfig does not make sense as case class", "2.0.1") - override def toString = "FromConfig(" + routerDispatcher + ")" - - @deprecated("FromConfig does not make sense as case class", "2.0.1") - override def equals(other: Any): Boolean = other match { - case FromConfig(x) ⇒ x == routerDispatcher - case _ ⇒ false - } - } object RoundRobinRouter { - def apply(routees: Iterable[ActorRef]) = new RoundRobinRouter(routees = routees map (_.path.toString)) + /** + * Creates a new RoundRobinRouter, routing to the specified routees + */ + def apply(routees: Iterable[ActorRef]): RoundRobinRouter = + new RoundRobinRouter(routees = routees map (_.path.toString)) /** * Java API to create router with the supplied 'routees' actors. @@ -512,9 +481,7 @@ case class RoundRobinRouter(nrOfInstances: Int = 0, routees: Iterable[String] = * Constructor that sets nrOfInstances to be created. * Java API */ - def this(nr: Int) = { - this(nrOfInstances = nr) - } + def this(nr: Int) = this(nrOfInstances = nr) /** * Constructor that sets the routees to be used. @@ -522,9 +489,7 @@ case class RoundRobinRouter(nrOfInstances: Int = 0, routees: Iterable[String] = * @param routeePaths string representation of the actor paths of the routees that will be looked up * using `actorFor` in [[akka.actor.ActorRefProvider]] */ - def this(routeePaths: java.lang.Iterable[String]) = { - this(routees = iterableAsScalaIterable(routeePaths)) - } + def this(routeePaths: java.lang.Iterable[String]) = this(routees = iterableAsScalaIterable(routeePaths)) /** * Constructor that sets the resizer to be used. @@ -535,13 +500,13 @@ case class RoundRobinRouter(nrOfInstances: Int = 0, routees: Iterable[String] = /** * Java API for setting routerDispatcher */ - def withDispatcher(dispatcherId: String) = copy(routerDispatcher = dispatcherId) + def withDispatcher(dispatcherId: String): RoundRobinRouter = copy(routerDispatcher = dispatcherId) /** * Java API for setting the supervisor strategy to be used for the “head” * Router actor. */ - def withSupervisorStrategy(strategy: SupervisorStrategy) = copy(supervisorStrategy = strategy) + def withSupervisorStrategy(strategy: SupervisorStrategy): RoundRobinRouter = copy(supervisorStrategy = strategy) } trait RoundRobinLike { this: RouterConfig ⇒ @@ -571,7 +536,10 @@ trait RoundRobinLike { this: RouterConfig ⇒ } object RandomRouter { - def apply(routees: Iterable[ActorRef]) = new RandomRouter(routees = routees map (_.path.toString)) + /** + * Creates a new RandomRouter, routing to the specified routees + */ + def apply(routees: Iterable[ActorRef]): RandomRouter = new RandomRouter(routees = routees map (_.path.toString)) /** * Java API to create router with the supplied 'routees' actors. @@ -632,9 +600,7 @@ case class RandomRouter(nrOfInstances: Int = 0, routees: Iterable[String] = Nil, * Constructor that sets nrOfInstances to be created. * Java API */ - def this(nr: Int) = { - this(nrOfInstances = nr) - } + def this(nr: Int) = this(nrOfInstances = nr) /** * Constructor that sets the routees to be used. @@ -642,9 +608,7 @@ case class RandomRouter(nrOfInstances: Int = 0, routees: Iterable[String] = Nil, * @param routeePaths string representation of the actor paths of the routees that will be looked up * using `actorFor` in [[akka.actor.ActorRefProvider]] */ - def this(routeePaths: java.lang.Iterable[String]) = { - this(routees = iterableAsScalaIterable(routeePaths)) - } + def this(routeePaths: java.lang.Iterable[String]) = this(routees = iterableAsScalaIterable(routeePaths)) /** * Constructor that sets the resizer to be used. @@ -655,13 +619,13 @@ case class RandomRouter(nrOfInstances: Int = 0, routees: Iterable[String] = Nil, /** * Java API for setting routerDispatcher */ - def withDispatcher(dispatcherId: String) = copy(routerDispatcher = dispatcherId) + def withDispatcher(dispatcherId: String): RandomRouter = copy(routerDispatcher = dispatcherId) /** * Java API for setting the supervisor strategy to be used for the “head” * Router actor. */ - def withSupervisorStrategy(strategy: SupervisorStrategy) = copy(supervisorStrategy = strategy) + def withSupervisorStrategy(strategy: SupervisorStrategy): RandomRouter = copy(supervisorStrategy = strategy) } trait RandomLike { this: RouterConfig ⇒ @@ -688,7 +652,11 @@ trait RandomLike { this: RouterConfig ⇒ } object SmallestMailboxRouter { - def apply(routees: Iterable[ActorRef]) = new SmallestMailboxRouter(routees = routees map (_.path.toString)) + /** + * Creates a new SmallestMailboxRouter, routing to the specified routees + */ + def apply(routees: Iterable[ActorRef]): SmallestMailboxRouter = + new SmallestMailboxRouter(routees = routees map (_.path.toString)) /** * Java API to create router with the supplied 'routees' actors. @@ -758,9 +726,7 @@ case class SmallestMailboxRouter(nrOfInstances: Int = 0, routees: Iterable[Strin * Constructor that sets nrOfInstances to be created. * Java API */ - def this(nr: Int) = { - this(nrOfInstances = nr) - } + def this(nr: Int) = this(nrOfInstances = nr) /** * Constructor that sets the routees to be used. @@ -768,9 +734,7 @@ case class SmallestMailboxRouter(nrOfInstances: Int = 0, routees: Iterable[Strin * @param routeePaths string representation of the actor paths of the routees that will be looked up * using `actorFor` in [[akka.actor.ActorRefProvider]] */ - def this(routeePaths: java.lang.Iterable[String]) = { - this(routees = iterableAsScalaIterable(routeePaths)) - } + def this(routeePaths: java.lang.Iterable[String]) = this(routees = iterableAsScalaIterable(routeePaths)) /** * Constructor that sets the resizer to be used. @@ -781,19 +745,16 @@ case class SmallestMailboxRouter(nrOfInstances: Int = 0, routees: Iterable[Strin /** * Java API for setting routerDispatcher */ - def withDispatcher(dispatcherId: String) = copy(routerDispatcher = dispatcherId) + def withDispatcher(dispatcherId: String): SmallestMailboxRouter = copy(routerDispatcher = dispatcherId) /** * Java API for setting the supervisor strategy to be used for the “head” * Router actor. */ - def withSupervisorStrategy(strategy: SupervisorStrategy) = copy(supervisorStrategy = strategy) + def withSupervisorStrategy(strategy: SupervisorStrategy): SmallestMailboxRouter = copy(supervisorStrategy = strategy) } trait SmallestMailboxLike { this: RouterConfig ⇒ - - import java.security.SecureRandom - def nrOfInstances: Int def routees: Iterable[String] @@ -895,7 +856,10 @@ trait SmallestMailboxLike { this: RouterConfig ⇒ } object BroadcastRouter { - def apply(routees: Iterable[ActorRef]) = new BroadcastRouter(routees = routees map (_.path.toString)) + /** + * Creates a new BroadcastRouter, routing to the specified routees + */ + def apply(routees: Iterable[ActorRef]): BroadcastRouter = new BroadcastRouter(routees = routees map (_.path.toString)) /** * Java API to create router with the supplied 'routees' actors. @@ -956,9 +920,7 @@ case class BroadcastRouter(nrOfInstances: Int = 0, routees: Iterable[String] = N * Constructor that sets nrOfInstances to be created. * Java API */ - def this(nr: Int) = { - this(nrOfInstances = nr) - } + def this(nr: Int) = this(nrOfInstances = nr) /** * Constructor that sets the routees to be used. @@ -966,9 +928,7 @@ case class BroadcastRouter(nrOfInstances: Int = 0, routees: Iterable[String] = N * @param routeePaths string representation of the actor paths of the routees that will be looked up * using `actorFor` in [[akka.actor.ActorRefProvider]] */ - def this(routeePaths: java.lang.Iterable[String]) = { - this(routees = iterableAsScalaIterable(routeePaths)) - } + def this(routeePaths: java.lang.Iterable[String]) = this(routees = iterableAsScalaIterable(routeePaths)) /** * Constructor that sets the resizer to be used. @@ -979,13 +939,13 @@ case class BroadcastRouter(nrOfInstances: Int = 0, routees: Iterable[String] = N /** * Java API for setting routerDispatcher */ - def withDispatcher(dispatcherId: String) = copy(routerDispatcher = dispatcherId) + def withDispatcher(dispatcherId: String): BroadcastRouter = copy(routerDispatcher = dispatcherId) /** * Java API for setting the supervisor strategy to be used for the “head” * Router actor. */ - def withSupervisorStrategy(strategy: SupervisorStrategy) = copy(supervisorStrategy = strategy) + def withSupervisorStrategy(strategy: SupervisorStrategy): BroadcastRouter = copy(supervisorStrategy = strategy) } trait BroadcastLike { this: RouterConfig ⇒ @@ -1004,7 +964,11 @@ trait BroadcastLike { this: RouterConfig ⇒ } object ScatterGatherFirstCompletedRouter { - def apply(routees: Iterable[ActorRef], within: Duration) = new ScatterGatherFirstCompletedRouter(routees = routees map (_.path.toString), within = within) + /** + * Creates a new ScatterGatherFirstCompletedRouter, routing to the specified routees, timing out after the specified Duration + */ + def apply(routees: Iterable[ActorRef], within: Duration): ScatterGatherFirstCompletedRouter = + new ScatterGatherFirstCompletedRouter(routees = routees map (_.path.toString), within = within) /** * Java API to create router with the supplied 'routees' actors. @@ -1071,9 +1035,7 @@ case class ScatterGatherFirstCompletedRouter(nrOfInstances: Int = 0, routees: It * Constructor that sets nrOfInstances to be created. * Java API */ - def this(nr: Int, w: Duration) = { - this(nrOfInstances = nr, within = w) - } + def this(nr: Int, w: Duration) = this(nrOfInstances = nr, within = w) /** * Constructor that sets the routees to be used. @@ -1081,9 +1043,8 @@ case class ScatterGatherFirstCompletedRouter(nrOfInstances: Int = 0, routees: It * @param routeePaths string representation of the actor paths of the routees that will be looked up * using `actorFor` in [[akka.actor.ActorRefProvider]] */ - def this(routeePaths: java.lang.Iterable[String], w: Duration) = { + def this(routeePaths: java.lang.Iterable[String], w: Duration) = this(routees = iterableAsScalaIterable(routeePaths), within = w) - } /** * Constructor that sets the resizer to be used. @@ -1152,10 +1113,14 @@ trait Resizer { * This method is invoked only in the context of the Router actor in order to safely * create/stop children. */ - def resize(props: Props, routeeProvider: RouteeProvider) + def resize(props: Props, routeeProvider: RouteeProvider): Unit } case object DefaultResizer { + + /** + * Creates a new DefaultResizer from the given configuration + */ def apply(resizerConfig: Config): DefaultResizer = DefaultResizer( lowerBound = resizerConfig.getInt("lower-bound"), @@ -1168,6 +1133,7 @@ case object DefaultResizer { messagesPerResize = resizerConfig.getInt("messages-per-resize")) } +//FIXME DOCUMENT ME case class DefaultResizer( /** * The fewest number of routees the router should ever have. @@ -1242,7 +1208,7 @@ case class DefaultResizer( def isTimeForResize(messageCounter: Long): Boolean = (messageCounter % messagesPerResize == 0) - def resize(props: Props, routeeProvider: RouteeProvider) { + def resize(props: Props, routeeProvider: RouteeProvider): Unit = { val currentRoutees = routeeProvider.routees val requestedCapacity = capacity(currentRoutees) @@ -1260,7 +1226,7 @@ case class DefaultResizer( * Give concurrent messages a chance to be placed in mailbox before * sending PoisonPill. */ - protected def delayedStop(scheduler: Scheduler, abandon: IndexedSeq[ActorRef]) { + protected def delayedStop(scheduler: Scheduler, abandon: IndexedSeq[ActorRef]): Unit = { if (abandon.nonEmpty) { if (stopDelay <= Duration.Zero) { abandon foreach (_ ! PoisonPill) @@ -1329,9 +1295,7 @@ case class DefaultResizer( * @param capacity current number of routees * @return proposed change in the capacity */ - def filter(pressure: Int, capacity: Int): Int = { - rampup(pressure, capacity) + backoff(pressure, capacity) - } + def filter(pressure: Int, capacity: Int): Int = rampup(pressure, capacity) + backoff(pressure, capacity) /** * Computes a proposed positive (or zero) capacity delta using diff --git a/akka-actor/src/main/scala/akka/serialization/Serialization.scala b/akka-actor/src/main/scala/akka/serialization/Serialization.scala index ce0f56a238..7355e4f7fb 100644 --- a/akka-actor/src/main/scala/akka/serialization/Serialization.scala +++ b/akka-actor/src/main/scala/akka/serialization/Serialization.scala @@ -14,8 +14,6 @@ import akka.util.NonFatal import scala.collection.mutable.ArrayBuffer import java.io.NotSerializableException -case class NoSerializerFoundException(m: String) extends AkkaException(m) - object Serialization { /** @@ -85,7 +83,7 @@ class Serialization(val system: ExtendedActorSystem) extends Extension { /** * Returns the Serializer configured for the given object, returns the NullSerializer if it's null. * - * @throws akka.config.ConfigurationException if no `serialization-bindings` is configured for the + * @throws akka.ConfigurationException if no `serialization-bindings` is configured for the * class of the object */ def findSerializerFor(o: AnyRef): Serializer = o match { @@ -120,9 +118,7 @@ class Serialization(val system: ExtendedActorSystem) extends Extension { possibilities(0)._2 } serializerMap.putIfAbsent(clazz, ser) match { - case null ⇒ - log.debug("Using serializer[{}] for message [{}]", ser.getClass.getName, clazz.getName) - ser + case null ⇒ log.debug("Using serializer[{}] for message [{}]", ser.getClass.getName, clazz.getName); ser case some ⇒ some } case ser ⇒ ser @@ -140,10 +136,8 @@ class Serialization(val system: ExtendedActorSystem) extends Extension { * A Map of serializer from alias to implementation (class implementing akka.serialization.Serializer) * By default always contains the following mapping: "java" -> akka.serialization.JavaSerializer */ - private val serializers: Map[String, Serializer] = { - for ((k: String, v: String) ← settings.Serializers) - yield k -> serializerOf(v).fold(throw _, identity) - } + private val serializers: Map[String, Serializer] = + for ((k: String, v: String) ← settings.Serializers) yield k -> serializerOf(v).fold(throw _, identity) /** * bindings is a Seq of tuple representing the mapping from Class to Serializer. diff --git a/akka-actor/src/main/scala/akka/serialization/Serializer.scala b/akka-actor/src/main/scala/akka/serialization/Serializer.scala index 5696201f62..f6300ca998 100644 --- a/akka-actor/src/main/scala/akka/serialization/Serializer.scala +++ b/akka-actor/src/main/scala/akka/serialization/Serializer.scala @@ -6,7 +6,6 @@ package akka.serialization import java.io.{ ObjectOutputStream, ByteArrayOutputStream, ObjectInputStream, ByteArrayInputStream } import akka.util.ClassLoaderObjectInputStream -import akka.actor.DynamicAccess import akka.actor.ExtendedActorSystem import scala.util.DynamicVariable diff --git a/akka-actor/src/main/scala/akka/util/BoundedBlockingQueue.scala b/akka-actor/src/main/scala/akka/util/BoundedBlockingQueue.scala index 7eb90b8ef0..c7c8308de0 100644 --- a/akka-actor/src/main/scala/akka/util/BoundedBlockingQueue.scala +++ b/akka-actor/src/main/scala/akka/util/BoundedBlockingQueue.scala @@ -8,6 +8,12 @@ import java.util.concurrent.locks.ReentrantLock import java.util.concurrent.{ TimeUnit, BlockingQueue } import java.util.{ AbstractQueue, Queue, Collection, Iterator } +/** + * BoundedBlockingQueue wraps any Queue and turns the result into a BlockingQueue with a limited capacity + * @param maxCapacity - the maximum capacity of this Queue, needs to be > 0 + * @param backing - the backing Queue + * @tparam E - The type of the contents of this Queue + */ class BoundedBlockingQueue[E <: AnyRef]( val maxCapacity: Int, private val backing: Queue[E]) extends AbstractQueue[E] with BlockingQueue[E] { @@ -22,7 +28,7 @@ class BoundedBlockingQueue[E <: AnyRef]( require(maxCapacity > 0) } - protected val lock = new ReentrantLock(false) + protected val lock = new ReentrantLock(false) // TODO might want to switch to ReentrantReadWriteLock private val notEmpty = lock.newCondition() private val notFull = lock.newCondition() diff --git a/akka-actor/src/main/scala/akka/util/ByteString.scala b/akka-actor/src/main/scala/akka/util/ByteString.scala index 6d869826a8..ac074d5b28 100644 --- a/akka-actor/src/main/scala/akka/util/ByteString.scala +++ b/akka-actor/src/main/scala/akka/util/ByteString.scala @@ -11,6 +11,7 @@ import scala.collection.mutable.{ Builder, WrappedArray } import scala.collection.immutable.{ IndexedSeq, VectorBuilder } import scala.collection.generic.CanBuildFrom +//FIXME MORE DOCS object ByteString { /** @@ -53,15 +54,16 @@ object ByteString { val empty: ByteString = CompactByteString(Array.empty[Byte]) - def newBuilder = new ByteStringBuilder + def newBuilder: ByteStringBuilder = new ByteStringBuilder - implicit def canBuildFrom = new CanBuildFrom[TraversableOnce[Byte], Byte, ByteString] { - def apply(from: TraversableOnce[Byte]) = newBuilder - def apply() = newBuilder - } + implicit val canBuildFrom: CanBuildFrom[TraversableOnce[Byte], Byte, ByteString] = + new CanBuildFrom[TraversableOnce[Byte], Byte, ByteString] { + def apply(ignore: TraversableOnce[Byte]): ByteStringBuilder = newBuilder + def apply(): ByteStringBuilder = newBuilder + } private[akka] object ByteString1C { - def apply(bytes: Array[Byte]) = new ByteString1C(bytes) + def apply(bytes: Array[Byte]): ByteString1C = new ByteString1C(bytes) } /** @@ -71,7 +73,7 @@ object ByteString { final class ByteString1C private (private val bytes: Array[Byte]) extends CompactByteString { def apply(idx: Int): Byte = bytes(idx) - override def length = bytes.length + override def length: Int = bytes.length def toArray: Array[Byte] = bytes.clone @@ -81,13 +83,11 @@ object ByteString { def compact: ByteString1C = this - def asByteBuffer: ByteBuffer = - toByteString1.asByteBuffer + def asByteBuffer: ByteBuffer = toByteString1.asByteBuffer def decodeString(charset: String): String = new String(bytes, charset) - def ++(that: ByteString): ByteString = - if (!that.isEmpty) toByteString1 ++ that else this + def ++(that: ByteString): ByteString = if (!that.isEmpty) toByteString1 ++ that else this override def slice(from: Int, until: Int): ByteString = if ((from != 0) || (until != length)) toByteString1.slice(from, until) @@ -96,12 +96,11 @@ object ByteString { override def copyToArray[A >: Byte](xs: Array[A], start: Int, len: Int): Unit = toByteString1.copyToArray(xs, start, len) - def copyToBuffer(buffer: ByteBuffer): Int = - toByteString1.copyToBuffer(buffer) + def copyToBuffer(buffer: ByteBuffer): Int = toByteString1.copyToBuffer(buffer) } private[akka] object ByteString1 { - def apply(bytes: Array[Byte]) = new ByteString1(bytes) + def apply(bytes: Array[Byte]): ByteString1 = new ByteString1(bytes) } /** @@ -113,7 +112,7 @@ object ByteString { def apply(idx: Int): Byte = bytes(checkRangeConvert(idx)) - private def checkRangeConvert(index: Int) = { + private def checkRangeConvert(index: Int): Int = { if (0 <= index && length > index) index + startIndex else @@ -128,8 +127,7 @@ object ByteString { override def clone: CompactByteString = ByteString1C(toArray) - def compact: CompactByteString = - if (length == bytes.length) ByteString1C(bytes) else clone + def compact: CompactByteString = if (length == bytes.length) ByteString1C(bytes) else clone def asByteBuffer: ByteBuffer = { val buffer = ByteBuffer.wrap(bytes, startIndex, length).asReadOnlyBuffer @@ -161,7 +159,6 @@ object ByteString { if (copyLength > 0) buffer.put(bytes, startIndex, copyLength) copyLength } - } private[akka] object ByteStrings { @@ -198,10 +195,11 @@ object ByteString { } // 0: both empty, 1: 2nd empty, 2: 1st empty, 3: neither empty + // Using length to check emptiness is prohibited by law def compare(b1: ByteString, b2: ByteString): Int = - if (b1.length == 0) - if (b2.length == 0) 0 else 2 - else if (b2.length == 0) 1 else 3 + if (b1.isEmpty) + if (b2.isEmpty) 0 else 2 + else if (b2.isEmpty) 1 else 3 } @@ -439,7 +437,7 @@ final class ByteStringBuilder extends Builder[Byte, ByteString] { private var _tempLength = 0 private var _tempCapacity = 0 - private def clearTemp() { + private def clearTemp(): Unit = { if (_tempLength > 0) { val arr = new Array[Byte](_tempLength) Array.copy(_temp, 0, arr, 0, _tempLength) @@ -448,14 +446,14 @@ final class ByteStringBuilder extends Builder[Byte, ByteString] { } } - private def resizeTemp(size: Int) { + private def resizeTemp(size: Int): Unit = { val newtemp = new Array[Byte](size) if (_tempLength > 0) Array.copy(_temp, 0, newtemp, 0, _tempLength) _temp = newtemp _tempCapacity = _temp.length } - private def ensureTempSize(size: Int) { + private def ensureTempSize(size: Int): Unit = { if (_tempCapacity < size || _tempCapacity == 0) { var newSize = if (_tempCapacity == 0) 16 else _tempCapacity * 2 while (newSize < size) newSize *= 2 @@ -498,7 +496,7 @@ final class ByteStringBuilder extends Builder[Byte, ByteString] { this } - def clear() { + def clear(): Unit = { _builder.clear _length = 0 _tempLength = 0 diff --git a/akka-actor/src/main/scala/akka/util/ClassLoaderObjectInputStream.scala b/akka-actor/src/main/scala/akka/util/ClassLoaderObjectInputStream.scala index 3ad55d69eb..ab2514861e 100644 --- a/akka-actor/src/main/scala/akka/util/ClassLoaderObjectInputStream.scala +++ b/akka-actor/src/main/scala/akka/util/ClassLoaderObjectInputStream.scala @@ -6,6 +6,13 @@ package akka.util import java.io.{ InputStream, ObjectInputStream, ObjectStreamClass } +/** + * ClassLoaderObjectInputStream tries to utilize the provided ClassLoader to load Classes and falls + * back to ObjectInputStreams resolver. + * + * @param classLoader - the ClassLoader which is to be used primarily + * @param is - the InputStream that is wrapped + */ class ClassLoaderObjectInputStream(classLoader: ClassLoader, is: InputStream) extends ObjectInputStream(is) { override protected def resolveClass(objectStreamClass: ObjectStreamClass): Class[_] = try Class.forName(objectStreamClass.getName, false, classLoader) catch { diff --git a/akka-actor/src/main/scala/akka/util/Convert.scala b/akka-actor/src/main/scala/akka/util/Convert.scala index a805b17fb2..3fead7aef7 100644 --- a/akka-actor/src/main/scala/akka/util/Convert.scala +++ b/akka-actor/src/main/scala/akka/util/Convert.scala @@ -3,7 +3,7 @@ */ package akka.util - +//FIXME DOCS! object Convert { def intToBytes(value: Int): Array[Byte] = { diff --git a/akka-actor/src/main/scala/akka/util/Crypt.scala b/akka-actor/src/main/scala/akka/util/Crypt.scala index 7dd678e748..280cd90768 100644 --- a/akka-actor/src/main/scala/akka/util/Crypt.scala +++ b/akka-actor/src/main/scala/akka/util/Crypt.scala @@ -5,7 +5,7 @@ package akka.util import java.security.{ MessageDigest, SecureRandom } - +//FIXME DOCS object Crypt { val hex = "0123456789ABCDEF" val lineSeparator = System.getProperty("line.separator") @@ -32,7 +32,7 @@ object Crypt { } def hexify(bytes: Array[Byte]): String = { - val builder = new StringBuilder + val builder = new StringBuilder(bytes.length * 2) bytes.foreach { byte ⇒ builder.append(hex.charAt((byte & 0xF0) >> 4)).append(hex.charAt(byte & 0xF)) } builder.toString } diff --git a/akka-actor/src/main/scala/akka/util/Duration.scala b/akka-actor/src/main/scala/akka/util/Duration.scala index a213fe1869..b37cf24c3b 100644 --- a/akka-actor/src/main/scala/akka/util/Duration.scala +++ b/akka-actor/src/main/scala/akka/util/Duration.scala @@ -110,6 +110,7 @@ object Duration { } val Zero: FiniteDuration = new FiniteDuration(0, NANOSECONDS) + val Undefined: Duration = new Duration with Infinite { override def toString = "Duration.Undefined" override def equals(other: Any) = other.asInstanceOf[AnyRef] eq this @@ -166,8 +167,8 @@ object Duration { * including itself. */ val Inf: Duration = new Duration with Infinite { - override def toString = "Duration.Inf" - def compare(other: Duration) = if (other eq this) 0 else 1 + override def toString: String = "Duration.Inf" + def compare(other: Duration): Int = if (other eq this) 0 else 1 def unary_- : Duration = MinusInf } @@ -177,7 +178,7 @@ object Duration { */ val MinusInf: Duration = new Duration with Infinite { override def toString = "Duration.MinusInf" - def compare(other: Duration) = if (other eq this) 0 else -1 + def compare(other: Duration): Int = if (other eq this) 0 else -1 def unary_- : Duration = Inf } @@ -188,7 +189,7 @@ object Duration { def parse(s: String): Duration = unapply(s).get implicit object DurationIsOrdered extends Ordering[Duration] { - def compare(a: Duration, b: Duration) = a compare b + def compare(a: Duration, b: Duration): Int = a compare b } } @@ -263,17 +264,17 @@ abstract class Duration extends Serializable with Ordered[Duration] { def fromNow: Deadline = Deadline.now + this // Java API - def lt(other: Duration) = this < other - def lteq(other: Duration) = this <= other - def gt(other: Duration) = this > other - def gteq(other: Duration) = this >= other - def plus(other: Duration) = this + other - def minus(other: Duration) = this - other - def mul(factor: Double) = this * factor - def div(factor: Double) = this / factor - def div(other: Duration) = this / other - def neg() = -this - def isFinite() = finite_? + def lt(other: Duration): Boolean = this < other + def lteq(other: Duration): Boolean = this <= other + def gt(other: Duration): Boolean = this > other + def gteq(other: Duration): Boolean = this >= other + def plus(other: Duration): Duration = this + other + def minus(other: Duration): Duration = this - other + def mul(factor: Double): Duration = this * factor + def div(factor: Double): Duration = this / factor + def div(other: Duration): Double = this / other + def neg(): Duration = -this + def isFinite(): Boolean = finite_? } object FiniteDuration { @@ -349,31 +350,19 @@ class FiniteDuration(val length: Long, val unit: TimeUnit) extends Duration { else c } - def +(other: Duration) = { - if (!other.finite_?) { - other - } else { - fromNanos(add(toNanos, other.toNanos)) - } - } + def +(other: Duration): Duration = if (!other.finite_?) other else fromNanos(add(toNanos, other.toNanos)) - def -(other: Duration) = { - if (!other.finite_?) { - other - } else { - fromNanos(add(toNanos, -other.toNanos)) - } - } + def -(other: Duration): Duration = if (!other.finite_?) other else fromNanos(add(toNanos, -other.toNanos)) - def *(factor: Double) = fromNanos(long2double(toNanos) * factor) + def *(factor: Double): FiniteDuration = fromNanos(long2double(toNanos) * factor) - def /(factor: Double) = fromNanos(long2double(toNanos) / factor) + def /(factor: Double): FiniteDuration = fromNanos(long2double(toNanos) / factor) - def /(other: Duration) = if (other.finite_?) long2double(toNanos) / other.toNanos else 0 + def /(other: Duration): Double = if (other.finite_?) long2double(toNanos) / other.toNanos else 0 - def unary_- = Duration(-length, unit) + def unary_- : FiniteDuration = Duration(-length, unit) - def finite_? = true + def finite_? : Boolean = true override def equals(other: Any) = (other.asInstanceOf[AnyRef] eq this) || other.isInstanceOf[FiniteDuration] && @@ -385,178 +374,74 @@ class FiniteDuration(val length: Long, val unit: TimeUnit) extends Duration { } } -class DurationInt(n: Int) { +private[akka] trait DurationOps { import duration.Classifier + protected def from(timeUnit: TimeUnit): FiniteDuration + def nanoseconds: FiniteDuration = from(NANOSECONDS) + def nanos: FiniteDuration = from(NANOSECONDS) + def nanosecond: FiniteDuration = from(NANOSECONDS) + def nano: FiniteDuration = from(NANOSECONDS) - def nanoseconds = Duration(n, NANOSECONDS) - def nanos = Duration(n, NANOSECONDS) - def nanosecond = Duration(n, NANOSECONDS) - def nano = Duration(n, NANOSECONDS) + def microseconds: FiniteDuration = from(MICROSECONDS) + def micros: FiniteDuration = from(MICROSECONDS) + def microsecond: FiniteDuration = from(MICROSECONDS) + def micro: FiniteDuration = from(MICROSECONDS) - def microseconds = Duration(n, MICROSECONDS) - def micros = Duration(n, MICROSECONDS) - def microsecond = Duration(n, MICROSECONDS) - def micro = Duration(n, MICROSECONDS) + def milliseconds: FiniteDuration = from(MILLISECONDS) + def millis: FiniteDuration = from(MILLISECONDS) + def millisecond: FiniteDuration = from(MILLISECONDS) + def milli: FiniteDuration = from(MILLISECONDS) - def milliseconds = Duration(n, MILLISECONDS) - def millis = Duration(n, MILLISECONDS) - def millisecond = Duration(n, MILLISECONDS) - def milli = Duration(n, MILLISECONDS) + def seconds: FiniteDuration = from(SECONDS) + def second: FiniteDuration = from(SECONDS) - def seconds = Duration(n, SECONDS) - def second = Duration(n, SECONDS) + def minutes: FiniteDuration = from(MINUTES) + def minute: FiniteDuration = from(MINUTES) - def minutes = Duration(n, MINUTES) - def minute = Duration(n, MINUTES) + def hours: FiniteDuration = from(HOURS) + def hour: FiniteDuration = from(HOURS) - def hours = Duration(n, HOURS) - def hour = Duration(n, HOURS) + def days: FiniteDuration = from(DAYS) + def day: FiniteDuration = from(DAYS) - def days = Duration(n, DAYS) - def day = Duration(n, DAYS) + def nanoseconds[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(from(NANOSECONDS)) + def nanos[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(from(NANOSECONDS)) + def nanosecond[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(from(NANOSECONDS)) + def nano[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(from(NANOSECONDS)) - def nanoseconds[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, NANOSECONDS)) - def nanos[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, NANOSECONDS)) - def nanosecond[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, NANOSECONDS)) - def nano[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, NANOSECONDS)) + def microseconds[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(from(MICROSECONDS)) + def micros[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(from(MICROSECONDS)) + def microsecond[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(from(MICROSECONDS)) + def micro[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(from(MICROSECONDS)) - def microseconds[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, MICROSECONDS)) - def micros[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, MICROSECONDS)) - def microsecond[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, MICROSECONDS)) - def micro[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, MICROSECONDS)) + def milliseconds[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(from(MILLISECONDS)) + def millis[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(from(MILLISECONDS)) + def millisecond[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(from(MILLISECONDS)) + def milli[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(from(MILLISECONDS)) - def milliseconds[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, MILLISECONDS)) - def millis[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, MILLISECONDS)) - def millisecond[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, MILLISECONDS)) - def milli[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, MILLISECONDS)) + def seconds[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(from(SECONDS)) + def second[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(from(SECONDS)) - def seconds[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, SECONDS)) - def second[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, SECONDS)) + def minutes[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(from(MINUTES)) + def minute[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(from(MINUTES)) - def minutes[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, MINUTES)) - def minute[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, MINUTES)) + def hours[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(from(HOURS)) + def hour[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(from(HOURS)) - def hours[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, HOURS)) - def hour[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, HOURS)) - - def days[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, DAYS)) - def day[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, DAYS)) + def days[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(from(DAYS)) + def day[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(from(DAYS)) } -class DurationLong(n: Long) { - import duration.Classifier - - def nanoseconds = Duration(n, NANOSECONDS) - def nanos = Duration(n, NANOSECONDS) - def nanosecond = Duration(n, NANOSECONDS) - def nano = Duration(n, NANOSECONDS) - - def microseconds = Duration(n, MICROSECONDS) - def micros = Duration(n, MICROSECONDS) - def microsecond = Duration(n, MICROSECONDS) - def micro = Duration(n, MICROSECONDS) - - def milliseconds = Duration(n, MILLISECONDS) - def millis = Duration(n, MILLISECONDS) - def millisecond = Duration(n, MILLISECONDS) - def milli = Duration(n, MILLISECONDS) - - def seconds = Duration(n, SECONDS) - def second = Duration(n, SECONDS) - - def minutes = Duration(n, MINUTES) - def minute = Duration(n, MINUTES) - - def hours = Duration(n, HOURS) - def hour = Duration(n, HOURS) - - def days = Duration(n, DAYS) - def day = Duration(n, DAYS) - - def nanoseconds[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, NANOSECONDS)) - def nanos[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, NANOSECONDS)) - def nanosecond[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, NANOSECONDS)) - def nano[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, NANOSECONDS)) - - def microseconds[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, MICROSECONDS)) - def micros[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, MICROSECONDS)) - def microsecond[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, MICROSECONDS)) - def micro[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, MICROSECONDS)) - - def milliseconds[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, MILLISECONDS)) - def millis[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, MILLISECONDS)) - def millisecond[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, MILLISECONDS)) - def milli[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, MILLISECONDS)) - - def seconds[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, SECONDS)) - def second[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, SECONDS)) - - def minutes[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, MINUTES)) - def minute[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, MINUTES)) - - def hours[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, HOURS)) - def hour[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, HOURS)) - - def days[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, DAYS)) - def day[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(n, DAYS)) +class DurationInt(n: Int) extends DurationOps { + override protected def from(timeUnit: TimeUnit): FiniteDuration = Duration(n, timeUnit) } -class DurationDouble(d: Double) { - import duration.Classifier +class DurationLong(n: Long) extends DurationOps { + override protected def from(timeUnit: TimeUnit): FiniteDuration = Duration(n, timeUnit) +} - def nanoseconds = Duration(d, NANOSECONDS) - def nanos = Duration(d, NANOSECONDS) - def nanosecond = Duration(d, NANOSECONDS) - def nano = Duration(d, NANOSECONDS) - - def microseconds = Duration(d, MICROSECONDS) - def micros = Duration(d, MICROSECONDS) - def microsecond = Duration(d, MICROSECONDS) - def micro = Duration(d, MICROSECONDS) - - def milliseconds = Duration(d, MILLISECONDS) - def millis = Duration(d, MILLISECONDS) - def millisecond = Duration(d, MILLISECONDS) - def milli = Duration(d, MILLISECONDS) - - def seconds = Duration(d, SECONDS) - def second = Duration(d, SECONDS) - - def minutes = Duration(d, MINUTES) - def minute = Duration(d, MINUTES) - - def hours = Duration(d, HOURS) - def hour = Duration(d, HOURS) - - def days = Duration(d, DAYS) - def day = Duration(d, DAYS) - - def nanoseconds[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(d, NANOSECONDS)) - def nanos[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(d, NANOSECONDS)) - def nanosecond[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(d, NANOSECONDS)) - def nano[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(d, NANOSECONDS)) - - def microseconds[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(d, MICROSECONDS)) - def micros[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(d, MICROSECONDS)) - def microsecond[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(d, MICROSECONDS)) - def micro[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(d, MICROSECONDS)) - - def milliseconds[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(d, MILLISECONDS)) - def millis[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(d, MILLISECONDS)) - def millisecond[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(d, MILLISECONDS)) - def milli[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(d, MILLISECONDS)) - - def seconds[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(d, SECONDS)) - def second[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(d, SECONDS)) - - def minutes[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(d, MINUTES)) - def minute[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(d, MINUTES)) - - def hours[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(d, HOURS)) - def hour[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(d, HOURS)) - - def days[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(d, DAYS)) - def day[C, CC <: Classifier[C]](c: C)(implicit ev: CC): CC#R = ev.convert(Duration(d, DAYS)) +class DurationDouble(d: Double) extends DurationOps { + override protected def from(timeUnit: TimeUnit): FiniteDuration = Duration(d, timeUnit) } //TODO add @SerialVersionUID(1L) when SI-4804 is fixed @@ -565,24 +450,27 @@ case class Timeout(duration: Duration) { def this(length: Long, unit: TimeUnit) = this(Duration(length, unit)) } +/** + * A Timeout is a wrapper on top of Duration to be more specific about what the duration means. + */ object Timeout { /** * A timeout with zero duration, will cause most requests to always timeout. */ - val zero = new Timeout(Duration.Zero) + val zero: Timeout = new Timeout(Duration.Zero) /** * A Timeout with infinite duration. Will never timeout. Use extreme caution with this * as it may cause memory leaks, blocked threads, or may not even be supported by * the receiver, which would result in an exception. */ - val never = new Timeout(Duration.Inf) + val never: Timeout = new Timeout(Duration.Inf) - def apply(timeout: Long) = new Timeout(timeout) - def apply(length: Long, unit: TimeUnit) = new Timeout(length, unit) + def apply(timeout: Long): Timeout = new Timeout(timeout) + def apply(length: Long, unit: TimeUnit): Timeout = new Timeout(length, unit) - implicit def durationToTimeout(duration: Duration) = new Timeout(duration) - implicit def intToTimeout(timeout: Int) = new Timeout(timeout) - implicit def longToTimeout(timeout: Long) = new Timeout(timeout) + implicit def durationToTimeout(duration: Duration): Timeout = new Timeout(duration) + implicit def intToTimeout(timeout: Int): Timeout = new Timeout(timeout) + implicit def longToTimeout(timeout: Long): Timeout = new Timeout(timeout) } diff --git a/akka-actor/src/main/scala/akka/util/Helpers.scala b/akka-actor/src/main/scala/akka/util/Helpers.scala index 25cb279f2e..a3618359ac 100644 --- a/akka-actor/src/main/scala/akka/util/Helpers.scala +++ b/akka-actor/src/main/scala/akka/util/Helpers.scala @@ -45,18 +45,13 @@ object Helpers { else base64(next, sb) } - def ignore[E: Manifest](body: ⇒ Unit) { - try { - body - } catch { - case e if manifest[E].erasure.isAssignableFrom(e.getClass) ⇒ () - } - } + //FIXME docs + def ignore[E: Manifest](body: ⇒ Unit): Unit = + try body catch { case e if manifest[E].erasure.isAssignableFrom(e.getClass) ⇒ () } - def withPrintStackTraceOnError(body: ⇒ Unit) { - try { - body - } catch { + //FIXME docs + def withPrintStackTraceOnError(body: ⇒ Unit): Unit = { + try body catch { case e: Throwable ⇒ val sw = new java.io.StringWriter() var root = e diff --git a/akka-actor/src/main/scala/akka/util/Index.scala b/akka-actor/src/main/scala/akka/util/Index.scala index 1153c9e045..3289ed8f13 100644 --- a/akka-actor/src/main/scala/akka/util/Index.scala +++ b/akka-actor/src/main/scala/akka/util/Index.scala @@ -91,7 +91,7 @@ class Index[K, V](val mapSize: Int, val valueComparator: Comparator[V]) { /** * Applies the supplied function to all keys and their values */ - def foreach(fun: (K, V) ⇒ Unit) { + def foreach(fun: (K, V) ⇒ Unit): Unit = { import scala.collection.JavaConversions._ container.entrySet foreach { e ⇒ e.getValue.foreach(fun(e.getKey, _)) } } @@ -112,7 +112,7 @@ class Index[K, V](val mapSize: Int, val valueComparator: Comparator[V]) { /** * Returns the key set. */ - def keys = scala.collection.JavaConversions.collectionAsScalaIterable(container.keySet) + def keys: Iterable[K] = scala.collection.JavaConversions.collectionAsScalaIterable(container.keySet) /** * Disassociates the value of type V from the key of type K diff --git a/akka-actor/src/main/scala/akka/util/LockUtil.scala b/akka-actor/src/main/scala/akka/util/LockUtil.scala index 739232c3c9..c465002b70 100644 --- a/akka-actor/src/main/scala/akka/util/LockUtil.scala +++ b/akka-actor/src/main/scala/akka/util/LockUtil.scala @@ -7,17 +7,12 @@ package akka.util import java.util.concurrent.locks.{ ReentrantLock } import java.util.concurrent.atomic.{ AtomicBoolean } -final class ReentrantGuard { - final val lock = new ReentrantLock +final class ReentrantGuard extends ReentrantLock { @inline final def withGuard[T](body: ⇒ T): T = { - lock.lock - try { - body - } finally { - lock.unlock - } + lock() + try body finally unlock() } } @@ -29,9 +24,7 @@ class Switch(startAsOn: Boolean = false) { protected def transcend(from: Boolean, action: ⇒ Unit): Boolean = synchronized { if (switch.compareAndSet(from, !from)) { - try { - action - } catch { + try action catch { case e ⇒ switch.compareAndSet(!from, from) // revert status throw e @@ -67,18 +60,12 @@ class Switch(startAsOn: Boolean = false) { /** * Executes the provided action and returns its value if the switch is IMMEDIATELY on (i.e. no lock involved) */ - def ifOnYield[T](action: ⇒ T): Option[T] = { - if (switch.get) Some(action) - else None - } + def ifOnYield[T](action: ⇒ T): Option[T] = if (switch.get) Some(action) else None /** * Executes the provided action and returns its value if the switch is IMMEDIATELY off (i.e. no lock involved) */ - def ifOffYield[T](action: ⇒ T): Option[T] = { - if (!switch.get) Some(action) - else None - } + def ifOffYield[T](action: ⇒ T): Option[T] = if (!switch.get) Some(action) else None /** * Executes the provided action and returns if the action was executed or not, if the switch is IMMEDIATELY on (i.e. no lock involved) @@ -104,19 +91,13 @@ class Switch(startAsOn: Boolean = false) { * Executes the provided action and returns its value if the switch is on, waiting for any pending changes to happen before (locking) * Be careful of longrunning or blocking within the provided action as it can lead to deadlocks or bad performance */ - def whileOnYield[T](action: ⇒ T): Option[T] = synchronized { - if (switch.get) Some(action) - else None - } + def whileOnYield[T](action: ⇒ T): Option[T] = synchronized { if (switch.get) Some(action) else None } /** * Executes the provided action and returns its value if the switch is off, waiting for any pending changes to happen before (locking) * Be careful of longrunning or blocking within the provided action as it can lead to deadlocks or bad performance */ - def whileOffYield[T](action: ⇒ T): Option[T] = synchronized { - if (!switch.get) Some(action) - else None - } + def whileOffYield[T](action: ⇒ T): Option[T] = synchronized { if (!switch.get) Some(action) else None } /** * Executes the provided action and returns if the action was executed or not, if the switch is on, waiting for any pending changes to happen before (locking) @@ -144,22 +125,20 @@ class Switch(startAsOn: Boolean = false) { * Executes the provided callbacks depending on if the switch is either on or off waiting for any pending changes to happen before (locking) * Be careful of longrunning or blocking within the provided action as it can lead to deadlocks or bad performance */ - def fold[T](on: ⇒ T)(off: ⇒ T) = synchronized { - if (switch.get) on else off - } + def fold[T](on: ⇒ T)(off: ⇒ T): T = synchronized { if (switch.get) on else off } /** * Executes the given code while holding this switch’s lock, i.e. protected from concurrent modification of the switch status. */ - def locked[T](code: ⇒ T) = synchronized { code } + def locked[T](code: ⇒ T): T = synchronized { code } /** * Returns whether the switch is IMMEDIATELY on (no locking) */ - def isOn = switch.get + def isOn: Boolean = switch.get /** * Returns whether the switch is IMMEDDIATELY off (no locking) */ - def isOff = !isOn + def isOff: Boolean = !isOn } diff --git a/akka-actor/src/main/scala/akka/util/Reflect.scala b/akka-actor/src/main/scala/akka/util/Reflect.scala index 25c56a983f..3a46edeab1 100644 --- a/akka-actor/src/main/scala/akka/util/Reflect.scala +++ b/akka-actor/src/main/scala/akka/util/Reflect.scala @@ -6,8 +6,10 @@ package akka.util /** * Collection of internal reflection utilities which may or may not be * available (most services specific to HotSpot, but fails gracefully). + * + * INTERNAL API */ -object Reflect { +private[akka] object Reflect { /** * This optionally holds a function which looks N levels above itself diff --git a/akka-actor/src/main/scala/akka/util/Unsafe.java b/akka-actor/src/main/scala/akka/util/Unsafe.java index 608cb3d46e..ace3c1baac 100644 --- a/akka-actor/src/main/scala/akka/util/Unsafe.java +++ b/akka-actor/src/main/scala/akka/util/Unsafe.java @@ -7,6 +7,9 @@ package akka.util; import java.lang.reflect.Field; +/** + * INTERNAL API + */ public final class Unsafe { public final static sun.misc.Unsafe instance; static { diff --git a/akka-actor/src/main/scala/akka/util/cps/package.scala b/akka-actor/src/main/scala/akka/util/cps/package.scala index 198c2beacd..a1b4bc39eb 100644 --- a/akka-actor/src/main/scala/akka/util/cps/package.scala +++ b/akka-actor/src/main/scala/akka/util/cps/package.scala @@ -7,6 +7,7 @@ package akka.util import scala.util.continuations._ import akka.dispatch.MessageDispatcher +//FIXME Needs docs package object cps { def matchC[A, B, C, D](in: A)(pf: PartialFunction[A, B @cpsParam[C, D]]): B @cpsParam[C, D] = pf(in) diff --git a/akka-actor/src/main/scala/akka/util/duration/package.scala b/akka-actor/src/main/scala/akka/util/duration/package.scala index 7f14a0be48..6a7d28a6e6 100644 --- a/akka-actor/src/main/scala/akka/util/duration/package.scala +++ b/akka-actor/src/main/scala/akka/util/duration/package.scala @@ -5,7 +5,7 @@ package akka.util import java.util.concurrent.TimeUnit - +//FIXME Needs docs package object duration { trait Classifier[C] { type R @@ -15,38 +15,32 @@ package object duration { object span implicit object spanConvert extends Classifier[span.type] { type R = FiniteDuration - def convert(d: FiniteDuration) = d + def convert(d: FiniteDuration): FiniteDuration = d } object fromNow implicit object fromNowConvert extends Classifier[fromNow.type] { type R = Deadline - def convert(d: FiniteDuration) = Deadline.now + d + def convert(d: FiniteDuration): Deadline = Deadline.now + d } - implicit def intToDurationInt(n: Int) = new DurationInt(n) - implicit def longToDurationLong(n: Long) = new DurationLong(n) - implicit def doubleToDurationDouble(d: Double) = new DurationDouble(d) + implicit def intToDurationInt(n: Int): DurationInt = new DurationInt(n) + implicit def longToDurationLong(n: Long): DurationLong = new DurationLong(n) + implicit def doubleToDurationDouble(d: Double): DurationDouble = new DurationDouble(d) - implicit def pairIntToDuration(p: (Int, TimeUnit)) = Duration(p._1, p._2) - implicit def pairLongToDuration(p: (Long, TimeUnit)) = Duration(p._1, p._2) - implicit def durationToPair(d: Duration) = (d.length, d.unit) + implicit def pairIntToDuration(p: (Int, TimeUnit)): FiniteDuration = Duration(p._1, p._2) + implicit def pairLongToDuration(p: (Long, TimeUnit)): FiniteDuration = Duration(p._1, p._2) + implicit def durationToPair(d: Duration): (Long, TimeUnit) = (d.length, d.unit) /* * avoid reflection based invocation by using non-duck type */ - class IntMult(i: Int) { - def *(d: Duration) = d * i - } - implicit def intMult(i: Int) = new IntMult(i) + class IntMult(i: Int) { def *(d: Duration): Duration = d * i } + implicit def intMult(i: Int): IntMult = new IntMult(i) - class LongMult(l: Long) { - def *(d: Duration) = d * l - } - implicit def longMult(l: Long) = new LongMult(l) + class LongMult(l: Long) { def *(d: Duration): Duration = d * l } + implicit def longMult(l: Long): LongMult = new LongMult(l) - class DoubleMult(f: Double) { - def *(d: Duration) = d * f - } - implicit def doubleMult(f: Double) = new DoubleMult(f) + class DoubleMult(f: Double) { def *(d: Duration): Duration = d * f } + implicit def doubleMult(f: Double): DoubleMult = new DoubleMult(f) } diff --git a/akka-agent/src/main/scala/akka/agent/Agent.scala b/akka-agent/src/main/scala/akka/agent/Agent.scala index af551d00c8..64834178a8 100644 --- a/akka-agent/src/main/scala/akka/agent/Agent.scala +++ b/akka-agent/src/main/scala/akka/agent/Agent.scala @@ -96,18 +96,18 @@ object Agent { * }}} */ class Agent[T](initialValue: T, system: ActorSystem) { - private[akka] val ref = Ref(initialValue) - private[akka] val updater = system.actorOf(Props(new AgentUpdater(this))).asInstanceOf[LocalActorRef] //TODO can we avoid this somehow? + private val ref = Ref(initialValue) + private val updater = system.actorOf(Props(new AgentUpdater(this, ref))).asInstanceOf[LocalActorRef] //TODO can we avoid this somehow? /** * Read the internal state of the agent. */ - def get() = ref.single.get + def get(): T = ref.single.get /** * Read the internal state of the agent. */ - def apply() = get + def apply(): T = get /** * Dispatch a function to update the internal state. @@ -154,7 +154,7 @@ class Agent[T](initialValue: T, system: ActorSystem) { def sendOff(f: T ⇒ T): Unit = { send((value: T) ⇒ { suspend() - val threadBased = system.actorOf(Props(new ThreadBasedAgentUpdater(this)).withDispatcher("akka.agent.send-off-dispatcher")) + val threadBased = system.actorOf(Props(new ThreadBasedAgentUpdater(this, ref)).withDispatcher("akka.agent.send-off-dispatcher")) threadBased ! Update(f) value }) @@ -171,7 +171,7 @@ class Agent[T](initialValue: T, system: ActorSystem) { val result = Promise[T]()(system.dispatcher) send((value: T) ⇒ { suspend() - val threadBased = system.actorOf(Props(new ThreadBasedAgentUpdater(this)).withDispatcher("akka.agent.alter-off-dispatcher")) + val threadBased = system.actorOf(Props(new ThreadBasedAgentUpdater(this, ref)).withDispatcher("akka.agent.alter-off-dispatcher")) result completeWith ask(threadBased, Alter(f))(timeout).asInstanceOf[Future[T]] value }) @@ -209,18 +209,18 @@ class Agent[T](initialValue: T, system: ActorSystem) { /** * Suspends processing of `send` actions for the agent. */ - def suspend() = updater.suspend() + def suspend(): Unit = updater.suspend() /** * Resumes processing of `send` actions for the agent. */ - def resume() = updater.resume() + def resume(): Unit = updater.resume() /** * Closes the agents and makes it eligible for garbage collection. * A closed agent cannot accept any `send` actions. */ - def close() = updater.stop() + def close(): Unit = updater.stop() // --------------------------------------------- // Support for Java API Functions and Procedures @@ -281,8 +281,10 @@ class Agent[T](initialValue: T, system: ActorSystem) { /** * Agent updater actor. Used internally for `send` actions. + * + * INTERNAL API */ -class AgentUpdater[T](agent: Agent[T]) extends Actor { +private[akka] class AgentUpdater[T](agent: Agent[T], ref: Ref[T]) extends Actor { def receive = { case u: Update[_] ⇒ update(u.function.asInstanceOf[T ⇒ T]) case a: Alter[_] ⇒ sender ! update(a.function.asInstanceOf[T ⇒ T]) @@ -290,13 +292,15 @@ class AgentUpdater[T](agent: Agent[T]) extends Actor { case _ ⇒ } - def update(function: T ⇒ T): T = agent.ref.single.transformAndGet(function) + def update(function: T ⇒ T): T = ref.single.transformAndGet(function) } /** * Thread-based agent updater actor. Used internally for `sendOff` actions. + * + * INTERNAL API */ -class ThreadBasedAgentUpdater[T](agent: Agent[T]) extends Actor { +private[akka] class ThreadBasedAgentUpdater[T](agent: Agent[T], ref: Ref[T]) extends Actor { def receive = { case u: Update[_] ⇒ try { update(u.function.asInstanceOf[T ⇒ T]) @@ -313,5 +317,5 @@ class ThreadBasedAgentUpdater[T](agent: Agent[T]) extends Actor { case _ ⇒ context.stop(self) } - def update(function: T ⇒ T): T = agent.ref.single.transformAndGet(function) + def update(function: T ⇒ T): T = ref.single.transformAndGet(function) } diff --git a/akka-camel/src/main/scala/akka/camel/Activation.scala b/akka-camel/src/main/scala/akka/camel/Activation.scala index 56d116dca8..d01c990136 100644 --- a/akka-camel/src/main/scala/akka/camel/Activation.scala +++ b/akka-camel/src/main/scala/akka/camel/Activation.scala @@ -18,9 +18,9 @@ import akka.pattern._ trait Activation { import akka.dispatch.Await - def system: ActorSystem + def system: ActorSystem //FIXME Why is this here, what's it needed for and who should use it? - private val activationTracker = system.actorOf(Props[ActivationTracker], "camelActivationTracker") + private val activationTracker = system.actorOf(Props[ActivationTracker], "camelActivationTracker") //FIXME Why is this also top level? /** * Awaits for endpoint to be activated. It blocks until the endpoint is registered in camel context or timeout expires. @@ -29,13 +29,10 @@ trait Activation { * @throws akka.camel.ActivationTimeoutException if endpoint is not activated within timeout. * @return the activated ActorRef */ - def awaitActivation(endpoint: ActorRef, timeout: Duration): ActorRef = { - try { - Await.result(activationFutureFor(endpoint, timeout), timeout) - } catch { + def awaitActivation(endpoint: ActorRef, timeout: Duration): ActorRef = + try Await.result(activationFutureFor(endpoint, timeout), timeout) catch { case e: TimeoutException ⇒ throw new ActivationTimeoutException(endpoint, timeout) } - } /** * Awaits for endpoint to be de-activated. It is blocking until endpoint is unregistered in camel context or timeout expires. @@ -43,37 +40,32 @@ trait Activation { * @param timeout the timeout for the wait * @throws akka.camel.DeActivationTimeoutException if endpoint is not de-activated within timeout. */ - def awaitDeactivation(endpoint: ActorRef, timeout: Duration) { - try { - Await.result(deactivationFutureFor(endpoint, timeout), timeout) - } catch { + def awaitDeactivation(endpoint: ActorRef, timeout: Duration): Unit = + try Await.result(deactivationFutureFor(endpoint, timeout), timeout) catch { case e: TimeoutException ⇒ throw new DeActivationTimeoutException(endpoint, timeout) } - } /** * Similar to `awaitActivation` but returns a future instead. * @param endpoint the endpoint to be activated * @param timeout the timeout for the Future */ - def activationFutureFor(endpoint: ActorRef, timeout: Duration): Future[ActorRef] = { + def activationFutureFor(endpoint: ActorRef, timeout: Duration): Future[ActorRef] = (activationTracker.ask(AwaitActivation(endpoint))(Timeout(timeout))).map[ActorRef] { case EndpointActivated(_) ⇒ endpoint case EndpointFailedToActivate(_, cause) ⇒ throw cause } - } /** * Similar to awaitDeactivation but returns a future instead. * @param endpoint the endpoint to be deactivated * @param timeout the timeout of the Future */ - def deactivationFutureFor(endpoint: ActorRef, timeout: Duration): Future[Unit] = { + def deactivationFutureFor(endpoint: ActorRef, timeout: Duration): Future[Unit] = (activationTracker.ask(AwaitDeActivation(endpoint))(Timeout(timeout))).map[Unit] { case EndpointDeActivated(_) ⇒ () case EndpointFailedToDeActivate(_, cause) ⇒ throw cause } - } } /** @@ -82,7 +74,7 @@ trait Activation { * @param timeout the timeout */ class DeActivationTimeoutException(endpoint: ActorRef, timeout: Duration) extends TimeoutException { - override def getMessage = "Timed out after %s, while waiting for de-activation of %s" format (timeout, endpoint.path) + override def getMessage: String = "Timed out after %s, while waiting for de-activation of %s" format (timeout, endpoint.path) } /** @@ -91,5 +83,5 @@ class DeActivationTimeoutException(endpoint: ActorRef, timeout: Duration) extend * @param timeout the timeout */ class ActivationTimeoutException(endpoint: ActorRef, timeout: Duration) extends TimeoutException { - override def getMessage = "Timed out after %s, while waiting for activation of %s" format (timeout, endpoint.path) + override def getMessage: String = "Timed out after %s, while waiting for activation of %s" format (timeout, endpoint.path) } \ No newline at end of file diff --git a/akka-camel/src/main/scala/akka/camel/ActorNotRegisteredException.scala b/akka-camel/src/main/scala/akka/camel/ActorNotRegisteredException.scala index a468eeace5..7a303e47b3 100644 --- a/akka-camel/src/main/scala/akka/camel/ActorNotRegisteredException.scala +++ b/akka-camel/src/main/scala/akka/camel/ActorNotRegisteredException.scala @@ -6,5 +6,5 @@ package akka.camel * @author Martin Krasser */ class ActorNotRegisteredException(uri: String) extends RuntimeException { - override def getMessage = "Actor [%s] doesn't exist" format uri + override def getMessage: String = "Actor [%s] doesn't exist" format uri } diff --git a/akka-camel/src/main/scala/akka/camel/ActorRouteDefinition.scala b/akka-camel/src/main/scala/akka/camel/ActorRouteDefinition.scala index f5175b90eb..6286edad87 100644 --- a/akka-camel/src/main/scala/akka/camel/ActorRouteDefinition.scala +++ b/akka-camel/src/main/scala/akka/camel/ActorRouteDefinition.scala @@ -29,7 +29,8 @@ class ActorRouteDefinition(definition: ProcessorDefinition[_]) { * @param actorRef the consumer with a default configuration. * @return the path to the actor, as a camel uri String */ - def to(actorRef: ActorRef) = definition.to(ActorEndpointPath(actorRef).toCamelPath()) + def to(actorRef: ActorRef) = //FIXME What is the return type of this? + definition.to(ActorEndpointPath(actorRef).toCamelPath()) /** * Sends the message to an ActorRef endpoint @@ -37,6 +38,7 @@ class ActorRouteDefinition(definition: ProcessorDefinition[_]) { * @param consumerConfig the configuration for the consumer * @return the path to the actor, as a camel uri String */ - def to(actorRef: ActorRef, consumerConfig: ConsumerConfig) = definition.to(ActorEndpointPath(actorRef).toCamelPath(consumerConfig)) + def to(actorRef: ActorRef, consumerConfig: ConsumerConfig) = //FIXME What is the return type of this? + definition.to(ActorEndpointPath(actorRef).toCamelPath(consumerConfig)) } diff --git a/akka-camel/src/main/scala/akka/camel/Camel.scala b/akka-camel/src/main/scala/akka/camel/Camel.scala index 4e96f038e5..72252212cf 100644 --- a/akka-camel/src/main/scala/akka/camel/Camel.scala +++ b/akka-camel/src/main/scala/akka/camel/Camel.scala @@ -50,13 +50,13 @@ object CamelExtension extends ExtensionId[Camel] with ExtensionIdProvider { /** * Creates a new instance of Camel and makes sure it gets stopped when the actor system is shutdown. */ - def createExtension(system: ExtendedActorSystem) = { + override def createExtension(system: ExtendedActorSystem): Camel = { val camel = new DefaultCamel(system).start system.registerOnTermination(camel.shutdown()) camel } - def lookup(): ExtensionId[Camel] = CamelExtension + override def lookup(): ExtensionId[Camel] = CamelExtension override def get(system: ActorSystem): Camel = super.get(system) } \ No newline at end of file diff --git a/akka-camel/src/main/scala/akka/camel/CamelMessage.scala b/akka-camel/src/main/scala/akka/camel/CamelMessage.scala index 2ea046b856..4f617c83a4 100644 --- a/akka-camel/src/main/scala/akka/camel/CamelMessage.scala +++ b/akka-camel/src/main/scala/akka/camel/CamelMessage.scala @@ -21,12 +21,12 @@ case class CamelMessage(body: Any, headers: Map[String, Any]) { def this(body: Any, headers: JMap[String, Any]) = this(body, headers.toMap) //for Java - override def toString = "CamelMessage(%s, %s)" format (body, headers) + override def toString: String = "CamelMessage(%s, %s)" format (body, headers) /** * Returns those headers from this message whose name is contained in names. */ - def headers(names: Set[String]): Map[String, Any] = headers.filterKeys(names contains _) + def headers(names: Set[String]): Map[String, Any] = headers filterKeys names /** * Returns those headers from this message whose name is contained in names. @@ -75,7 +75,7 @@ case class CamelMessage(body: Any, headers: Map[String, Any]) { /** * Creates a CamelMessage with a given body. */ - def withBody(body: Any) = CamelMessage(body, this.headers) + def withBody(body: Any): CamelMessage = CamelMessage(body, this.headers) /** * Creates a new CamelMessage with given headers. @@ -119,9 +119,9 @@ case class CamelMessage(body: Any, headers: Map[String, Any]) { * Creates a new CamelMessage where the header with given headerName is removed from * the existing headers. */ - def withoutHeader(headerName: String) = copy(this.body, this.headers - headerName) + def withoutHeader(headerName: String): CamelMessage = copy(this.body, this.headers - headerName) - def copyContentTo(to: JCamelMessage) = { + def copyContentTo(to: JCamelMessage): Unit = { to.setBody(this.body) for ((name, value) ← this.headers) to.getHeaders.put(name, value.asInstanceOf[AnyRef]) } @@ -145,8 +145,7 @@ case class CamelMessage(body: Any, headers: Map[String, Any]) { * Java API * */ - def getBodyAs[T](clazz: Class[T], camelContext: CamelContext): T = - camelContext.getTypeConverter.mandatoryConvertTo[T](clazz, body) + def getBodyAs[T](clazz: Class[T], camelContext: CamelContext): T = camelContext.getTypeConverter.mandatoryConvertTo[T](clazz, body) /** * Creates a CamelMessage with current body converted to type T. @@ -184,7 +183,7 @@ case class CamelMessage(body: Any, headers: Map[String, Any]) { *

* Java API */ - def getHeaderAs[T](name: String, clazz: Class[T], camelContext: CamelContext) = headerAs[T](name)(Manifest.classType(clazz), camelContext).get + def getHeaderAs[T](name: String, clazz: Class[T], camelContext: CamelContext): T = headerAs[T](name)(Manifest.classType(clazz), camelContext).get } @@ -201,7 +200,7 @@ object CamelMessage { * so that it can be correlated with an asynchronous response. Messages send to Consumer * actors have this header already set. */ - val MessageExchangeId = "MessageExchangeId".intern + val MessageExchangeId = "MessageExchangeId".intern //Deliberately without type ascription to make it a constant /** * Creates a canonical form of the given message msg. If msg of type @@ -244,5 +243,7 @@ case object Ack { * message or Exchange.getOut message, depending on the exchange pattern. * */ -class AkkaCamelException private[akka] (cause: Throwable, val headers: Map[String, Any] = Map.empty) - extends AkkaException(cause.getMessage, cause) +class AkkaCamelException private[akka] (cause: Throwable, val headers: Map[String, Any]) + extends AkkaException(cause.getMessage, cause) { + def this(cause: Throwable) = this(cause, Map.empty) +} diff --git a/akka-camel/src/main/scala/akka/camel/Consumer.scala b/akka-camel/src/main/scala/akka/camel/Consumer.scala index 1d21ffbec7..0351ce39cb 100644 --- a/akka-camel/src/main/scala/akka/camel/Consumer.scala +++ b/akka-camel/src/main/scala/akka/camel/Consumer.scala @@ -31,7 +31,7 @@ trait ConsumerConfig { /** * How long the actor should wait for activation before it fails. */ - def activationTimeout: Duration = 10 seconds + def activationTimeout: Duration = 10 seconds // FIXME Should be configured in reference.conf /** * When endpoint is out-capable (can produce responses) replyTimeout is the maximum time @@ -39,14 +39,14 @@ trait ConsumerConfig { * This setting is used for out-capable, in-only, manually acknowledged communication. * When the blocking is set to Blocking replyTimeout is ignored. */ - def replyTimeout: Duration = 1 minute + def replyTimeout: Duration = 1 minute // FIXME Should be configured in reference.conf /** * Determines whether one-way communications between an endpoint and this consumer actor * should be auto-acknowledged or application-acknowledged. * This flag has only effect when exchange is in-only. */ - def autoack: Boolean = true + def autoack: Boolean = true // FIXME Should be configured in reference.conf /** * The route definition handler for creating a custom route to this consumer instance. diff --git a/akka-camel/src/main/scala/akka/camel/Producer.scala b/akka-camel/src/main/scala/akka/camel/Producer.scala index 80537fda12..5a7262a133 100644 --- a/akka-camel/src/main/scala/akka/camel/Producer.scala +++ b/akka-camel/src/main/scala/akka/camel/Producer.scala @@ -6,8 +6,9 @@ package akka.camel import akka.actor.Actor import internal.CamelExchangeAdapter -import org.apache.camel.{ Exchange, ExchangePattern, AsyncCallback } import akka.actor.Status.Failure +import org.apache.camel.{ Endpoint, Exchange, ExchangePattern, AsyncCallback } +import org.apache.camel.processor.SendProcessor /** * Support trait for producing messages to Camel endpoints. @@ -15,19 +16,19 @@ import akka.actor.Status.Failure * @author Martin Krasser */ trait ProducerSupport { this: Actor ⇒ - protected[this] implicit def camel = CamelExtension(context.system) + protected[this] implicit def camel = CamelExtension(context.system) // FIXME This is duplicated from Consumer, create a common base-trait? /** * camelContext implicit is useful when using advanced methods of CamelMessage. */ - protected[this] implicit def camelContext = camel.context + protected[this] implicit def camelContext = camel.context // FIXME This is duplicated from Consumer, create a common base-trait? - protected[this] lazy val (endpoint, processor) = camel.registerProducer(self, endpointUri) + protected[this] lazy val (endpoint: Endpoint, processor: SendProcessor) = camel.registerProducer(self, endpointUri) /** * CamelMessage headers to copy by default from request message to response-message. */ - private val headersToCopyDefault = Set(CamelMessage.MessageExchangeId) + private val headersToCopyDefault: Set[String] = Set(CamelMessage.MessageExchangeId) /** * If set to false (default), this producer expects a response message from the Camel endpoint. @@ -64,20 +65,21 @@ trait ProducerSupport { this: Actor ⇒ * @param pattern exchange pattern */ protected def produce(msg: Any, pattern: ExchangePattern): Unit = { - implicit def toExchangeAdapter(exchange: Exchange): CamelExchangeAdapter = new CamelExchangeAdapter(exchange) + // Need copies of sender reference here since the callback could be done + // later by another thread. + val producer = self + val originalSender = sender val cmsg = CamelMessage.canonicalize(msg) - val exchange = endpoint.createExchange(pattern) - exchange.setRequest(cmsg) - processor.process(exchange, new AsyncCallback { - val producer = self - // Need copies of sender reference here since the callback could be done - // later by another thread. - val originalSender = sender + val xchg = new CamelExchangeAdapter(endpoint.createExchange(pattern)) + + xchg.setRequest(cmsg) + + processor.process(xchg.exchange, new AsyncCallback { // Ignoring doneSync, sending back async uniformly. def done(doneSync: Boolean): Unit = producer.tell( - if (exchange.isFailed) exchange.toFailureResult(cmsg.headers(headersToCopy)) - else MessageResult(exchange.toResponseMessage(cmsg.headers(headersToCopy))), originalSender) + if (xchg.exchange.isFailed) xchg.toFailureResult(cmsg.headers(headersToCopy)) + else MessageResult(xchg.toResponseMessage(cmsg.headers(headersToCopy))), originalSender) }) } @@ -94,9 +96,7 @@ trait ProducerSupport { this: Actor ⇒ val e = new AkkaCamelException(res.cause, res.headers) routeResponse(Failure(e)) throw e - case msg ⇒ - val exchangePattern = if (oneway) ExchangePattern.InOnly else ExchangePattern.InOut - produce(transformOutgoingMessage(msg), exchangePattern) + case msg ⇒ produce(transformOutgoingMessage(msg), if (oneway) ExchangePattern.InOnly else ExchangePattern.InOut) } /** @@ -134,7 +134,7 @@ trait Producer extends ProducerSupport { this: Actor ⇒ * Default implementation of Actor.receive. Any messages received by this actors * will be produced to the endpoint specified by endpointUri. */ - protected def receive = produce + def receive: Actor.Receive = produce } /** @@ -153,6 +153,6 @@ private case class FailureResult(cause: Throwable, headers: Map[String, Any] = M * @author Martin Krasser */ trait Oneway extends Producer { this: Actor ⇒ - override def oneway = true + override def oneway: Boolean = true } diff --git a/akka-camel/src/main/scala/akka/camel/internal/ActivationMessage.scala b/akka-camel/src/main/scala/akka/camel/internal/ActivationMessage.scala index b8c3f42a47..bdd915ff70 100644 --- a/akka-camel/src/main/scala/akka/camel/internal/ActivationMessage.scala +++ b/akka-camel/src/main/scala/akka/camel/internal/ActivationMessage.scala @@ -20,7 +20,7 @@ private[camel] abstract class ActivationMessage(val actor: ActorRef) * */ private[camel] object ActivationMessage { - def unapply(msg: ActivationMessage): Option[ActorRef] = Some(msg.actor) + def unapply(msg: ActivationMessage): Option[ActorRef] = Option(msg.actor) } /** diff --git a/akka-camel/src/main/scala/akka/camel/internal/ActivationTracker.scala b/akka-camel/src/main/scala/akka/camel/internal/ActivationTracker.scala index 0b93460be0..f5a87eff25 100644 --- a/akka-camel/src/main/scala/akka/camel/internal/ActivationTracker.scala +++ b/akka-camel/src/main/scala/akka/camel/internal/ActivationTracker.scala @@ -96,17 +96,15 @@ private[akka] final class ActivationTracker extends Actor with ActorLogging { /** * Subscribes self to messages of type ActivationMessage */ - override def preStart() { - context.system.eventStream.subscribe(self, classOf[ActivationMessage]) - } + override def preStart(): Unit = context.system.eventStream.subscribe(self, classOf[ActivationMessage]) override def receive = { case msg @ ActivationMessage(ref) ⇒ - val state = activations.getOrElseUpdate(ref, new ActivationStateMachine) - (state.receive orElse logStateWarning(ref))(msg) + (activations.getOrElseUpdate(ref, new ActivationStateMachine).receive orElse logStateWarning(ref))(msg) } - private[this] def logStateWarning(actorRef: ActorRef): Receive = { case msg ⇒ log.warning("Message [{}] not expected in current state of actor [{}]", msg, actorRef) } + private[this] def logStateWarning(actorRef: ActorRef): Receive = + { case msg ⇒ log.warning("Message [{}] not expected in current state of actor [{}]", msg, actorRef) } } /** diff --git a/akka-camel/src/main/scala/akka/camel/internal/CamelExchangeAdapter.scala b/akka-camel/src/main/scala/akka/camel/internal/CamelExchangeAdapter.scala index 1f2d80e6df..5de9eb447d 100644 --- a/akka-camel/src/main/scala/akka/camel/internal/CamelExchangeAdapter.scala +++ b/akka-camel/src/main/scala/akka/camel/internal/CamelExchangeAdapter.scala @@ -16,34 +16,34 @@ import akka.camel.{ FailureResult, AkkaCamelException, CamelMessage } * * @author Martin Krasser */ -private[camel] class CamelExchangeAdapter(exchange: Exchange) { +private[camel] class CamelExchangeAdapter(val exchange: Exchange) { /** * Returns the exchange id */ - def getExchangeId = exchange.getExchangeId + def getExchangeId: String = exchange.getExchangeId /** * Returns if the exchange is out capable. */ - def isOutCapable = exchange.getPattern.isOutCapable + def isOutCapable: Boolean = exchange.getPattern.isOutCapable /** * Sets Exchange.getIn from the given CamelMessage object. */ - def setRequest(msg: CamelMessage) { msg.copyContentTo(request) } + def setRequest(msg: CamelMessage): Unit = msg.copyContentTo(request) /** * Depending on the exchange pattern, sets Exchange.getIn or Exchange.getOut from the given * CamelMessage object. If the exchange is out-capable then the Exchange.getOut is set, otherwise * Exchange.getIn. */ - def setResponse(msg: CamelMessage) { msg.copyContentTo(response) } + def setResponse(msg: CamelMessage): Unit = msg.copyContentTo(response) /** * Sets Exchange.getException from the given FailureResult message. Headers of the FailureResult message * are ignored. */ - def setFailure(msg: FailureResult) { exchange.setException(msg.cause) } + def setFailure(msg: FailureResult): Unit = exchange.setException(msg.cause) /** * Creates an immutable CamelMessage object from Exchange.getIn so it can be used with Actors. @@ -120,7 +120,7 @@ private[camel] class CamelExchangeAdapter(exchange: Exchange) { */ def toResponseMessage(headers: Map[String, Any]): CamelMessage = CamelMessage.from(response, headers) - private def request = exchange.getIn + private def request: JCamelMessage = exchange.getIn private def response: JCamelMessage = ExchangeHelper.getResultMessage(exchange) diff --git a/akka-camel/src/main/scala/akka/camel/internal/DefaultCamel.scala b/akka-camel/src/main/scala/akka/camel/internal/DefaultCamel.scala index 1754bb0073..2ac35fdec2 100644 --- a/akka-camel/src/main/scala/akka/camel/internal/DefaultCamel.scala +++ b/akka-camel/src/main/scala/akka/camel/internal/DefaultCamel.scala @@ -2,12 +2,12 @@ package akka.camel.internal import akka.actor.ActorSystem import component.{ DurationTypeConverter, ActorComponent } -import org.apache.camel.CamelContext import org.apache.camel.impl.DefaultCamelContext import scala.Predef._ import akka.event.Logging import akka.camel.Camel import akka.util.{ NonFatal, Duration } +import org.apache.camel.{ ProducerTemplate, CamelContext } /** * For internal use only. @@ -33,14 +33,14 @@ private[camel] class DefaultCamel(val system: ActorSystem) extends Camel { ctx } - lazy val template = context.createProducerTemplate() + lazy val template: ProducerTemplate = context.createProducerTemplate() /** * Starts camel and underlying camel context and template. * Only the creator of Camel should start and stop it. * @see akka.camel.DefaultCamel#stop() */ - def start = { + def start(): this.type = { context.start() try template.start() catch { case NonFatal(e) ⇒ context.stop(); throw e } log.debug("Started CamelContext[{}] for ActorSystem[{}]", context.getName, system.name) @@ -54,9 +54,9 @@ private[camel] class DefaultCamel(val system: ActorSystem) extends Camel { * * @see akka.camel.DefaultCamel#start() */ - def shutdown() { + def shutdown(): Unit = { try context.stop() finally { - try { template.stop() } catch { case NonFatal(e) ⇒ log.debug("Swallowing non-fatal exception [{}] on stopping Camel producer template", e) } + try template.stop() catch { case NonFatal(e) ⇒ log.debug("Swallowing non-fatal exception [{}] on stopping Camel producer template", e) } } log.debug("Stopped CamelContext[{}] for ActorSystem[{}]", context.getName, system.name) } diff --git a/akka-camel/src/main/scala/akka/camel/internal/ProducerRegistry.scala b/akka-camel/src/main/scala/akka/camel/internal/ProducerRegistry.scala index 03d130efe2..d338dbfdea 100644 --- a/akka-camel/src/main/scala/akka/camel/internal/ProducerRegistry.scala +++ b/akka-camel/src/main/scala/akka/camel/internal/ProducerRegistry.scala @@ -11,6 +11,8 @@ import akka.util.NonFatal * Watches the end of life of Producers. * Removes a Producer from the ProducerRegistry when it is Terminated, * which in turn stops the SendProcessor. + * + * INTERNAL API */ private class ProducerWatcher(registry: ProducerRegistry) extends Actor { override def receive = { @@ -19,6 +21,9 @@ private class ProducerWatcher(registry: ProducerRegistry) extends Actor { } } +/** + * INTERNAL API + */ private case class RegisterProducer(actorRef: ActorRef) /** @@ -27,14 +32,11 @@ private case class RegisterProducer(actorRef: ActorRef) * Every Producer needs an Endpoint and a SendProcessor * to produce messages over an Exchange. */ -private[camel] trait ProducerRegistry { - this: Camel ⇒ +private[camel] trait ProducerRegistry { this: Camel ⇒ private val camelObjects = new ConcurrentHashMap[ActorRef, (Endpoint, SendProcessor)]() - private val watcher = system.actorOf(Props(new ProducerWatcher(this))) + private val watcher = system.actorOf(Props(new ProducerWatcher(this))) //FIXME should this really be top level? - private def registerWatch(actorRef: ActorRef) { - watcher ! RegisterProducer(actorRef) - } + private def registerWatch(actorRef: ActorRef): Unit = watcher ! RegisterProducer(actorRef) /** * For internal use only. @@ -77,7 +79,7 @@ private[camel] trait ProducerRegistry { case NonFatal(e) ⇒ { system.eventStream.publish(EndpointFailedToActivate(actorRef, e)) // can't return null to the producer actor, so blow up actor in initialization. - throw e + throw e //FIXME I'm not a huge fan of log-rethrow, either log or rethrow } } } diff --git a/akka-camel/src/main/scala/akka/camel/internal/component/ActorComponent.scala b/akka-camel/src/main/scala/akka/camel/internal/component/ActorComponent.scala index 7ec5919dc9..d52f74f2f6 100644 --- a/akka-camel/src/main/scala/akka/camel/internal/component/ActorComponent.scala +++ b/akka-camel/src/main/scala/akka/camel/internal/component/ActorComponent.scala @@ -35,10 +35,8 @@ private[camel] class ActorComponent(camel: Camel) extends DefaultComponent { /** * @see org.apache.camel.Component */ - def createEndpoint(uri: String, remaining: String, parameters: JMap[String, Object]): ActorEndpoint = { - val path = ActorEndpointPath.fromCamelPath(remaining) - new ActorEndpoint(uri, this, path, camel) - } + def createEndpoint(uri: String, remaining: String, parameters: JMap[String, Object]): ActorEndpoint = + new ActorEndpoint(uri, this, ActorEndpointPath.fromCamelPath(remaining), camel) } /** @@ -92,7 +90,7 @@ private[camel] class ActorEndpoint(uri: String, private[camel] trait ActorEndpointConfig { def path: ActorEndpointPath - @BeanProperty var replyTimeout: Duration = 1 minute + @BeanProperty var replyTimeout: Duration = 1 minute // FIXME default should be in config, not code /** * Whether to auto-acknowledge one-way message exchanges with (untyped) actors. This is @@ -117,7 +115,7 @@ private[camel] class ActorProducer(val endpoint: ActorEndpoint, camel: Camel) ex * Calls the asynchronous version of the method and waits for the result (blocking). * @param exchange the exchange to process */ - def process(exchange: Exchange) { processExchangeAdapter(new CamelExchangeAdapter(exchange)) } + def process(exchange: Exchange): Unit = processExchangeAdapter(new CamelExchangeAdapter(exchange)) /** * Processes the message exchange. the caller supports having the exchange asynchronously processed. @@ -129,13 +127,15 @@ private[camel] class ActorProducer(val endpoint: ActorEndpoint, camel: Camel) ex * The callback should therefore be careful of starting recursive loop. * @return (doneSync) true to continue execute synchronously, false to continue being executed asynchronously */ - def process(exchange: Exchange, callback: AsyncCallback): Boolean = { processExchangeAdapter(new CamelExchangeAdapter(exchange), callback) } + def process(exchange: Exchange, callback: AsyncCallback): Boolean = processExchangeAdapter(new CamelExchangeAdapter(exchange), callback) /** * For internal use only. Processes the [[akka.camel.internal.CamelExchangeAdapter]] * @param exchange the [[akka.camel.internal.CamelExchangeAdapter]] + * + * WARNING UNBOUNDED BLOCKING AWAITS */ - private[camel] def processExchangeAdapter(exchange: CamelExchangeAdapter) { + private[camel] def processExchangeAdapter(exchange: CamelExchangeAdapter): Unit = { val isDone = new CountDownLatch(1) processExchangeAdapter(exchange, new AsyncCallback { def done(doneSync: Boolean) { isDone.countDown() } }) isDone.await() // this should never wait forever as the process(exchange, callback) method guarantees that. @@ -151,10 +151,10 @@ private[camel] class ActorProducer(val endpoint: ActorEndpoint, camel: Camel) ex private[camel] def processExchangeAdapter(exchange: CamelExchangeAdapter, callback: AsyncCallback): Boolean = { // these notify methods are just a syntax sugar - def notifyDoneSynchronously[A](a: A = null) = callback.done(true) - def notifyDoneAsynchronously[A](a: A = null) = callback.done(false) + def notifyDoneSynchronously[A](a: A = null): Unit = callback.done(true) + def notifyDoneAsynchronously[A](a: A = null): Unit = callback.done(false) - def message = messageFor(exchange) + def message: CamelMessage = messageFor(exchange) if (exchange.isOutCapable) { //InOut sendAsync(message, onComplete = forwardResponseTo(exchange) andThen notifyDoneAsynchronously) @@ -186,42 +186,41 @@ private[camel] class ActorProducer(val endpoint: ActorEndpoint, camel: Camel) ex private def sendAsync(message: CamelMessage, onComplete: PartialFunction[Either[Throwable, Any], Unit]): Boolean = { try { - val actor = actorFor(endpoint.path) - val future = actor.ask(message)(new Timeout(endpoint.replyTimeout)) - future.onComplete(onComplete) + actorFor(endpoint.path).ask(message)(Timeout(endpoint.replyTimeout)).onComplete(onComplete) } catch { case NonFatal(e) ⇒ onComplete(Left(e)) } false // Done async } - private def fireAndForget(message: CamelMessage, exchange: CamelExchangeAdapter) { - try { - actorFor(endpoint.path) ! message - } catch { - case e ⇒ exchange.setFailure(new FailureResult(e)) - } - } + private def fireAndForget(message: CamelMessage, exchange: CamelExchangeAdapter): Unit = + try { actorFor(endpoint.path) ! message } catch { case NonFatal(e) ⇒ exchange.setFailure(new FailureResult(e)) } private[this] def actorFor(path: ActorEndpointPath): ActorRef = path.findActorIn(camel.system) getOrElse (throw new ActorNotRegisteredException(path.actorPath)) private[this] def messageFor(exchange: CamelExchangeAdapter) = exchange.toRequestMessage(Map(CamelMessage.MessageExchangeId -> exchange.getExchangeId)) - } /** * For internal use only. Converts Strings to [[akka.util.Duration]]s */ private[camel] object DurationTypeConverter extends TypeConverter { - def convertTo[T](`type`: Class[T], value: AnyRef) = { - Duration(value.toString).asInstanceOf[T] + override def convertTo[T](`type`: Class[T], value: AnyRef): T = `type`.cast(try { + val d = Duration(value.toString) + if (`type`.isInstance(d)) d else null + } catch { + case NonFatal(_) ⇒ null + }) + + def convertTo[T](`type`: Class[T], exchange: Exchange, value: AnyRef): T = convertTo(`type`, value) + def mandatoryConvertTo[T](`type`: Class[T], value: AnyRef): T = convertTo(`type`, value) match { + case null ⇒ throw new NoTypeConversionAvailableException(value, `type`) + case some ⇒ some } - def convertTo[T](`type`: Class[T], exchange: Exchange, value: AnyRef) = convertTo(`type`, value) - def mandatoryConvertTo[T](`type`: Class[T], value: AnyRef) = convertTo(`type`, value) - def mandatoryConvertTo[T](`type`: Class[T], exchange: Exchange, value: AnyRef) = convertTo(`type`, value) - def toString(duration: Duration) = duration.toNanos + " nanos" + def mandatoryConvertTo[T](`type`: Class[T], exchange: Exchange, value: AnyRef): T = mandatoryConvertTo(`type`, value) + def toString(duration: Duration): String = duration.toNanos + " nanos" } /** @@ -243,15 +242,15 @@ private[camel] case class ActorEndpointPath private (actorPath: String) { * For internal use only. Companion of `ActorEndpointPath` */ private[camel] object ActorEndpointPath { - private val consumerConfig = new ConsumerConfig {} + private val consumerConfig: ConsumerConfig = new ConsumerConfig {} - def apply(actorRef: ActorRef) = new ActorEndpointPath(actorRef.path.toString) + def apply(actorRef: ActorRef): ActorEndpointPath = new ActorEndpointPath(actorRef.path.toString) /** * Creates an [[akka.camel.internal.component.ActorEndpointPath]] from the remaining part of the endpoint URI (the part after the scheme, without the parameters of the URI). * Expects the remaining part of the URI (the actor path) in a format: path:%s */ - def fromCamelPath(camelPath: String) = camelPath match { + def fromCamelPath(camelPath: String): ActorEndpointPath = camelPath match { case id if id startsWith "path:" ⇒ new ActorEndpointPath(id substring 5) case _ ⇒ throw new IllegalArgumentException("Invalid path: [%s] - should be path:" format camelPath) } diff --git a/akka-camel/src/main/scala/akka/camel/javaapi/UntypedConsumer.scala b/akka-camel/src/main/scala/akka/camel/javaapi/UntypedConsumer.scala index 56f11831d0..a4671583bb 100644 --- a/akka-camel/src/main/scala/akka/camel/javaapi/UntypedConsumer.scala +++ b/akka-camel/src/main/scala/akka/camel/javaapi/UntypedConsumer.scala @@ -13,7 +13,7 @@ import org.apache.camel.{ ProducerTemplate, CamelContext } * class is meant to be used from Java. */ abstract class UntypedConsumerActor extends UntypedActor with Consumer { - final def endpointUri = getEndpointUri + final def endpointUri: String = getEndpointUri /** * Returns the Camel endpoint URI to consume messages from. diff --git a/akka-camel/src/main/scala/akka/camel/javaapi/UntypedProducerActor.scala b/akka-camel/src/main/scala/akka/camel/javaapi/UntypedProducerActor.scala index c4d0a9c1a0..f44daf0725 100644 --- a/akka-camel/src/main/scala/akka/camel/javaapi/UntypedProducerActor.scala +++ b/akka-camel/src/main/scala/akka/camel/javaapi/UntypedProducerActor.scala @@ -40,16 +40,14 @@ abstract class UntypedProducerActor extends UntypedActor with ProducerSupport { final override def transformResponse(msg: Any): AnyRef = onTransformResponse(msg.asInstanceOf[AnyRef]) final override def routeResponse(msg: Any): Unit = onRouteResponse(msg.asInstanceOf[AnyRef]) - final override def endpointUri = getEndpointUri + final override def endpointUri: String = getEndpointUri - final override def oneway = isOneway + final override def oneway: Boolean = isOneway /** * Default implementation of UntypedActor.onReceive */ - def onReceive(message: Any) { - produce(message) - } + def onReceive(message: Any): Unit = produce(message) /** * Returns the Camel endpoint URI to produce messages to. @@ -61,7 +59,7 @@ abstract class UntypedProducerActor extends UntypedActor with ProducerSupport { * If set to true, this producer communicates with the Camel endpoint with an in-only message * exchange pattern (fire and forget). */ - def isOneway() = super.oneway + def isOneway(): Boolean = super.oneway /** * Returns the CamelContext. diff --git a/akka-camel/src/main/scala/akka/camelexamples/ExamplesSupport.scala b/akka-camel/src/main/scala/akka/camelexamples/ExamplesSupport.scala index 3e35b8c7c9..df5b0e5508 100644 --- a/akka-camel/src/main/scala/akka/camelexamples/ExamplesSupport.scala +++ b/akka-camel/src/main/scala/akka/camelexamples/ExamplesSupport.scala @@ -19,7 +19,7 @@ private[camelexamples] class SysOutConsumer extends Consumer { override def activationTimeout = 10 seconds def endpointUri = "file://data/input/CamelConsumer" - protected def receive = { + def receive = { case msg: CamelMessage ⇒ { printf("Received '%s'\n", msg.bodyAs[String]) } @@ -30,12 +30,12 @@ private[camelexamples] class TroubleMaker extends Consumer { def endpointUri = "WRONG URI" println("Trying to instantiate conumer with uri: " + endpointUri) - protected def receive = { case _ ⇒ } + def receive = { case _ ⇒ } } private[camelexamples] class SysOutActor(implicit camel: Camel) extends Actor { implicit val camelContext = camel.context - protected def receive = { + def receive = { case msg: CamelMessage ⇒ { printf("Received '%s'\n", msg.bodyAs[String]) } diff --git a/akka-camel/src/main/scala/akka/camelexamples/_2_SupervisedConsumers.scala b/akka-camel/src/main/scala/akka/camelexamples/_2_SupervisedConsumers.scala index 5d321b28db..cdf46f012f 100644 --- a/akka-camel/src/main/scala/akka/camelexamples/_2_SupervisedConsumers.scala +++ b/akka-camel/src/main/scala/akka/camelexamples/_2_SupervisedConsumers.scala @@ -14,7 +14,7 @@ private[camelexamples] object SupervisedConsumersExample extends App { system.actorOf(Props(new Actor { context.watch(context.actorOf(Props[EndpointManager])) - protected def receive = { + def receive = { case Terminated(ref) ⇒ system.shutdown() } })) @@ -30,7 +30,7 @@ private[camelexamples] class EndpointManager extends Actor { watch(actorOf(Props[SysOutConsumer])) watch(actorOf(Props[TroubleMaker])) - protected def receive = { + def receive = { case Terminated(ref) ⇒ { printf("Hey! One of the endpoints has died: %s. I am doing sepuku...\n", ref) self ! PoisonPill diff --git a/akka-camel/src/main/scala/akka/package.scala b/akka-camel/src/main/scala/akka/package.scala index 436d2fc1b3..d3e60ae24f 100644 --- a/akka-camel/src/main/scala/akka/package.scala +++ b/akka-camel/src/main/scala/akka/package.scala @@ -7,5 +7,12 @@ package akka import org.apache.camel.model.ProcessorDefinition package object camel { + /** + * To allow using Actors with the Camel Route DSL: + * + * {{{ + * from("file://data/input/CamelConsumer").to(actor) + * }}} + */ implicit def toActorRouteDefinition(definition: ProcessorDefinition[_]) = new ActorRouteDefinition(definition) } \ No newline at end of file diff --git a/akka-camel/src/test/scala/akka/camel/ProducerFeatureTest.scala b/akka-camel/src/test/scala/akka/camel/ProducerFeatureTest.scala index cef098b8fe..a7e5b9e4cb 100644 --- a/akka-camel/src/test/scala/akka/camel/ProducerFeatureTest.scala +++ b/akka-camel/src/test/scala/akka/camel/ProducerFeatureTest.scala @@ -244,7 +244,7 @@ object ProducerFeatureTest { } class TestResponder extends Actor { - protected def receive = { + def receive = { case msg: CamelMessage ⇒ msg.body match { case "fail" ⇒ context.sender ! akka.actor.Status.Failure(new AkkaCamelException(new Exception("failure"), msg.headers)) case _ ⇒ @@ -256,7 +256,7 @@ object ProducerFeatureTest { } class ReplyingForwardTarget extends Actor { - protected def receive = { + def receive = { case msg: CamelMessage ⇒ context.sender ! (msg.addHeader("test" -> "result")) case msg: akka.actor.Status.Failure ⇒ diff --git a/akka-camel/src/test/scala/akka/camel/internal/component/ActorProducerTest.scala b/akka-camel/src/test/scala/akka/camel/internal/component/ActorProducerTest.scala index 8146b17399..a0e153fd54 100644 --- a/akka-camel/src/test/scala/akka/camel/internal/component/ActorProducerTest.scala +++ b/akka-camel/src/test/scala/akka/camel/internal/component/ActorProducerTest.scala @@ -334,7 +334,7 @@ trait ActorProducerFixture extends MockitoSugar with BeforeAndAfterAll with Befo } def echoActor = system.actorOf(Props(new Actor { - protected def receive = { + def receive = { case msg ⇒ sender ! "received " + msg } })) diff --git a/akka-camel/src/test/scala/akka/camel/internal/component/DurationConverterTest.scala b/akka-camel/src/test/scala/akka/camel/internal/component/DurationConverterTest.scala index 3787a9f46f..53729a0b6f 100644 --- a/akka-camel/src/test/scala/akka/camel/internal/component/DurationConverterTest.scala +++ b/akka-camel/src/test/scala/akka/camel/internal/component/DurationConverterTest.scala @@ -8,8 +8,9 @@ import org.scalatest.matchers.MustMatchers import akka.util.duration._ import akka.util.Duration import org.scalatest.WordSpec +import org.apache.camel.NoTypeConversionAvailableException -class DurationConverterTest extends WordSpec with MustMatchers { +class DurationConverterSpec extends WordSpec with MustMatchers { import DurationTypeConverter._ "DurationTypeConverter must convert '10 nanos'" in { @@ -21,15 +22,19 @@ class DurationConverterTest extends WordSpec with MustMatchers { } "DurationTypeConverter must throw if invalid format" in { - intercept[Exception] { - convertTo(classOf[Duration], "abc nanos") must be(10 nanos) - } + convertTo(classOf[Duration], "abc nanos") must be === null + + intercept[NoTypeConversionAvailableException] { + mandatoryConvertTo(classOf[Duration], "abc nanos") must be(10 nanos) + }.getValue must be === "abc nanos" } - "DurationTypeConverter must throw if doesn't end with nanos" in { - intercept[Exception] { - convertTo(classOf[Duration], "10233") must be(10 nanos) - } + "DurationTypeConverter must throw if doesn't end with time unit" in { + convertTo(classOf[Duration], "10233") must be === null + + intercept[NoTypeConversionAvailableException] { + mandatoryConvertTo(classOf[Duration], "10233") must be(10 nanos) + }.getValue must be === "10233" } } diff --git a/akka-cluster/src/main/scala/akka/cluster/Cluster.scala b/akka-cluster/src/main/scala/akka/cluster/Cluster.scala index e3429cfdb3..76e3356143 100644 --- a/akka-cluster/src/main/scala/akka/cluster/Cluster.scala +++ b/akka-cluster/src/main/scala/akka/cluster/Cluster.scala @@ -13,7 +13,7 @@ import akka.dispatch.Await import akka.pattern.ask import akka.util._ import akka.util.duration._ -import akka.config.ConfigurationException +import akka.ConfigurationException import java.util.concurrent.atomic.{ AtomicReference, AtomicBoolean } import java.util.concurrent.TimeUnit._ diff --git a/akka-cluster/src/main/scala/akka/cluster/ClusterSettings.scala b/akka-cluster/src/main/scala/akka/cluster/ClusterSettings.scala index a24c75b436..8e9b9c770d 100644 --- a/akka-cluster/src/main/scala/akka/cluster/ClusterSettings.scala +++ b/akka-cluster/src/main/scala/akka/cluster/ClusterSettings.scala @@ -6,7 +6,7 @@ package akka.cluster import com.typesafe.config.Config import akka.util.Duration import java.util.concurrent.TimeUnit.MILLISECONDS -import akka.config.ConfigurationException +import akka.ConfigurationException import scala.collection.JavaConverters._ import akka.actor.Address import akka.actor.AddressFromURIString diff --git a/akka-cluster/src/multi-jvm/scala/akka/cluster/NodeStartupSpec.scala b/akka-cluster/src/multi-jvm/scala/akka/cluster/NodeStartupSpec.scala new file mode 100644 index 0000000000..694d4ac57d --- /dev/null +++ b/akka-cluster/src/multi-jvm/scala/akka/cluster/NodeStartupSpec.scala @@ -0,0 +1,91 @@ +/** + * Copyright (C) 2009-2012 Typesafe Inc. + */ +package akka.cluster + +import com.typesafe.config.ConfigFactory +import org.scalatest.BeforeAndAfter +import akka.remote.testkit.MultiNodeConfig +import akka.remote.testkit.MultiNodeSpec +import akka.testkit._ + +object NodeStartupMultiJvmSpec extends MultiNodeConfig { + val first = role("first") + val second = role("second") + + commonConfig(debugConfig(on = false)) + + nodeConfig(first, ConfigFactory.parseString(""" + # FIXME get rid of this hardcoded port + akka.remote.netty.port=2601 + """)) + + nodeConfig(second, ConfigFactory.parseString(""" + # FIXME get rid of this hardcoded host:port + akka.cluster.node-to-join = "akka://MultiNodeSpec@localhost:2601" + """)) + +} + +class NodeStartupMultiJvmNode1 extends NodeStartupSpec +class NodeStartupMultiJvmNode2 extends NodeStartupSpec + +class NodeStartupSpec extends MultiNodeSpec(NodeStartupMultiJvmSpec) with ImplicitSender with BeforeAndAfter { + import NodeStartupMultiJvmSpec._ + + override def initialParticipants = 2 + + var firstNode: Cluster = _ + + after { + testConductor.enter("after") + } + + runOn(first) { + firstNode = Cluster(system) + } + + "A first cluster node with a 'node-to-join' config set to empty string (singleton cluster)" must { + + "be a singleton cluster when started up" in { + runOn(first) { + awaitCond(firstNode.isSingletonCluster) + // FIXME #2117 singletonCluster should reach convergence + //awaitCond(firstNode.convergence.isDefined) + } + } + + "be in 'Joining' phase when started up" in { + runOn(first) { + val members = firstNode.latestGossip.members + members.size must be(1) + val firstAddress = testConductor.getAddressFor(first).await + val joiningMember = members find (_.address == firstAddress) + joiningMember must not be (None) + joiningMember.get.status must be(MemberStatus.Joining) + } + } + } + + "A second cluster node with a 'node-to-join' config defined" must { + "join the other node cluster when sending a Join command" in { + runOn(second) { + // start cluster on second node, and join + val secondNode = Cluster(system) + awaitCond(secondNode.convergence.isDefined) + } + + runOn(first) { + val secondAddress = testConductor.getAddressFor(second).await + awaitCond { + firstNode.latestGossip.members.exists { member ⇒ + member.address == secondAddress && member.status == MemberStatus.Up + } + } + firstNode.latestGossip.members.size must be(2) + awaitCond(firstNode.convergence.isDefined) + } + } + } + +} diff --git a/akka-cluster/src/test/scala/akka/cluster/NodeStartupSpec.scala b/akka-cluster/src/test/scala/akka/cluster/NodeStartupSpec.scala deleted file mode 100644 index 711a0552b4..0000000000 --- a/akka-cluster/src/test/scala/akka/cluster/NodeStartupSpec.scala +++ /dev/null @@ -1,84 +0,0 @@ -/** - * Copyright (C) 2009-2012 Typesafe Inc. - */ -package akka.cluster - -import java.net.InetSocketAddress - -import akka.testkit._ -import akka.dispatch._ -import akka.actor._ -import akka.remote._ -import akka.util.duration._ - -import com.typesafe.config._ - -class NodeStartupSpec extends ClusterSpec with ImplicitSender { - val portPrefix = 8 - - var node0: Cluster = _ - var node1: Cluster = _ - var system0: ActorSystemImpl = _ - var system1: ActorSystemImpl = _ - - try { - "A first cluster node with a 'node-to-join' config set to empty string (singleton cluster)" must { - system0 = ActorSystem("system0", ConfigFactory - .parseString(""" - akka { - actor.provider = "akka.remote.RemoteActorRefProvider" - remote.netty.port=%d550 - }""".format(portPrefix)) - .withFallback(system.settings.config)) - .asInstanceOf[ActorSystemImpl] - val remote0 = system0.provider.asInstanceOf[RemoteActorRefProvider] - node0 = Cluster(system0) - - "be a singleton cluster when started up" taggedAs LongRunningTest in { - Thread.sleep(1.seconds.dilated.toMillis) - node0.isSingletonCluster must be(true) - } - - "be in 'Joining' phase when started up" taggedAs LongRunningTest in { - val members = node0.latestGossip.members - val joiningMember = members find (_.address.port.get == 550.withPortPrefix) - joiningMember must be('defined) - joiningMember.get.status must be(MemberStatus.Joining) - } - } - - "A second cluster node with a 'node-to-join' config defined" must { - "join the other node cluster when sending a Join command" taggedAs LongRunningTest in { - system1 = ActorSystem("system1", ConfigFactory - .parseString(""" - akka { - actor.provider = "akka.remote.RemoteActorRefProvider" - remote.netty.port=%d551 - cluster.node-to-join = "akka://system0@localhost:%d550" - }""".format(portPrefix, portPrefix)) - .withFallback(system.settings.config)) - .asInstanceOf[ActorSystemImpl] - val remote1 = system1.provider.asInstanceOf[RemoteActorRefProvider] - node1 = Cluster(system1) - - Thread.sleep(10.seconds.dilated.toMillis) // give enough time for node1 to JOIN node0 and leader to move him to UP - val members = node0.latestGossip.members - val joiningMember = members find (_.address.port.get == 551.withPortPrefix) - joiningMember must be('defined) - joiningMember.get.status must be(MemberStatus.Up) - } - } - } catch { - case e: Exception ⇒ - e.printStackTrace - fail(e.toString) - } - - override def atTermination() { - if (node0 ne null) node0.shutdown() - if (system0 ne null) system0.shutdown() - - if (node1 ne null) node1.shutdown() - if (system1 ne null) system1.shutdown() - } -} diff --git a/akka-docs/_sphinx/static/akka-intellij-code-style.jar b/akka-docs/_sphinx/static/akka-intellij-code-style.jar deleted file mode 100644 index 55866c22c5..0000000000 Binary files a/akka-docs/_sphinx/static/akka-intellij-code-style.jar and /dev/null differ diff --git a/akka-docs/dev/multi-jvm-testing.rst b/akka-docs/dev/multi-jvm-testing.rst index 16271c5390..0ba053d2a4 100644 --- a/akka-docs/dev/multi-jvm-testing.rst +++ b/akka-docs/dev/multi-jvm-testing.rst @@ -334,3 +334,10 @@ same machine at the same time. The machines that are used for testing (slaves) should have ssh access to the outside world and be able to talk to each other with the internal addresses given. On the master machine ssh client is required. Obviosly git and sbt should be installed on both master and slave machines. + +The Test Conductor Extension +============================ + +The Test Conductor Extension is aimed at enhancing the multi JVM and multi node testing facilities. + +.. image:: ../images/akka-remote-testconductor.png diff --git a/akka-docs/general/actor-systems.rst b/akka-docs/general/actor-systems.rst index 2051f2d845..1b7d6a7759 100644 --- a/akka-docs/general/actor-systems.rst +++ b/akka-docs/general/actor-systems.rst @@ -14,6 +14,11 @@ which means that we need not concern ourselves with their emotional state or moral issues). The result can then serve as a mental scaffolding for building the software implementation. +.. note:: + + An ActorSystem is a heavyweight structure that will allocate 1…N Threads, + so create one per logical application. + Hierarchical Structure ---------------------- diff --git a/akka-docs/general/code/akka/docs/config/ConfigDoc.java b/akka-docs/general/code/docs/config/ConfigDoc.java similarity index 97% rename from akka-docs/general/code/akka/docs/config/ConfigDoc.java rename to akka-docs/general/code/docs/config/ConfigDoc.java index 69d856947f..ee6393fb1a 100644 --- a/akka-docs/general/code/akka/docs/config/ConfigDoc.java +++ b/akka-docs/general/code/docs/config/ConfigDoc.java @@ -1,7 +1,7 @@ /** * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.config; +package docs.config; import akka.actor.ActorSystem; import com.typesafe.config.*; diff --git a/akka-docs/general/code/akka/docs/config/ConfigDocSpec.scala b/akka-docs/general/code/docs/config/ConfigDocSpec.scala similarity index 97% rename from akka-docs/general/code/akka/docs/config/ConfigDocSpec.scala rename to akka-docs/general/code/docs/config/ConfigDocSpec.scala index 3b7cb10ed2..643116e14f 100644 --- a/akka-docs/general/code/akka/docs/config/ConfigDocSpec.scala +++ b/akka-docs/general/code/docs/config/ConfigDocSpec.scala @@ -1,7 +1,7 @@ /** * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.config +package docs.config import org.scalatest.WordSpec import org.scalatest.matchers.MustMatchers diff --git a/akka-docs/images/akka-remote-testconductor.png b/akka-docs/images/akka-remote-testconductor.png new file mode 100644 index 0000000000..b213538326 Binary files /dev/null and b/akka-docs/images/akka-remote-testconductor.png differ diff --git a/akka-docs/java/code/akka/docs/serialization/SerializationDocTestBase.java b/akka-docs/java/code/akka/docs/serialization/SerializationDocTestBase.java deleted file mode 100644 index aa24c92249..0000000000 --- a/akka-docs/java/code/akka/docs/serialization/SerializationDocTestBase.java +++ /dev/null @@ -1,109 +0,0 @@ -/** - * Copyright (C) 2009-2012 Typesafe Inc. - */ -package akka.docs.serialization; - -import org.junit.Test; -import static org.junit.Assert.*; -//#imports -import akka.actor.*; -import akka.serialization.*; -import com.typesafe.config.*; - -//#imports - -public class SerializationDocTestBase { - //#my-own-serializer - public static class MyOwnSerializer extends JSerializer { - - // This is whether "fromBinary" requires a "clazz" or not - @Override public boolean includeManifest() { - return false; - } - - // Pick a unique identifier for your Serializer, - // you've got a couple of billions to choose from, - // 0 - 16 is reserved by Akka itself - @Override public int identifier() { - return 1234567; - } - - // "toBinary" serializes the given object to an Array of Bytes - @Override public byte[] toBinary(Object obj) { - // Put the code that serializes the object here - //#... - return new byte[0]; - //#... - } - - // "fromBinary" deserializes the given array, - // using the type hint (if any, see "includeManifest" above) - @Override public Object fromBinaryJava(byte[] bytes, - Class clazz) { - // Put your code that deserializes here - //#... - return null; - //#... - } - } -//#my-own-serializer - - @Test public void serializeActorRefs() { - final ActorSystem theActorSystem = - ActorSystem.create("whatever"); - final ActorRef theActorRef = - theActorSystem.deadLetters(); // Of course this should be you - - //#actorref-serializer - // Serialize - // (beneath toBinary) - final Address transportAddress = - Serialization.currentTransportAddress().value(); - String identifier; - - // If there is no transportAddress, - // it means that either this Serializer isn't called - // within a piece of code that sets it, - // so either you need to supply your own, - // or simply use the local path. - if (transportAddress == null) identifier = theActorRef.path().toString(); - else identifier = theActorRef.path().toStringWithAddress(transportAddress); - // Then just serialize the identifier however you like - - - // Deserialize - // (beneath fromBinary) - final ActorRef deserializedActorRef = theActorSystem.actorFor(identifier); - // Then just use the ActorRef - //#actorref-serializer - theActorSystem.shutdown(); - } - - - @Test public void demonstrateTheProgrammaticAPI() { - //#programmatic - ActorSystem system = ActorSystem.create("example"); - - // Get the Serialization Extension - Serialization serialization = SerializationExtension.get(system); - - // Have something to serialize - String original = "woohoo"; - - // Find the Serializer for it - Serializer serializer = serialization.findSerializerFor(original); - - // Turn it into bytes - byte[] bytes = serializer.toBinary(original); - - // Turn it back into an object, - // the nulls are for the class manifest and for the classloader - String back = (String)serializer.fromBinary(bytes); - - // Voilá! - assertEquals(original, back); - - //#programmatic - system.shutdown(); - } -} diff --git a/akka-docs/java/code/akka/docs/actor/FSMDocTest.scala b/akka-docs/java/code/docs/actor/FSMDocTest.scala similarity index 87% rename from akka-docs/java/code/akka/docs/actor/FSMDocTest.scala rename to akka-docs/java/code/docs/actor/FSMDocTest.scala index 11bb542808..7077365d6d 100644 --- a/akka-docs/java/code/akka/docs/actor/FSMDocTest.scala +++ b/akka-docs/java/code/docs/actor/FSMDocTest.scala @@ -1,7 +1,7 @@ /** * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.actor +package docs.actor import org.scalatest.junit.JUnitSuite diff --git a/akka-docs/java/code/akka/docs/actor/FSMDocTestBase.java b/akka-docs/java/code/docs/actor/FSMDocTestBase.java similarity index 99% rename from akka-docs/java/code/akka/docs/actor/FSMDocTestBase.java rename to akka-docs/java/code/docs/actor/FSMDocTestBase.java index aeaca63f92..9064833cb0 100644 --- a/akka-docs/java/code/akka/docs/actor/FSMDocTestBase.java +++ b/akka-docs/java/code/docs/actor/FSMDocTestBase.java @@ -1,7 +1,7 @@ /** * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.actor; +package docs.actor; //#imports-data import java.util.ArrayList; diff --git a/akka-docs/java/code/akka/docs/actor/FaultHandlingTest.scala b/akka-docs/java/code/docs/actor/FaultHandlingTest.scala similarity index 88% rename from akka-docs/java/code/akka/docs/actor/FaultHandlingTest.scala rename to akka-docs/java/code/docs/actor/FaultHandlingTest.scala index 03802d6968..9b6fad0609 100644 --- a/akka-docs/java/code/akka/docs/actor/FaultHandlingTest.scala +++ b/akka-docs/java/code/docs/actor/FaultHandlingTest.scala @@ -1,7 +1,7 @@ /** * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.actor +package docs.actor import org.scalatest.junit.JUnitSuite class FaultHandlingTest extends FaultHandlingTestBase with JUnitSuite diff --git a/akka-docs/java/code/akka/docs/actor/FaultHandlingTestBase.java b/akka-docs/java/code/docs/actor/FaultHandlingTestBase.java similarity index 99% rename from akka-docs/java/code/akka/docs/actor/FaultHandlingTestBase.java rename to akka-docs/java/code/docs/actor/FaultHandlingTestBase.java index dc2ce9bae7..bcc4705948 100644 --- a/akka-docs/java/code/akka/docs/actor/FaultHandlingTestBase.java +++ b/akka-docs/java/code/docs/actor/FaultHandlingTestBase.java @@ -1,7 +1,7 @@ /** * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.actor; +package docs.actor; //#testkit import akka.actor.ActorRef; diff --git a/akka-docs/java/code/akka/docs/actor/FirstUntypedActor.java b/akka-docs/java/code/docs/actor/FirstUntypedActor.java similarity index 95% rename from akka-docs/java/code/akka/docs/actor/FirstUntypedActor.java rename to akka-docs/java/code/docs/actor/FirstUntypedActor.java index 6cfbe75b99..fa5d3d35a0 100644 --- a/akka-docs/java/code/akka/docs/actor/FirstUntypedActor.java +++ b/akka-docs/java/code/docs/actor/FirstUntypedActor.java @@ -1,7 +1,7 @@ /** * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.actor; +package docs.actor; import akka.actor.ActorRef; import akka.actor.Props; diff --git a/akka-docs/java/code/akka/docs/actor/ImmutableMessage.java b/akka-docs/java/code/docs/actor/ImmutableMessage.java similarity index 96% rename from akka-docs/java/code/akka/docs/actor/ImmutableMessage.java rename to akka-docs/java/code/docs/actor/ImmutableMessage.java index 41bc4eb0e5..60e72ecfb5 100644 --- a/akka-docs/java/code/akka/docs/actor/ImmutableMessage.java +++ b/akka-docs/java/code/docs/actor/ImmutableMessage.java @@ -1,7 +1,7 @@ /** * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.actor; +package docs.actor; import java.util.ArrayList; import java.util.Collections; diff --git a/akka-docs/java/code/akka/docs/actor/MyReceivedTimeoutUntypedActor.java b/akka-docs/java/code/docs/actor/MyReceivedTimeoutUntypedActor.java similarity index 96% rename from akka-docs/java/code/akka/docs/actor/MyReceivedTimeoutUntypedActor.java rename to akka-docs/java/code/docs/actor/MyReceivedTimeoutUntypedActor.java index 97742d9bd1..025d634b09 100644 --- a/akka-docs/java/code/akka/docs/actor/MyReceivedTimeoutUntypedActor.java +++ b/akka-docs/java/code/docs/actor/MyReceivedTimeoutUntypedActor.java @@ -1,7 +1,7 @@ /** * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.actor; +package docs.actor; //#receive-timeout import akka.actor.ReceiveTimeout; diff --git a/akka-docs/java/code/akka/docs/actor/MyUntypedActor.java b/akka-docs/java/code/docs/actor/MyUntypedActor.java similarity index 95% rename from akka-docs/java/code/akka/docs/actor/MyUntypedActor.java rename to akka-docs/java/code/docs/actor/MyUntypedActor.java index 93a817ef2c..f31fc402c7 100644 --- a/akka-docs/java/code/akka/docs/actor/MyUntypedActor.java +++ b/akka-docs/java/code/docs/actor/MyUntypedActor.java @@ -1,7 +1,7 @@ /** * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.actor; +package docs.actor; //#my-untyped-actor import akka.actor.UntypedActor; diff --git a/akka-docs/java/code/akka/docs/actor/SchedulerDocTest.scala b/akka-docs/java/code/docs/actor/SchedulerDocTest.scala similarity index 88% rename from akka-docs/java/code/akka/docs/actor/SchedulerDocTest.scala rename to akka-docs/java/code/docs/actor/SchedulerDocTest.scala index ecad03213e..9e6b4c9613 100644 --- a/akka-docs/java/code/akka/docs/actor/SchedulerDocTest.scala +++ b/akka-docs/java/code/docs/actor/SchedulerDocTest.scala @@ -1,7 +1,7 @@ /** * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.actor +package docs.actor import org.scalatest.junit.JUnitSuite diff --git a/akka-docs/java/code/akka/docs/actor/SchedulerDocTestBase.java b/akka-docs/java/code/docs/actor/SchedulerDocTestBase.java similarity index 98% rename from akka-docs/java/code/akka/docs/actor/SchedulerDocTestBase.java rename to akka-docs/java/code/docs/actor/SchedulerDocTestBase.java index 7a58da0f5e..d7e8fa644f 100644 --- a/akka-docs/java/code/akka/docs/actor/SchedulerDocTestBase.java +++ b/akka-docs/java/code/docs/actor/SchedulerDocTestBase.java @@ -1,7 +1,7 @@ /** * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.actor; +package docs.actor; //#imports1 import akka.actor.Props; diff --git a/akka-docs/java/code/akka/docs/actor/TypedActorDocTest.scala b/akka-docs/java/code/docs/actor/TypedActorDocTest.scala similarity index 88% rename from akka-docs/java/code/akka/docs/actor/TypedActorDocTest.scala rename to akka-docs/java/code/docs/actor/TypedActorDocTest.scala index 476d570b4a..0d9796ca56 100644 --- a/akka-docs/java/code/akka/docs/actor/TypedActorDocTest.scala +++ b/akka-docs/java/code/docs/actor/TypedActorDocTest.scala @@ -1,7 +1,7 @@ /** * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.actor +package docs.actor import org.scalatest.junit.JUnitSuite diff --git a/akka-docs/java/code/akka/docs/actor/TypedActorDocTestBase.java b/akka-docs/java/code/docs/actor/TypedActorDocTestBase.java similarity index 99% rename from akka-docs/java/code/akka/docs/actor/TypedActorDocTestBase.java rename to akka-docs/java/code/docs/actor/TypedActorDocTestBase.java index 30db92ee0f..99dda513ab 100644 --- a/akka-docs/java/code/akka/docs/actor/TypedActorDocTestBase.java +++ b/akka-docs/java/code/docs/actor/TypedActorDocTestBase.java @@ -1,7 +1,7 @@ /** * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.actor; +package docs.actor; //#imports diff --git a/akka-docs/java/code/akka/docs/actor/UntypedActorDocTest.scala b/akka-docs/java/code/docs/actor/UntypedActorDocTest.scala similarity index 88% rename from akka-docs/java/code/akka/docs/actor/UntypedActorDocTest.scala rename to akka-docs/java/code/docs/actor/UntypedActorDocTest.scala index e341914c8c..8047b94df9 100644 --- a/akka-docs/java/code/akka/docs/actor/UntypedActorDocTest.scala +++ b/akka-docs/java/code/docs/actor/UntypedActorDocTest.scala @@ -1,7 +1,7 @@ /** * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.actor +package docs.actor import org.scalatest.junit.JUnitSuite diff --git a/akka-docs/java/code/akka/docs/actor/UntypedActorDocTestBase.java b/akka-docs/java/code/docs/actor/UntypedActorDocTestBase.java similarity index 98% rename from akka-docs/java/code/akka/docs/actor/UntypedActorDocTestBase.java rename to akka-docs/java/code/docs/actor/UntypedActorDocTestBase.java index 65ff37c10e..c82ce30661 100644 --- a/akka-docs/java/code/akka/docs/actor/UntypedActorDocTestBase.java +++ b/akka-docs/java/code/docs/actor/UntypedActorDocTestBase.java @@ -1,7 +1,7 @@ /** * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.actor; +package docs.actor; //#imports import akka.actor.ActorRef; @@ -36,7 +36,7 @@ import static akka.pattern.Patterns.gracefulStop; import akka.dispatch.Future; import akka.dispatch.Await; import akka.util.Duration; -import akka.actor.ActorTimeoutException; +import akka.pattern.AskTimeoutException; //#import-gracefulStop //#import-askPipe @@ -207,7 +207,7 @@ public class UntypedActorDocTestBase { Future stopped = gracefulStop(actorRef, Duration.create(5, TimeUnit.SECONDS), system); Await.result(stopped, Duration.create(6, TimeUnit.SECONDS)); // the actor has been stopped - } catch (ActorTimeoutException e) { + } catch (AskTimeoutException e) { // the actor wasn't stopped within 5 seconds } //#gracefulStop diff --git a/akka-docs/java/code/akka/docs/actor/UntypedActorSwapper.java b/akka-docs/java/code/docs/actor/UntypedActorSwapper.java similarity index 93% rename from akka-docs/java/code/akka/docs/actor/UntypedActorSwapper.java rename to akka-docs/java/code/docs/actor/UntypedActorSwapper.java index b2fb98c305..985c75bfd7 100644 --- a/akka-docs/java/code/akka/docs/actor/UntypedActorSwapper.java +++ b/akka-docs/java/code/docs/actor/UntypedActorSwapper.java @@ -1,9 +1,9 @@ /** * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.actor; +package docs.actor; -import static akka.docs.actor.UntypedActorSwapper.Swap.SWAP; +import static docs.actor.UntypedActorSwapper.Swap.SWAP; import akka.actor.ActorRef; import akka.actor.Props; import akka.actor.ActorSystem; diff --git a/akka-docs/java/code/akka/docs/actor/japi/FaultHandlingDocSample.java b/akka-docs/java/code/docs/actor/japi/FaultHandlingDocSample.java similarity index 97% rename from akka-docs/java/code/akka/docs/actor/japi/FaultHandlingDocSample.java rename to akka-docs/java/code/docs/actor/japi/FaultHandlingDocSample.java index 4ba8358174..1213ab5949 100644 --- a/akka-docs/java/code/akka/docs/actor/japi/FaultHandlingDocSample.java +++ b/akka-docs/java/code/docs/actor/japi/FaultHandlingDocSample.java @@ -1,7 +1,7 @@ /** * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.actor.japi; +package docs.actor.japi; //#all //#imports @@ -26,10 +26,10 @@ import static akka.actor.SupervisorStrategy.*; import static akka.pattern.Patterns.ask; import static akka.pattern.Patterns.pipe; -import static akka.docs.actor.japi.FaultHandlingDocSample.WorkerApi.*; -import static akka.docs.actor.japi.FaultHandlingDocSample.CounterServiceApi.*; -import static akka.docs.actor.japi.FaultHandlingDocSample.CounterApi.*; -import static akka.docs.actor.japi.FaultHandlingDocSample.StorageApi.*; +import static docs.actor.japi.FaultHandlingDocSample.WorkerApi.*; +import static docs.actor.japi.FaultHandlingDocSample.CounterServiceApi.*; +import static docs.actor.japi.FaultHandlingDocSample.CounterApi.*; +import static docs.actor.japi.FaultHandlingDocSample.StorageApi.*; //#imports diff --git a/akka-docs/java/code/akka/docs/agent/AgentDocJavaSpec.scala b/akka-docs/java/code/docs/agent/AgentDocJavaSpec.scala similarity index 78% rename from akka-docs/java/code/akka/docs/agent/AgentDocJavaSpec.scala rename to akka-docs/java/code/docs/agent/AgentDocJavaSpec.scala index c3c0c296ed..566a439c62 100644 --- a/akka-docs/java/code/akka/docs/agent/AgentDocJavaSpec.scala +++ b/akka-docs/java/code/docs/agent/AgentDocJavaSpec.scala @@ -1,10 +1,10 @@ /** * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.agent +package docs.agent import org.scalatest.junit.JUnitWrapperSuite class AgentDocJavaSpec extends JUnitWrapperSuite( - "akka.docs.agent.AgentDocTest", + "docs.agent.AgentDocTest", Thread.currentThread.getContextClassLoader) \ No newline at end of file diff --git a/akka-docs/java/code/akka/docs/agent/AgentDocTest.java b/akka-docs/java/code/docs/agent/AgentDocTest.java similarity index 98% rename from akka-docs/java/code/akka/docs/agent/AgentDocTest.java rename to akka-docs/java/code/docs/agent/AgentDocTest.java index 553d64eee5..0da96ebfc9 100644 --- a/akka-docs/java/code/akka/docs/agent/AgentDocTest.java +++ b/akka-docs/java/code/docs/agent/AgentDocTest.java @@ -1,7 +1,7 @@ /** * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.agent; +package docs.agent; import static org.junit.Assert.*; diff --git a/akka-docs/java/code/akka/docs/dispatcher/DispatcherDocTest.scala b/akka-docs/java/code/docs/dispatcher/DispatcherDocTest.scala similarity index 86% rename from akka-docs/java/code/akka/docs/dispatcher/DispatcherDocTest.scala rename to akka-docs/java/code/docs/dispatcher/DispatcherDocTest.scala index 8216c36757..62c9e37051 100644 --- a/akka-docs/java/code/akka/docs/dispatcher/DispatcherDocTest.scala +++ b/akka-docs/java/code/docs/dispatcher/DispatcherDocTest.scala @@ -1,7 +1,7 @@ /** * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.dispatcher +package docs.dispatcher import org.scalatest.junit.JUnitSuite diff --git a/akka-docs/java/code/akka/docs/dispatcher/DispatcherDocTestBase.java b/akka-docs/java/code/docs/dispatcher/DispatcherDocTestBase.java similarity index 96% rename from akka-docs/java/code/akka/docs/dispatcher/DispatcherDocTestBase.java rename to akka-docs/java/code/docs/dispatcher/DispatcherDocTestBase.java index f080dd52b9..94e4b38121 100644 --- a/akka-docs/java/code/akka/docs/dispatcher/DispatcherDocTestBase.java +++ b/akka-docs/java/code/docs/dispatcher/DispatcherDocTestBase.java @@ -1,7 +1,7 @@ /** * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.dispatcher; +package docs.dispatcher; //#imports import akka.actor.*; @@ -32,8 +32,8 @@ import static org.junit.Assert.*; import com.typesafe.config.ConfigFactory; -import akka.docs.actor.MyUntypedActor; -import akka.docs.actor.UntypedActorDocTestBase.MyActor; +import docs.actor.MyUntypedActor; +import docs.actor.UntypedActorDocTestBase.MyActor; import akka.testkit.AkkaSpec; public class DispatcherDocTestBase { diff --git a/akka-docs/java/code/akka/docs/event/LoggingDocTest.scala b/akka-docs/java/code/docs/event/LoggingDocTest.scala similarity index 88% rename from akka-docs/java/code/akka/docs/event/LoggingDocTest.scala rename to akka-docs/java/code/docs/event/LoggingDocTest.scala index ee44f502a4..1d7f34827f 100644 --- a/akka-docs/java/code/akka/docs/event/LoggingDocTest.scala +++ b/akka-docs/java/code/docs/event/LoggingDocTest.scala @@ -1,7 +1,7 @@ /** * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.event +package docs.event import org.scalatest.junit.JUnitSuite diff --git a/akka-docs/java/code/akka/docs/event/LoggingDocTestBase.java b/akka-docs/java/code/docs/event/LoggingDocTestBase.java similarity index 99% rename from akka-docs/java/code/akka/docs/event/LoggingDocTestBase.java rename to akka-docs/java/code/docs/event/LoggingDocTestBase.java index 8f7b63d8a8..77e46b3f92 100644 --- a/akka-docs/java/code/akka/docs/event/LoggingDocTestBase.java +++ b/akka-docs/java/code/docs/event/LoggingDocTestBase.java @@ -1,7 +1,7 @@ /** * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.event; +package docs.event; //#imports import akka.event.Logging; diff --git a/akka-docs/java/code/akka/docs/extension/ExtensionDocTest.scala b/akka-docs/java/code/docs/extension/ExtensionDocTest.scala similarity index 86% rename from akka-docs/java/code/akka/docs/extension/ExtensionDocTest.scala rename to akka-docs/java/code/docs/extension/ExtensionDocTest.scala index 7b1b43b6ca..f22e300cfc 100644 --- a/akka-docs/java/code/akka/docs/extension/ExtensionDocTest.scala +++ b/akka-docs/java/code/docs/extension/ExtensionDocTest.scala @@ -1,7 +1,7 @@ /** * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.extension +package docs.extension import org.scalatest.junit.JUnitSuite diff --git a/akka-docs/java/code/akka/docs/extension/ExtensionDocTestBase.java b/akka-docs/java/code/docs/extension/ExtensionDocTestBase.java similarity index 98% rename from akka-docs/java/code/akka/docs/extension/ExtensionDocTestBase.java rename to akka-docs/java/code/docs/extension/ExtensionDocTestBase.java index 11dfe4c198..7623d1cc0a 100644 --- a/akka-docs/java/code/akka/docs/extension/ExtensionDocTestBase.java +++ b/akka-docs/java/code/docs/extension/ExtensionDocTestBase.java @@ -1,7 +1,7 @@ /** * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.extension; +package docs.extension; //#imports import akka.actor.*; diff --git a/akka-docs/java/code/akka/docs/extension/SettingsExtensionDocTest.scala b/akka-docs/java/code/docs/extension/SettingsExtensionDocTest.scala similarity index 87% rename from akka-docs/java/code/akka/docs/extension/SettingsExtensionDocTest.scala rename to akka-docs/java/code/docs/extension/SettingsExtensionDocTest.scala index 0979c00d4f..60289bfdca 100644 --- a/akka-docs/java/code/akka/docs/extension/SettingsExtensionDocTest.scala +++ b/akka-docs/java/code/docs/extension/SettingsExtensionDocTest.scala @@ -1,7 +1,7 @@ /** * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.extension +package docs.extension import org.scalatest.junit.JUnitSuite diff --git a/akka-docs/java/code/akka/docs/extension/SettingsExtensionDocTestBase.java b/akka-docs/java/code/docs/extension/SettingsExtensionDocTestBase.java similarity index 98% rename from akka-docs/java/code/akka/docs/extension/SettingsExtensionDocTestBase.java rename to akka-docs/java/code/docs/extension/SettingsExtensionDocTestBase.java index 9aef290ecb..265c91b206 100644 --- a/akka-docs/java/code/akka/docs/extension/SettingsExtensionDocTestBase.java +++ b/akka-docs/java/code/docs/extension/SettingsExtensionDocTestBase.java @@ -1,7 +1,7 @@ /** * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.extension; +package docs.extension; //#imports import akka.actor.Extension; diff --git a/akka-docs/java/code/akka/docs/future/FutureDocTest.scala b/akka-docs/java/code/docs/future/FutureDocTest.scala similarity index 87% rename from akka-docs/java/code/akka/docs/future/FutureDocTest.scala rename to akka-docs/java/code/docs/future/FutureDocTest.scala index 8716beeced..fef5f3d967 100644 --- a/akka-docs/java/code/akka/docs/future/FutureDocTest.scala +++ b/akka-docs/java/code/docs/future/FutureDocTest.scala @@ -1,7 +1,7 @@ /** * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.future +package docs.future import org.scalatest.junit.JUnitSuite diff --git a/akka-docs/java/code/akka/docs/future/FutureDocTestBase.java b/akka-docs/java/code/docs/future/FutureDocTestBase.java similarity index 99% rename from akka-docs/java/code/akka/docs/future/FutureDocTestBase.java rename to akka-docs/java/code/docs/future/FutureDocTestBase.java index d8e59f5d30..2fe2220223 100644 --- a/akka-docs/java/code/akka/docs/future/FutureDocTestBase.java +++ b/akka-docs/java/code/docs/future/FutureDocTestBase.java @@ -1,7 +1,7 @@ /** * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.future; +package docs.future; //#imports1 import akka.dispatch.*; diff --git a/akka-docs/java/code/akka/docs/jrouting/CustomRouterDocTest.scala b/akka-docs/java/code/docs/jrouting/CustomRouterDocTest.scala similarity index 80% rename from akka-docs/java/code/akka/docs/jrouting/CustomRouterDocTest.scala rename to akka-docs/java/code/docs/jrouting/CustomRouterDocTest.scala index 48e323c634..d11b07f22a 100644 --- a/akka-docs/java/code/akka/docs/jrouting/CustomRouterDocTest.scala +++ b/akka-docs/java/code/docs/jrouting/CustomRouterDocTest.scala @@ -1,4 +1,4 @@ -package akka.docs.jrouting; +package docs.jrouting; import org.scalatest.junit.JUnitSuite diff --git a/akka-docs/java/code/akka/docs/jrouting/CustomRouterDocTestBase.java b/akka-docs/java/code/docs/jrouting/CustomRouterDocTestBase.java similarity index 95% rename from akka-docs/java/code/akka/docs/jrouting/CustomRouterDocTestBase.java rename to akka-docs/java/code/docs/jrouting/CustomRouterDocTestBase.java index dc4d140ec3..74e7759b62 100644 --- a/akka-docs/java/code/akka/docs/jrouting/CustomRouterDocTestBase.java +++ b/akka-docs/java/code/docs/jrouting/CustomRouterDocTestBase.java @@ -1,7 +1,7 @@ /** * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.jrouting; +package docs.jrouting; import java.util.List; import java.util.Arrays; @@ -22,9 +22,9 @@ import akka.testkit.AkkaSpec; import com.typesafe.config.ConfigFactory; import static akka.pattern.Patterns.ask; -import static akka.docs.jrouting.CustomRouterDocTestBase.DemocratActor; -import static akka.docs.jrouting.CustomRouterDocTestBase.RepublicanActor; -import static akka.docs.jrouting.CustomRouterDocTestBase.Message.*; +import static docs.jrouting.CustomRouterDocTestBase.DemocratActor; +import static docs.jrouting.CustomRouterDocTestBase.RepublicanActor; +import static docs.jrouting.CustomRouterDocTestBase.Message.*; public class CustomRouterDocTestBase { diff --git a/akka-docs/java/code/akka/docs/jrouting/FibonacciActor.java b/akka-docs/java/code/docs/jrouting/FibonacciActor.java similarity index 97% rename from akka-docs/java/code/akka/docs/jrouting/FibonacciActor.java rename to akka-docs/java/code/docs/jrouting/FibonacciActor.java index 8e426cf8fe..e316f27bce 100644 --- a/akka-docs/java/code/akka/docs/jrouting/FibonacciActor.java +++ b/akka-docs/java/code/docs/jrouting/FibonacciActor.java @@ -1,7 +1,7 @@ /** * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.jrouting; +package docs.jrouting; import java.io.Serializable; diff --git a/akka-docs/java/code/akka/docs/jrouting/ParentActor.java b/akka-docs/java/code/docs/jrouting/ParentActor.java similarity index 98% rename from akka-docs/java/code/akka/docs/jrouting/ParentActor.java rename to akka-docs/java/code/docs/jrouting/ParentActor.java index 32a33b3a1b..ada9e92138 100644 --- a/akka-docs/java/code/akka/docs/jrouting/ParentActor.java +++ b/akka-docs/java/code/docs/jrouting/ParentActor.java @@ -1,7 +1,7 @@ /** * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.jrouting; +package docs.jrouting; import akka.routing.ScatterGatherFirstCompletedRouter; import akka.routing.BroadcastRouter; diff --git a/akka-docs/java/code/akka/docs/jrouting/PrintlnActor.java b/akka-docs/java/code/docs/jrouting/PrintlnActor.java similarity index 92% rename from akka-docs/java/code/akka/docs/jrouting/PrintlnActor.java rename to akka-docs/java/code/docs/jrouting/PrintlnActor.java index d6ad652ebe..adf56fe863 100644 --- a/akka-docs/java/code/akka/docs/jrouting/PrintlnActor.java +++ b/akka-docs/java/code/docs/jrouting/PrintlnActor.java @@ -1,7 +1,7 @@ /** * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.jrouting; +package docs.jrouting; import akka.actor.UntypedActor; diff --git a/akka-docs/java/code/akka/docs/jrouting/RouterViaConfigExample.java b/akka-docs/java/code/docs/jrouting/RouterViaConfigExample.java similarity index 98% rename from akka-docs/java/code/akka/docs/jrouting/RouterViaConfigExample.java rename to akka-docs/java/code/docs/jrouting/RouterViaConfigExample.java index 61b9a573d7..1505766196 100644 --- a/akka-docs/java/code/akka/docs/jrouting/RouterViaConfigExample.java +++ b/akka-docs/java/code/docs/jrouting/RouterViaConfigExample.java @@ -1,7 +1,7 @@ /** * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.jrouting; +package docs.jrouting; import akka.routing.FromConfig; import akka.actor.ActorRef; diff --git a/akka-docs/java/code/akka/docs/jrouting/RouterViaProgramExample.java b/akka-docs/java/code/docs/jrouting/RouterViaProgramExample.java similarity index 95% rename from akka-docs/java/code/akka/docs/jrouting/RouterViaProgramExample.java rename to akka-docs/java/code/docs/jrouting/RouterViaProgramExample.java index 44984c3ec7..72843b44c6 100644 --- a/akka-docs/java/code/akka/docs/jrouting/RouterViaProgramExample.java +++ b/akka-docs/java/code/docs/jrouting/RouterViaProgramExample.java @@ -1,7 +1,7 @@ /** * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.jrouting; +package docs.jrouting; import akka.routing.RoundRobinRouter; import akka.routing.DefaultResizer; @@ -55,7 +55,7 @@ public class RouterViaProgramExample { ActorRef actor2 = system.actorOf(new Props(ExampleActor.class)); ActorRef actor3 = system.actorOf(new Props(ExampleActor.class)); Iterable routees = Arrays.asList(new ActorRef[] { actor1, actor2, actor3 }); - ActorRef router2 = system.actorOf(new Props(ExampleActor.class).withRouter(RoundRobinRouter.create(routees))); + ActorRef router2 = system.actorOf(new Props().withRouter(RoundRobinRouter.create(routees))); //#programmaticRoutingRoutees for (int i = 1; i <= 6; i++) { router2.tell(new ExampleActor.Message(i)); diff --git a/akka-docs/java/code/akka/docs/remoting/RemoteActorExample.java b/akka-docs/java/code/docs/remoting/RemoteActorExample.java similarity index 95% rename from akka-docs/java/code/akka/docs/remoting/RemoteActorExample.java rename to akka-docs/java/code/docs/remoting/RemoteActorExample.java index f7686e744a..3ca25bd153 100644 --- a/akka-docs/java/code/akka/docs/remoting/RemoteActorExample.java +++ b/akka-docs/java/code/docs/remoting/RemoteActorExample.java @@ -1,7 +1,7 @@ /** * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.remoting; +package docs.remoting; import akka.actor.ActorRef; import akka.actor.UntypedActor; diff --git a/akka-docs/java/code/akka/docs/remoting/RemoteDeploymentDocTest.scala b/akka-docs/java/code/docs/remoting/RemoteDeploymentDocTest.scala similarity index 87% rename from akka-docs/java/code/akka/docs/remoting/RemoteDeploymentDocTest.scala rename to akka-docs/java/code/docs/remoting/RemoteDeploymentDocTest.scala index 9290b7c897..4ac46c4504 100644 --- a/akka-docs/java/code/akka/docs/remoting/RemoteDeploymentDocTest.scala +++ b/akka-docs/java/code/docs/remoting/RemoteDeploymentDocTest.scala @@ -1,7 +1,7 @@ /** * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.remoting +package docs.remoting import org.scalatest.junit.JUnitSuite diff --git a/akka-docs/java/code/akka/docs/remoting/RemoteDeploymentDocTestBase.java b/akka-docs/java/code/docs/remoting/RemoteDeploymentDocTestBase.java similarity index 97% rename from akka-docs/java/code/akka/docs/remoting/RemoteDeploymentDocTestBase.java rename to akka-docs/java/code/docs/remoting/RemoteDeploymentDocTestBase.java index b105e2b42a..cfb12ac7c4 100644 --- a/akka-docs/java/code/akka/docs/remoting/RemoteDeploymentDocTestBase.java +++ b/akka-docs/java/code/docs/remoting/RemoteDeploymentDocTestBase.java @@ -1,7 +1,7 @@ /** * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.remoting; +package docs.remoting; import org.junit.AfterClass; import org.junit.BeforeClass; diff --git a/akka-docs/java/code/akka/docs/serialization/SerializationDocTest.scala b/akka-docs/java/code/docs/serialization/SerializationDocTest.scala similarity index 85% rename from akka-docs/java/code/akka/docs/serialization/SerializationDocTest.scala rename to akka-docs/java/code/docs/serialization/SerializationDocTest.scala index 26685dea80..ffac606928 100644 --- a/akka-docs/java/code/akka/docs/serialization/SerializationDocTest.scala +++ b/akka-docs/java/code/docs/serialization/SerializationDocTest.scala @@ -1,7 +1,7 @@ /** * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.serialization +package docs.serialization import org.scalatest.junit.JUnitSuite diff --git a/akka-docs/java/code/docs/serialization/SerializationDocTestBase.java b/akka-docs/java/code/docs/serialization/SerializationDocTestBase.java new file mode 100644 index 0000000000..5d27e4f37f --- /dev/null +++ b/akka-docs/java/code/docs/serialization/SerializationDocTestBase.java @@ -0,0 +1,196 @@ +/** + * Copyright (C) 2009-2012 Typesafe Inc. + */ +package docs.serialization; + +import org.junit.Test; +import static org.junit.Assert.*; +//#imports +import akka.actor.*; +import akka.remote.RemoteActorRefProvider; +import akka.serialization.*; +import com.typesafe.config.*; + +//#imports + +public class SerializationDocTestBase { + //#my-own-serializer + public static class MyOwnSerializer extends JSerializer { + + // This is whether "fromBinary" requires a "clazz" or not + @Override public boolean includeManifest() { + return false; + } + + // Pick a unique identifier for your Serializer, + // you've got a couple of billions to choose from, + // 0 - 16 is reserved by Akka itself + @Override public int identifier() { + return 1234567; + } + + // "toBinary" serializes the given object to an Array of Bytes + @Override public byte[] toBinary(Object obj) { + // Put the code that serializes the object here + //#... + return new byte[0]; + //#... + } + + // "fromBinary" deserializes the given array, + // using the type hint (if any, see "includeManifest" above) + @Override public Object fromBinaryJava(byte[] bytes, + Class clazz) { + // Put your code that deserializes here + //#... + return null; + //#... + } + } +//#my-own-serializer + + @Test public void serializeActorRefs() { + final ActorSystem theActorSystem = + ActorSystem.create("whatever"); + final ActorRef theActorRef = + theActorSystem.deadLetters(); // Of course this should be you + + //#actorref-serializer + // Serialize + // (beneath toBinary) + final Address transportAddress = + Serialization.currentTransportAddress().value(); + String identifier; + + // If there is no transportAddress, + // it means that either this Serializer isn't called + // within a piece of code that sets it, + // so either you need to supply your own, + // or simply use the local path. + if (transportAddress == null) identifier = theActorRef.path().toString(); + else identifier = theActorRef.path().toStringWithAddress(transportAddress); + // Then just serialize the identifier however you like + + + // Deserialize + // (beneath fromBinary) + final ActorRef deserializedActorRef = theActorSystem.actorFor(identifier); + // Then just use the ActorRef + //#actorref-serializer + theActorSystem.shutdown(); + } + + //#external-address + public static class ExternalAddressExt implements Extension { + private final ExtendedActorSystem system; + + public ExternalAddressExt(ExtendedActorSystem system) { + this.system = system; + } + + public Address getAddressFor(Address remoteAddress) { + final scala.Option

optAddr = system.provider() + .getExternalAddressFor(remoteAddress); + if (optAddr.isDefined()) { + return optAddr.get(); + } else { + throw new UnsupportedOperationException( + "cannot send to remote address " + remoteAddress); + } + } + } + + public static class ExternalAddress extends + AbstractExtensionId implements ExtensionIdProvider { + public static final ExternalAddress ID = new ExternalAddress(); + + public ExternalAddress lookup() { + return ID; + } + + public ExternalAddressExt createExtension(ExtendedActorSystem system) { + return new ExternalAddressExt(system); + } + } + + //#external-address + + public void demonstrateExternalAddress() { + // this is not meant to be run, only to be compiled + final ActorSystem system = ActorSystem.create(); + final Address remoteAddr = new Address("", ""); + // #external-address + final Address addr = ExternalAddress.ID.get(system).getAddressFor(remoteAddr); + // #external-address + } + + //#external-address-default + public static class DefaultAddressExt implements Extension { + private final ExtendedActorSystem system; + + public DefaultAddressExt(ExtendedActorSystem system) { + this.system = system; + } + + public Address getAddress() { + final ActorRefProvider provider = system.provider(); + if (provider instanceof RemoteActorRefProvider) { + return ((RemoteActorRefProvider) provider).transport().address(); + } else { + throw new UnsupportedOperationException("need RemoteActorRefProvider"); + } + } + } + + public static class DefaultAddress extends + AbstractExtensionId implements ExtensionIdProvider { + public static final DefaultAddress ID = new DefaultAddress(); + + public DefaultAddress lookup() { + return ID; + } + + public DefaultAddressExt createExtension(ExtendedActorSystem system) { + return new DefaultAddressExt(system); + } + } + + //#external-address-default + + public void demonstrateDefaultAddress() { + // this is not meant to be run, only to be compiled + final ActorSystem system = ActorSystem.create(); + final Address remoteAddr = new Address("", ""); + // #external-address-default + final Address addr = DefaultAddress.ID.get(system).getAddress(); + // #external-address-default + } + + @Test + public void demonstrateTheProgrammaticAPI() { + // #programmatic + ActorSystem system = ActorSystem.create("example"); + + // Get the Serialization Extension + Serialization serialization = SerializationExtension.get(system); + + // Have something to serialize + String original = "woohoo"; + + // Find the Serializer for it + Serializer serializer = serialization.findSerializerFor(original); + + // Turn it into bytes + byte[] bytes = serializer.toBinary(original); + + // Turn it back into an object, + // the nulls are for the class manifest and for the classloader + String back = (String) serializer.fromBinary(bytes); + + // Voilá! + assertEquals(original, back); + + // #programmatic + system.shutdown(); + } +} diff --git a/akka-docs/java/code/akka/docs/transactor/CoordinatedCounter.java b/akka-docs/java/code/docs/transactor/CoordinatedCounter.java similarity index 97% rename from akka-docs/java/code/akka/docs/transactor/CoordinatedCounter.java rename to akka-docs/java/code/docs/transactor/CoordinatedCounter.java index dd7f119005..4bd679f1eb 100644 --- a/akka-docs/java/code/akka/docs/transactor/CoordinatedCounter.java +++ b/akka-docs/java/code/docs/transactor/CoordinatedCounter.java @@ -2,7 +2,7 @@ * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.transactor; +package docs.transactor; //#class import akka.actor.*; diff --git a/akka-docs/java/code/akka/docs/transactor/Coordinator.java b/akka-docs/java/code/docs/transactor/Coordinator.java similarity index 96% rename from akka-docs/java/code/akka/docs/transactor/Coordinator.java rename to akka-docs/java/code/docs/transactor/Coordinator.java index f1f04761cd..644eb4312e 100644 --- a/akka-docs/java/code/akka/docs/transactor/Coordinator.java +++ b/akka-docs/java/code/docs/transactor/Coordinator.java @@ -2,7 +2,7 @@ * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.transactor; +package docs.transactor; import akka.actor.*; import akka.transactor.*; diff --git a/akka-docs/java/code/akka/docs/transactor/Counter.java b/akka-docs/java/code/docs/transactor/Counter.java similarity index 95% rename from akka-docs/java/code/akka/docs/transactor/Counter.java rename to akka-docs/java/code/docs/transactor/Counter.java index ea2291afeb..06092c5db0 100644 --- a/akka-docs/java/code/akka/docs/transactor/Counter.java +++ b/akka-docs/java/code/docs/transactor/Counter.java @@ -2,7 +2,7 @@ * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.transactor; +package docs.transactor; //#class import akka.transactor.*; diff --git a/akka-docs/java/code/akka/docs/transactor/FriendlyCounter.java b/akka-docs/java/code/docs/transactor/FriendlyCounter.java similarity index 97% rename from akka-docs/java/code/akka/docs/transactor/FriendlyCounter.java rename to akka-docs/java/code/docs/transactor/FriendlyCounter.java index 18f2137ea4..f24c044750 100644 --- a/akka-docs/java/code/akka/docs/transactor/FriendlyCounter.java +++ b/akka-docs/java/code/docs/transactor/FriendlyCounter.java @@ -2,7 +2,7 @@ * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.transactor; +package docs.transactor; //#class import akka.actor.*; diff --git a/akka-docs/java/code/akka/docs/transactor/Increment.java b/akka-docs/java/code/docs/transactor/Increment.java similarity index 93% rename from akka-docs/java/code/akka/docs/transactor/Increment.java rename to akka-docs/java/code/docs/transactor/Increment.java index 1d789c99e2..3794ce631d 100644 --- a/akka-docs/java/code/akka/docs/transactor/Increment.java +++ b/akka-docs/java/code/docs/transactor/Increment.java @@ -2,7 +2,7 @@ * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.transactor; +package docs.transactor; //#class import akka.actor.ActorRef; diff --git a/akka-docs/java/code/akka/docs/transactor/Message.java b/akka-docs/java/code/docs/transactor/Message.java similarity index 77% rename from akka-docs/java/code/akka/docs/transactor/Message.java rename to akka-docs/java/code/docs/transactor/Message.java index 6a8da72070..0f1edfc51f 100644 --- a/akka-docs/java/code/akka/docs/transactor/Message.java +++ b/akka-docs/java/code/docs/transactor/Message.java @@ -2,6 +2,6 @@ * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.transactor; +package docs.transactor; public class Message {} diff --git a/akka-docs/java/code/akka/docs/transactor/TransactorDocJavaSpec.scala b/akka-docs/java/code/docs/transactor/TransactorDocJavaSpec.scala similarity index 75% rename from akka-docs/java/code/akka/docs/transactor/TransactorDocJavaSpec.scala rename to akka-docs/java/code/docs/transactor/TransactorDocJavaSpec.scala index 4c61a156e8..6293b2effa 100644 --- a/akka-docs/java/code/akka/docs/transactor/TransactorDocJavaSpec.scala +++ b/akka-docs/java/code/docs/transactor/TransactorDocJavaSpec.scala @@ -2,10 +2,10 @@ * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.transactor +package docs.transactor import org.scalatest.junit.JUnitWrapperSuite class TransactorDocJavaSpec extends JUnitWrapperSuite( - "akka.docs.transactor.TransactorDocTest", + "docs.transactor.TransactorDocTest", Thread.currentThread.getContextClassLoader) \ No newline at end of file diff --git a/akka-docs/java/code/akka/docs/transactor/TransactorDocTest.java b/akka-docs/java/code/docs/transactor/TransactorDocTest.java similarity index 99% rename from akka-docs/java/code/akka/docs/transactor/TransactorDocTest.java rename to akka-docs/java/code/docs/transactor/TransactorDocTest.java index bb1d38651b..4eaaa0bb31 100644 --- a/akka-docs/java/code/akka/docs/transactor/TransactorDocTest.java +++ b/akka-docs/java/code/docs/transactor/TransactorDocTest.java @@ -2,7 +2,7 @@ * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.transactor; +package docs.transactor; import static org.junit.Assert.*; import org.junit.Test; diff --git a/akka-docs/java/code/akka/docs/zeromq/ZeromqDocTest.scala b/akka-docs/java/code/docs/zeromq/ZeromqDocTest.scala similarity index 87% rename from akka-docs/java/code/akka/docs/zeromq/ZeromqDocTest.scala rename to akka-docs/java/code/docs/zeromq/ZeromqDocTest.scala index a9747959e3..c5e6f224da 100644 --- a/akka-docs/java/code/akka/docs/zeromq/ZeromqDocTest.scala +++ b/akka-docs/java/code/docs/zeromq/ZeromqDocTest.scala @@ -1,7 +1,7 @@ /** * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.zeromq +package docs.zeromq import org.scalatest.junit.JUnitSuite diff --git a/akka-docs/java/code/akka/docs/zeromq/ZeromqDocTestBase.java b/akka-docs/java/code/docs/zeromq/ZeromqDocTestBase.java similarity index 99% rename from akka-docs/java/code/akka/docs/zeromq/ZeromqDocTestBase.java rename to akka-docs/java/code/docs/zeromq/ZeromqDocTestBase.java index ee8252a6ad..1a311c9529 100644 --- a/akka-docs/java/code/akka/docs/zeromq/ZeromqDocTestBase.java +++ b/akka-docs/java/code/docs/zeromq/ZeromqDocTestBase.java @@ -1,7 +1,7 @@ /** * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.zeromq; +package docs.zeromq; //#pub-socket import akka.zeromq.Bind; diff --git a/akka-docs/java/dispatchers.rst b/akka-docs/java/dispatchers.rst index 6ef0d44d7e..90a0e9cb6a 100644 --- a/akka-docs/java/dispatchers.rst +++ b/akka-docs/java/dispatchers.rst @@ -70,7 +70,7 @@ There are 4 different types of message dispatchers: * BalancingDispatcher - - This is an executor based event driven dispatcher that will try to redistribute work from busy actors to idle actors. + - This is an executor based event driven dispatcher that will try to redistribute work from busy actors to idle actors. - It is assumed that all actors using the same instance of this dispatcher can process all messages that have been sent to one of the actors; i.e. the actors belong to a pool of actors, and to the client there is no guarantee about which actor instance actually processes a given message. @@ -85,9 +85,11 @@ There are 4 different types of message dispatchers: "thread-pool-executor" or the FQCN of an ``akka.dispatcher.ExecutorServiceConfigurator`` + - Note that you can **not** use a ``BalancingDispatcher`` together with any kind of ``Router``, trying to do so will make your actor fail verification. + * CallingThreadDispatcher - - This dispatcher runs invocations on the current thread only. This dispatcher does not create any new threads, + - This dispatcher runs invocations on the current thread only. This dispatcher does not create any new threads, but it can be used from different threads concurrently for the same actor. See :ref:`TestCallingThreadDispatcherRef` for details and restrictions. diff --git a/akka-docs/java/extending-akka.rst b/akka-docs/java/extending-akka.rst index 6e8bfca4cb..38fedf575a 100644 --- a/akka-docs/java/extending-akka.rst +++ b/akka-docs/java/extending-akka.rst @@ -54,7 +54,7 @@ in the "akka.extensions" section of the config you provide to your ``ActorSystem :: akka { - extensions = ["akka.docs.extension.ExtensionDocTestBase.CountExtension"] + extensions = ["docs.extension.ExtensionDocTestBase.CountExtension"] } Applicability diff --git a/akka-docs/java/microkernel.rst b/akka-docs/java/microkernel.rst index d6652fe316..970b174549 100644 --- a/akka-docs/java/microkernel.rst +++ b/akka-docs/java/microkernel.rst @@ -4,6 +4,10 @@ Microkernel (Java) ================== +The purpose of the Akka Microkernel is to offer a bundling mechanism so that you can distribute +an Akka application as a single payload, without the need to run in a Java Application Server or manually +having to create a launcher script. + The Akka Microkernel is included in the Akka download found at `downloads`_. .. _downloads: http://akka.io/downloads diff --git a/akka-docs/java/remoting.rst b/akka-docs/java/remoting.rst index 376eab2584..c4c5edee5f 100644 --- a/akka-docs/java/remoting.rst +++ b/akka-docs/java/remoting.rst @@ -294,3 +294,63 @@ which holds the transport used (RemoteTransport) and optionally the address that To intercept when an inbound remote client has been closed you listen to ``RemoteServerClientClosed`` which holds the transport used (RemoteTransport) and optionally the address of the remote client that was closed (Option
). +Remote Security +^^^^^^^^^^^^^^^ + +Akka provides a couple of ways to enhance security between remote nodes (client/server): + +* Untrusted Mode +* Security Cookie Handshake + +Untrusted Mode +-------------- + +You can enable untrusted mode for preventing system messages to be send by clients, e.g. messages like. +This will prevent the client to send these messages to the server: + +* ``Create`` +* ``Recreate`` +* ``Suspend`` +* ``Resume`` +* ``Terminate`` +* ``Supervise`` +* ``ChildTerminated`` +* ``Link`` +* ``Unlink`` + +Here is how to turn it on in the config:: + + akka { + actor { + remote { + untrusted-mode = on + } + } + } + +Secure Cookie Handshake +----------------------- + +Akka remoting also allows you to specify a secure cookie that will be exchanged and ensured to be identical +in the connection handshake between the client and the server. If they are not identical then the client +will be refused to connect to the server. + +The secure cookie can be any kind of string. But the recommended approach is to generate a cryptographically +secure cookie using this script ``$AKKA_HOME/scripts/generate_config_with_secure_cookie.sh`` or from code +using the ``akka.util.Crypt.generateSecureCookie()`` utility method. + +You have to ensure that both the connecting client and the server have the same secure cookie as well +as the ``require-cookie`` option turned on. + +Here is an example config:: + + akka { + actor { + remote { + netty { + secure-cookie = "090A030E0F0A05010900000A0C0E0C0B03050D05" + require-cookie = on + } + } + } + } diff --git a/akka-docs/java/routing.rst b/akka-docs/java/routing.rst index 4d01642a72..7027925fbc 100644 --- a/akka-docs/java/routing.rst +++ b/akka-docs/java/routing.rst @@ -33,6 +33,11 @@ You can also give the router already created routees as in: .. includecode:: code/akka/docs/jrouting/RouterViaProgramExample.java#programmaticRoutingRoutees +It should be noted that no actor factory or class needs to be provided in this +case, as the ``Router`` will not create any children on its own (which is not +true anymore when using a resizer). The routees can also be specified by giving +their path strings. + When you create a router programmatically you define the number of routees *or* you pass already created routees to it. If you send both parameters to the router *only* the latter will be used, i.e. ``nrOfInstances`` is disregarded. @@ -48,7 +53,7 @@ Once you have the router actor it is just to send messages to it as you would to router.tell(new MyMsg()); -The router will apply its behavior to the message it receives and forward it to the routees. +The router will forward the message to its routees according to its routing policy. Remotely Deploying Routees ************************** @@ -375,7 +380,8 @@ The dispatcher for created children of the router will be taken from makes sense to configure the :class:`BalancingDispatcher` if the precise routing is not so important (i.e. no consistent hashing or round-robin is required); this enables newly created routees to pick up work immediately by -stealing it from their siblings. +stealing it from their siblings. Note that you can **not** use a ``BalancingDispatcher`` +together with any kind of ``Router``, trying to do so will make your actor fail verification. The “head” router, of course, cannot run on the same balancing dispatcher, because it does not process the same messages, hence this special actor does diff --git a/akka-docs/java/serialization.rst b/akka-docs/java/serialization.rst index 4c7b023959..7618ffa4a8 100644 --- a/akka-docs/java/serialization.rst +++ b/akka-docs/java/serialization.rst @@ -85,7 +85,7 @@ Customization ============= So, lets say that you want to create your own ``Serializer``, -you saw the ``akka.docs.serialization.MyOwnSerializer`` in the config example above? +you saw the ``docs.serialization.MyOwnSerializer`` in the config example above? Creating new Serializers ------------------------ @@ -109,6 +109,47 @@ you might want to know how to serialize and deserialize them properly, here's th .. includecode:: code/akka/docs/serialization/SerializationDocTestBase.java :include: imports,actorref-serializer +.. note:: + + ``ActorPath.toStringWithAddress`` only differs from ``toString`` if the + address does not already have ``host`` and ``port`` components, i.e. it only + inserts address information for local addresses. + +This assumes that serialization happens in the context of sending a message +through the remote transport. There are other uses of serialization, though, +e.g. storing actor references outside of an actor application (database, +durable mailbox, etc.). In this case, it is important to keep in mind that the +address part of an actor’s path determines how that actor is communicated with. +Storing a local actor path might be the right choice if the retrieval happens +in the same logical context, but it is not enough when deserializing it on a +different network host: for that it would need to include the system’s remote +transport address. An actor system is not limited to having just one remote +transport per se, which makes this question a bit more interesting. + +In the general case, the local address to be used depends on the type of remote +address which shall be the recipient of the serialized information. Use +:meth:`ActorRefProvider.getExternalAddressFor(remoteAddr)` to query the system +for the appropriate address to use when sending to ``remoteAddr``: + +.. includecode:: code/akka/docs/serialization/SerializationDocTestBase.java + :include: external-address + +This requires that you know at least which type of address will be supported by +the system which will deserialize the resulting actor reference; if you have no +concrete address handy you can create a dummy one for the right protocol using +``new Address(protocol, "", "", 0)`` (assuming that the actual transport used is as +lenient as Akka’s RemoteActorRefProvider). + +There is a possible simplification available if you are just using the default +:class:`NettyRemoteTransport` with the :meth:`RemoteActorRefProvider`, which is +enabled by the fact that this combination has just a single remote address: + +.. includecode:: code/akka/docs/serialization/SerializationDocTestBase.java + :include: external-address-default + +This solution has to be adapted once other providers are used (like the planned +extensions for clustering). + Deep serialization of Actors ---------------------------- @@ -137,3 +178,10 @@ representation into a real reference. :class:`DynamicVariable` is a thread-local variable, so be sure to have it set while deserializing anything which might contain actor references. +External Akka Serializers +========================= + +`Akka-protostuff by Roman Levenstein`_ + + +`Akka-quickser by Roman Levenstein`_ diff --git a/akka-docs/modules/code/akka/docs/actor/mailbox/DurableMailboxDocSpec.scala b/akka-docs/modules/code/docs/actor/mailbox/DurableMailboxDocSpec.scala similarity index 97% rename from akka-docs/modules/code/akka/docs/actor/mailbox/DurableMailboxDocSpec.scala rename to akka-docs/modules/code/docs/actor/mailbox/DurableMailboxDocSpec.scala index c81f16e896..ac6c58ad08 100644 --- a/akka-docs/modules/code/akka/docs/actor/mailbox/DurableMailboxDocSpec.scala +++ b/akka-docs/modules/code/docs/actor/mailbox/DurableMailboxDocSpec.scala @@ -1,7 +1,7 @@ /** * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.actor.mailbox +package docs.actor.mailbox //#imports import akka.actor.Props @@ -107,7 +107,7 @@ import akka.actor.mailbox.DurableMailboxSpec object MyMailboxSpec { val config = """ MyStorage-dispatcher { - mailbox-type = akka.docs.actor.mailbox.MyMailboxType + mailbox-type = docs.actor.mailbox.MyMailboxType } """ } diff --git a/akka-docs/modules/code/akka/docs/actor/mailbox/DurableMailboxDocTest.scala b/akka-docs/modules/code/docs/actor/mailbox/DurableMailboxDocTest.scala similarity index 85% rename from akka-docs/modules/code/akka/docs/actor/mailbox/DurableMailboxDocTest.scala rename to akka-docs/modules/code/docs/actor/mailbox/DurableMailboxDocTest.scala index eba732e6a7..6b156ef791 100644 --- a/akka-docs/modules/code/akka/docs/actor/mailbox/DurableMailboxDocTest.scala +++ b/akka-docs/modules/code/docs/actor/mailbox/DurableMailboxDocTest.scala @@ -1,7 +1,7 @@ /** * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.actor.mailbox +package docs.actor.mailbox import org.scalatest.junit.JUnitSuite diff --git a/akka-docs/modules/code/akka/docs/actor/mailbox/DurableMailboxDocTestBase.java b/akka-docs/modules/code/docs/actor/mailbox/DurableMailboxDocTestBase.java similarity index 97% rename from akka-docs/modules/code/akka/docs/actor/mailbox/DurableMailboxDocTestBase.java rename to akka-docs/modules/code/docs/actor/mailbox/DurableMailboxDocTestBase.java index 25158446b6..06e867c786 100644 --- a/akka-docs/modules/code/akka/docs/actor/mailbox/DurableMailboxDocTestBase.java +++ b/akka-docs/modules/code/docs/actor/mailbox/DurableMailboxDocTestBase.java @@ -1,7 +1,7 @@ /** * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.actor.mailbox; +package docs.actor.mailbox; //#imports import akka.actor.Props; diff --git a/akka-docs/scala/actors.rst b/akka-docs/scala/actors.rst index 5374c8a37c..9269c841f5 100644 --- a/akka-docs/scala/actors.rst +++ b/akka-docs/scala/actors.rst @@ -443,7 +443,7 @@ An Actor has to implement the ``receive`` method to receive messages: .. code-block:: scala - protected def receive: PartialFunction[Any, Unit] + def receive: PartialFunction[Any, Unit] Note: Akka has an alias to the ``PartialFunction[Any, Unit]`` type called ``Receive`` (``akka.actor.Actor.Receive``), so you can use this type instead for diff --git a/akka-docs/scala/code/akka/docs/actor/ActorDocSpec.scala b/akka-docs/scala/code/docs/actor/ActorDocSpec.scala similarity index 98% rename from akka-docs/scala/code/akka/docs/actor/ActorDocSpec.scala rename to akka-docs/scala/code/docs/actor/ActorDocSpec.scala index 0bc540f970..ee05e95d42 100644 --- a/akka-docs/scala/code/akka/docs/actor/ActorDocSpec.scala +++ b/akka-docs/scala/code/docs/actor/ActorDocSpec.scala @@ -1,7 +1,7 @@ /** * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.actor +package docs.actor //#imports1 import akka.actor.Actor @@ -326,14 +326,13 @@ class ActorDocSpec extends AkkaSpec(Map("akka.loglevel" -> "INFO")) { //#gracefulStop import akka.pattern.gracefulStop import akka.dispatch.Await - import akka.actor.ActorTimeoutException try { val stopped: Future[Boolean] = gracefulStop(actorRef, 5 seconds)(system) Await.result(stopped, 6 seconds) // the actor has been stopped } catch { - case e: ActorTimeoutException ⇒ // the actor wasn't stopped within 5 seconds + case e: akka.pattern.AskTimeoutException ⇒ // the actor wasn't stopped within 5 seconds } //#gracefulStop } diff --git a/akka-docs/scala/code/akka/docs/actor/FSMDocSpec.scala b/akka-docs/scala/code/docs/actor/FSMDocSpec.scala similarity index 99% rename from akka-docs/scala/code/akka/docs/actor/FSMDocSpec.scala rename to akka-docs/scala/code/docs/actor/FSMDocSpec.scala index 158f8979a0..75b0309a42 100644 --- a/akka-docs/scala/code/akka/docs/actor/FSMDocSpec.scala +++ b/akka-docs/scala/code/docs/actor/FSMDocSpec.scala @@ -1,7 +1,7 @@ /** * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.actor +package docs.actor //#test-code import akka.testkit.AkkaSpec diff --git a/akka-docs/scala/code/akka/docs/actor/FaultHandlingDocSample.scala b/akka-docs/scala/code/docs/actor/FaultHandlingDocSample.scala similarity index 99% rename from akka-docs/scala/code/akka/docs/actor/FaultHandlingDocSample.scala rename to akka-docs/scala/code/docs/actor/FaultHandlingDocSample.scala index d08bcb53b2..79f5a5d084 100644 --- a/akka-docs/scala/code/akka/docs/actor/FaultHandlingDocSample.scala +++ b/akka-docs/scala/code/docs/actor/FaultHandlingDocSample.scala @@ -1,7 +1,7 @@ /** * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.actor +package docs.actor //#all //#imports diff --git a/akka-docs/scala/code/akka/docs/actor/FaultHandlingDocSpec.scala b/akka-docs/scala/code/docs/actor/FaultHandlingDocSpec.scala similarity index 99% rename from akka-docs/scala/code/akka/docs/actor/FaultHandlingDocSpec.scala rename to akka-docs/scala/code/docs/actor/FaultHandlingDocSpec.scala index ca1eccb73a..8ce16f1021 100644 --- a/akka-docs/scala/code/akka/docs/actor/FaultHandlingDocSpec.scala +++ b/akka-docs/scala/code/docs/actor/FaultHandlingDocSpec.scala @@ -1,7 +1,7 @@ /** * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.actor +package docs.actor //#testkit import akka.testkit.{ AkkaSpec, ImplicitSender, EventFilter } diff --git a/akka-docs/scala/code/akka/docs/actor/SchedulerDocSpec.scala b/akka-docs/scala/code/docs/actor/SchedulerDocSpec.scala similarity index 98% rename from akka-docs/scala/code/akka/docs/actor/SchedulerDocSpec.scala rename to akka-docs/scala/code/docs/actor/SchedulerDocSpec.scala index b6bffecb46..f711d85129 100644 --- a/akka-docs/scala/code/akka/docs/actor/SchedulerDocSpec.scala +++ b/akka-docs/scala/code/docs/actor/SchedulerDocSpec.scala @@ -1,7 +1,7 @@ /** * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.actor +package docs.actor //#imports1 import akka.actor.Actor diff --git a/akka-docs/scala/code/akka/docs/actor/TypedActorDocSpec.scala b/akka-docs/scala/code/docs/actor/TypedActorDocSpec.scala similarity index 99% rename from akka-docs/scala/code/akka/docs/actor/TypedActorDocSpec.scala rename to akka-docs/scala/code/docs/actor/TypedActorDocSpec.scala index f7c5fa9bf7..e2c8db16a4 100644 --- a/akka-docs/scala/code/akka/docs/actor/TypedActorDocSpec.scala +++ b/akka-docs/scala/code/docs/actor/TypedActorDocSpec.scala @@ -1,7 +1,7 @@ /** * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.actor +package docs.actor //#imports import akka.dispatch.{ Promise, Future, Await } diff --git a/akka-docs/scala/code/akka/docs/actor/UnnestedReceives.scala b/akka-docs/scala/code/docs/actor/UnnestedReceives.scala similarity index 98% rename from akka-docs/scala/code/akka/docs/actor/UnnestedReceives.scala rename to akka-docs/scala/code/docs/actor/UnnestedReceives.scala index 194a958cce..bb77fe4d1d 100644 --- a/akka-docs/scala/code/akka/docs/actor/UnnestedReceives.scala +++ b/akka-docs/scala/code/docs/actor/UnnestedReceives.scala @@ -1,7 +1,7 @@ /** * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.actor +package docs.actor import akka.actor._ import scala.collection.mutable.ListBuffer diff --git a/akka-docs/scala/code/akka/docs/agent/AgentDocSpec.scala b/akka-docs/scala/code/docs/agent/AgentDocSpec.scala similarity index 99% rename from akka-docs/scala/code/akka/docs/agent/AgentDocSpec.scala rename to akka-docs/scala/code/docs/agent/AgentDocSpec.scala index 1e9ec1fd69..418159f638 100644 --- a/akka-docs/scala/code/akka/docs/agent/AgentDocSpec.scala +++ b/akka-docs/scala/code/docs/agent/AgentDocSpec.scala @@ -1,7 +1,7 @@ /** * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.agent +package docs.agent import akka.agent.Agent import akka.util.duration._ diff --git a/akka-docs/scala/code/akka/docs/camel/Consumers.scala b/akka-docs/scala/code/docs/camel/Consumers.scala similarity index 96% rename from akka-docs/scala/code/akka/docs/camel/Consumers.scala rename to akka-docs/scala/code/docs/camel/Consumers.scala index 90f181df3f..df7161b9e6 100644 --- a/akka-docs/scala/code/akka/docs/camel/Consumers.scala +++ b/akka-docs/scala/code/docs/camel/Consumers.scala @@ -1,4 +1,4 @@ -package akka.docs.camel +package docs.camel object Consumers { { diff --git a/akka-docs/scala/code/akka/docs/camel/Introduction.scala b/akka-docs/scala/code/docs/camel/Introduction.scala similarity index 98% rename from akka-docs/scala/code/akka/docs/camel/Introduction.scala rename to akka-docs/scala/code/docs/camel/Introduction.scala index 4899843a27..eaf4c400f6 100644 --- a/akka-docs/scala/code/akka/docs/camel/Introduction.scala +++ b/akka-docs/scala/code/docs/camel/Introduction.scala @@ -1,4 +1,4 @@ -package akka.docs.camel +package docs.camel object Introduction { { diff --git a/akka-docs/scala/code/akka/docs/dispatcher/DispatcherDocSpec.scala b/akka-docs/scala/code/docs/dispatcher/DispatcherDocSpec.scala similarity index 97% rename from akka-docs/scala/code/akka/docs/dispatcher/DispatcherDocSpec.scala rename to akka-docs/scala/code/docs/dispatcher/DispatcherDocSpec.scala index 1452d72088..3ff8d9c1ea 100644 --- a/akka-docs/scala/code/akka/docs/dispatcher/DispatcherDocSpec.scala +++ b/akka-docs/scala/code/docs/dispatcher/DispatcherDocSpec.scala @@ -1,7 +1,7 @@ /** * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.dispatcher +package docs.dispatcher import org.scalatest.{ BeforeAndAfterAll, WordSpec } import org.scalatest.matchers.MustMatchers @@ -91,13 +91,13 @@ object DispatcherDocSpec { //#prio-dispatcher-config prio-dispatcher { - mailbox-type = "akka.docs.dispatcher.DispatcherDocSpec$MyPrioMailbox" + mailbox-type = "docs.dispatcher.DispatcherDocSpec$MyPrioMailbox" } //#prio-dispatcher-config //#prio-dispatcher-config-java prio-dispatcher-java { - mailbox-type = "akka.docs.dispatcher.DispatcherDocTestBase$MyPrioMailbox" + mailbox-type = "docs.dispatcher.DispatcherDocTestBase$MyPrioMailbox" //Other dispatcher configuration goes here } //#prio-dispatcher-config-java diff --git a/akka-docs/scala/code/akka/docs/event/LoggingDocSpec.scala b/akka-docs/scala/code/docs/event/LoggingDocSpec.scala similarity index 99% rename from akka-docs/scala/code/akka/docs/event/LoggingDocSpec.scala rename to akka-docs/scala/code/docs/event/LoggingDocSpec.scala index 0aa29549c9..7e2fccb876 100644 --- a/akka-docs/scala/code/akka/docs/event/LoggingDocSpec.scala +++ b/akka-docs/scala/code/docs/event/LoggingDocSpec.scala @@ -1,7 +1,7 @@ /** * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.event +package docs.event import akka.testkit.AkkaSpec import akka.actor.Actor diff --git a/akka-docs/scala/code/akka/docs/extension/ExtensionDocSpec.scala b/akka-docs/scala/code/docs/extension/ExtensionDocSpec.scala similarity index 96% rename from akka-docs/scala/code/akka/docs/extension/ExtensionDocSpec.scala rename to akka-docs/scala/code/docs/extension/ExtensionDocSpec.scala index 05baa28ecb..c2558fb4f1 100644 --- a/akka-docs/scala/code/akka/docs/extension/ExtensionDocSpec.scala +++ b/akka-docs/scala/code/docs/extension/ExtensionDocSpec.scala @@ -1,7 +1,7 @@ /** * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.extension +package docs.extension import java.util.concurrent.atomic.AtomicLong import akka.actor.Actor @@ -45,7 +45,7 @@ object ExtensionDocSpec { val config = """ //#config akka { - extensions = ["akka.docs.extension.CountExtension$"] + extensions = ["docs.extension.CountExtension$"] } //#config """ diff --git a/akka-docs/scala/code/akka/docs/extension/SettingsExtensionDocSpec.scala b/akka-docs/scala/code/docs/extension/SettingsExtensionDocSpec.scala similarity index 98% rename from akka-docs/scala/code/akka/docs/extension/SettingsExtensionDocSpec.scala rename to akka-docs/scala/code/docs/extension/SettingsExtensionDocSpec.scala index 05765d27a5..a1e033e386 100644 --- a/akka-docs/scala/code/akka/docs/extension/SettingsExtensionDocSpec.scala +++ b/akka-docs/scala/code/docs/extension/SettingsExtensionDocSpec.scala @@ -1,7 +1,7 @@ /** * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.extension +package docs.extension //#imports import akka.actor.Extension diff --git a/akka-docs/scala/code/akka/docs/future/FutureDocSpec.scala b/akka-docs/scala/code/docs/future/FutureDocSpec.scala similarity index 99% rename from akka-docs/scala/code/akka/docs/future/FutureDocSpec.scala rename to akka-docs/scala/code/docs/future/FutureDocSpec.scala index cee2eaeef8..66e80578fd 100644 --- a/akka-docs/scala/code/akka/docs/future/FutureDocSpec.scala +++ b/akka-docs/scala/code/docs/future/FutureDocSpec.scala @@ -1,7 +1,7 @@ /** * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.future +package docs.future import org.scalatest.{ BeforeAndAfterAll, WordSpec } import org.scalatest.matchers.MustMatchers diff --git a/akka-docs/scala/code/akka/docs/io/HTTPServer.scala b/akka-docs/scala/code/docs/io/HTTPServer.scala similarity index 99% rename from akka-docs/scala/code/akka/docs/io/HTTPServer.scala rename to akka-docs/scala/code/docs/io/HTTPServer.scala index 01bb53023b..b6b80aa27f 100644 --- a/akka-docs/scala/code/akka/docs/io/HTTPServer.scala +++ b/akka-docs/scala/code/docs/io/HTTPServer.scala @@ -1,7 +1,7 @@ /** * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.io +package docs.io //#imports import akka.actor._ diff --git a/akka-docs/scala/code/akka/docs/remoting/RemoteDeploymentDocSpec.scala b/akka-docs/scala/code/docs/remoting/RemoteDeploymentDocSpec.scala similarity index 98% rename from akka-docs/scala/code/akka/docs/remoting/RemoteDeploymentDocSpec.scala rename to akka-docs/scala/code/docs/remoting/RemoteDeploymentDocSpec.scala index 0c65b3dc76..b391494a3b 100644 --- a/akka-docs/scala/code/akka/docs/remoting/RemoteDeploymentDocSpec.scala +++ b/akka-docs/scala/code/docs/remoting/RemoteDeploymentDocSpec.scala @@ -1,7 +1,7 @@ /** * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.remoting +package docs.remoting import akka.actor.{ ExtendedActorSystem, ActorSystem, Actor, ActorRef } import akka.testkit.{ AkkaSpec, ImplicitSender } diff --git a/akka-docs/scala/code/akka/docs/routing/RouterDocSpec.scala b/akka-docs/scala/code/docs/routing/RouterDocSpec.scala similarity index 96% rename from akka-docs/scala/code/akka/docs/routing/RouterDocSpec.scala rename to akka-docs/scala/code/docs/routing/RouterDocSpec.scala index 229c66f13e..c71228d06c 100644 --- a/akka-docs/scala/code/akka/docs/routing/RouterDocSpec.scala +++ b/akka-docs/scala/code/docs/routing/RouterDocSpec.scala @@ -1,7 +1,7 @@ /** * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.routing +package docs.routing import RouterDocSpec.MyActor import akka.actor.{ Props, Actor } diff --git a/akka-docs/scala/code/akka/docs/routing/RouterTypeExample.scala b/akka-docs/scala/code/docs/routing/RouterTypeExample.scala similarity index 99% rename from akka-docs/scala/code/akka/docs/routing/RouterTypeExample.scala rename to akka-docs/scala/code/docs/routing/RouterTypeExample.scala index 6ec475a874..421c7af3bb 100644 --- a/akka-docs/scala/code/akka/docs/routing/RouterTypeExample.scala +++ b/akka-docs/scala/code/docs/routing/RouterTypeExample.scala @@ -1,7 +1,7 @@ /** * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.routing +package docs.routing import akka.routing.{ ScatterGatherFirstCompletedRouter, BroadcastRouter, RandomRouter, RoundRobinRouter } import annotation.tailrec diff --git a/akka-docs/scala/code/akka/docs/routing/RouterViaConfigExample.scala b/akka-docs/scala/code/docs/routing/RouterViaConfigExample.scala similarity index 98% rename from akka-docs/scala/code/akka/docs/routing/RouterViaConfigExample.scala rename to akka-docs/scala/code/docs/routing/RouterViaConfigExample.scala index cc840eedc5..5d34e429bb 100644 --- a/akka-docs/scala/code/akka/docs/routing/RouterViaConfigExample.scala +++ b/akka-docs/scala/code/docs/routing/RouterViaConfigExample.scala @@ -1,7 +1,7 @@ /** * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.routing +package docs.routing import akka.actor.{ Actor, Props, ActorSystem } import com.typesafe.config.ConfigFactory diff --git a/akka-docs/scala/code/akka/docs/routing/RouterViaProgramExample.scala b/akka-docs/scala/code/docs/routing/RouterViaProgramExample.scala similarity index 95% rename from akka-docs/scala/code/akka/docs/routing/RouterViaProgramExample.scala rename to akka-docs/scala/code/docs/routing/RouterViaProgramExample.scala index 50b141e7b7..79219b742b 100644 --- a/akka-docs/scala/code/akka/docs/routing/RouterViaProgramExample.scala +++ b/akka-docs/scala/code/docs/routing/RouterViaProgramExample.scala @@ -1,7 +1,7 @@ /** * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.routing +package docs.routing import akka.routing.RoundRobinRouter import akka.actor.{ ActorRef, Props, Actor, ActorSystem } @@ -29,7 +29,7 @@ object RoutingProgrammaticallyExample extends App { val actor2 = system.actorOf(Props[ExampleActor1]) val actor3 = system.actorOf(Props[ExampleActor1]) val routees = Vector[ActorRef](actor1, actor2, actor3) - val router2 = system.actorOf(Props[ExampleActor1].withRouter( + val router2 = system.actorOf(Props().withRouter( RoundRobinRouter(routees = routees))) //#programmaticRoutingRoutees 1 to 6 foreach { i ⇒ router2 ! Message1(i) } diff --git a/akka-docs/scala/code/akka/docs/serialization/SerializationDocSpec.scala b/akka-docs/scala/code/docs/serialization/SerializationDocSpec.scala similarity index 74% rename from akka-docs/scala/code/akka/docs/serialization/SerializationDocSpec.scala rename to akka-docs/scala/code/docs/serialization/SerializationDocSpec.scala index e614cc9903..b3eb4cfe13 100644 --- a/akka-docs/scala/code/akka/docs/serialization/SerializationDocSpec.scala +++ b/akka-docs/scala/code/docs/serialization/SerializationDocSpec.scala @@ -1,17 +1,21 @@ /** * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.serialization +package docs.serialization import org.scalatest.matchers.MustMatchers import akka.testkit._ -import akka.actor.{ ActorRef, ActorSystem } - //#imports +import akka.actor.{ ActorRef, ActorSystem } import akka.serialization._ import com.typesafe.config.ConfigFactory //#imports +import akka.actor.ExtensionKey +import akka.actor.ExtendedActorSystem +import akka.actor.Extension +import akka.actor.Address +import akka.remote.RemoteActorRefProvider //#my-own-serializer class MyOwnSerializer extends Serializer { @@ -87,7 +91,7 @@ class SerializationDocSpec extends AkkaSpec { serializers { java = "akka.serialization.JavaSerializer" proto = "akka.serialization.ProtobufSerializer" - myown = "akka.docs.serialization.MyOwnSerializer" + myown = "docs.serialization.MyOwnSerializer" } } } @@ -105,14 +109,14 @@ class SerializationDocSpec extends AkkaSpec { serializers { java = "akka.serialization.JavaSerializer" proto = "akka.serialization.ProtobufSerializer" - myown = "akka.docs.serialization.MyOwnSerializer" + myown = "docs.serialization.MyOwnSerializer" } serialization-bindings { "java.lang.String" = java - "akka.docs.serialization.Customer" = java + "docs.serialization.Customer" = java "com.google.protobuf.Message" = proto - "akka.docs.serialization.MyOwnSerializable" = myown + "docs.serialization.MyOwnSerializable" = myown "java.lang.Boolean" = myown } } @@ -176,5 +180,38 @@ class SerializationDocSpec extends AkkaSpec { val deserializedActorRef = theActorSystem actorFor identifier // Then just use the ActorRef //#actorref-serializer + + //#external-address + object ExternalAddress extends ExtensionKey[ExternalAddressExt] + + class ExternalAddressExt(system: ExtendedActorSystem) extends Extension { + def addressFor(remoteAddr: Address): Address = + system.provider.getExternalAddressFor(remoteAddr) getOrElse + (throw new UnsupportedOperationException("cannot send to " + remoteAddr)) + } + + def serializeTo(ref: ActorRef, remote: Address): String = + ref.path.toStringWithAddress(ExternalAddress(theActorSystem).addressFor(remote)) + //#external-address + } + + "demonstrate how to do default Akka serialization of ActorRef" in { + val theActorSystem: ActorSystem = system + + //#external-address-default + object ExternalAddress extends ExtensionKey[ExternalAddressExt] + + class ExternalAddressExt(system: ExtendedActorSystem) extends Extension { + def addressForAkka: Address = system.provider match { + case r: RemoteActorRefProvider ⇒ r.transport.address + case _ ⇒ + throw new UnsupportedOperationException( + "this method requires the RemoteActorRefProvider to be configured") + } + } + + def serializeAkkaDefault(ref: ActorRef): String = + ref.path.toStringWithAddress(ExternalAddress(theActorSystem).addressForAkka) + //#external-address-default } } diff --git a/akka-docs/scala/code/akka/docs/testkit/PlainWordSpec.scala b/akka-docs/scala/code/docs/testkit/PlainWordSpec.scala similarity index 97% rename from akka-docs/scala/code/akka/docs/testkit/PlainWordSpec.scala rename to akka-docs/scala/code/docs/testkit/PlainWordSpec.scala index 8df13da2ca..2da67c9156 100644 --- a/akka-docs/scala/code/akka/docs/testkit/PlainWordSpec.scala +++ b/akka-docs/scala/code/docs/testkit/PlainWordSpec.scala @@ -1,7 +1,7 @@ /** * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.testkit +package docs.testkit //#plain-spec import akka.actor.ActorSystem diff --git a/akka-docs/scala/code/akka/docs/testkit/TestKitUsageSpec.scala b/akka-docs/scala/code/docs/testkit/TestKitUsageSpec.scala similarity index 99% rename from akka-docs/scala/code/akka/docs/testkit/TestKitUsageSpec.scala rename to akka-docs/scala/code/docs/testkit/TestKitUsageSpec.scala index d2b2f9367d..2ca1dbcef8 100644 --- a/akka-docs/scala/code/akka/docs/testkit/TestKitUsageSpec.scala +++ b/akka-docs/scala/code/docs/testkit/TestKitUsageSpec.scala @@ -1,7 +1,7 @@ /** * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.testkit +package docs.testkit //#testkit-usage import scala.util.Random diff --git a/akka-docs/scala/code/akka/docs/testkit/TestkitDocSpec.scala b/akka-docs/scala/code/docs/testkit/TestkitDocSpec.scala similarity index 99% rename from akka-docs/scala/code/akka/docs/testkit/TestkitDocSpec.scala rename to akka-docs/scala/code/docs/testkit/TestkitDocSpec.scala index 2b2cb003a9..ddb3eeaf1d 100644 --- a/akka-docs/scala/code/akka/docs/testkit/TestkitDocSpec.scala +++ b/akka-docs/scala/code/docs/testkit/TestkitDocSpec.scala @@ -1,7 +1,7 @@ /** * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.testkit +package docs.testkit //#imports-test-probe import akka.testkit.TestProbe diff --git a/akka-docs/scala/code/akka/docs/transactor/TransactorDocSpec.scala b/akka-docs/scala/code/docs/transactor/TransactorDocSpec.scala similarity index 99% rename from akka-docs/scala/code/akka/docs/transactor/TransactorDocSpec.scala rename to akka-docs/scala/code/docs/transactor/TransactorDocSpec.scala index fa76f54744..c1556b837d 100644 --- a/akka-docs/scala/code/akka/docs/transactor/TransactorDocSpec.scala +++ b/akka-docs/scala/code/docs/transactor/TransactorDocSpec.scala @@ -2,7 +2,7 @@ * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.transactor +package docs.transactor import akka.actor._ import akka.transactor._ diff --git a/akka-docs/scala/code/akka/docs/zeromq/ZeromqDocSpec.scala b/akka-docs/scala/code/docs/zeromq/ZeromqDocSpec.scala similarity index 99% rename from akka-docs/scala/code/akka/docs/zeromq/ZeromqDocSpec.scala rename to akka-docs/scala/code/docs/zeromq/ZeromqDocSpec.scala index dba4989d87..812e0edaaa 100644 --- a/akka-docs/scala/code/akka/docs/zeromq/ZeromqDocSpec.scala +++ b/akka-docs/scala/code/docs/zeromq/ZeromqDocSpec.scala @@ -1,7 +1,7 @@ /** * Copyright (C) 2009-2012 Typesafe Inc. */ -package akka.docs.zeromq +package docs.zeromq import akka.actor.Actor import akka.actor.Props diff --git a/akka-docs/scala/dispatchers.rst b/akka-docs/scala/dispatchers.rst index 7d6a1f6334..a1cc431643 100644 --- a/akka-docs/scala/dispatchers.rst +++ b/akka-docs/scala/dispatchers.rst @@ -71,7 +71,7 @@ There are 4 different types of message dispatchers: * BalancingDispatcher - - This is an executor based event driven dispatcher that will try to redistribute work from busy actors to idle actors. + - This is an executor based event driven dispatcher that will try to redistribute work from busy actors to idle actors. - It is assumed that all actors using the same instance of this dispatcher can process all messages that have been sent to one of the actors; i.e. the actors belong to a pool of actors, and to the client there is no guarantee about which actor instance actually processes a given message. @@ -86,9 +86,11 @@ There are 4 different types of message dispatchers: "thread-pool-executor" or the FQCN of an ``akka.dispatcher.ExecutorServiceConfigurator`` + - Note that you can **not** use a ``BalancingDispatcher`` together with any kind of ``Router``, trying to do so will make your actor fail verification. + * CallingThreadDispatcher - - This dispatcher runs invocations on the current thread only. This dispatcher does not create any new threads, + - This dispatcher runs invocations on the current thread only. This dispatcher does not create any new threads, but it can be used from different threads concurrently for the same actor. See :ref:`TestCallingThreadDispatcherRef` for details and restrictions. @@ -112,8 +114,8 @@ And then using it: .. includecode:: ../scala/code/akka/docs/dispatcher/DispatcherDocSpec.scala#defining-pinned-dispatcher -Note that ``thread-pool-executor`` configuration as per the above ``my-thread-pool-dispatcher`` exmaple is -NOT applicable. This is because every actor will have its own thread pool when using ``PinnedDispatcher``, +Note that ``thread-pool-executor`` configuration as per the above ``my-thread-pool-dispatcher`` exmaple is +NOT applicable. This is because every actor will have its own thread pool when using ``PinnedDispatcher``, and that pool will have only one thread. Mailboxes diff --git a/akka-docs/scala/microkernel.rst b/akka-docs/scala/microkernel.rst index 108a00588a..c2bc95cb8b 100644 --- a/akka-docs/scala/microkernel.rst +++ b/akka-docs/scala/microkernel.rst @@ -4,6 +4,10 @@ Microkernel (Scala) =================== +The purpose of the Akka Microkernel is to offer a bundling mechanism so that you can distribute +an Akka application as a single payload, without the need to run in a Java Application Server or manually +having to create a launcher script. + The Akka Microkernel is included in the Akka download found at `downloads`_. .. _downloads: http://akka.io/downloads diff --git a/akka-docs/scala/remoting.rst b/akka-docs/scala/remoting.rst index 88096d90d1..5b36226b24 100644 --- a/akka-docs/scala/remoting.rst +++ b/akka-docs/scala/remoting.rst @@ -301,3 +301,64 @@ which holds the transport used (RemoteTransport) and optionally the address that To intercept when an inbound remote client has been closed you listen to ``RemoteServerClientClosed`` which holds the transport used (RemoteTransport) and optionally the address of the remote client that was closed (Option[Address]). + +Remote Security +^^^^^^^^^^^^^^^ + +Akka provides a couple of ways to enhance security between remote nodes (client/server): + +* Untrusted Mode +* Security Cookie Handshake + +Untrusted Mode +-------------- + +You can enable untrusted mode for preventing system messages to be send by clients, e.g. messages like. +This will prevent the client to send these messages to the server: + +* ``Create`` +* ``Recreate`` +* ``Suspend`` +* ``Resume`` +* ``Terminate`` +* ``Supervise`` +* ``ChildTerminated`` +* ``Link`` +* ``Unlink`` + +Here is how to turn it on in the config:: + + akka { + actor { + remote { + untrusted-mode = on + } + } + } + +Secure Cookie Handshake +----------------------- + +Akka remoting also allows you to specify a secure cookie that will be exchanged and ensured to be identical +in the connection handshake between the client and the server. If they are not identical then the client +will be refused to connect to the server. + +The secure cookie can be any kind of string. But the recommended approach is to generate a cryptographically +secure cookie using this script ``$AKKA_HOME/scripts/generate_config_with_secure_cookie.sh`` or from code +using the ``akka.util.Crypt.generateSecureCookie()`` utility method. + +You have to ensure that both the connecting client and the server have the same secure cookie as well +as the ``require-cookie`` option turned on. + +Here is an example config:: + + akka { + actor { + remote { + netty { + secure-cookie = "090A030E0F0A05010900000A0C0E0C0B03050D05" + require-cookie = on + } + } + } + } diff --git a/akka-docs/scala/routing.rst b/akka-docs/scala/routing.rst index 737c9e31e7..2a5ac138c9 100644 --- a/akka-docs/scala/routing.rst +++ b/akka-docs/scala/routing.rst @@ -33,6 +33,11 @@ You can also give the router already created routees as in: .. includecode:: code/akka/docs/routing/RouterViaProgramExample.scala#programmaticRoutingRoutees +It should be noted that no actor factory or class needs to be provided in this +case, as the ``Router`` will not create any children on its own (which is not +true anymore when using a resizer). The routees can also be specified by giving +their path strings. + When you create a router programmatically you define the number of routees *or* you pass already created routees to it. If you send both parameters to the router *only* the latter will be used, i.e. ``nrOfInstances`` is disregarded. @@ -48,7 +53,7 @@ Once you have the router actor it is just to send messages to it as you would to router ! MyMsg -The router will apply its behavior to the message it receives and forward it to the routees. +The router will forward the message to its routees according to its routing policy. Remotely Deploying Routees ************************** @@ -375,7 +380,9 @@ The dispatcher for created children of the router will be taken from makes sense to configure the :class:`BalancingDispatcher` if the precise routing is not so important (i.e. no consistent hashing or round-robin is required); this enables newly created routees to pick up work immediately by -stealing it from their siblings. +stealing it from their siblings. Note that you can **not** use a ``BalancingDispatcher`` +together with any kind of ``Router``, trying to do so will make your actor fail verification. + .. note:: diff --git a/akka-docs/scala/serialization.rst b/akka-docs/scala/serialization.rst index 2ab0a7b633..88fe74fd13 100644 --- a/akka-docs/scala/serialization.rst +++ b/akka-docs/scala/serialization.rst @@ -84,7 +84,7 @@ Customization ============= So, lets say that you want to create your own ``Serializer``, -you saw the ``akka.docs.serialization.MyOwnSerializer`` in the config example above? +you saw the ``docs.serialization.MyOwnSerializer`` in the config example above? Creating new Serializers ------------------------ @@ -107,6 +107,47 @@ you might want to know how to serialize and deserialize them properly, here's th .. includecode:: code/akka/docs/serialization/SerializationDocSpec.scala :include: imports,actorref-serializer +.. note:: + + ``ActorPath.toStringWithAddress`` only differs from ``toString`` if the + address does not already have ``host`` and ``port`` components, i.e. it only + inserts address information for local addresses. + +This assumes that serialization happens in the context of sending a message +through the remote transport. There are other uses of serialization, though, +e.g. storing actor references outside of an actor application (database, +durable mailbox, etc.). In this case, it is important to keep in mind that the +address part of an actor’s path determines how that actor is communicated with. +Storing a local actor path might be the right choice if the retrieval happens +in the same logical context, but it is not enough when deserializing it on a +different network host: for that it would need to include the system’s remote +transport address. An actor system is not limited to having just one remote +transport per se, which makes this question a bit more interesting. + +In the general case, the local address to be used depends on the type of remote +address which shall be the recipient of the serialized information. Use +:meth:`ActorRefProvider.getExternalAddressFor(remoteAddr)` to query the system +for the appropriate address to use when sending to ``remoteAddr``: + +.. includecode:: code/akka/docs/serialization/SerializationDocSpec.scala + :include: external-address + +This requires that you know at least which type of address will be supported by +the system which will deserialize the resulting actor reference; if you have no +concrete address handy you can create a dummy one for the right protocol using +``Address(protocol, "", "", 0)`` (assuming that the actual transport used is as +lenient as Akka’s RemoteActorRefProvider). + +There is a possible simplification available if you are just using the default +:class:`NettyRemoteTransport` with the :meth:`RemoteActorRefProvider`, which is +enabled by the fact that this combination has just a single remote address: + +.. includecode:: code/akka/docs/serialization/SerializationDocSpec.scala + :include: external-address-default + +This solution has to be adapted once other providers are used (like the planned +extensions for clustering). + Deep serialization of Actors ---------------------------- @@ -135,3 +176,11 @@ representation into a real reference. :class:`DynamicVariable` is a thread-local variable, so be sure to have it set while deserializing anything which might contain actor references. + +External Akka Serializers +========================= + +`Akka-protostuff by Roman Levenstein`_ + + +`Akka-quickser by Roman Levenstein`_ diff --git a/akka-durable-mailboxes/akka-file-mailbox/src/main/scala/akka/actor/mailbox/FileBasedMailbox.scala b/akka-durable-mailboxes/akka-file-mailbox/src/main/scala/akka/actor/mailbox/FileBasedMailbox.scala index ef8a28b2cf..c595fdcdd3 100644 --- a/akka-durable-mailboxes/akka-file-mailbox/src/main/scala/akka/actor/mailbox/FileBasedMailbox.scala +++ b/akka-durable-mailboxes/akka-file-mailbox/src/main/scala/akka/actor/mailbox/FileBasedMailbox.scala @@ -11,7 +11,7 @@ import akka.actor.ActorRef import akka.dispatch.MailboxType import com.typesafe.config.Config import akka.util.NonFatal -import akka.config.ConfigurationException +import akka.ConfigurationException import akka.actor.ActorSystem class FileBasedMailboxType(systemSettings: ActorSystem.Settings, config: Config) extends MailboxType { @@ -23,47 +23,37 @@ class FileBasedMailboxType(systemSettings: ActorSystem.Settings, config: Config) } class FileBasedMessageQueue(_owner: ActorContext, val settings: FileBasedMailboxSettings) extends DurableMessageQueue(_owner) with DurableMessageSerialization { - - val log = Logging(system, "FileBasedMessageQueue") - - val queuePath = settings.QueuePath + // TODO Is it reasonable for all FileBasedMailboxes to have their own logger? + private val log = Logging(system, "FileBasedMessageQueue") private val queue = try { - (new java.io.File(queuePath)) match { + (new java.io.File(settings.QueuePath)) match { case dir if dir.exists && !dir.isDirectory ⇒ throw new IllegalStateException("Path already occupied by non-directory " + dir) case dir if !dir.exists ⇒ if (!dir.mkdirs() && !dir.isDirectory) throw new IllegalStateException("Creation of directory failed " + dir) case _ ⇒ //All good } - val queue = new filequeue.PersistentQueue(queuePath, name, settings, log) + val queue = new filequeue.PersistentQueue(settings.QueuePath, name, settings, log) queue.setup // replays journal queue.discardExpired queue } catch { - case e: Exception ⇒ + case NonFatal(e) ⇒ log.error(e, "Could not create a file-based mailbox") throw e } - def enqueue(receiver: ActorRef, envelope: Envelope) { - queue.add(serialize(envelope)) - } + def enqueue(receiver: ActorRef, envelope: Envelope): Unit = queue.add(serialize(envelope)) def dequeue(): Envelope = try { - val item = queue.remove - if (item.isDefined) { - queue.confirmRemove(item.get.xid) - deserialize(item.get.data) - } else null + queue.remove.map(item ⇒ { queue.confirmRemove(item.xid); deserialize(item.data) }).orNull } catch { - case e: java.util.NoSuchElementException ⇒ null - case e: Exception ⇒ + case _: java.util.NoSuchElementException ⇒ null + case NonFatal(e) ⇒ log.error(e, "Couldn't dequeue from file-based mailbox") throw e } - def numberOfMessages: Int = { - queue.length.toInt - } + def numberOfMessages: Int = queue.length.toInt def hasMessages: Boolean = numberOfMessages > 0 @@ -78,5 +68,4 @@ class FileBasedMessageQueue(_owner: ActorContext, val settings: FileBasedMailbox } def cleanUp(owner: ActorContext, deadLetters: MessageQueue): Unit = () - } diff --git a/akka-durable-mailboxes/akka-file-mailbox/src/main/scala/akka/actor/mailbox/FileBasedMailboxSettings.scala b/akka-durable-mailboxes/akka-file-mailbox/src/main/scala/akka/actor/mailbox/FileBasedMailboxSettings.scala index 6511bf9e00..87dc25840f 100644 --- a/akka-durable-mailboxes/akka-file-mailbox/src/main/scala/akka/actor/mailbox/FileBasedMailboxSettings.scala +++ b/akka-durable-mailboxes/akka-file-mailbox/src/main/scala/akka/actor/mailbox/FileBasedMailboxSettings.scala @@ -11,24 +11,22 @@ import akka.actor.ActorSystem class FileBasedMailboxSettings(val systemSettings: ActorSystem.Settings, val userConfig: Config) extends DurableMailboxSettings { - def name = "file-based" + def name: String = "file-based" val config = initialize - import config._ - val QueuePath = getString("directory-path") - - val MaxItems = getInt("max-items") - val MaxSize = getBytes("max-size") - val MaxItemSize = getBytes("max-item-size") - val MaxAge = Duration(getMilliseconds("max-age"), MILLISECONDS) - val MaxJournalSize = getBytes("max-journal-size") - val MaxMemorySize = getBytes("max-memory-size") - val MaxJournalOverflow = getInt("max-journal-overflow") - val MaxJournalSizeAbsolute = getBytes("max-journal-size-absolute") - val DiscardOldWhenFull = getBoolean("discard-old-when-full") - val KeepJournal = getBoolean("keep-journal") - val SyncJournal = getBoolean("sync-journal") + val QueuePath: String = getString("directory-path") + val MaxItems: Int = getInt("max-items") + val MaxSize: Long = getBytes("max-size") + val MaxItemSize: Long = getBytes("max-item-size") + val MaxAge: Duration = Duration(getMilliseconds("max-age"), MILLISECONDS) + val MaxJournalSize: Long = getBytes("max-journal-size") + val MaxMemorySize: Long = getBytes("max-memory-size") + val MaxJournalOverflow: Int = getInt("max-journal-overflow") + val MaxJournalSizeAbsolute: Long = getBytes("max-journal-size-absolute") + val DiscardOldWhenFull: Boolean = getBoolean("discard-old-when-full") + val KeepJournal: Boolean = getBoolean("keep-journal") + val SyncJournal: Boolean = getBoolean("sync-journal") } \ No newline at end of file diff --git a/akka-durable-mailboxes/akka-mailboxes-common/src/main/scala/akka/actor/mailbox/DurableMailbox.scala b/akka-durable-mailboxes/akka-mailboxes-common/src/main/scala/akka/actor/mailbox/DurableMailbox.scala index 0744215bae..b21878d00e 100644 --- a/akka-durable-mailboxes/akka-mailboxes-common/src/main/scala/akka/actor/mailbox/DurableMailbox.scala +++ b/akka-durable-mailboxes/akka-mailboxes-common/src/main/scala/akka/actor/mailbox/DurableMailbox.scala @@ -3,12 +3,11 @@ */ package akka.actor.mailbox -import akka.actor.{ ActorContext, ActorRef, ExtendedActorSystem } import akka.dispatch.{ Envelope, MessageQueue } import akka.remote.MessageSerializer import akka.remote.RemoteProtocol.{ ActorRefProtocol, RemoteMessageProtocol } import com.typesafe.config.Config -import akka.actor.ActorSystem +import akka.actor._ private[akka] object DurableExecutableMailboxConfig { val Name = "[\\.\\/\\$\\s]".r @@ -18,14 +17,21 @@ abstract class DurableMessageQueue(val owner: ActorContext) extends MessageQueue import DurableExecutableMailboxConfig._ def system: ExtendedActorSystem = owner.system.asInstanceOf[ExtendedActorSystem] - def ownerPath = owner.self.path - val ownerPathString = ownerPath.elements.mkString("/") - val name = "mailbox_" + Name.replaceAllIn(ownerPathString, "_") + def ownerPath: ActorPath = owner.self.path + val ownerPathString: String = ownerPath.elements.mkString("/") + val name: String = "mailbox_" + Name.replaceAllIn(ownerPathString, "_") } +/** + * DurableMessageSerialization can be mixed into a DurableMessageQueue and adds functionality + * to serialize and deserialize Envelopes (messages) + */ trait DurableMessageSerialization { this: DurableMessageQueue ⇒ + /** + * Serializes the given Envelope into an Array of Bytes using an efficient serialization/deserialization strategy + */ def serialize(durableMessage: Envelope): Array[Byte] = { // It's alright to use ref.path.toString here @@ -42,6 +48,10 @@ trait DurableMessageSerialization { this: DurableMessageQueue ⇒ builder.build.toByteArray } + /** + * Deserializes an array of Bytes that were serialized using the DurableMessageSerialization.serialize method, + * into an Envelope. + */ def deserialize(bytes: Array[Byte]): Envelope = { def deserializeActorRef(refProtocol: ActorRefProtocol): ActorRef = system.actorFor(refProtocol.getPath) @@ -50,7 +60,7 @@ trait DurableMessageSerialization { this: DurableMessageQueue ⇒ val message = MessageSerializer.deserialize(system, durableMessage.getMessage) val sender = deserializeActorRef(durableMessage.getSender) - new Envelope(message, sender)(system) + Envelope(message, sender)(system) } } diff --git a/akka-kernel/src/main/java/akka/jmx/Client.java b/akka-kernel/src/main/java/akka/jmx/Client.java index 9ebf63e9eb..83a8f9246f 100644 --- a/akka-kernel/src/main/java/akka/jmx/Client.java +++ b/akka-kernel/src/main/java/akka/jmx/Client.java @@ -201,12 +201,10 @@ public class Client { * @param password * @return Credentials as map for RMI. */ - protected Map formatCredentials(final String login, + protected Map formatCredentials(final String login, final String password) { - Map env = null; - String[] creds = new String[] {login, password}; - env = new HashMap(1); - env.put(JMXConnector.CREDENTIALS, creds); + Map env = new HashMap(1); + env.put(JMXConnector.CREDENTIALS, new String[] {login, password}); return env; } @@ -214,10 +212,8 @@ public class Client { final String login, final String password) throws IOException { // Make up the jmx rmi URL and get a connector. - JMXServiceURL rmiurl = new JMXServiceURL("service:jmx:rmi://" - + hostport + "/jndi/rmi://" + hostport + "/jmxrmi"); - return JMXConnectorFactory.connect(rmiurl, - formatCredentials(login, password)); + JMXServiceURL rmiurl = new JMXServiceURL("service:jmx:rmi://"+hostport+"/jndi/rmi://"+hostport+"/jmxrmi"); + return JMXConnectorFactory.connect(rmiurl,formatCredentials(login, password)); } protected ObjectName getObjectName(final String beanname) diff --git a/akka-kernel/src/main/scala/akka/kernel/Main.scala b/akka-kernel/src/main/scala/akka/kernel/Main.scala index ead2c28121..97ff625ab8 100644 --- a/akka-kernel/src/main/scala/akka/kernel/Main.scala +++ b/akka-kernel/src/main/scala/akka/kernel/Main.scala @@ -59,9 +59,9 @@ trait Bootable { * Main class for running the microkernel. */ object Main { - val quiet = getBoolean("akka.kernel.quiet") + private val quiet = getBoolean("akka.kernel.quiet") - def log(s: String) = if (!quiet) println(s) + private def log(s: String) = if (!quiet) println(s) def main(args: Array[String]) = { if (args.isEmpty) { @@ -90,7 +90,7 @@ object Main { log("Successfully started Akka") } - def createClassLoader(): ClassLoader = { + private def createClassLoader(): ClassLoader = { if (ActorSystem.GlobalHome.isDefined) { val home = ActorSystem.GlobalHome.get val deploy = new File(home, "deploy") @@ -106,7 +106,7 @@ object Main { } } - def loadDeployJars(deploy: File): ClassLoader = { + private def loadDeployJars(deploy: File): ClassLoader = { val jars = deploy.listFiles.filter(_.getName.endsWith(".jar")) val nestedJars = jars flatMap { jar ⇒ @@ -122,7 +122,7 @@ object Main { new URLClassLoader(urls, Thread.currentThread.getContextClassLoader) } - def addShutdownHook(bootables: Seq[Bootable]): Unit = { + private def addShutdownHook(bootables: Seq[Bootable]): Unit = { Runtime.getRuntime.addShutdownHook(new Thread(new Runnable { def run = { log("") @@ -138,7 +138,7 @@ object Main { })) } - def banner = """ + private def banner = """ ============================================================================== ZZ: diff --git a/akka-remote-tests/src/main/java/akka/remote/testconductor/TestConductorProtocol.java b/akka-remote-tests/src/main/java/akka/remote/testconductor/TestConductorProtocol.java new file mode 100644 index 0000000000..99c33e6728 --- /dev/null +++ b/akka-remote-tests/src/main/java/akka/remote/testconductor/TestConductorProtocol.java @@ -0,0 +1,4136 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: TestConductorProtocol.proto + +package akka.remote.testconductor; + +public final class TestConductorProtocol { + private TestConductorProtocol() {} + public static void registerAllExtensions( + com.google.protobuf.ExtensionRegistry registry) { + } + public enum FailType + implements com.google.protobuf.ProtocolMessageEnum { + Throttle(0, 1), + Disconnect(1, 2), + Abort(2, 3), + Shutdown(3, 4), + ; + + public static final int Throttle_VALUE = 1; + public static final int Disconnect_VALUE = 2; + public static final int Abort_VALUE = 3; + public static final int Shutdown_VALUE = 4; + + + public final int getNumber() { return value; } + + public static FailType valueOf(int value) { + switch (value) { + case 1: return Throttle; + case 2: return Disconnect; + case 3: return Abort; + case 4: return Shutdown; + default: return null; + } + } + + public static com.google.protobuf.Internal.EnumLiteMap + internalGetValueMap() { + return internalValueMap; + } + private static com.google.protobuf.Internal.EnumLiteMap + internalValueMap = + new com.google.protobuf.Internal.EnumLiteMap() { + public FailType findValueByNumber(int number) { + return FailType.valueOf(number); + } + }; + + public final com.google.protobuf.Descriptors.EnumValueDescriptor + getValueDescriptor() { + return getDescriptor().getValues().get(index); + } + public final com.google.protobuf.Descriptors.EnumDescriptor + getDescriptorForType() { + return getDescriptor(); + } + public static final com.google.protobuf.Descriptors.EnumDescriptor + getDescriptor() { + return akka.remote.testconductor.TestConductorProtocol.getDescriptor().getEnumTypes().get(0); + } + + private static final FailType[] VALUES = { + Throttle, Disconnect, Abort, Shutdown, + }; + + public static FailType valueOf( + com.google.protobuf.Descriptors.EnumValueDescriptor desc) { + if (desc.getType() != getDescriptor()) { + throw new java.lang.IllegalArgumentException( + "EnumValueDescriptor is not for this type."); + } + return VALUES[desc.getIndex()]; + } + + private final int index; + private final int value; + + private FailType(int index, int value) { + this.index = index; + this.value = value; + } + + // @@protoc_insertion_point(enum_scope:FailType) + } + + public enum Direction + implements com.google.protobuf.ProtocolMessageEnum { + Send(0, 1), + Receive(1, 2), + Both(2, 3), + ; + + public static final int Send_VALUE = 1; + public static final int Receive_VALUE = 2; + public static final int Both_VALUE = 3; + + + public final int getNumber() { return value; } + + public static Direction valueOf(int value) { + switch (value) { + case 1: return Send; + case 2: return Receive; + case 3: return Both; + default: return null; + } + } + + public static com.google.protobuf.Internal.EnumLiteMap + internalGetValueMap() { + return internalValueMap; + } + private static com.google.protobuf.Internal.EnumLiteMap + internalValueMap = + new com.google.protobuf.Internal.EnumLiteMap() { + public Direction findValueByNumber(int number) { + return Direction.valueOf(number); + } + }; + + public final com.google.protobuf.Descriptors.EnumValueDescriptor + getValueDescriptor() { + return getDescriptor().getValues().get(index); + } + public final com.google.protobuf.Descriptors.EnumDescriptor + getDescriptorForType() { + return getDescriptor(); + } + public static final com.google.protobuf.Descriptors.EnumDescriptor + getDescriptor() { + return akka.remote.testconductor.TestConductorProtocol.getDescriptor().getEnumTypes().get(1); + } + + private static final Direction[] VALUES = { + Send, Receive, Both, + }; + + public static Direction valueOf( + com.google.protobuf.Descriptors.EnumValueDescriptor desc) { + if (desc.getType() != getDescriptor()) { + throw new java.lang.IllegalArgumentException( + "EnumValueDescriptor is not for this type."); + } + return VALUES[desc.getIndex()]; + } + + private final int index; + private final int value; + + private Direction(int index, int value) { + this.index = index; + this.value = value; + } + + // @@protoc_insertion_point(enum_scope:Direction) + } + + public interface WrapperOrBuilder + extends com.google.protobuf.MessageOrBuilder { + + // optional .Hello hello = 1; + boolean hasHello(); + akka.remote.testconductor.TestConductorProtocol.Hello getHello(); + akka.remote.testconductor.TestConductorProtocol.HelloOrBuilder getHelloOrBuilder(); + + // optional .EnterBarrier barrier = 2; + boolean hasBarrier(); + akka.remote.testconductor.TestConductorProtocol.EnterBarrier getBarrier(); + akka.remote.testconductor.TestConductorProtocol.EnterBarrierOrBuilder getBarrierOrBuilder(); + + // optional .InjectFailure failure = 3; + boolean hasFailure(); + akka.remote.testconductor.TestConductorProtocol.InjectFailure getFailure(); + akka.remote.testconductor.TestConductorProtocol.InjectFailureOrBuilder getFailureOrBuilder(); + + // optional string done = 4; + boolean hasDone(); + String getDone(); + + // optional .AddressRequest addr = 5; + boolean hasAddr(); + akka.remote.testconductor.TestConductorProtocol.AddressRequest getAddr(); + akka.remote.testconductor.TestConductorProtocol.AddressRequestOrBuilder getAddrOrBuilder(); + } + public static final class Wrapper extends + com.google.protobuf.GeneratedMessage + implements WrapperOrBuilder { + // Use Wrapper.newBuilder() to construct. + private Wrapper(Builder builder) { + super(builder); + } + private Wrapper(boolean noInit) {} + + private static final Wrapper defaultInstance; + public static Wrapper getDefaultInstance() { + return defaultInstance; + } + + public Wrapper getDefaultInstanceForType() { + return defaultInstance; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return akka.remote.testconductor.TestConductorProtocol.internal_static_Wrapper_descriptor; + } + + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return akka.remote.testconductor.TestConductorProtocol.internal_static_Wrapper_fieldAccessorTable; + } + + private int bitField0_; + // optional .Hello hello = 1; + public static final int HELLO_FIELD_NUMBER = 1; + private akka.remote.testconductor.TestConductorProtocol.Hello hello_; + public boolean hasHello() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + public akka.remote.testconductor.TestConductorProtocol.Hello getHello() { + return hello_; + } + public akka.remote.testconductor.TestConductorProtocol.HelloOrBuilder getHelloOrBuilder() { + return hello_; + } + + // optional .EnterBarrier barrier = 2; + public static final int BARRIER_FIELD_NUMBER = 2; + private akka.remote.testconductor.TestConductorProtocol.EnterBarrier barrier_; + public boolean hasBarrier() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + public akka.remote.testconductor.TestConductorProtocol.EnterBarrier getBarrier() { + return barrier_; + } + public akka.remote.testconductor.TestConductorProtocol.EnterBarrierOrBuilder getBarrierOrBuilder() { + return barrier_; + } + + // optional .InjectFailure failure = 3; + public static final int FAILURE_FIELD_NUMBER = 3; + private akka.remote.testconductor.TestConductorProtocol.InjectFailure failure_; + public boolean hasFailure() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + public akka.remote.testconductor.TestConductorProtocol.InjectFailure getFailure() { + return failure_; + } + public akka.remote.testconductor.TestConductorProtocol.InjectFailureOrBuilder getFailureOrBuilder() { + return failure_; + } + + // optional string done = 4; + public static final int DONE_FIELD_NUMBER = 4; + private java.lang.Object done_; + public boolean hasDone() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + public String getDone() { + java.lang.Object ref = done_; + if (ref instanceof String) { + return (String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + String s = bs.toStringUtf8(); + if (com.google.protobuf.Internal.isValidUtf8(bs)) { + done_ = s; + } + return s; + } + } + private com.google.protobuf.ByteString getDoneBytes() { + java.lang.Object ref = done_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8((String) ref); + done_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + // optional .AddressRequest addr = 5; + public static final int ADDR_FIELD_NUMBER = 5; + private akka.remote.testconductor.TestConductorProtocol.AddressRequest addr_; + public boolean hasAddr() { + return ((bitField0_ & 0x00000010) == 0x00000010); + } + public akka.remote.testconductor.TestConductorProtocol.AddressRequest getAddr() { + return addr_; + } + public akka.remote.testconductor.TestConductorProtocol.AddressRequestOrBuilder getAddrOrBuilder() { + return addr_; + } + + private void initFields() { + hello_ = akka.remote.testconductor.TestConductorProtocol.Hello.getDefaultInstance(); + barrier_ = akka.remote.testconductor.TestConductorProtocol.EnterBarrier.getDefaultInstance(); + failure_ = akka.remote.testconductor.TestConductorProtocol.InjectFailure.getDefaultInstance(); + done_ = ""; + addr_ = akka.remote.testconductor.TestConductorProtocol.AddressRequest.getDefaultInstance(); + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized != -1) return isInitialized == 1; + + if (hasHello()) { + if (!getHello().isInitialized()) { + memoizedIsInitialized = 0; + return false; + } + } + if (hasBarrier()) { + if (!getBarrier().isInitialized()) { + memoizedIsInitialized = 0; + return false; + } + } + if (hasFailure()) { + if (!getFailure().isInitialized()) { + memoizedIsInitialized = 0; + return false; + } + } + if (hasAddr()) { + if (!getAddr().isInitialized()) { + memoizedIsInitialized = 0; + return false; + } + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeMessage(1, hello_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeMessage(2, barrier_); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + output.writeMessage(3, failure_); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + output.writeBytes(4, getDoneBytes()); + } + if (((bitField0_ & 0x00000010) == 0x00000010)) { + output.writeMessage(5, addr_); + } + getUnknownFields().writeTo(output); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(1, hello_); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(2, barrier_); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(3, failure_); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(4, getDoneBytes()); + } + if (((bitField0_ & 0x00000010) == 0x00000010)) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(5, addr_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static akka.remote.testconductor.TestConductorProtocol.Wrapper parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return newBuilder().mergeFrom(data).buildParsed(); + } + public static akka.remote.testconductor.TestConductorProtocol.Wrapper parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return newBuilder().mergeFrom(data, extensionRegistry) + .buildParsed(); + } + public static akka.remote.testconductor.TestConductorProtocol.Wrapper parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return newBuilder().mergeFrom(data).buildParsed(); + } + public static akka.remote.testconductor.TestConductorProtocol.Wrapper parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return newBuilder().mergeFrom(data, extensionRegistry) + .buildParsed(); + } + public static akka.remote.testconductor.TestConductorProtocol.Wrapper parseFrom(java.io.InputStream input) + throws java.io.IOException { + return newBuilder().mergeFrom(input).buildParsed(); + } + public static akka.remote.testconductor.TestConductorProtocol.Wrapper parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return newBuilder().mergeFrom(input, extensionRegistry) + .buildParsed(); + } + public static akka.remote.testconductor.TestConductorProtocol.Wrapper parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + Builder builder = newBuilder(); + if (builder.mergeDelimitedFrom(input)) { + return builder.buildParsed(); + } else { + return null; + } + } + public static akka.remote.testconductor.TestConductorProtocol.Wrapper parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + Builder builder = newBuilder(); + if (builder.mergeDelimitedFrom(input, extensionRegistry)) { + return builder.buildParsed(); + } else { + return null; + } + } + public static akka.remote.testconductor.TestConductorProtocol.Wrapper parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return newBuilder().mergeFrom(input).buildParsed(); + } + public static akka.remote.testconductor.TestConductorProtocol.Wrapper parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return newBuilder().mergeFrom(input, extensionRegistry) + .buildParsed(); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(akka.remote.testconductor.TestConductorProtocol.Wrapper prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder + implements akka.remote.testconductor.TestConductorProtocol.WrapperOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return akka.remote.testconductor.TestConductorProtocol.internal_static_Wrapper_descriptor; + } + + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return akka.remote.testconductor.TestConductorProtocol.internal_static_Wrapper_fieldAccessorTable; + } + + // Construct using akka.remote.testconductor.TestConductorProtocol.Wrapper.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder(com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) { + getHelloFieldBuilder(); + getBarrierFieldBuilder(); + getFailureFieldBuilder(); + getAddrFieldBuilder(); + } + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + if (helloBuilder_ == null) { + hello_ = akka.remote.testconductor.TestConductorProtocol.Hello.getDefaultInstance(); + } else { + helloBuilder_.clear(); + } + bitField0_ = (bitField0_ & ~0x00000001); + if (barrierBuilder_ == null) { + barrier_ = akka.remote.testconductor.TestConductorProtocol.EnterBarrier.getDefaultInstance(); + } else { + barrierBuilder_.clear(); + } + bitField0_ = (bitField0_ & ~0x00000002); + if (failureBuilder_ == null) { + failure_ = akka.remote.testconductor.TestConductorProtocol.InjectFailure.getDefaultInstance(); + } else { + failureBuilder_.clear(); + } + bitField0_ = (bitField0_ & ~0x00000004); + done_ = ""; + bitField0_ = (bitField0_ & ~0x00000008); + if (addrBuilder_ == null) { + addr_ = akka.remote.testconductor.TestConductorProtocol.AddressRequest.getDefaultInstance(); + } else { + addrBuilder_.clear(); + } + bitField0_ = (bitField0_ & ~0x00000010); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return akka.remote.testconductor.TestConductorProtocol.Wrapper.getDescriptor(); + } + + public akka.remote.testconductor.TestConductorProtocol.Wrapper getDefaultInstanceForType() { + return akka.remote.testconductor.TestConductorProtocol.Wrapper.getDefaultInstance(); + } + + public akka.remote.testconductor.TestConductorProtocol.Wrapper build() { + akka.remote.testconductor.TestConductorProtocol.Wrapper result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + private akka.remote.testconductor.TestConductorProtocol.Wrapper buildParsed() + throws com.google.protobuf.InvalidProtocolBufferException { + akka.remote.testconductor.TestConductorProtocol.Wrapper result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException( + result).asInvalidProtocolBufferException(); + } + return result; + } + + public akka.remote.testconductor.TestConductorProtocol.Wrapper buildPartial() { + akka.remote.testconductor.TestConductorProtocol.Wrapper result = new akka.remote.testconductor.TestConductorProtocol.Wrapper(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + if (helloBuilder_ == null) { + result.hello_ = hello_; + } else { + result.hello_ = helloBuilder_.build(); + } + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + if (barrierBuilder_ == null) { + result.barrier_ = barrier_; + } else { + result.barrier_ = barrierBuilder_.build(); + } + if (((from_bitField0_ & 0x00000004) == 0x00000004)) { + to_bitField0_ |= 0x00000004; + } + if (failureBuilder_ == null) { + result.failure_ = failure_; + } else { + result.failure_ = failureBuilder_.build(); + } + if (((from_bitField0_ & 0x00000008) == 0x00000008)) { + to_bitField0_ |= 0x00000008; + } + result.done_ = done_; + if (((from_bitField0_ & 0x00000010) == 0x00000010)) { + to_bitField0_ |= 0x00000010; + } + if (addrBuilder_ == null) { + result.addr_ = addr_; + } else { + result.addr_ = addrBuilder_.build(); + } + result.bitField0_ = to_bitField0_; + onBuilt(); + return result; + } + + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof akka.remote.testconductor.TestConductorProtocol.Wrapper) { + return mergeFrom((akka.remote.testconductor.TestConductorProtocol.Wrapper)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(akka.remote.testconductor.TestConductorProtocol.Wrapper other) { + if (other == akka.remote.testconductor.TestConductorProtocol.Wrapper.getDefaultInstance()) return this; + if (other.hasHello()) { + mergeHello(other.getHello()); + } + if (other.hasBarrier()) { + mergeBarrier(other.getBarrier()); + } + if (other.hasFailure()) { + mergeFailure(other.getFailure()); + } + if (other.hasDone()) { + setDone(other.getDone()); + } + if (other.hasAddr()) { + mergeAddr(other.getAddr()); + } + this.mergeUnknownFields(other.getUnknownFields()); + return this; + } + + public final boolean isInitialized() { + if (hasHello()) { + if (!getHello().isInitialized()) { + + return false; + } + } + if (hasBarrier()) { + if (!getBarrier().isInitialized()) { + + return false; + } + } + if (hasFailure()) { + if (!getFailure().isInitialized()) { + + return false; + } + } + if (hasAddr()) { + if (!getAddr().isInitialized()) { + + return false; + } + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.google.protobuf.UnknownFieldSet.Builder unknownFields = + com.google.protobuf.UnknownFieldSet.newBuilder( + this.getUnknownFields()); + while (true) { + int tag = input.readTag(); + switch (tag) { + case 0: + this.setUnknownFields(unknownFields.build()); + onChanged(); + return this; + default: { + if (!parseUnknownField(input, unknownFields, + extensionRegistry, tag)) { + this.setUnknownFields(unknownFields.build()); + onChanged(); + return this; + } + break; + } + case 10: { + akka.remote.testconductor.TestConductorProtocol.Hello.Builder subBuilder = akka.remote.testconductor.TestConductorProtocol.Hello.newBuilder(); + if (hasHello()) { + subBuilder.mergeFrom(getHello()); + } + input.readMessage(subBuilder, extensionRegistry); + setHello(subBuilder.buildPartial()); + break; + } + case 18: { + akka.remote.testconductor.TestConductorProtocol.EnterBarrier.Builder subBuilder = akka.remote.testconductor.TestConductorProtocol.EnterBarrier.newBuilder(); + if (hasBarrier()) { + subBuilder.mergeFrom(getBarrier()); + } + input.readMessage(subBuilder, extensionRegistry); + setBarrier(subBuilder.buildPartial()); + break; + } + case 26: { + akka.remote.testconductor.TestConductorProtocol.InjectFailure.Builder subBuilder = akka.remote.testconductor.TestConductorProtocol.InjectFailure.newBuilder(); + if (hasFailure()) { + subBuilder.mergeFrom(getFailure()); + } + input.readMessage(subBuilder, extensionRegistry); + setFailure(subBuilder.buildPartial()); + break; + } + case 34: { + bitField0_ |= 0x00000008; + done_ = input.readBytes(); + break; + } + case 42: { + akka.remote.testconductor.TestConductorProtocol.AddressRequest.Builder subBuilder = akka.remote.testconductor.TestConductorProtocol.AddressRequest.newBuilder(); + if (hasAddr()) { + subBuilder.mergeFrom(getAddr()); + } + input.readMessage(subBuilder, extensionRegistry); + setAddr(subBuilder.buildPartial()); + break; + } + } + } + } + + private int bitField0_; + + // optional .Hello hello = 1; + private akka.remote.testconductor.TestConductorProtocol.Hello hello_ = akka.remote.testconductor.TestConductorProtocol.Hello.getDefaultInstance(); + private com.google.protobuf.SingleFieldBuilder< + akka.remote.testconductor.TestConductorProtocol.Hello, akka.remote.testconductor.TestConductorProtocol.Hello.Builder, akka.remote.testconductor.TestConductorProtocol.HelloOrBuilder> helloBuilder_; + public boolean hasHello() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + public akka.remote.testconductor.TestConductorProtocol.Hello getHello() { + if (helloBuilder_ == null) { + return hello_; + } else { + return helloBuilder_.getMessage(); + } + } + public Builder setHello(akka.remote.testconductor.TestConductorProtocol.Hello value) { + if (helloBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + hello_ = value; + onChanged(); + } else { + helloBuilder_.setMessage(value); + } + bitField0_ |= 0x00000001; + return this; + } + public Builder setHello( + akka.remote.testconductor.TestConductorProtocol.Hello.Builder builderForValue) { + if (helloBuilder_ == null) { + hello_ = builderForValue.build(); + onChanged(); + } else { + helloBuilder_.setMessage(builderForValue.build()); + } + bitField0_ |= 0x00000001; + return this; + } + public Builder mergeHello(akka.remote.testconductor.TestConductorProtocol.Hello value) { + if (helloBuilder_ == null) { + if (((bitField0_ & 0x00000001) == 0x00000001) && + hello_ != akka.remote.testconductor.TestConductorProtocol.Hello.getDefaultInstance()) { + hello_ = + akka.remote.testconductor.TestConductorProtocol.Hello.newBuilder(hello_).mergeFrom(value).buildPartial(); + } else { + hello_ = value; + } + onChanged(); + } else { + helloBuilder_.mergeFrom(value); + } + bitField0_ |= 0x00000001; + return this; + } + public Builder clearHello() { + if (helloBuilder_ == null) { + hello_ = akka.remote.testconductor.TestConductorProtocol.Hello.getDefaultInstance(); + onChanged(); + } else { + helloBuilder_.clear(); + } + bitField0_ = (bitField0_ & ~0x00000001); + return this; + } + public akka.remote.testconductor.TestConductorProtocol.Hello.Builder getHelloBuilder() { + bitField0_ |= 0x00000001; + onChanged(); + return getHelloFieldBuilder().getBuilder(); + } + public akka.remote.testconductor.TestConductorProtocol.HelloOrBuilder getHelloOrBuilder() { + if (helloBuilder_ != null) { + return helloBuilder_.getMessageOrBuilder(); + } else { + return hello_; + } + } + private com.google.protobuf.SingleFieldBuilder< + akka.remote.testconductor.TestConductorProtocol.Hello, akka.remote.testconductor.TestConductorProtocol.Hello.Builder, akka.remote.testconductor.TestConductorProtocol.HelloOrBuilder> + getHelloFieldBuilder() { + if (helloBuilder_ == null) { + helloBuilder_ = new com.google.protobuf.SingleFieldBuilder< + akka.remote.testconductor.TestConductorProtocol.Hello, akka.remote.testconductor.TestConductorProtocol.Hello.Builder, akka.remote.testconductor.TestConductorProtocol.HelloOrBuilder>( + hello_, + getParentForChildren(), + isClean()); + hello_ = null; + } + return helloBuilder_; + } + + // optional .EnterBarrier barrier = 2; + private akka.remote.testconductor.TestConductorProtocol.EnterBarrier barrier_ = akka.remote.testconductor.TestConductorProtocol.EnterBarrier.getDefaultInstance(); + private com.google.protobuf.SingleFieldBuilder< + akka.remote.testconductor.TestConductorProtocol.EnterBarrier, akka.remote.testconductor.TestConductorProtocol.EnterBarrier.Builder, akka.remote.testconductor.TestConductorProtocol.EnterBarrierOrBuilder> barrierBuilder_; + public boolean hasBarrier() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + public akka.remote.testconductor.TestConductorProtocol.EnterBarrier getBarrier() { + if (barrierBuilder_ == null) { + return barrier_; + } else { + return barrierBuilder_.getMessage(); + } + } + public Builder setBarrier(akka.remote.testconductor.TestConductorProtocol.EnterBarrier value) { + if (barrierBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + barrier_ = value; + onChanged(); + } else { + barrierBuilder_.setMessage(value); + } + bitField0_ |= 0x00000002; + return this; + } + public Builder setBarrier( + akka.remote.testconductor.TestConductorProtocol.EnterBarrier.Builder builderForValue) { + if (barrierBuilder_ == null) { + barrier_ = builderForValue.build(); + onChanged(); + } else { + barrierBuilder_.setMessage(builderForValue.build()); + } + bitField0_ |= 0x00000002; + return this; + } + public Builder mergeBarrier(akka.remote.testconductor.TestConductorProtocol.EnterBarrier value) { + if (barrierBuilder_ == null) { + if (((bitField0_ & 0x00000002) == 0x00000002) && + barrier_ != akka.remote.testconductor.TestConductorProtocol.EnterBarrier.getDefaultInstance()) { + barrier_ = + akka.remote.testconductor.TestConductorProtocol.EnterBarrier.newBuilder(barrier_).mergeFrom(value).buildPartial(); + } else { + barrier_ = value; + } + onChanged(); + } else { + barrierBuilder_.mergeFrom(value); + } + bitField0_ |= 0x00000002; + return this; + } + public Builder clearBarrier() { + if (barrierBuilder_ == null) { + barrier_ = akka.remote.testconductor.TestConductorProtocol.EnterBarrier.getDefaultInstance(); + onChanged(); + } else { + barrierBuilder_.clear(); + } + bitField0_ = (bitField0_ & ~0x00000002); + return this; + } + public akka.remote.testconductor.TestConductorProtocol.EnterBarrier.Builder getBarrierBuilder() { + bitField0_ |= 0x00000002; + onChanged(); + return getBarrierFieldBuilder().getBuilder(); + } + public akka.remote.testconductor.TestConductorProtocol.EnterBarrierOrBuilder getBarrierOrBuilder() { + if (barrierBuilder_ != null) { + return barrierBuilder_.getMessageOrBuilder(); + } else { + return barrier_; + } + } + private com.google.protobuf.SingleFieldBuilder< + akka.remote.testconductor.TestConductorProtocol.EnterBarrier, akka.remote.testconductor.TestConductorProtocol.EnterBarrier.Builder, akka.remote.testconductor.TestConductorProtocol.EnterBarrierOrBuilder> + getBarrierFieldBuilder() { + if (barrierBuilder_ == null) { + barrierBuilder_ = new com.google.protobuf.SingleFieldBuilder< + akka.remote.testconductor.TestConductorProtocol.EnterBarrier, akka.remote.testconductor.TestConductorProtocol.EnterBarrier.Builder, akka.remote.testconductor.TestConductorProtocol.EnterBarrierOrBuilder>( + barrier_, + getParentForChildren(), + isClean()); + barrier_ = null; + } + return barrierBuilder_; + } + + // optional .InjectFailure failure = 3; + private akka.remote.testconductor.TestConductorProtocol.InjectFailure failure_ = akka.remote.testconductor.TestConductorProtocol.InjectFailure.getDefaultInstance(); + private com.google.protobuf.SingleFieldBuilder< + akka.remote.testconductor.TestConductorProtocol.InjectFailure, akka.remote.testconductor.TestConductorProtocol.InjectFailure.Builder, akka.remote.testconductor.TestConductorProtocol.InjectFailureOrBuilder> failureBuilder_; + public boolean hasFailure() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + public akka.remote.testconductor.TestConductorProtocol.InjectFailure getFailure() { + if (failureBuilder_ == null) { + return failure_; + } else { + return failureBuilder_.getMessage(); + } + } + public Builder setFailure(akka.remote.testconductor.TestConductorProtocol.InjectFailure value) { + if (failureBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + failure_ = value; + onChanged(); + } else { + failureBuilder_.setMessage(value); + } + bitField0_ |= 0x00000004; + return this; + } + public Builder setFailure( + akka.remote.testconductor.TestConductorProtocol.InjectFailure.Builder builderForValue) { + if (failureBuilder_ == null) { + failure_ = builderForValue.build(); + onChanged(); + } else { + failureBuilder_.setMessage(builderForValue.build()); + } + bitField0_ |= 0x00000004; + return this; + } + public Builder mergeFailure(akka.remote.testconductor.TestConductorProtocol.InjectFailure value) { + if (failureBuilder_ == null) { + if (((bitField0_ & 0x00000004) == 0x00000004) && + failure_ != akka.remote.testconductor.TestConductorProtocol.InjectFailure.getDefaultInstance()) { + failure_ = + akka.remote.testconductor.TestConductorProtocol.InjectFailure.newBuilder(failure_).mergeFrom(value).buildPartial(); + } else { + failure_ = value; + } + onChanged(); + } else { + failureBuilder_.mergeFrom(value); + } + bitField0_ |= 0x00000004; + return this; + } + public Builder clearFailure() { + if (failureBuilder_ == null) { + failure_ = akka.remote.testconductor.TestConductorProtocol.InjectFailure.getDefaultInstance(); + onChanged(); + } else { + failureBuilder_.clear(); + } + bitField0_ = (bitField0_ & ~0x00000004); + return this; + } + public akka.remote.testconductor.TestConductorProtocol.InjectFailure.Builder getFailureBuilder() { + bitField0_ |= 0x00000004; + onChanged(); + return getFailureFieldBuilder().getBuilder(); + } + public akka.remote.testconductor.TestConductorProtocol.InjectFailureOrBuilder getFailureOrBuilder() { + if (failureBuilder_ != null) { + return failureBuilder_.getMessageOrBuilder(); + } else { + return failure_; + } + } + private com.google.protobuf.SingleFieldBuilder< + akka.remote.testconductor.TestConductorProtocol.InjectFailure, akka.remote.testconductor.TestConductorProtocol.InjectFailure.Builder, akka.remote.testconductor.TestConductorProtocol.InjectFailureOrBuilder> + getFailureFieldBuilder() { + if (failureBuilder_ == null) { + failureBuilder_ = new com.google.protobuf.SingleFieldBuilder< + akka.remote.testconductor.TestConductorProtocol.InjectFailure, akka.remote.testconductor.TestConductorProtocol.InjectFailure.Builder, akka.remote.testconductor.TestConductorProtocol.InjectFailureOrBuilder>( + failure_, + getParentForChildren(), + isClean()); + failure_ = null; + } + return failureBuilder_; + } + + // optional string done = 4; + private java.lang.Object done_ = ""; + public boolean hasDone() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + public String getDone() { + java.lang.Object ref = done_; + if (!(ref instanceof String)) { + String s = ((com.google.protobuf.ByteString) ref).toStringUtf8(); + done_ = s; + return s; + } else { + return (String) ref; + } + } + public Builder setDone(String value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000008; + done_ = value; + onChanged(); + return this; + } + public Builder clearDone() { + bitField0_ = (bitField0_ & ~0x00000008); + done_ = getDefaultInstance().getDone(); + onChanged(); + return this; + } + void setDone(com.google.protobuf.ByteString value) { + bitField0_ |= 0x00000008; + done_ = value; + onChanged(); + } + + // optional .AddressRequest addr = 5; + private akka.remote.testconductor.TestConductorProtocol.AddressRequest addr_ = akka.remote.testconductor.TestConductorProtocol.AddressRequest.getDefaultInstance(); + private com.google.protobuf.SingleFieldBuilder< + akka.remote.testconductor.TestConductorProtocol.AddressRequest, akka.remote.testconductor.TestConductorProtocol.AddressRequest.Builder, akka.remote.testconductor.TestConductorProtocol.AddressRequestOrBuilder> addrBuilder_; + public boolean hasAddr() { + return ((bitField0_ & 0x00000010) == 0x00000010); + } + public akka.remote.testconductor.TestConductorProtocol.AddressRequest getAddr() { + if (addrBuilder_ == null) { + return addr_; + } else { + return addrBuilder_.getMessage(); + } + } + public Builder setAddr(akka.remote.testconductor.TestConductorProtocol.AddressRequest value) { + if (addrBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + addr_ = value; + onChanged(); + } else { + addrBuilder_.setMessage(value); + } + bitField0_ |= 0x00000010; + return this; + } + public Builder setAddr( + akka.remote.testconductor.TestConductorProtocol.AddressRequest.Builder builderForValue) { + if (addrBuilder_ == null) { + addr_ = builderForValue.build(); + onChanged(); + } else { + addrBuilder_.setMessage(builderForValue.build()); + } + bitField0_ |= 0x00000010; + return this; + } + public Builder mergeAddr(akka.remote.testconductor.TestConductorProtocol.AddressRequest value) { + if (addrBuilder_ == null) { + if (((bitField0_ & 0x00000010) == 0x00000010) && + addr_ != akka.remote.testconductor.TestConductorProtocol.AddressRequest.getDefaultInstance()) { + addr_ = + akka.remote.testconductor.TestConductorProtocol.AddressRequest.newBuilder(addr_).mergeFrom(value).buildPartial(); + } else { + addr_ = value; + } + onChanged(); + } else { + addrBuilder_.mergeFrom(value); + } + bitField0_ |= 0x00000010; + return this; + } + public Builder clearAddr() { + if (addrBuilder_ == null) { + addr_ = akka.remote.testconductor.TestConductorProtocol.AddressRequest.getDefaultInstance(); + onChanged(); + } else { + addrBuilder_.clear(); + } + bitField0_ = (bitField0_ & ~0x00000010); + return this; + } + public akka.remote.testconductor.TestConductorProtocol.AddressRequest.Builder getAddrBuilder() { + bitField0_ |= 0x00000010; + onChanged(); + return getAddrFieldBuilder().getBuilder(); + } + public akka.remote.testconductor.TestConductorProtocol.AddressRequestOrBuilder getAddrOrBuilder() { + if (addrBuilder_ != null) { + return addrBuilder_.getMessageOrBuilder(); + } else { + return addr_; + } + } + private com.google.protobuf.SingleFieldBuilder< + akka.remote.testconductor.TestConductorProtocol.AddressRequest, akka.remote.testconductor.TestConductorProtocol.AddressRequest.Builder, akka.remote.testconductor.TestConductorProtocol.AddressRequestOrBuilder> + getAddrFieldBuilder() { + if (addrBuilder_ == null) { + addrBuilder_ = new com.google.protobuf.SingleFieldBuilder< + akka.remote.testconductor.TestConductorProtocol.AddressRequest, akka.remote.testconductor.TestConductorProtocol.AddressRequest.Builder, akka.remote.testconductor.TestConductorProtocol.AddressRequestOrBuilder>( + addr_, + getParentForChildren(), + isClean()); + addr_ = null; + } + return addrBuilder_; + } + + // @@protoc_insertion_point(builder_scope:Wrapper) + } + + static { + defaultInstance = new Wrapper(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:Wrapper) + } + + public interface HelloOrBuilder + extends com.google.protobuf.MessageOrBuilder { + + // required string name = 1; + boolean hasName(); + String getName(); + + // required .Address address = 2; + boolean hasAddress(); + akka.remote.testconductor.TestConductorProtocol.Address getAddress(); + akka.remote.testconductor.TestConductorProtocol.AddressOrBuilder getAddressOrBuilder(); + } + public static final class Hello extends + com.google.protobuf.GeneratedMessage + implements HelloOrBuilder { + // Use Hello.newBuilder() to construct. + private Hello(Builder builder) { + super(builder); + } + private Hello(boolean noInit) {} + + private static final Hello defaultInstance; + public static Hello getDefaultInstance() { + return defaultInstance; + } + + public Hello getDefaultInstanceForType() { + return defaultInstance; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return akka.remote.testconductor.TestConductorProtocol.internal_static_Hello_descriptor; + } + + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return akka.remote.testconductor.TestConductorProtocol.internal_static_Hello_fieldAccessorTable; + } + + private int bitField0_; + // required string name = 1; + public static final int NAME_FIELD_NUMBER = 1; + private java.lang.Object name_; + public boolean hasName() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + public String getName() { + java.lang.Object ref = name_; + if (ref instanceof String) { + return (String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + String s = bs.toStringUtf8(); + if (com.google.protobuf.Internal.isValidUtf8(bs)) { + name_ = s; + } + return s; + } + } + private com.google.protobuf.ByteString getNameBytes() { + java.lang.Object ref = name_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8((String) ref); + name_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + // required .Address address = 2; + public static final int ADDRESS_FIELD_NUMBER = 2; + private akka.remote.testconductor.TestConductorProtocol.Address address_; + public boolean hasAddress() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + public akka.remote.testconductor.TestConductorProtocol.Address getAddress() { + return address_; + } + public akka.remote.testconductor.TestConductorProtocol.AddressOrBuilder getAddressOrBuilder() { + return address_; + } + + private void initFields() { + name_ = ""; + address_ = akka.remote.testconductor.TestConductorProtocol.Address.getDefaultInstance(); + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized != -1) return isInitialized == 1; + + if (!hasName()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasAddress()) { + memoizedIsInitialized = 0; + return false; + } + if (!getAddress().isInitialized()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeBytes(1, getNameBytes()); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeMessage(2, address_); + } + getUnknownFields().writeTo(output); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(1, getNameBytes()); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(2, address_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static akka.remote.testconductor.TestConductorProtocol.Hello parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return newBuilder().mergeFrom(data).buildParsed(); + } + public static akka.remote.testconductor.TestConductorProtocol.Hello parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return newBuilder().mergeFrom(data, extensionRegistry) + .buildParsed(); + } + public static akka.remote.testconductor.TestConductorProtocol.Hello parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return newBuilder().mergeFrom(data).buildParsed(); + } + public static akka.remote.testconductor.TestConductorProtocol.Hello parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return newBuilder().mergeFrom(data, extensionRegistry) + .buildParsed(); + } + public static akka.remote.testconductor.TestConductorProtocol.Hello parseFrom(java.io.InputStream input) + throws java.io.IOException { + return newBuilder().mergeFrom(input).buildParsed(); + } + public static akka.remote.testconductor.TestConductorProtocol.Hello parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return newBuilder().mergeFrom(input, extensionRegistry) + .buildParsed(); + } + public static akka.remote.testconductor.TestConductorProtocol.Hello parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + Builder builder = newBuilder(); + if (builder.mergeDelimitedFrom(input)) { + return builder.buildParsed(); + } else { + return null; + } + } + public static akka.remote.testconductor.TestConductorProtocol.Hello parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + Builder builder = newBuilder(); + if (builder.mergeDelimitedFrom(input, extensionRegistry)) { + return builder.buildParsed(); + } else { + return null; + } + } + public static akka.remote.testconductor.TestConductorProtocol.Hello parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return newBuilder().mergeFrom(input).buildParsed(); + } + public static akka.remote.testconductor.TestConductorProtocol.Hello parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return newBuilder().mergeFrom(input, extensionRegistry) + .buildParsed(); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(akka.remote.testconductor.TestConductorProtocol.Hello prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder + implements akka.remote.testconductor.TestConductorProtocol.HelloOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return akka.remote.testconductor.TestConductorProtocol.internal_static_Hello_descriptor; + } + + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return akka.remote.testconductor.TestConductorProtocol.internal_static_Hello_fieldAccessorTable; + } + + // Construct using akka.remote.testconductor.TestConductorProtocol.Hello.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder(com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) { + getAddressFieldBuilder(); + } + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + name_ = ""; + bitField0_ = (bitField0_ & ~0x00000001); + if (addressBuilder_ == null) { + address_ = akka.remote.testconductor.TestConductorProtocol.Address.getDefaultInstance(); + } else { + addressBuilder_.clear(); + } + bitField0_ = (bitField0_ & ~0x00000002); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return akka.remote.testconductor.TestConductorProtocol.Hello.getDescriptor(); + } + + public akka.remote.testconductor.TestConductorProtocol.Hello getDefaultInstanceForType() { + return akka.remote.testconductor.TestConductorProtocol.Hello.getDefaultInstance(); + } + + public akka.remote.testconductor.TestConductorProtocol.Hello build() { + akka.remote.testconductor.TestConductorProtocol.Hello result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + private akka.remote.testconductor.TestConductorProtocol.Hello buildParsed() + throws com.google.protobuf.InvalidProtocolBufferException { + akka.remote.testconductor.TestConductorProtocol.Hello result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException( + result).asInvalidProtocolBufferException(); + } + return result; + } + + public akka.remote.testconductor.TestConductorProtocol.Hello buildPartial() { + akka.remote.testconductor.TestConductorProtocol.Hello result = new akka.remote.testconductor.TestConductorProtocol.Hello(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.name_ = name_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + if (addressBuilder_ == null) { + result.address_ = address_; + } else { + result.address_ = addressBuilder_.build(); + } + result.bitField0_ = to_bitField0_; + onBuilt(); + return result; + } + + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof akka.remote.testconductor.TestConductorProtocol.Hello) { + return mergeFrom((akka.remote.testconductor.TestConductorProtocol.Hello)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(akka.remote.testconductor.TestConductorProtocol.Hello other) { + if (other == akka.remote.testconductor.TestConductorProtocol.Hello.getDefaultInstance()) return this; + if (other.hasName()) { + setName(other.getName()); + } + if (other.hasAddress()) { + mergeAddress(other.getAddress()); + } + this.mergeUnknownFields(other.getUnknownFields()); + return this; + } + + public final boolean isInitialized() { + if (!hasName()) { + + return false; + } + if (!hasAddress()) { + + return false; + } + if (!getAddress().isInitialized()) { + + return false; + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.google.protobuf.UnknownFieldSet.Builder unknownFields = + com.google.protobuf.UnknownFieldSet.newBuilder( + this.getUnknownFields()); + while (true) { + int tag = input.readTag(); + switch (tag) { + case 0: + this.setUnknownFields(unknownFields.build()); + onChanged(); + return this; + default: { + if (!parseUnknownField(input, unknownFields, + extensionRegistry, tag)) { + this.setUnknownFields(unknownFields.build()); + onChanged(); + return this; + } + break; + } + case 10: { + bitField0_ |= 0x00000001; + name_ = input.readBytes(); + break; + } + case 18: { + akka.remote.testconductor.TestConductorProtocol.Address.Builder subBuilder = akka.remote.testconductor.TestConductorProtocol.Address.newBuilder(); + if (hasAddress()) { + subBuilder.mergeFrom(getAddress()); + } + input.readMessage(subBuilder, extensionRegistry); + setAddress(subBuilder.buildPartial()); + break; + } + } + } + } + + private int bitField0_; + + // required string name = 1; + private java.lang.Object name_ = ""; + public boolean hasName() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + public String getName() { + java.lang.Object ref = name_; + if (!(ref instanceof String)) { + String s = ((com.google.protobuf.ByteString) ref).toStringUtf8(); + name_ = s; + return s; + } else { + return (String) ref; + } + } + public Builder setName(String value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000001; + name_ = value; + onChanged(); + return this; + } + public Builder clearName() { + bitField0_ = (bitField0_ & ~0x00000001); + name_ = getDefaultInstance().getName(); + onChanged(); + return this; + } + void setName(com.google.protobuf.ByteString value) { + bitField0_ |= 0x00000001; + name_ = value; + onChanged(); + } + + // required .Address address = 2; + private akka.remote.testconductor.TestConductorProtocol.Address address_ = akka.remote.testconductor.TestConductorProtocol.Address.getDefaultInstance(); + private com.google.protobuf.SingleFieldBuilder< + akka.remote.testconductor.TestConductorProtocol.Address, akka.remote.testconductor.TestConductorProtocol.Address.Builder, akka.remote.testconductor.TestConductorProtocol.AddressOrBuilder> addressBuilder_; + public boolean hasAddress() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + public akka.remote.testconductor.TestConductorProtocol.Address getAddress() { + if (addressBuilder_ == null) { + return address_; + } else { + return addressBuilder_.getMessage(); + } + } + public Builder setAddress(akka.remote.testconductor.TestConductorProtocol.Address value) { + if (addressBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + address_ = value; + onChanged(); + } else { + addressBuilder_.setMessage(value); + } + bitField0_ |= 0x00000002; + return this; + } + public Builder setAddress( + akka.remote.testconductor.TestConductorProtocol.Address.Builder builderForValue) { + if (addressBuilder_ == null) { + address_ = builderForValue.build(); + onChanged(); + } else { + addressBuilder_.setMessage(builderForValue.build()); + } + bitField0_ |= 0x00000002; + return this; + } + public Builder mergeAddress(akka.remote.testconductor.TestConductorProtocol.Address value) { + if (addressBuilder_ == null) { + if (((bitField0_ & 0x00000002) == 0x00000002) && + address_ != akka.remote.testconductor.TestConductorProtocol.Address.getDefaultInstance()) { + address_ = + akka.remote.testconductor.TestConductorProtocol.Address.newBuilder(address_).mergeFrom(value).buildPartial(); + } else { + address_ = value; + } + onChanged(); + } else { + addressBuilder_.mergeFrom(value); + } + bitField0_ |= 0x00000002; + return this; + } + public Builder clearAddress() { + if (addressBuilder_ == null) { + address_ = akka.remote.testconductor.TestConductorProtocol.Address.getDefaultInstance(); + onChanged(); + } else { + addressBuilder_.clear(); + } + bitField0_ = (bitField0_ & ~0x00000002); + return this; + } + public akka.remote.testconductor.TestConductorProtocol.Address.Builder getAddressBuilder() { + bitField0_ |= 0x00000002; + onChanged(); + return getAddressFieldBuilder().getBuilder(); + } + public akka.remote.testconductor.TestConductorProtocol.AddressOrBuilder getAddressOrBuilder() { + if (addressBuilder_ != null) { + return addressBuilder_.getMessageOrBuilder(); + } else { + return address_; + } + } + private com.google.protobuf.SingleFieldBuilder< + akka.remote.testconductor.TestConductorProtocol.Address, akka.remote.testconductor.TestConductorProtocol.Address.Builder, akka.remote.testconductor.TestConductorProtocol.AddressOrBuilder> + getAddressFieldBuilder() { + if (addressBuilder_ == null) { + addressBuilder_ = new com.google.protobuf.SingleFieldBuilder< + akka.remote.testconductor.TestConductorProtocol.Address, akka.remote.testconductor.TestConductorProtocol.Address.Builder, akka.remote.testconductor.TestConductorProtocol.AddressOrBuilder>( + address_, + getParentForChildren(), + isClean()); + address_ = null; + } + return addressBuilder_; + } + + // @@protoc_insertion_point(builder_scope:Hello) + } + + static { + defaultInstance = new Hello(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:Hello) + } + + public interface EnterBarrierOrBuilder + extends com.google.protobuf.MessageOrBuilder { + + // required string name = 1; + boolean hasName(); + String getName(); + + // optional bool status = 2; + boolean hasStatus(); + boolean getStatus(); + } + public static final class EnterBarrier extends + com.google.protobuf.GeneratedMessage + implements EnterBarrierOrBuilder { + // Use EnterBarrier.newBuilder() to construct. + private EnterBarrier(Builder builder) { + super(builder); + } + private EnterBarrier(boolean noInit) {} + + private static final EnterBarrier defaultInstance; + public static EnterBarrier getDefaultInstance() { + return defaultInstance; + } + + public EnterBarrier getDefaultInstanceForType() { + return defaultInstance; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return akka.remote.testconductor.TestConductorProtocol.internal_static_EnterBarrier_descriptor; + } + + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return akka.remote.testconductor.TestConductorProtocol.internal_static_EnterBarrier_fieldAccessorTable; + } + + private int bitField0_; + // required string name = 1; + public static final int NAME_FIELD_NUMBER = 1; + private java.lang.Object name_; + public boolean hasName() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + public String getName() { + java.lang.Object ref = name_; + if (ref instanceof String) { + return (String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + String s = bs.toStringUtf8(); + if (com.google.protobuf.Internal.isValidUtf8(bs)) { + name_ = s; + } + return s; + } + } + private com.google.protobuf.ByteString getNameBytes() { + java.lang.Object ref = name_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8((String) ref); + name_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + // optional bool status = 2; + public static final int STATUS_FIELD_NUMBER = 2; + private boolean status_; + public boolean hasStatus() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + public boolean getStatus() { + return status_; + } + + private void initFields() { + name_ = ""; + status_ = false; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized != -1) return isInitialized == 1; + + if (!hasName()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeBytes(1, getNameBytes()); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeBool(2, status_); + } + getUnknownFields().writeTo(output); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(1, getNameBytes()); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeBoolSize(2, status_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static akka.remote.testconductor.TestConductorProtocol.EnterBarrier parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return newBuilder().mergeFrom(data).buildParsed(); + } + public static akka.remote.testconductor.TestConductorProtocol.EnterBarrier parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return newBuilder().mergeFrom(data, extensionRegistry) + .buildParsed(); + } + public static akka.remote.testconductor.TestConductorProtocol.EnterBarrier parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return newBuilder().mergeFrom(data).buildParsed(); + } + public static akka.remote.testconductor.TestConductorProtocol.EnterBarrier parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return newBuilder().mergeFrom(data, extensionRegistry) + .buildParsed(); + } + public static akka.remote.testconductor.TestConductorProtocol.EnterBarrier parseFrom(java.io.InputStream input) + throws java.io.IOException { + return newBuilder().mergeFrom(input).buildParsed(); + } + public static akka.remote.testconductor.TestConductorProtocol.EnterBarrier parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return newBuilder().mergeFrom(input, extensionRegistry) + .buildParsed(); + } + public static akka.remote.testconductor.TestConductorProtocol.EnterBarrier parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + Builder builder = newBuilder(); + if (builder.mergeDelimitedFrom(input)) { + return builder.buildParsed(); + } else { + return null; + } + } + public static akka.remote.testconductor.TestConductorProtocol.EnterBarrier parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + Builder builder = newBuilder(); + if (builder.mergeDelimitedFrom(input, extensionRegistry)) { + return builder.buildParsed(); + } else { + return null; + } + } + public static akka.remote.testconductor.TestConductorProtocol.EnterBarrier parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return newBuilder().mergeFrom(input).buildParsed(); + } + public static akka.remote.testconductor.TestConductorProtocol.EnterBarrier parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return newBuilder().mergeFrom(input, extensionRegistry) + .buildParsed(); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(akka.remote.testconductor.TestConductorProtocol.EnterBarrier prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder + implements akka.remote.testconductor.TestConductorProtocol.EnterBarrierOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return akka.remote.testconductor.TestConductorProtocol.internal_static_EnterBarrier_descriptor; + } + + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return akka.remote.testconductor.TestConductorProtocol.internal_static_EnterBarrier_fieldAccessorTable; + } + + // Construct using akka.remote.testconductor.TestConductorProtocol.EnterBarrier.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder(com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) { + } + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + name_ = ""; + bitField0_ = (bitField0_ & ~0x00000001); + status_ = false; + bitField0_ = (bitField0_ & ~0x00000002); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return akka.remote.testconductor.TestConductorProtocol.EnterBarrier.getDescriptor(); + } + + public akka.remote.testconductor.TestConductorProtocol.EnterBarrier getDefaultInstanceForType() { + return akka.remote.testconductor.TestConductorProtocol.EnterBarrier.getDefaultInstance(); + } + + public akka.remote.testconductor.TestConductorProtocol.EnterBarrier build() { + akka.remote.testconductor.TestConductorProtocol.EnterBarrier result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + private akka.remote.testconductor.TestConductorProtocol.EnterBarrier buildParsed() + throws com.google.protobuf.InvalidProtocolBufferException { + akka.remote.testconductor.TestConductorProtocol.EnterBarrier result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException( + result).asInvalidProtocolBufferException(); + } + return result; + } + + public akka.remote.testconductor.TestConductorProtocol.EnterBarrier buildPartial() { + akka.remote.testconductor.TestConductorProtocol.EnterBarrier result = new akka.remote.testconductor.TestConductorProtocol.EnterBarrier(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.name_ = name_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.status_ = status_; + result.bitField0_ = to_bitField0_; + onBuilt(); + return result; + } + + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof akka.remote.testconductor.TestConductorProtocol.EnterBarrier) { + return mergeFrom((akka.remote.testconductor.TestConductorProtocol.EnterBarrier)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(akka.remote.testconductor.TestConductorProtocol.EnterBarrier other) { + if (other == akka.remote.testconductor.TestConductorProtocol.EnterBarrier.getDefaultInstance()) return this; + if (other.hasName()) { + setName(other.getName()); + } + if (other.hasStatus()) { + setStatus(other.getStatus()); + } + this.mergeUnknownFields(other.getUnknownFields()); + return this; + } + + public final boolean isInitialized() { + if (!hasName()) { + + return false; + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.google.protobuf.UnknownFieldSet.Builder unknownFields = + com.google.protobuf.UnknownFieldSet.newBuilder( + this.getUnknownFields()); + while (true) { + int tag = input.readTag(); + switch (tag) { + case 0: + this.setUnknownFields(unknownFields.build()); + onChanged(); + return this; + default: { + if (!parseUnknownField(input, unknownFields, + extensionRegistry, tag)) { + this.setUnknownFields(unknownFields.build()); + onChanged(); + return this; + } + break; + } + case 10: { + bitField0_ |= 0x00000001; + name_ = input.readBytes(); + break; + } + case 16: { + bitField0_ |= 0x00000002; + status_ = input.readBool(); + break; + } + } + } + } + + private int bitField0_; + + // required string name = 1; + private java.lang.Object name_ = ""; + public boolean hasName() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + public String getName() { + java.lang.Object ref = name_; + if (!(ref instanceof String)) { + String s = ((com.google.protobuf.ByteString) ref).toStringUtf8(); + name_ = s; + return s; + } else { + return (String) ref; + } + } + public Builder setName(String value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000001; + name_ = value; + onChanged(); + return this; + } + public Builder clearName() { + bitField0_ = (bitField0_ & ~0x00000001); + name_ = getDefaultInstance().getName(); + onChanged(); + return this; + } + void setName(com.google.protobuf.ByteString value) { + bitField0_ |= 0x00000001; + name_ = value; + onChanged(); + } + + // optional bool status = 2; + private boolean status_ ; + public boolean hasStatus() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + public boolean getStatus() { + return status_; + } + public Builder setStatus(boolean value) { + bitField0_ |= 0x00000002; + status_ = value; + onChanged(); + return this; + } + public Builder clearStatus() { + bitField0_ = (bitField0_ & ~0x00000002); + status_ = false; + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:EnterBarrier) + } + + static { + defaultInstance = new EnterBarrier(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:EnterBarrier) + } + + public interface AddressRequestOrBuilder + extends com.google.protobuf.MessageOrBuilder { + + // required string node = 1; + boolean hasNode(); + String getNode(); + + // optional .Address addr = 2; + boolean hasAddr(); + akka.remote.testconductor.TestConductorProtocol.Address getAddr(); + akka.remote.testconductor.TestConductorProtocol.AddressOrBuilder getAddrOrBuilder(); + } + public static final class AddressRequest extends + com.google.protobuf.GeneratedMessage + implements AddressRequestOrBuilder { + // Use AddressRequest.newBuilder() to construct. + private AddressRequest(Builder builder) { + super(builder); + } + private AddressRequest(boolean noInit) {} + + private static final AddressRequest defaultInstance; + public static AddressRequest getDefaultInstance() { + return defaultInstance; + } + + public AddressRequest getDefaultInstanceForType() { + return defaultInstance; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return akka.remote.testconductor.TestConductorProtocol.internal_static_AddressRequest_descriptor; + } + + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return akka.remote.testconductor.TestConductorProtocol.internal_static_AddressRequest_fieldAccessorTable; + } + + private int bitField0_; + // required string node = 1; + public static final int NODE_FIELD_NUMBER = 1; + private java.lang.Object node_; + public boolean hasNode() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + public String getNode() { + java.lang.Object ref = node_; + if (ref instanceof String) { + return (String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + String s = bs.toStringUtf8(); + if (com.google.protobuf.Internal.isValidUtf8(bs)) { + node_ = s; + } + return s; + } + } + private com.google.protobuf.ByteString getNodeBytes() { + java.lang.Object ref = node_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8((String) ref); + node_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + // optional .Address addr = 2; + public static final int ADDR_FIELD_NUMBER = 2; + private akka.remote.testconductor.TestConductorProtocol.Address addr_; + public boolean hasAddr() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + public akka.remote.testconductor.TestConductorProtocol.Address getAddr() { + return addr_; + } + public akka.remote.testconductor.TestConductorProtocol.AddressOrBuilder getAddrOrBuilder() { + return addr_; + } + + private void initFields() { + node_ = ""; + addr_ = akka.remote.testconductor.TestConductorProtocol.Address.getDefaultInstance(); + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized != -1) return isInitialized == 1; + + if (!hasNode()) { + memoizedIsInitialized = 0; + return false; + } + if (hasAddr()) { + if (!getAddr().isInitialized()) { + memoizedIsInitialized = 0; + return false; + } + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeBytes(1, getNodeBytes()); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeMessage(2, addr_); + } + getUnknownFields().writeTo(output); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(1, getNodeBytes()); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(2, addr_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static akka.remote.testconductor.TestConductorProtocol.AddressRequest parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return newBuilder().mergeFrom(data).buildParsed(); + } + public static akka.remote.testconductor.TestConductorProtocol.AddressRequest parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return newBuilder().mergeFrom(data, extensionRegistry) + .buildParsed(); + } + public static akka.remote.testconductor.TestConductorProtocol.AddressRequest parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return newBuilder().mergeFrom(data).buildParsed(); + } + public static akka.remote.testconductor.TestConductorProtocol.AddressRequest parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return newBuilder().mergeFrom(data, extensionRegistry) + .buildParsed(); + } + public static akka.remote.testconductor.TestConductorProtocol.AddressRequest parseFrom(java.io.InputStream input) + throws java.io.IOException { + return newBuilder().mergeFrom(input).buildParsed(); + } + public static akka.remote.testconductor.TestConductorProtocol.AddressRequest parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return newBuilder().mergeFrom(input, extensionRegistry) + .buildParsed(); + } + public static akka.remote.testconductor.TestConductorProtocol.AddressRequest parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + Builder builder = newBuilder(); + if (builder.mergeDelimitedFrom(input)) { + return builder.buildParsed(); + } else { + return null; + } + } + public static akka.remote.testconductor.TestConductorProtocol.AddressRequest parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + Builder builder = newBuilder(); + if (builder.mergeDelimitedFrom(input, extensionRegistry)) { + return builder.buildParsed(); + } else { + return null; + } + } + public static akka.remote.testconductor.TestConductorProtocol.AddressRequest parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return newBuilder().mergeFrom(input).buildParsed(); + } + public static akka.remote.testconductor.TestConductorProtocol.AddressRequest parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return newBuilder().mergeFrom(input, extensionRegistry) + .buildParsed(); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(akka.remote.testconductor.TestConductorProtocol.AddressRequest prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder + implements akka.remote.testconductor.TestConductorProtocol.AddressRequestOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return akka.remote.testconductor.TestConductorProtocol.internal_static_AddressRequest_descriptor; + } + + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return akka.remote.testconductor.TestConductorProtocol.internal_static_AddressRequest_fieldAccessorTable; + } + + // Construct using akka.remote.testconductor.TestConductorProtocol.AddressRequest.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder(com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) { + getAddrFieldBuilder(); + } + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + node_ = ""; + bitField0_ = (bitField0_ & ~0x00000001); + if (addrBuilder_ == null) { + addr_ = akka.remote.testconductor.TestConductorProtocol.Address.getDefaultInstance(); + } else { + addrBuilder_.clear(); + } + bitField0_ = (bitField0_ & ~0x00000002); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return akka.remote.testconductor.TestConductorProtocol.AddressRequest.getDescriptor(); + } + + public akka.remote.testconductor.TestConductorProtocol.AddressRequest getDefaultInstanceForType() { + return akka.remote.testconductor.TestConductorProtocol.AddressRequest.getDefaultInstance(); + } + + public akka.remote.testconductor.TestConductorProtocol.AddressRequest build() { + akka.remote.testconductor.TestConductorProtocol.AddressRequest result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + private akka.remote.testconductor.TestConductorProtocol.AddressRequest buildParsed() + throws com.google.protobuf.InvalidProtocolBufferException { + akka.remote.testconductor.TestConductorProtocol.AddressRequest result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException( + result).asInvalidProtocolBufferException(); + } + return result; + } + + public akka.remote.testconductor.TestConductorProtocol.AddressRequest buildPartial() { + akka.remote.testconductor.TestConductorProtocol.AddressRequest result = new akka.remote.testconductor.TestConductorProtocol.AddressRequest(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.node_ = node_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + if (addrBuilder_ == null) { + result.addr_ = addr_; + } else { + result.addr_ = addrBuilder_.build(); + } + result.bitField0_ = to_bitField0_; + onBuilt(); + return result; + } + + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof akka.remote.testconductor.TestConductorProtocol.AddressRequest) { + return mergeFrom((akka.remote.testconductor.TestConductorProtocol.AddressRequest)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(akka.remote.testconductor.TestConductorProtocol.AddressRequest other) { + if (other == akka.remote.testconductor.TestConductorProtocol.AddressRequest.getDefaultInstance()) return this; + if (other.hasNode()) { + setNode(other.getNode()); + } + if (other.hasAddr()) { + mergeAddr(other.getAddr()); + } + this.mergeUnknownFields(other.getUnknownFields()); + return this; + } + + public final boolean isInitialized() { + if (!hasNode()) { + + return false; + } + if (hasAddr()) { + if (!getAddr().isInitialized()) { + + return false; + } + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.google.protobuf.UnknownFieldSet.Builder unknownFields = + com.google.protobuf.UnknownFieldSet.newBuilder( + this.getUnknownFields()); + while (true) { + int tag = input.readTag(); + switch (tag) { + case 0: + this.setUnknownFields(unknownFields.build()); + onChanged(); + return this; + default: { + if (!parseUnknownField(input, unknownFields, + extensionRegistry, tag)) { + this.setUnknownFields(unknownFields.build()); + onChanged(); + return this; + } + break; + } + case 10: { + bitField0_ |= 0x00000001; + node_ = input.readBytes(); + break; + } + case 18: { + akka.remote.testconductor.TestConductorProtocol.Address.Builder subBuilder = akka.remote.testconductor.TestConductorProtocol.Address.newBuilder(); + if (hasAddr()) { + subBuilder.mergeFrom(getAddr()); + } + input.readMessage(subBuilder, extensionRegistry); + setAddr(subBuilder.buildPartial()); + break; + } + } + } + } + + private int bitField0_; + + // required string node = 1; + private java.lang.Object node_ = ""; + public boolean hasNode() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + public String getNode() { + java.lang.Object ref = node_; + if (!(ref instanceof String)) { + String s = ((com.google.protobuf.ByteString) ref).toStringUtf8(); + node_ = s; + return s; + } else { + return (String) ref; + } + } + public Builder setNode(String value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000001; + node_ = value; + onChanged(); + return this; + } + public Builder clearNode() { + bitField0_ = (bitField0_ & ~0x00000001); + node_ = getDefaultInstance().getNode(); + onChanged(); + return this; + } + void setNode(com.google.protobuf.ByteString value) { + bitField0_ |= 0x00000001; + node_ = value; + onChanged(); + } + + // optional .Address addr = 2; + private akka.remote.testconductor.TestConductorProtocol.Address addr_ = akka.remote.testconductor.TestConductorProtocol.Address.getDefaultInstance(); + private com.google.protobuf.SingleFieldBuilder< + akka.remote.testconductor.TestConductorProtocol.Address, akka.remote.testconductor.TestConductorProtocol.Address.Builder, akka.remote.testconductor.TestConductorProtocol.AddressOrBuilder> addrBuilder_; + public boolean hasAddr() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + public akka.remote.testconductor.TestConductorProtocol.Address getAddr() { + if (addrBuilder_ == null) { + return addr_; + } else { + return addrBuilder_.getMessage(); + } + } + public Builder setAddr(akka.remote.testconductor.TestConductorProtocol.Address value) { + if (addrBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + addr_ = value; + onChanged(); + } else { + addrBuilder_.setMessage(value); + } + bitField0_ |= 0x00000002; + return this; + } + public Builder setAddr( + akka.remote.testconductor.TestConductorProtocol.Address.Builder builderForValue) { + if (addrBuilder_ == null) { + addr_ = builderForValue.build(); + onChanged(); + } else { + addrBuilder_.setMessage(builderForValue.build()); + } + bitField0_ |= 0x00000002; + return this; + } + public Builder mergeAddr(akka.remote.testconductor.TestConductorProtocol.Address value) { + if (addrBuilder_ == null) { + if (((bitField0_ & 0x00000002) == 0x00000002) && + addr_ != akka.remote.testconductor.TestConductorProtocol.Address.getDefaultInstance()) { + addr_ = + akka.remote.testconductor.TestConductorProtocol.Address.newBuilder(addr_).mergeFrom(value).buildPartial(); + } else { + addr_ = value; + } + onChanged(); + } else { + addrBuilder_.mergeFrom(value); + } + bitField0_ |= 0x00000002; + return this; + } + public Builder clearAddr() { + if (addrBuilder_ == null) { + addr_ = akka.remote.testconductor.TestConductorProtocol.Address.getDefaultInstance(); + onChanged(); + } else { + addrBuilder_.clear(); + } + bitField0_ = (bitField0_ & ~0x00000002); + return this; + } + public akka.remote.testconductor.TestConductorProtocol.Address.Builder getAddrBuilder() { + bitField0_ |= 0x00000002; + onChanged(); + return getAddrFieldBuilder().getBuilder(); + } + public akka.remote.testconductor.TestConductorProtocol.AddressOrBuilder getAddrOrBuilder() { + if (addrBuilder_ != null) { + return addrBuilder_.getMessageOrBuilder(); + } else { + return addr_; + } + } + private com.google.protobuf.SingleFieldBuilder< + akka.remote.testconductor.TestConductorProtocol.Address, akka.remote.testconductor.TestConductorProtocol.Address.Builder, akka.remote.testconductor.TestConductorProtocol.AddressOrBuilder> + getAddrFieldBuilder() { + if (addrBuilder_ == null) { + addrBuilder_ = new com.google.protobuf.SingleFieldBuilder< + akka.remote.testconductor.TestConductorProtocol.Address, akka.remote.testconductor.TestConductorProtocol.Address.Builder, akka.remote.testconductor.TestConductorProtocol.AddressOrBuilder>( + addr_, + getParentForChildren(), + isClean()); + addr_ = null; + } + return addrBuilder_; + } + + // @@protoc_insertion_point(builder_scope:AddressRequest) + } + + static { + defaultInstance = new AddressRequest(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:AddressRequest) + } + + public interface AddressOrBuilder + extends com.google.protobuf.MessageOrBuilder { + + // required string protocol = 1; + boolean hasProtocol(); + String getProtocol(); + + // required string system = 2; + boolean hasSystem(); + String getSystem(); + + // required string host = 3; + boolean hasHost(); + String getHost(); + + // required int32 port = 4; + boolean hasPort(); + int getPort(); + } + public static final class Address extends + com.google.protobuf.GeneratedMessage + implements AddressOrBuilder { + // Use Address.newBuilder() to construct. + private Address(Builder builder) { + super(builder); + } + private Address(boolean noInit) {} + + private static final Address defaultInstance; + public static Address getDefaultInstance() { + return defaultInstance; + } + + public Address getDefaultInstanceForType() { + return defaultInstance; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return akka.remote.testconductor.TestConductorProtocol.internal_static_Address_descriptor; + } + + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return akka.remote.testconductor.TestConductorProtocol.internal_static_Address_fieldAccessorTable; + } + + private int bitField0_; + // required string protocol = 1; + public static final int PROTOCOL_FIELD_NUMBER = 1; + private java.lang.Object protocol_; + public boolean hasProtocol() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + public String getProtocol() { + java.lang.Object ref = protocol_; + if (ref instanceof String) { + return (String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + String s = bs.toStringUtf8(); + if (com.google.protobuf.Internal.isValidUtf8(bs)) { + protocol_ = s; + } + return s; + } + } + private com.google.protobuf.ByteString getProtocolBytes() { + java.lang.Object ref = protocol_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8((String) ref); + protocol_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + // required string system = 2; + public static final int SYSTEM_FIELD_NUMBER = 2; + private java.lang.Object system_; + public boolean hasSystem() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + public String getSystem() { + java.lang.Object ref = system_; + if (ref instanceof String) { + return (String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + String s = bs.toStringUtf8(); + if (com.google.protobuf.Internal.isValidUtf8(bs)) { + system_ = s; + } + return s; + } + } + private com.google.protobuf.ByteString getSystemBytes() { + java.lang.Object ref = system_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8((String) ref); + system_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + // required string host = 3; + public static final int HOST_FIELD_NUMBER = 3; + private java.lang.Object host_; + public boolean hasHost() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + public String getHost() { + java.lang.Object ref = host_; + if (ref instanceof String) { + return (String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + String s = bs.toStringUtf8(); + if (com.google.protobuf.Internal.isValidUtf8(bs)) { + host_ = s; + } + return s; + } + } + private com.google.protobuf.ByteString getHostBytes() { + java.lang.Object ref = host_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8((String) ref); + host_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + // required int32 port = 4; + public static final int PORT_FIELD_NUMBER = 4; + private int port_; + public boolean hasPort() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + public int getPort() { + return port_; + } + + private void initFields() { + protocol_ = ""; + system_ = ""; + host_ = ""; + port_ = 0; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized != -1) return isInitialized == 1; + + if (!hasProtocol()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasSystem()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasHost()) { + memoizedIsInitialized = 0; + return false; + } + if (!hasPort()) { + memoizedIsInitialized = 0; + return false; + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeBytes(1, getProtocolBytes()); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeBytes(2, getSystemBytes()); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + output.writeBytes(3, getHostBytes()); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + output.writeInt32(4, port_); + } + getUnknownFields().writeTo(output); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(1, getProtocolBytes()); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(2, getSystemBytes()); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + size += com.google.protobuf.CodedOutputStream + .computeBytesSize(3, getHostBytes()); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + size += com.google.protobuf.CodedOutputStream + .computeInt32Size(4, port_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static akka.remote.testconductor.TestConductorProtocol.Address parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return newBuilder().mergeFrom(data).buildParsed(); + } + public static akka.remote.testconductor.TestConductorProtocol.Address parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return newBuilder().mergeFrom(data, extensionRegistry) + .buildParsed(); + } + public static akka.remote.testconductor.TestConductorProtocol.Address parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return newBuilder().mergeFrom(data).buildParsed(); + } + public static akka.remote.testconductor.TestConductorProtocol.Address parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return newBuilder().mergeFrom(data, extensionRegistry) + .buildParsed(); + } + public static akka.remote.testconductor.TestConductorProtocol.Address parseFrom(java.io.InputStream input) + throws java.io.IOException { + return newBuilder().mergeFrom(input).buildParsed(); + } + public static akka.remote.testconductor.TestConductorProtocol.Address parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return newBuilder().mergeFrom(input, extensionRegistry) + .buildParsed(); + } + public static akka.remote.testconductor.TestConductorProtocol.Address parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + Builder builder = newBuilder(); + if (builder.mergeDelimitedFrom(input)) { + return builder.buildParsed(); + } else { + return null; + } + } + public static akka.remote.testconductor.TestConductorProtocol.Address parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + Builder builder = newBuilder(); + if (builder.mergeDelimitedFrom(input, extensionRegistry)) { + return builder.buildParsed(); + } else { + return null; + } + } + public static akka.remote.testconductor.TestConductorProtocol.Address parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return newBuilder().mergeFrom(input).buildParsed(); + } + public static akka.remote.testconductor.TestConductorProtocol.Address parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return newBuilder().mergeFrom(input, extensionRegistry) + .buildParsed(); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(akka.remote.testconductor.TestConductorProtocol.Address prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder + implements akka.remote.testconductor.TestConductorProtocol.AddressOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return akka.remote.testconductor.TestConductorProtocol.internal_static_Address_descriptor; + } + + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return akka.remote.testconductor.TestConductorProtocol.internal_static_Address_fieldAccessorTable; + } + + // Construct using akka.remote.testconductor.TestConductorProtocol.Address.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder(com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) { + } + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + protocol_ = ""; + bitField0_ = (bitField0_ & ~0x00000001); + system_ = ""; + bitField0_ = (bitField0_ & ~0x00000002); + host_ = ""; + bitField0_ = (bitField0_ & ~0x00000004); + port_ = 0; + bitField0_ = (bitField0_ & ~0x00000008); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return akka.remote.testconductor.TestConductorProtocol.Address.getDescriptor(); + } + + public akka.remote.testconductor.TestConductorProtocol.Address getDefaultInstanceForType() { + return akka.remote.testconductor.TestConductorProtocol.Address.getDefaultInstance(); + } + + public akka.remote.testconductor.TestConductorProtocol.Address build() { + akka.remote.testconductor.TestConductorProtocol.Address result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + private akka.remote.testconductor.TestConductorProtocol.Address buildParsed() + throws com.google.protobuf.InvalidProtocolBufferException { + akka.remote.testconductor.TestConductorProtocol.Address result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException( + result).asInvalidProtocolBufferException(); + } + return result; + } + + public akka.remote.testconductor.TestConductorProtocol.Address buildPartial() { + akka.remote.testconductor.TestConductorProtocol.Address result = new akka.remote.testconductor.TestConductorProtocol.Address(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.protocol_ = protocol_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.system_ = system_; + if (((from_bitField0_ & 0x00000004) == 0x00000004)) { + to_bitField0_ |= 0x00000004; + } + result.host_ = host_; + if (((from_bitField0_ & 0x00000008) == 0x00000008)) { + to_bitField0_ |= 0x00000008; + } + result.port_ = port_; + result.bitField0_ = to_bitField0_; + onBuilt(); + return result; + } + + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof akka.remote.testconductor.TestConductorProtocol.Address) { + return mergeFrom((akka.remote.testconductor.TestConductorProtocol.Address)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(akka.remote.testconductor.TestConductorProtocol.Address other) { + if (other == akka.remote.testconductor.TestConductorProtocol.Address.getDefaultInstance()) return this; + if (other.hasProtocol()) { + setProtocol(other.getProtocol()); + } + if (other.hasSystem()) { + setSystem(other.getSystem()); + } + if (other.hasHost()) { + setHost(other.getHost()); + } + if (other.hasPort()) { + setPort(other.getPort()); + } + this.mergeUnknownFields(other.getUnknownFields()); + return this; + } + + public final boolean isInitialized() { + if (!hasProtocol()) { + + return false; + } + if (!hasSystem()) { + + return false; + } + if (!hasHost()) { + + return false; + } + if (!hasPort()) { + + return false; + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.google.protobuf.UnknownFieldSet.Builder unknownFields = + com.google.protobuf.UnknownFieldSet.newBuilder( + this.getUnknownFields()); + while (true) { + int tag = input.readTag(); + switch (tag) { + case 0: + this.setUnknownFields(unknownFields.build()); + onChanged(); + return this; + default: { + if (!parseUnknownField(input, unknownFields, + extensionRegistry, tag)) { + this.setUnknownFields(unknownFields.build()); + onChanged(); + return this; + } + break; + } + case 10: { + bitField0_ |= 0x00000001; + protocol_ = input.readBytes(); + break; + } + case 18: { + bitField0_ |= 0x00000002; + system_ = input.readBytes(); + break; + } + case 26: { + bitField0_ |= 0x00000004; + host_ = input.readBytes(); + break; + } + case 32: { + bitField0_ |= 0x00000008; + port_ = input.readInt32(); + break; + } + } + } + } + + private int bitField0_; + + // required string protocol = 1; + private java.lang.Object protocol_ = ""; + public boolean hasProtocol() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + public String getProtocol() { + java.lang.Object ref = protocol_; + if (!(ref instanceof String)) { + String s = ((com.google.protobuf.ByteString) ref).toStringUtf8(); + protocol_ = s; + return s; + } else { + return (String) ref; + } + } + public Builder setProtocol(String value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000001; + protocol_ = value; + onChanged(); + return this; + } + public Builder clearProtocol() { + bitField0_ = (bitField0_ & ~0x00000001); + protocol_ = getDefaultInstance().getProtocol(); + onChanged(); + return this; + } + void setProtocol(com.google.protobuf.ByteString value) { + bitField0_ |= 0x00000001; + protocol_ = value; + onChanged(); + } + + // required string system = 2; + private java.lang.Object system_ = ""; + public boolean hasSystem() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + public String getSystem() { + java.lang.Object ref = system_; + if (!(ref instanceof String)) { + String s = ((com.google.protobuf.ByteString) ref).toStringUtf8(); + system_ = s; + return s; + } else { + return (String) ref; + } + } + public Builder setSystem(String value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000002; + system_ = value; + onChanged(); + return this; + } + public Builder clearSystem() { + bitField0_ = (bitField0_ & ~0x00000002); + system_ = getDefaultInstance().getSystem(); + onChanged(); + return this; + } + void setSystem(com.google.protobuf.ByteString value) { + bitField0_ |= 0x00000002; + system_ = value; + onChanged(); + } + + // required string host = 3; + private java.lang.Object host_ = ""; + public boolean hasHost() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + public String getHost() { + java.lang.Object ref = host_; + if (!(ref instanceof String)) { + String s = ((com.google.protobuf.ByteString) ref).toStringUtf8(); + host_ = s; + return s; + } else { + return (String) ref; + } + } + public Builder setHost(String value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000004; + host_ = value; + onChanged(); + return this; + } + public Builder clearHost() { + bitField0_ = (bitField0_ & ~0x00000004); + host_ = getDefaultInstance().getHost(); + onChanged(); + return this; + } + void setHost(com.google.protobuf.ByteString value) { + bitField0_ |= 0x00000004; + host_ = value; + onChanged(); + } + + // required int32 port = 4; + private int port_ ; + public boolean hasPort() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + public int getPort() { + return port_; + } + public Builder setPort(int value) { + bitField0_ |= 0x00000008; + port_ = value; + onChanged(); + return this; + } + public Builder clearPort() { + bitField0_ = (bitField0_ & ~0x00000008); + port_ = 0; + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:Address) + } + + static { + defaultInstance = new Address(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:Address) + } + + public interface InjectFailureOrBuilder + extends com.google.protobuf.MessageOrBuilder { + + // required .FailType failure = 1; + boolean hasFailure(); + akka.remote.testconductor.TestConductorProtocol.FailType getFailure(); + + // optional .Direction direction = 2; + boolean hasDirection(); + akka.remote.testconductor.TestConductorProtocol.Direction getDirection(); + + // optional .Address address = 3; + boolean hasAddress(); + akka.remote.testconductor.TestConductorProtocol.Address getAddress(); + akka.remote.testconductor.TestConductorProtocol.AddressOrBuilder getAddressOrBuilder(); + + // optional float rateMBit = 6; + boolean hasRateMBit(); + float getRateMBit(); + + // optional int32 exitValue = 7; + boolean hasExitValue(); + int getExitValue(); + } + public static final class InjectFailure extends + com.google.protobuf.GeneratedMessage + implements InjectFailureOrBuilder { + // Use InjectFailure.newBuilder() to construct. + private InjectFailure(Builder builder) { + super(builder); + } + private InjectFailure(boolean noInit) {} + + private static final InjectFailure defaultInstance; + public static InjectFailure getDefaultInstance() { + return defaultInstance; + } + + public InjectFailure getDefaultInstanceForType() { + return defaultInstance; + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return akka.remote.testconductor.TestConductorProtocol.internal_static_InjectFailure_descriptor; + } + + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return akka.remote.testconductor.TestConductorProtocol.internal_static_InjectFailure_fieldAccessorTable; + } + + private int bitField0_; + // required .FailType failure = 1; + public static final int FAILURE_FIELD_NUMBER = 1; + private akka.remote.testconductor.TestConductorProtocol.FailType failure_; + public boolean hasFailure() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + public akka.remote.testconductor.TestConductorProtocol.FailType getFailure() { + return failure_; + } + + // optional .Direction direction = 2; + public static final int DIRECTION_FIELD_NUMBER = 2; + private akka.remote.testconductor.TestConductorProtocol.Direction direction_; + public boolean hasDirection() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + public akka.remote.testconductor.TestConductorProtocol.Direction getDirection() { + return direction_; + } + + // optional .Address address = 3; + public static final int ADDRESS_FIELD_NUMBER = 3; + private akka.remote.testconductor.TestConductorProtocol.Address address_; + public boolean hasAddress() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + public akka.remote.testconductor.TestConductorProtocol.Address getAddress() { + return address_; + } + public akka.remote.testconductor.TestConductorProtocol.AddressOrBuilder getAddressOrBuilder() { + return address_; + } + + // optional float rateMBit = 6; + public static final int RATEMBIT_FIELD_NUMBER = 6; + private float rateMBit_; + public boolean hasRateMBit() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + public float getRateMBit() { + return rateMBit_; + } + + // optional int32 exitValue = 7; + public static final int EXITVALUE_FIELD_NUMBER = 7; + private int exitValue_; + public boolean hasExitValue() { + return ((bitField0_ & 0x00000010) == 0x00000010); + } + public int getExitValue() { + return exitValue_; + } + + private void initFields() { + failure_ = akka.remote.testconductor.TestConductorProtocol.FailType.Throttle; + direction_ = akka.remote.testconductor.TestConductorProtocol.Direction.Send; + address_ = akka.remote.testconductor.TestConductorProtocol.Address.getDefaultInstance(); + rateMBit_ = 0F; + exitValue_ = 0; + } + private byte memoizedIsInitialized = -1; + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized != -1) return isInitialized == 1; + + if (!hasFailure()) { + memoizedIsInitialized = 0; + return false; + } + if (hasAddress()) { + if (!getAddress().isInitialized()) { + memoizedIsInitialized = 0; + return false; + } + } + memoizedIsInitialized = 1; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (((bitField0_ & 0x00000001) == 0x00000001)) { + output.writeEnum(1, failure_.getNumber()); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + output.writeEnum(2, direction_.getNumber()); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + output.writeMessage(3, address_); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + output.writeFloat(6, rateMBit_); + } + if (((bitField0_ & 0x00000010) == 0x00000010)) { + output.writeInt32(7, exitValue_); + } + getUnknownFields().writeTo(output); + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (((bitField0_ & 0x00000001) == 0x00000001)) { + size += com.google.protobuf.CodedOutputStream + .computeEnumSize(1, failure_.getNumber()); + } + if (((bitField0_ & 0x00000002) == 0x00000002)) { + size += com.google.protobuf.CodedOutputStream + .computeEnumSize(2, direction_.getNumber()); + } + if (((bitField0_ & 0x00000004) == 0x00000004)) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(3, address_); + } + if (((bitField0_ & 0x00000008) == 0x00000008)) { + size += com.google.protobuf.CodedOutputStream + .computeFloatSize(6, rateMBit_); + } + if (((bitField0_ & 0x00000010) == 0x00000010)) { + size += com.google.protobuf.CodedOutputStream + .computeInt32Size(7, exitValue_); + } + size += getUnknownFields().getSerializedSize(); + memoizedSerializedSize = size; + return size; + } + + private static final long serialVersionUID = 0L; + @java.lang.Override + protected java.lang.Object writeReplace() + throws java.io.ObjectStreamException { + return super.writeReplace(); + } + + public static akka.remote.testconductor.TestConductorProtocol.InjectFailure parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return newBuilder().mergeFrom(data).buildParsed(); + } + public static akka.remote.testconductor.TestConductorProtocol.InjectFailure parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return newBuilder().mergeFrom(data, extensionRegistry) + .buildParsed(); + } + public static akka.remote.testconductor.TestConductorProtocol.InjectFailure parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return newBuilder().mergeFrom(data).buildParsed(); + } + public static akka.remote.testconductor.TestConductorProtocol.InjectFailure parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return newBuilder().mergeFrom(data, extensionRegistry) + .buildParsed(); + } + public static akka.remote.testconductor.TestConductorProtocol.InjectFailure parseFrom(java.io.InputStream input) + throws java.io.IOException { + return newBuilder().mergeFrom(input).buildParsed(); + } + public static akka.remote.testconductor.TestConductorProtocol.InjectFailure parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return newBuilder().mergeFrom(input, extensionRegistry) + .buildParsed(); + } + public static akka.remote.testconductor.TestConductorProtocol.InjectFailure parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + Builder builder = newBuilder(); + if (builder.mergeDelimitedFrom(input)) { + return builder.buildParsed(); + } else { + return null; + } + } + public static akka.remote.testconductor.TestConductorProtocol.InjectFailure parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + Builder builder = newBuilder(); + if (builder.mergeDelimitedFrom(input, extensionRegistry)) { + return builder.buildParsed(); + } else { + return null; + } + } + public static akka.remote.testconductor.TestConductorProtocol.InjectFailure parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return newBuilder().mergeFrom(input).buildParsed(); + } + public static akka.remote.testconductor.TestConductorProtocol.InjectFailure parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return newBuilder().mergeFrom(input, extensionRegistry) + .buildParsed(); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(akka.remote.testconductor.TestConductorProtocol.InjectFailure prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessage.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + public static final class Builder extends + com.google.protobuf.GeneratedMessage.Builder + implements akka.remote.testconductor.TestConductorProtocol.InjectFailureOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return akka.remote.testconductor.TestConductorProtocol.internal_static_InjectFailure_descriptor; + } + + protected com.google.protobuf.GeneratedMessage.FieldAccessorTable + internalGetFieldAccessorTable() { + return akka.remote.testconductor.TestConductorProtocol.internal_static_InjectFailure_fieldAccessorTable; + } + + // Construct using akka.remote.testconductor.TestConductorProtocol.InjectFailure.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder(com.google.protobuf.GeneratedMessage.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) { + getAddressFieldBuilder(); + } + } + private static Builder create() { + return new Builder(); + } + + public Builder clear() { + super.clear(); + failure_ = akka.remote.testconductor.TestConductorProtocol.FailType.Throttle; + bitField0_ = (bitField0_ & ~0x00000001); + direction_ = akka.remote.testconductor.TestConductorProtocol.Direction.Send; + bitField0_ = (bitField0_ & ~0x00000002); + if (addressBuilder_ == null) { + address_ = akka.remote.testconductor.TestConductorProtocol.Address.getDefaultInstance(); + } else { + addressBuilder_.clear(); + } + bitField0_ = (bitField0_ & ~0x00000004); + rateMBit_ = 0F; + bitField0_ = (bitField0_ & ~0x00000008); + exitValue_ = 0; + bitField0_ = (bitField0_ & ~0x00000010); + return this; + } + + public Builder clone() { + return create().mergeFrom(buildPartial()); + } + + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return akka.remote.testconductor.TestConductorProtocol.InjectFailure.getDescriptor(); + } + + public akka.remote.testconductor.TestConductorProtocol.InjectFailure getDefaultInstanceForType() { + return akka.remote.testconductor.TestConductorProtocol.InjectFailure.getDefaultInstance(); + } + + public akka.remote.testconductor.TestConductorProtocol.InjectFailure build() { + akka.remote.testconductor.TestConductorProtocol.InjectFailure result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + private akka.remote.testconductor.TestConductorProtocol.InjectFailure buildParsed() + throws com.google.protobuf.InvalidProtocolBufferException { + akka.remote.testconductor.TestConductorProtocol.InjectFailure result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException( + result).asInvalidProtocolBufferException(); + } + return result; + } + + public akka.remote.testconductor.TestConductorProtocol.InjectFailure buildPartial() { + akka.remote.testconductor.TestConductorProtocol.InjectFailure result = new akka.remote.testconductor.TestConductorProtocol.InjectFailure(this); + int from_bitField0_ = bitField0_; + int to_bitField0_ = 0; + if (((from_bitField0_ & 0x00000001) == 0x00000001)) { + to_bitField0_ |= 0x00000001; + } + result.failure_ = failure_; + if (((from_bitField0_ & 0x00000002) == 0x00000002)) { + to_bitField0_ |= 0x00000002; + } + result.direction_ = direction_; + if (((from_bitField0_ & 0x00000004) == 0x00000004)) { + to_bitField0_ |= 0x00000004; + } + if (addressBuilder_ == null) { + result.address_ = address_; + } else { + result.address_ = addressBuilder_.build(); + } + if (((from_bitField0_ & 0x00000008) == 0x00000008)) { + to_bitField0_ |= 0x00000008; + } + result.rateMBit_ = rateMBit_; + if (((from_bitField0_ & 0x00000010) == 0x00000010)) { + to_bitField0_ |= 0x00000010; + } + result.exitValue_ = exitValue_; + result.bitField0_ = to_bitField0_; + onBuilt(); + return result; + } + + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof akka.remote.testconductor.TestConductorProtocol.InjectFailure) { + return mergeFrom((akka.remote.testconductor.TestConductorProtocol.InjectFailure)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(akka.remote.testconductor.TestConductorProtocol.InjectFailure other) { + if (other == akka.remote.testconductor.TestConductorProtocol.InjectFailure.getDefaultInstance()) return this; + if (other.hasFailure()) { + setFailure(other.getFailure()); + } + if (other.hasDirection()) { + setDirection(other.getDirection()); + } + if (other.hasAddress()) { + mergeAddress(other.getAddress()); + } + if (other.hasRateMBit()) { + setRateMBit(other.getRateMBit()); + } + if (other.hasExitValue()) { + setExitValue(other.getExitValue()); + } + this.mergeUnknownFields(other.getUnknownFields()); + return this; + } + + public final boolean isInitialized() { + if (!hasFailure()) { + + return false; + } + if (hasAddress()) { + if (!getAddress().isInitialized()) { + + return false; + } + } + return true; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + com.google.protobuf.UnknownFieldSet.Builder unknownFields = + com.google.protobuf.UnknownFieldSet.newBuilder( + this.getUnknownFields()); + while (true) { + int tag = input.readTag(); + switch (tag) { + case 0: + this.setUnknownFields(unknownFields.build()); + onChanged(); + return this; + default: { + if (!parseUnknownField(input, unknownFields, + extensionRegistry, tag)) { + this.setUnknownFields(unknownFields.build()); + onChanged(); + return this; + } + break; + } + case 8: { + int rawValue = input.readEnum(); + akka.remote.testconductor.TestConductorProtocol.FailType value = akka.remote.testconductor.TestConductorProtocol.FailType.valueOf(rawValue); + if (value == null) { + unknownFields.mergeVarintField(1, rawValue); + } else { + bitField0_ |= 0x00000001; + failure_ = value; + } + break; + } + case 16: { + int rawValue = input.readEnum(); + akka.remote.testconductor.TestConductorProtocol.Direction value = akka.remote.testconductor.TestConductorProtocol.Direction.valueOf(rawValue); + if (value == null) { + unknownFields.mergeVarintField(2, rawValue); + } else { + bitField0_ |= 0x00000002; + direction_ = value; + } + break; + } + case 26: { + akka.remote.testconductor.TestConductorProtocol.Address.Builder subBuilder = akka.remote.testconductor.TestConductorProtocol.Address.newBuilder(); + if (hasAddress()) { + subBuilder.mergeFrom(getAddress()); + } + input.readMessage(subBuilder, extensionRegistry); + setAddress(subBuilder.buildPartial()); + break; + } + case 53: { + bitField0_ |= 0x00000008; + rateMBit_ = input.readFloat(); + break; + } + case 56: { + bitField0_ |= 0x00000010; + exitValue_ = input.readInt32(); + break; + } + } + } + } + + private int bitField0_; + + // required .FailType failure = 1; + private akka.remote.testconductor.TestConductorProtocol.FailType failure_ = akka.remote.testconductor.TestConductorProtocol.FailType.Throttle; + public boolean hasFailure() { + return ((bitField0_ & 0x00000001) == 0x00000001); + } + public akka.remote.testconductor.TestConductorProtocol.FailType getFailure() { + return failure_; + } + public Builder setFailure(akka.remote.testconductor.TestConductorProtocol.FailType value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000001; + failure_ = value; + onChanged(); + return this; + } + public Builder clearFailure() { + bitField0_ = (bitField0_ & ~0x00000001); + failure_ = akka.remote.testconductor.TestConductorProtocol.FailType.Throttle; + onChanged(); + return this; + } + + // optional .Direction direction = 2; + private akka.remote.testconductor.TestConductorProtocol.Direction direction_ = akka.remote.testconductor.TestConductorProtocol.Direction.Send; + public boolean hasDirection() { + return ((bitField0_ & 0x00000002) == 0x00000002); + } + public akka.remote.testconductor.TestConductorProtocol.Direction getDirection() { + return direction_; + } + public Builder setDirection(akka.remote.testconductor.TestConductorProtocol.Direction value) { + if (value == null) { + throw new NullPointerException(); + } + bitField0_ |= 0x00000002; + direction_ = value; + onChanged(); + return this; + } + public Builder clearDirection() { + bitField0_ = (bitField0_ & ~0x00000002); + direction_ = akka.remote.testconductor.TestConductorProtocol.Direction.Send; + onChanged(); + return this; + } + + // optional .Address address = 3; + private akka.remote.testconductor.TestConductorProtocol.Address address_ = akka.remote.testconductor.TestConductorProtocol.Address.getDefaultInstance(); + private com.google.protobuf.SingleFieldBuilder< + akka.remote.testconductor.TestConductorProtocol.Address, akka.remote.testconductor.TestConductorProtocol.Address.Builder, akka.remote.testconductor.TestConductorProtocol.AddressOrBuilder> addressBuilder_; + public boolean hasAddress() { + return ((bitField0_ & 0x00000004) == 0x00000004); + } + public akka.remote.testconductor.TestConductorProtocol.Address getAddress() { + if (addressBuilder_ == null) { + return address_; + } else { + return addressBuilder_.getMessage(); + } + } + public Builder setAddress(akka.remote.testconductor.TestConductorProtocol.Address value) { + if (addressBuilder_ == null) { + if (value == null) { + throw new NullPointerException(); + } + address_ = value; + onChanged(); + } else { + addressBuilder_.setMessage(value); + } + bitField0_ |= 0x00000004; + return this; + } + public Builder setAddress( + akka.remote.testconductor.TestConductorProtocol.Address.Builder builderForValue) { + if (addressBuilder_ == null) { + address_ = builderForValue.build(); + onChanged(); + } else { + addressBuilder_.setMessage(builderForValue.build()); + } + bitField0_ |= 0x00000004; + return this; + } + public Builder mergeAddress(akka.remote.testconductor.TestConductorProtocol.Address value) { + if (addressBuilder_ == null) { + if (((bitField0_ & 0x00000004) == 0x00000004) && + address_ != akka.remote.testconductor.TestConductorProtocol.Address.getDefaultInstance()) { + address_ = + akka.remote.testconductor.TestConductorProtocol.Address.newBuilder(address_).mergeFrom(value).buildPartial(); + } else { + address_ = value; + } + onChanged(); + } else { + addressBuilder_.mergeFrom(value); + } + bitField0_ |= 0x00000004; + return this; + } + public Builder clearAddress() { + if (addressBuilder_ == null) { + address_ = akka.remote.testconductor.TestConductorProtocol.Address.getDefaultInstance(); + onChanged(); + } else { + addressBuilder_.clear(); + } + bitField0_ = (bitField0_ & ~0x00000004); + return this; + } + public akka.remote.testconductor.TestConductorProtocol.Address.Builder getAddressBuilder() { + bitField0_ |= 0x00000004; + onChanged(); + return getAddressFieldBuilder().getBuilder(); + } + public akka.remote.testconductor.TestConductorProtocol.AddressOrBuilder getAddressOrBuilder() { + if (addressBuilder_ != null) { + return addressBuilder_.getMessageOrBuilder(); + } else { + return address_; + } + } + private com.google.protobuf.SingleFieldBuilder< + akka.remote.testconductor.TestConductorProtocol.Address, akka.remote.testconductor.TestConductorProtocol.Address.Builder, akka.remote.testconductor.TestConductorProtocol.AddressOrBuilder> + getAddressFieldBuilder() { + if (addressBuilder_ == null) { + addressBuilder_ = new com.google.protobuf.SingleFieldBuilder< + akka.remote.testconductor.TestConductorProtocol.Address, akka.remote.testconductor.TestConductorProtocol.Address.Builder, akka.remote.testconductor.TestConductorProtocol.AddressOrBuilder>( + address_, + getParentForChildren(), + isClean()); + address_ = null; + } + return addressBuilder_; + } + + // optional float rateMBit = 6; + private float rateMBit_ ; + public boolean hasRateMBit() { + return ((bitField0_ & 0x00000008) == 0x00000008); + } + public float getRateMBit() { + return rateMBit_; + } + public Builder setRateMBit(float value) { + bitField0_ |= 0x00000008; + rateMBit_ = value; + onChanged(); + return this; + } + public Builder clearRateMBit() { + bitField0_ = (bitField0_ & ~0x00000008); + rateMBit_ = 0F; + onChanged(); + return this; + } + + // optional int32 exitValue = 7; + private int exitValue_ ; + public boolean hasExitValue() { + return ((bitField0_ & 0x00000010) == 0x00000010); + } + public int getExitValue() { + return exitValue_; + } + public Builder setExitValue(int value) { + bitField0_ |= 0x00000010; + exitValue_ = value; + onChanged(); + return this; + } + public Builder clearExitValue() { + bitField0_ = (bitField0_ & ~0x00000010); + exitValue_ = 0; + onChanged(); + return this; + } + + // @@protoc_insertion_point(builder_scope:InjectFailure) + } + + static { + defaultInstance = new InjectFailure(true); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:InjectFailure) + } + + private static com.google.protobuf.Descriptors.Descriptor + internal_static_Wrapper_descriptor; + private static + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_Wrapper_fieldAccessorTable; + private static com.google.protobuf.Descriptors.Descriptor + internal_static_Hello_descriptor; + private static + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_Hello_fieldAccessorTable; + private static com.google.protobuf.Descriptors.Descriptor + internal_static_EnterBarrier_descriptor; + private static + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_EnterBarrier_fieldAccessorTable; + private static com.google.protobuf.Descriptors.Descriptor + internal_static_AddressRequest_descriptor; + private static + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_AddressRequest_fieldAccessorTable; + private static com.google.protobuf.Descriptors.Descriptor + internal_static_Address_descriptor; + private static + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_Address_fieldAccessorTable; + private static com.google.protobuf.Descriptors.Descriptor + internal_static_InjectFailure_descriptor; + private static + com.google.protobuf.GeneratedMessage.FieldAccessorTable + internal_static_InjectFailure_fieldAccessorTable; + + public static com.google.protobuf.Descriptors.FileDescriptor + getDescriptor() { + return descriptor; + } + private static com.google.protobuf.Descriptors.FileDescriptor + descriptor; + static { + java.lang.String[] descriptorData = { + "\n\033TestConductorProtocol.proto\"\216\001\n\007Wrappe" + + "r\022\025\n\005hello\030\001 \001(\0132\006.Hello\022\036\n\007barrier\030\002 \001(" + + "\0132\r.EnterBarrier\022\037\n\007failure\030\003 \001(\0132\016.Inje" + + "ctFailure\022\014\n\004done\030\004 \001(\t\022\035\n\004addr\030\005 \001(\0132\017." + + "AddressRequest\"0\n\005Hello\022\014\n\004name\030\001 \002(\t\022\031\n" + + "\007address\030\002 \002(\0132\010.Address\",\n\014EnterBarrier" + + "\022\014\n\004name\030\001 \002(\t\022\016\n\006status\030\002 \001(\010\"6\n\016Addres" + + "sRequest\022\014\n\004node\030\001 \002(\t\022\026\n\004addr\030\002 \001(\0132\010.A" + + "ddress\"G\n\007Address\022\020\n\010protocol\030\001 \002(\t\022\016\n\006s" + + "ystem\030\002 \002(\t\022\014\n\004host\030\003 \002(\t\022\014\n\004port\030\004 \002(\005\"", + "\212\001\n\rInjectFailure\022\032\n\007failure\030\001 \002(\0162\t.Fai" + + "lType\022\035\n\tdirection\030\002 \001(\0162\n.Direction\022\031\n\007" + + "address\030\003 \001(\0132\010.Address\022\020\n\010rateMBit\030\006 \001(" + + "\002\022\021\n\texitValue\030\007 \001(\005*A\n\010FailType\022\014\n\010Thro" + + "ttle\020\001\022\016\n\nDisconnect\020\002\022\t\n\005Abort\020\003\022\014\n\010Shu" + + "tdown\020\004*,\n\tDirection\022\010\n\004Send\020\001\022\013\n\007Receiv" + + "e\020\002\022\010\n\004Both\020\003B\035\n\031akka.remote.testconduct" + + "orH\001" + }; + com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner = + new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() { + public com.google.protobuf.ExtensionRegistry assignDescriptors( + com.google.protobuf.Descriptors.FileDescriptor root) { + descriptor = root; + internal_static_Wrapper_descriptor = + getDescriptor().getMessageTypes().get(0); + internal_static_Wrapper_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_Wrapper_descriptor, + new java.lang.String[] { "Hello", "Barrier", "Failure", "Done", "Addr", }, + akka.remote.testconductor.TestConductorProtocol.Wrapper.class, + akka.remote.testconductor.TestConductorProtocol.Wrapper.Builder.class); + internal_static_Hello_descriptor = + getDescriptor().getMessageTypes().get(1); + internal_static_Hello_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_Hello_descriptor, + new java.lang.String[] { "Name", "Address", }, + akka.remote.testconductor.TestConductorProtocol.Hello.class, + akka.remote.testconductor.TestConductorProtocol.Hello.Builder.class); + internal_static_EnterBarrier_descriptor = + getDescriptor().getMessageTypes().get(2); + internal_static_EnterBarrier_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_EnterBarrier_descriptor, + new java.lang.String[] { "Name", "Status", }, + akka.remote.testconductor.TestConductorProtocol.EnterBarrier.class, + akka.remote.testconductor.TestConductorProtocol.EnterBarrier.Builder.class); + internal_static_AddressRequest_descriptor = + getDescriptor().getMessageTypes().get(3); + internal_static_AddressRequest_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_AddressRequest_descriptor, + new java.lang.String[] { "Node", "Addr", }, + akka.remote.testconductor.TestConductorProtocol.AddressRequest.class, + akka.remote.testconductor.TestConductorProtocol.AddressRequest.Builder.class); + internal_static_Address_descriptor = + getDescriptor().getMessageTypes().get(4); + internal_static_Address_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_Address_descriptor, + new java.lang.String[] { "Protocol", "System", "Host", "Port", }, + akka.remote.testconductor.TestConductorProtocol.Address.class, + akka.remote.testconductor.TestConductorProtocol.Address.Builder.class); + internal_static_InjectFailure_descriptor = + getDescriptor().getMessageTypes().get(5); + internal_static_InjectFailure_fieldAccessorTable = new + com.google.protobuf.GeneratedMessage.FieldAccessorTable( + internal_static_InjectFailure_descriptor, + new java.lang.String[] { "Failure", "Direction", "Address", "RateMBit", "ExitValue", }, + akka.remote.testconductor.TestConductorProtocol.InjectFailure.class, + akka.remote.testconductor.TestConductorProtocol.InjectFailure.Builder.class); + return null; + } + }; + com.google.protobuf.Descriptors.FileDescriptor + .internalBuildGeneratedFileFrom(descriptorData, + new com.google.protobuf.Descriptors.FileDescriptor[] { + }, assigner); + } + + // @@protoc_insertion_point(outer_class_scope) +} diff --git a/akka-remote-tests/src/main/protocol/TestConductorProtocol.proto b/akka-remote-tests/src/main/protocol/TestConductorProtocol.proto new file mode 100644 index 0000000000..648234614e --- /dev/null +++ b/akka-remote-tests/src/main/protocol/TestConductorProtocol.proto @@ -0,0 +1,62 @@ +/** + * Copyright (C) 2009-2011 Typesafe Inc. + */ + +option java_package = "akka.remote.testconductor"; +option optimize_for = SPEED; + +/****************************************** + Compile with: + cd ./akka-remote/src/main/protocol + protoc TestConductorProtocol.proto --java_out ../java +*******************************************/ + +message Wrapper { + optional Hello hello = 1; + optional EnterBarrier barrier = 2; + optional InjectFailure failure = 3; + optional string done = 4; + optional AddressRequest addr = 5; +} + +message Hello { + required string name = 1; + required Address address = 2; +} + +message EnterBarrier { + required string name = 1; + optional bool status = 2; +} + +message AddressRequest { + required string node = 1; + optional Address addr = 2; +} + +message Address { + required string protocol = 1; + required string system = 2; + required string host = 3; + required int32 port = 4; +} + +enum FailType { + Throttle = 1; + Disconnect = 2; + Abort = 3; + Shutdown = 4; +} +enum Direction { + Send = 1; + Receive = 2; + Both = 3; +} +message InjectFailure { + required FailType failure = 1; + optional Direction direction = 2; + optional Address address = 3; + optional float rateMBit = 6; + optional int32 exitValue = 7; +} + diff --git a/akka-remote-tests/src/main/resources/reference.conf b/akka-remote-tests/src/main/resources/reference.conf new file mode 100644 index 0000000000..40c16c4ccd --- /dev/null +++ b/akka-remote-tests/src/main/resources/reference.conf @@ -0,0 +1,33 @@ +############################################# +# Akka Remote Testing Reference Config File # +############################################# + +# This is the reference config file that contains all the default settings. +# Make your edits/overrides in your application.conf. + +akka { + testconductor { + + # Timeout for joining a barrier: this is the maximum time any participants + # waits for everybody else to join a named barrier. + barrier-timeout = 30s + + # Timeout for interrogation of TestConductor’s Controller actor + query-timeout = 5s + + # Threshold for packet size in time unit above which the failure injector will + # split the packet and deliver in smaller portions; do not give value smaller + # than HashedWheelTimer resolution (would not make sense) + packet-split-threshold = 100ms + + # amount of time for the ClientFSM to wait for the connection to the conductor + # to be successful + connect-timeout = 20s + + # Number of connect attempts to be made to the conductor controller + client-reconnects = 10 + + # minimum time interval which is to be inserted between reconnect attempts + reconnect-backoff = 1s + } +} \ No newline at end of file diff --git a/akka-remote-tests/src/main/scala/akka/remote/testconductor/Conductor.scala b/akka-remote-tests/src/main/scala/akka/remote/testconductor/Conductor.scala new file mode 100644 index 0000000000..d46f682d58 --- /dev/null +++ b/akka-remote-tests/src/main/scala/akka/remote/testconductor/Conductor.scala @@ -0,0 +1,566 @@ +/** + * Copyright (C) 2009-2012 Typesafe Inc. + */ +package akka.remote.testconductor + +import akka.actor.{ Actor, ActorRef, ActorSystem, LoggingFSM, Props } +import RemoteConnection.getAddrString +import TestConductorProtocol._ +import org.jboss.netty.channel.{ Channel, SimpleChannelUpstreamHandler, ChannelHandlerContext, ChannelStateEvent, MessageEvent } +import com.typesafe.config.ConfigFactory +import akka.util.Timeout +import akka.util.Duration +import akka.util.duration._ +import akka.pattern.ask +import java.util.concurrent.TimeUnit.MILLISECONDS +import akka.dispatch.Await +import akka.event.LoggingAdapter +import akka.actor.PoisonPill +import akka.event.Logging +import scala.util.control.NoStackTrace +import akka.event.LoggingReceive +import akka.actor.Address +import java.net.InetSocketAddress +import akka.dispatch.Future +import akka.actor.OneForOneStrategy +import akka.actor.SupervisorStrategy +import java.util.concurrent.ConcurrentHashMap +import akka.actor.Status + +sealed trait Direction { + def includes(other: Direction): Boolean +} + +object Direction { + case object Send extends Direction { + override def includes(other: Direction): Boolean = other match { + case Send ⇒ true + case _ ⇒ false + } + } + case object Receive extends Direction { + override def includes(other: Direction): Boolean = other match { + case Receive ⇒ true + case _ ⇒ false + } + } + case object Both extends Direction { + override def includes(other: Direction): Boolean = true + } +} + +/** + * The conductor is the one orchestrating the test: it governs the + * [[akka.remote.testconductor.Controller]]’s port to which all + * [[akka.remote.testconductor.Player]]s connect, it issues commands to their + * [[akka.remote.testconductor.NetworkFailureInjector]] and provides support + * for barriers using the [[akka.remote.testconductor.BarrierCoordinator]]. + * All of this is bundled inside the [[akka.remote.testconductor.TestConductorExt]] + * extension. + */ +trait Conductor { this: TestConductorExt ⇒ + + import Controller._ + + private var _controller: ActorRef = _ + private def controller: ActorRef = _controller match { + case null ⇒ throw new IllegalStateException("TestConductorServer was not started") + case x ⇒ x + } + + /** + * Start the [[akka.remote.testconductor.Controller]], which in turn will + * bind to a TCP port as specified in the `akka.testconductor.port` config + * property, where 0 denotes automatic allocation. Since the latter is + * actually preferred, a `Future[Int]` is returned which will be completed + * with the port number actually chosen, so that this can then be communicated + * to the players for their proper start-up. + * + * This method also invokes [[akka.remote.testconductor.Player]].startClient, + * since it is expected that the conductor participates in barriers for + * overall coordination. The returned Future will only be completed once the + * client’s start-up finishes, which in fact waits for all other players to + * connect. + * + * @param participants gives the number of participants which shall connect + * before any of their startClient() operations complete. + */ + def startController(participants: Int, name: RoleName, controllerPort: InetSocketAddress): Future[InetSocketAddress] = { + if (_controller ne null) throw new RuntimeException("TestConductorServer was already started") + _controller = system.actorOf(Props(new Controller(participants, controllerPort)), "controller") + import Settings.BarrierTimeout + controller ? GetSockAddr flatMap { case sockAddr: InetSocketAddress ⇒ startClient(name, sockAddr) map (_ ⇒ sockAddr) } + } + + /** + * Obtain the port to which the controller’s socket is actually bound. This + * will deviate from the configuration in `akka.testconductor.port` in case + * that was given as zero. + */ + def sockAddr: Future[InetSocketAddress] = { + import Settings.QueryTimeout + controller ? GetSockAddr mapTo + } + + /** + * Make the remoting pipeline on the node throttle data sent to or received + * from the given remote peer. Throttling works by delaying packet submission + * within the netty pipeline until the packet would have been completely sent + * according to the given rate, the previous packet completion and the current + * packet length. In case of large packets they are split up if the calculated + * send pause would exceed `akka.testconductor.packet-split-threshold` + * (roughly). All of this uses the system’s HashedWheelTimer, which is not + * terribly precise and will execute tasks later than they are schedule (even + * on average), but that is countered by using the actual execution time for + * determining how much to send, leading to the correct output rate, but with + * increased latency. + * + * @param node is the symbolic name of the node which is to be affected + * @param target is the symbolic name of the other node to which connectivity shall be throttled + * @param direction can be either `Direction.Send`, `Direction.Receive` or `Direction.Both` + * @param rateMBit is the maximum data rate in MBit + */ + def throttle(node: RoleName, target: RoleName, direction: Direction, rateMBit: Double): Future[Done] = { + import Settings.QueryTimeout + controller ? Throttle(node, target, direction, rateMBit.toFloat) mapTo + } + + /** + * Switch the Netty pipeline of the remote support into blackhole mode for + * sending and/or receiving: it will just drop all messages right before + * submitting them to the Socket or right after receiving them from the + * Socket. + * + * @param node is the symbolic name of the node which is to be affected + * @param target is the symbolic name of the other node to which connectivity shall be impeded + * @param direction can be either `Direction.Send`, `Direction.Receive` or `Direction.Both` + */ + def blackhole(node: RoleName, target: RoleName, direction: Direction): Future[Done] = { + import Settings.QueryTimeout + controller ? Throttle(node, target, direction, 0f) mapTo + } + + /** + * Tell the remote support to shutdown the connection to the given remote + * peer. It works regardless of whether the recipient was initiator or + * responder. + * + * @param node is the symbolic name of the node which is to be affected + * @param target is the symbolic name of the other node to which connectivity shall be impeded + */ + def disconnect(node: RoleName, target: RoleName): Future[Done] = { + import Settings.QueryTimeout + controller ? Disconnect(node, target, false) mapTo + } + + /** + * Tell the remote support to TCP_RESET the connection to the given remote + * peer. It works regardless of whether the recipient was initiator or + * responder. + * + * @param node is the symbolic name of the node which is to be affected + * @param target is the symbolic name of the other node to which connectivity shall be impeded + */ + def abort(node: RoleName, target: RoleName): Future[Done] = { + import Settings.QueryTimeout + controller ? Disconnect(node, target, true) mapTo + } + + /** + * Tell the remote node to shut itself down using System.exit with the given + * exitValue. + * + * @param node is the symbolic name of the node which is to be affected + * @param exitValue is the return code which shall be given to System.exit + */ + def shutdown(node: RoleName, exitValue: Int): Future[Done] = { + import Settings.QueryTimeout + controller ? Terminate(node, exitValue) mapTo + } + + /** + * Tell the SBT plugin to forcibly terminate the given remote node using Process.destroy. + * + * @param node is the symbolic name of the node which is to be affected + */ + // TODO: uncomment (and implement in Controller) if really needed + // def kill(node: RoleName): Future[Done] = { + // import Settings.QueryTimeout + // controller ? Terminate(node, -1) mapTo + // } + + /** + * Obtain the list of remote host names currently registered. + */ + def getNodes: Future[Iterable[RoleName]] = { + import Settings.QueryTimeout + controller ? GetNodes mapTo + } + + /** + * Remove a remote host from the list, so that the remaining nodes may still + * pass subsequent barriers. This must be done before the client connection + * breaks down in order to affect an “orderly” removal (i.e. without failing + * present and future barriers). + * + * @param node is the symbolic name of the node which is to be removed + */ + def removeNode(node: RoleName): Future[Done] = { + import Settings.QueryTimeout + controller ? Remove(node) mapTo + } + +} + +/** + * This handler is installed at the end of the controller’s netty pipeline. Its only + * purpose is to dispatch incoming messages to the right ServerFSM actor. There is + * one shared instance of this class for all connections accepted by one Controller. + * + * INTERNAL API. + */ +private[akka] class ConductorHandler(_createTimeout: Timeout, controller: ActorRef, log: LoggingAdapter) extends SimpleChannelUpstreamHandler { + + implicit val createTimeout = _createTimeout + val clients = new ConcurrentHashMap[Channel, ActorRef]() + + override def channelConnected(ctx: ChannelHandlerContext, event: ChannelStateEvent) = { + val channel = event.getChannel + log.debug("connection from {}", getAddrString(channel)) + val fsm: ActorRef = Await.result(controller ? Controller.CreateServerFSM(channel) mapTo, Duration.Inf) + clients.put(channel, fsm) + } + + override def channelDisconnected(ctx: ChannelHandlerContext, event: ChannelStateEvent) = { + val channel = event.getChannel + log.debug("disconnect from {}", getAddrString(channel)) + val fsm = clients.get(channel) + fsm ! Controller.ClientDisconnected + clients.remove(channel) + } + + override def messageReceived(ctx: ChannelHandlerContext, event: MessageEvent) = { + val channel = event.getChannel + log.debug("message from {}: {}", getAddrString(channel), event.getMessage) + event.getMessage match { + case msg: NetworkOp ⇒ + clients.get(channel) ! msg + case msg ⇒ + log.info("client {} sent garbage '{}', disconnecting", getAddrString(channel), msg) + channel.close() + } + } + +} + +/** + * INTERNAL API. + */ +private[akka] object ServerFSM { + sealed trait State + case object Initial extends State + case object Ready extends State +} + +/** + * The server part of each client connection is represented by a ServerFSM. + * The Initial state handles reception of the new client’s + * [[akka.remote.testconductor.Hello]] message (which is needed for all subsequent + * node name translations). + * + * In the Ready state, messages from the client are forwarded to the controller + * and [[akka.remote.testconductor.Send]] requests are sent, but the latter is + * treated specially: all client operations are to be confirmed by a + * [[akka.remote.testconductor.Done]] message, and there can be only one such + * request outstanding at a given time (i.e. a Send fails if the previous has + * not yet been acknowledged). + * + * INTERNAL API. + */ +private[akka] class ServerFSM(val controller: ActorRef, val channel: Channel) extends Actor with LoggingFSM[ServerFSM.State, Option[ActorRef]] { + import ServerFSM._ + import akka.actor.FSM._ + import Controller._ + + startWith(Initial, None) + + whenUnhandled { + case Event(ClientDisconnected, Some(s)) ⇒ + s ! Status.Failure(new RuntimeException("client disconnected in state " + stateName + ": " + channel)) + stop() + case Event(ClientDisconnected, None) ⇒ stop() + } + + onTermination { + case _ ⇒ controller ! ClientDisconnected + } + + when(Initial, stateTimeout = 10 seconds) { + case Event(Hello(name, addr), _) ⇒ + controller ! NodeInfo(RoleName(name), addr, self) + goto(Ready) + case Event(x: NetworkOp, _) ⇒ + log.warning("client {} sent no Hello in first message (instead {}), disconnecting", getAddrString(channel), x) + channel.close() + stop() + case Event(ToClient(msg), _) ⇒ + log.warning("cannot send {} in state Initial", msg) + stay + case Event(StateTimeout, _) ⇒ + log.info("closing channel to {} because of Hello timeout", getAddrString(channel)) + channel.close() + stop() + } + + when(Ready) { + case Event(d: Done, Some(s)) ⇒ + s ! d + stay using None + case Event(op: ServerOp, _) ⇒ + controller ! op + stay + case Event(msg: NetworkOp, _) ⇒ + log.warning("client {} sent unsupported message {}", getAddrString(channel), msg) + stop() + case Event(ToClient(msg: UnconfirmedClientOp), _) ⇒ + channel.write(msg) + stay + case Event(ToClient(msg), None) ⇒ + channel.write(msg) + stay using Some(sender) + case Event(ToClient(msg), _) ⇒ + log.warning("cannot send {} while waiting for previous ACK", msg) + stay + } + + initialize + + onTermination { + case _ ⇒ channel.close() + } +} + +/** + * INTERNAL API. + */ +private[akka] object Controller { + case class ClientDisconnected(name: RoleName) + case object GetNodes + case object GetSockAddr + case class CreateServerFSM(channel: Channel) + + case class NodeInfo(name: RoleName, addr: Address, fsm: ActorRef) +} + +/** + * This controls test execution by managing barriers (delegated to + * [[akka.remote.testconductor.BarrierCoordinator]], its child) and allowing + * network and other failures to be injected at the test nodes. + * + * INTERNAL API. + */ +private[akka] class Controller(private var initialParticipants: Int, controllerPort: InetSocketAddress) extends Actor { + import Controller._ + import BarrierCoordinator._ + + val settings = TestConductor().Settings + val connection = RemoteConnection(Server, controllerPort, + new ConductorHandler(settings.QueryTimeout, self, Logging(context.system, "ConductorHandler"))) + + /* + * Supervision of the BarrierCoordinator means to catch all his bad emotions + * and sometimes console him (BarrierEmpty, BarrierTimeout), sometimes tell + * him to hate the world (WrongBarrier, DuplicateNode, ClientLost). The latter shall help + * terminate broken tests as quickly as possible (i.e. without awaiting + * BarrierTimeouts in the players). + */ + override def supervisorStrategy = OneForOneStrategy() { + case BarrierTimeout(data) ⇒ SupervisorStrategy.Resume + case BarrierEmpty(data, msg) ⇒ SupervisorStrategy.Resume + case WrongBarrier(name, client, data) ⇒ client ! ToClient(BarrierResult(name, false)); failBarrier(data) + case ClientLost(data, node) ⇒ failBarrier(data) + case DuplicateNode(data, node) ⇒ failBarrier(data) + } + + def failBarrier(data: Data): SupervisorStrategy.Directive = { + for (c ← data.arrived) c ! ToClient(BarrierResult(data.barrier, false)) + SupervisorStrategy.Restart + } + + val barrier = context.actorOf(Props[BarrierCoordinator], "barriers") + var nodes = Map[RoleName, NodeInfo]() + + // map keeping unanswered queries for node addresses (enqueued upon GetAddress, serviced upon NodeInfo) + var addrInterest = Map[RoleName, Set[ActorRef]]() + val generation = Iterator from 1 + + override def receive = LoggingReceive { + case CreateServerFSM(channel) ⇒ + val (ip, port) = channel.getRemoteAddress match { case s: InetSocketAddress ⇒ (s.getAddress.getHostAddress, s.getPort) } + val name = ip + ":" + port + "-server" + generation.next + sender ! context.actorOf(Props(new ServerFSM(self, channel)), name) + case c @ NodeInfo(name, addr, fsm) ⇒ + barrier forward c + if (nodes contains name) { + if (initialParticipants > 0) { + for (NodeInfo(_, _, client) ← nodes.values) client ! ToClient(BarrierResult("initial startup", false)) + initialParticipants = 0 + } + fsm ! ToClient(BarrierResult("initial startup", false)) + } else { + nodes += name -> c + if (initialParticipants <= 0) fsm ! ToClient(Done) + else if (nodes.size == initialParticipants) { + for (NodeInfo(_, _, client) ← nodes.values) client ! ToClient(Done) + initialParticipants = 0 + } + if (addrInterest contains name) { + addrInterest(name) foreach (_ ! ToClient(AddressReply(name, addr))) + addrInterest -= name + } + } + case c @ ClientDisconnected(name) ⇒ + nodes -= name + barrier forward c + case op: ServerOp ⇒ + op match { + case _: EnterBarrier ⇒ barrier forward op + case GetAddress(node) ⇒ + if (nodes contains node) sender ! ToClient(AddressReply(node, nodes(node).addr)) + else addrInterest += node -> ((addrInterest get node getOrElse Set()) + sender) + } + case op: CommandOp ⇒ + op match { + case Throttle(node, target, direction, rateMBit) ⇒ + val t = nodes(target) + nodes(node).fsm forward ToClient(ThrottleMsg(t.addr, direction, rateMBit)) + case Disconnect(node, target, abort) ⇒ + val t = nodes(target) + nodes(node).fsm forward ToClient(DisconnectMsg(t.addr, abort)) + case Terminate(node, exitValueOrKill) ⇒ + if (exitValueOrKill < 0) { + // TODO: kill via SBT + } else { + nodes(node).fsm forward ToClient(TerminateMsg(exitValueOrKill)) + } + case Remove(node) ⇒ + nodes -= node + barrier ! BarrierCoordinator.RemoveClient(node) + } + case GetNodes ⇒ sender ! nodes.keys + case GetSockAddr ⇒ sender ! connection.getLocalAddress + } +} + +/** + * INTERNAL API. + */ +private[akka] object BarrierCoordinator { + sealed trait State + case object Idle extends State + case object Waiting extends State + + case class RemoveClient(name: RoleName) + + case class Data(clients: Set[Controller.NodeInfo], barrier: String, arrived: List[ActorRef]) + + trait Printer { this: Product with Throwable with NoStackTrace ⇒ + override def toString = productPrefix + productIterator.mkString("(", ", ", ")") + } + + case class BarrierTimeout(data: Data) extends RuntimeException(data.barrier) with NoStackTrace with Printer + case class DuplicateNode(data: Data, node: Controller.NodeInfo) extends RuntimeException with NoStackTrace with Printer + case class WrongBarrier(barrier: String, client: ActorRef, data: Data) extends RuntimeException(barrier) with NoStackTrace with Printer + case class BarrierEmpty(data: Data, msg: String) extends RuntimeException(msg) with NoStackTrace with Printer + case class ClientLost(data: Data, client: RoleName) extends RuntimeException with NoStackTrace with Printer +} + +/** + * This barrier coordinator gets informed of players connecting (NodeInfo), + * players being deliberately removed (RemoveClient) or failing (ClientDisconnected) + * by the controller. It also receives EnterBarrier requests, where upon the first + * one received the name of the current barrier is set and all other known clients + * are expected to join the barrier, whereupon all of the will be sent the successful + * EnterBarrier return message. In case of planned removals, this may just happen + * earlier, in case of failures the current barrier (and all subsequent ones) will + * be failed by sending BarrierFailed responses. + * + * INTERNAL API. + */ +private[akka] class BarrierCoordinator extends Actor with LoggingFSM[BarrierCoordinator.State, BarrierCoordinator.Data] { + import BarrierCoordinator._ + import akka.actor.FSM._ + import Controller._ + + // this shall be set to false if all subsequent barriers shall fail + var failed = false + override def preRestart(reason: Throwable, message: Option[Any]) {} + override def postRestart(reason: Throwable) { failed = true } + + // TODO what happens with the other waiting players in case of a test failure? + + startWith(Idle, Data(Set(), "", Nil)) + + whenUnhandled { + case Event(n: NodeInfo, d @ Data(clients, _, _)) ⇒ + if (clients.find(_.name == n.name).isDefined) throw new DuplicateNode(d, n) + stay using d.copy(clients = clients + n) + case Event(ClientDisconnected(name), d @ Data(clients, _, arrived)) ⇒ + if (clients.isEmpty) throw BarrierEmpty(d, "no client to disconnect") + (clients find (_.name == name)) match { + case None ⇒ stay + case Some(c) ⇒ throw ClientLost(d.copy(clients = clients - c, arrived = arrived filterNot (_ == c.fsm)), name) + } + } + + when(Idle) { + case Event(EnterBarrier(name), d @ Data(clients, _, _)) ⇒ + if (failed) + stay replying ToClient(BarrierResult(name, false)) + else if (clients.map(_.fsm) == Set(sender)) + stay replying ToClient(BarrierResult(name, true)) + else if (clients.find(_.fsm == sender).isEmpty) + stay replying ToClient(BarrierResult(name, false)) + else + goto(Waiting) using d.copy(barrier = name, arrived = sender :: Nil) + case Event(RemoveClient(name), d @ Data(clients, _, _)) ⇒ + if (clients.isEmpty) throw BarrierEmpty(d, "no client to remove") + stay using d.copy(clients = clients filterNot (_.name == name)) + } + + onTransition { + case Idle -> Waiting ⇒ setTimer("Timeout", StateTimeout, TestConductor().Settings.BarrierTimeout.duration, false) + case Waiting -> Idle ⇒ cancelTimer("Timeout") + } + + when(Waiting) { + case Event(EnterBarrier(name), d @ Data(clients, barrier, arrived)) ⇒ + if (name != barrier || clients.find(_.fsm == sender).isEmpty) throw WrongBarrier(name, sender, d) + val together = sender :: arrived + handleBarrier(d.copy(arrived = together)) + case Event(RemoveClient(name), d @ Data(clients, barrier, arrived)) ⇒ + clients find (_.name == name) match { + case None ⇒ stay + case Some(client) ⇒ + handleBarrier(d.copy(clients = clients - client, arrived = arrived filterNot (_ == client.fsm))) + } + case Event(StateTimeout, data) ⇒ + throw BarrierTimeout(data) + } + + initialize + + def handleBarrier(data: Data): State = { + log.debug("handleBarrier({})", data) + if (data.arrived.isEmpty) { + goto(Idle) using data.copy(barrier = "") + } else if ((data.clients.map(_.fsm) -- data.arrived).isEmpty) { + data.arrived foreach (_ ! ToClient(BarrierResult(data.barrier, true))) + goto(Idle) using data.copy(barrier = "", arrived = Nil) + } else { + stay using data + } + } + +} + diff --git a/akka-remote-tests/src/main/scala/akka/remote/testconductor/DataTypes.scala b/akka-remote-tests/src/main/scala/akka/remote/testconductor/DataTypes.scala new file mode 100644 index 0000000000..022ae2d89b --- /dev/null +++ b/akka-remote-tests/src/main/scala/akka/remote/testconductor/DataTypes.scala @@ -0,0 +1,139 @@ +/** + * Copyright (C) 2009-2011 Typesafe Inc. + */ +package akka.remote.testconductor + +import org.jboss.netty.handler.codec.oneone.OneToOneEncoder +import org.jboss.netty.channel.ChannelHandlerContext +import org.jboss.netty.channel.Channel +import akka.remote.testconductor.{ TestConductorProtocol ⇒ TCP } +import com.google.protobuf.Message +import akka.actor.Address +import org.jboss.netty.handler.codec.oneone.OneToOneDecoder + +case class RoleName(name: String) + +private[akka] case class ToClient(msg: ClientOp with NetworkOp) +private[akka] case class ToServer(msg: ServerOp with NetworkOp) + +private[akka] sealed trait ClientOp // messages sent to from Conductor to Player +private[akka] sealed trait ServerOp // messages sent to from Player to Conductor +private[akka] sealed trait CommandOp // messages sent from TestConductorExt to Conductor +private[akka] sealed trait NetworkOp // messages sent over the wire +private[akka] sealed trait UnconfirmedClientOp extends ClientOp // unconfirmed messages going to the Player +private[akka] sealed trait ConfirmedClientOp extends ClientOp + +/** + * First message of connection sets names straight. + */ +private[akka] case class Hello(name: String, addr: Address) extends NetworkOp + +private[akka] case class EnterBarrier(name: String) extends ServerOp with NetworkOp +private[akka] case class BarrierResult(name: String, success: Boolean) extends UnconfirmedClientOp with NetworkOp + +private[akka] case class Throttle(node: RoleName, target: RoleName, direction: Direction, rateMBit: Float) extends CommandOp +private[akka] case class ThrottleMsg(target: Address, direction: Direction, rateMBit: Float) extends ConfirmedClientOp with NetworkOp + +private[akka] case class Disconnect(node: RoleName, target: RoleName, abort: Boolean) extends CommandOp +private[akka] case class DisconnectMsg(target: Address, abort: Boolean) extends ConfirmedClientOp with NetworkOp + +private[akka] case class Terminate(node: RoleName, exitValueOrKill: Int) extends CommandOp +private[akka] case class TerminateMsg(exitValue: Int) extends ConfirmedClientOp with NetworkOp + +private[akka] case class GetAddress(node: RoleName) extends ServerOp with NetworkOp +private[akka] case class AddressReply(node: RoleName, addr: Address) extends UnconfirmedClientOp with NetworkOp + +private[akka] abstract class Done extends ServerOp with UnconfirmedClientOp with NetworkOp +private[akka] case object Done extends Done { + def getInstance: Done = this +} + +private[akka] case class Remove(node: RoleName) extends CommandOp + +private[akka] class MsgEncoder extends OneToOneEncoder { + + implicit def address2proto(addr: Address): TCP.Address = + TCP.Address.newBuilder + .setProtocol(addr.protocol) + .setSystem(addr.system) + .setHost(addr.host.get) + .setPort(addr.port.get) + .build + + implicit def direction2proto(dir: Direction): TCP.Direction = dir match { + case Direction.Send ⇒ TCP.Direction.Send + case Direction.Receive ⇒ TCP.Direction.Receive + case Direction.Both ⇒ TCP.Direction.Both + } + + def encode(ctx: ChannelHandlerContext, ch: Channel, msg: AnyRef): AnyRef = msg match { + case x: NetworkOp ⇒ + val w = TCP.Wrapper.newBuilder + x match { + case Hello(name, addr) ⇒ + w.setHello(TCP.Hello.newBuilder.setName(name).setAddress(addr)) + case EnterBarrier(name) ⇒ + w.setBarrier(TCP.EnterBarrier.newBuilder.setName(name)) + case BarrierResult(name, success) ⇒ + w.setBarrier(TCP.EnterBarrier.newBuilder.setName(name).setStatus(success)) + case ThrottleMsg(target, dir, rate) ⇒ + w.setFailure(TCP.InjectFailure.newBuilder.setAddress(target) + .setFailure(TCP.FailType.Throttle).setDirection(dir).setRateMBit(rate)) + case DisconnectMsg(target, abort) ⇒ + w.setFailure(TCP.InjectFailure.newBuilder.setAddress(target) + .setFailure(if (abort) TCP.FailType.Abort else TCP.FailType.Disconnect)) + case TerminateMsg(exitValue) ⇒ + w.setFailure(TCP.InjectFailure.newBuilder.setFailure(TCP.FailType.Shutdown).setExitValue(exitValue)) + case GetAddress(node) ⇒ + w.setAddr(TCP.AddressRequest.newBuilder.setNode(node.name)) + case AddressReply(node, addr) ⇒ + w.setAddr(TCP.AddressRequest.newBuilder.setNode(node.name).setAddr(addr)) + case _: Done ⇒ + w.setDone("") + } + w.build + case _ ⇒ throw new IllegalArgumentException("wrong message " + msg) + } +} + +private[akka] class MsgDecoder extends OneToOneDecoder { + + implicit def address2scala(addr: TCP.Address): Address = + Address(addr.getProtocol, addr.getSystem, addr.getHost, addr.getPort) + + implicit def direction2scala(dir: TCP.Direction): Direction = dir match { + case TCP.Direction.Send ⇒ Direction.Send + case TCP.Direction.Receive ⇒ Direction.Receive + case TCP.Direction.Both ⇒ Direction.Both + } + + def decode(ctx: ChannelHandlerContext, ch: Channel, msg: AnyRef): AnyRef = msg match { + case w: TCP.Wrapper if w.getAllFields.size == 1 ⇒ + if (w.hasHello) { + val h = w.getHello + Hello(h.getName, h.getAddress) + } else if (w.hasBarrier) { + val barrier = w.getBarrier + if (barrier.hasStatus) BarrierResult(barrier.getName, barrier.getStatus) + else EnterBarrier(w.getBarrier.getName) + } else if (w.hasFailure) { + val f = w.getFailure + import TCP.{ FailType ⇒ FT } + f.getFailure match { + case FT.Throttle ⇒ ThrottleMsg(f.getAddress, f.getDirection, f.getRateMBit) + case FT.Abort ⇒ DisconnectMsg(f.getAddress, true) + case FT.Disconnect ⇒ DisconnectMsg(f.getAddress, false) + case FT.Shutdown ⇒ TerminateMsg(f.getExitValue) + } + } else if (w.hasAddr) { + val a = w.getAddr + if (a.hasAddr) AddressReply(RoleName(a.getNode), a.getAddr) + else GetAddress(RoleName(a.getNode)) + } else if (w.hasDone) { + Done + } else { + throw new IllegalArgumentException("unknown message " + msg) + } + case _ ⇒ throw new IllegalArgumentException("wrong message " + msg) + } +} diff --git a/akka-remote-tests/src/main/scala/akka/remote/testconductor/Extension.scala b/akka-remote-tests/src/main/scala/akka/remote/testconductor/Extension.scala new file mode 100644 index 0000000000..48f3983a78 --- /dev/null +++ b/akka-remote-tests/src/main/scala/akka/remote/testconductor/Extension.scala @@ -0,0 +1,73 @@ +package akka.remote.testconductor + +import akka.actor.ExtensionKey +import akka.actor.Extension +import akka.actor.ExtendedActorSystem +import akka.remote.RemoteActorRefProvider +import akka.actor.ActorContext +import akka.util.{ Duration, Timeout } +import java.util.concurrent.TimeUnit.MILLISECONDS +import akka.actor.ActorRef +import java.util.concurrent.ConcurrentHashMap +import akka.actor.Address +import akka.actor.ActorSystemImpl +import akka.actor.Props + +/** + * Access to the [[akka.remote.testconductor.TestConductorExt]] extension: + * + * {{{ + * val tc = TestConductor(system) + * tc.startController(numPlayers) + * // OR + * tc.startClient(conductorPort) + * }}} + */ +object TestConductor extends ExtensionKey[TestConductorExt] { + + def apply()(implicit ctx: ActorContext): TestConductorExt = apply(ctx.system) + +} + +/** + * This binds together the [[akka.remote.testconductor.Conductor]] and + * [[akka.remote.testconductor.Player]] roles inside an Akka + * [[akka.actor.Extension]]. Please follow the aforementioned links for + * more information. + * + * This extension requires the `akka.actor.provider` + * to be a [[akka.remote.RemoteActorRefProvider]]. + */ +class TestConductorExt(val system: ExtendedActorSystem) extends Extension with Conductor with Player { + + object Settings { + val config = system.settings.config + + val ConnectTimeout = Duration(config.getMilliseconds("akka.testconductor.connect-timeout"), MILLISECONDS) + val ClientReconnects = config.getInt("akka.testconductor.client-reconnects") + val ReconnectBackoff = Duration(config.getMilliseconds("akka.testconductor.reconnect-backoff"), MILLISECONDS) + + implicit val BarrierTimeout = Timeout(Duration(config.getMilliseconds("akka.testconductor.barrier-timeout"), MILLISECONDS)) + implicit val QueryTimeout = Timeout(Duration(config.getMilliseconds("akka.testconductor.query-timeout"), MILLISECONDS)) + val PacketSplitThreshold = Duration(config.getMilliseconds("akka.testconductor.packet-split-threshold"), MILLISECONDS) + } + + /** + * Remote transport used by the actor ref provider. + */ + val transport = system.provider.asInstanceOf[RemoteActorRefProvider].transport + + /** + * Transport address of this Netty-like remote transport. + */ + val address = transport.address + + /** + * INTERNAL API. + * + * [[akka.remote.testconductor.NetworkFailureInjector]]s register themselves here so that + * failures can be injected. + */ + private[akka] val failureInjector = system.asInstanceOf[ActorSystemImpl].systemActorOf(Props[FailureInjector], "FailureInjector") + +} diff --git a/akka-remote-tests/src/main/scala/akka/remote/testconductor/NetworkFailureInjector.scala b/akka-remote-tests/src/main/scala/akka/remote/testconductor/NetworkFailureInjector.scala new file mode 100644 index 0000000000..bf5d7d6007 --- /dev/null +++ b/akka-remote-tests/src/main/scala/akka/remote/testconductor/NetworkFailureInjector.scala @@ -0,0 +1,378 @@ +/** + * Copyright (C) 2009-2012 Typesafe Inc. + */ +package akka.remote.testconductor + +import java.net.InetSocketAddress + +import scala.annotation.tailrec +import scala.collection.immutable.Queue + +import org.jboss.netty.buffer.ChannelBuffer +import org.jboss.netty.channel.{ SimpleChannelHandler, MessageEvent, Channels, ChannelStateEvent, ChannelHandlerContext, ChannelFutureListener, ChannelFuture } + +import akka.actor.{ Props, LoggingFSM, Address, ActorSystem, ActorRef, ActorLogging, Actor, FSM } +import akka.event.Logging +import akka.remote.netty.ChannelAddress +import akka.util.Duration +import akka.util.duration._ + +/** + * INTERNAL API. + */ +private[akka] class FailureInjector extends Actor with ActorLogging { + import ThrottleActor._ + import NetworkFailureInjector._ + + case class ChannelSettings( + ctx: Option[ChannelHandlerContext] = None, + throttleSend: Option[SetRate] = None, + throttleReceive: Option[SetRate] = None) + case class Injectors(sender: ActorRef, receiver: ActorRef) + + var channels = Map[ChannelHandlerContext, Injectors]() + var settings = Map[Address, ChannelSettings]() + var generation = Iterator from 1 + + /** + * Only for a NEW ctx, start ThrottleActors, prime them and update all maps. + */ + def ingestContextAddress(ctx: ChannelHandlerContext, addr: Address): Injectors = { + val gen = generation.next + val name = addr.host.get + ":" + addr.port.get + val thrSend = context.actorOf(Props(new ThrottleActor(ctx)), name + "-snd" + gen) + val thrRecv = context.actorOf(Props(new ThrottleActor(ctx)), name + "-rcv" + gen) + val injectors = Injectors(thrSend, thrRecv) + channels += ctx -> injectors + settings += addr -> (settings get addr map { + case c @ ChannelSettings(prevCtx, ts, tr) ⇒ + ts foreach (thrSend ! _) + tr foreach (thrRecv ! _) + prevCtx match { + case Some(p) ⇒ log.warning("installing context {} instead of {} for address {}", ctx, p, addr) + case None ⇒ // okay + } + c.copy(ctx = Some(ctx)) + } getOrElse ChannelSettings(Some(ctx))) + injectors + } + + /** + * Retrieve target settings, also if they were sketchy before (i.e. no system name). + * In the latter case, copy settings from the sketchy address and remove the old + * mapping. + */ + def retrieveTargetSettings(target: Address): Option[ChannelSettings] = { + settings get target orElse { + val host = target.host + val port = target.port + settings find { + case (Address("akka", "", `host`, `port`), s) ⇒ true + case _ ⇒ false + } map { + case (a, s) ⇒ settings -= a; settings += target -> s; s + } + } + } + + def receive = { + /* + * If a channel handler tells us that he’s been disconnected, stop the + * throttle actors and forget about them (but not possibly applied settings) + */ + case RemoveContext(ctx) ⇒ + channels get ctx foreach { inj ⇒ + context stop inj.sender + context stop inj.receiver + } + channels -= ctx + settings ++= settings collect { case (addr, c @ ChannelSettings(Some(`ctx`), _, _)) ⇒ (addr, c.copy(ctx = None)) } + /* + * Throttle/Blackhole/Unblock connections, based on the sign of rateMBit; + * will inform throttle actors for that destination if currently connected + * and update the settings for the target address; reply is needed to + * confirm this operation and tell the master that he can proceed. + */ + case ThrottleMsg(target, dir, rateMBit) ⇒ + val setting = retrieveTargetSettings(target) + settings += target -> ((setting getOrElse ChannelSettings() match { + case cs @ ChannelSettings(ctx, _, _) if dir includes Direction.Send ⇒ + ctx foreach (c ⇒ channels get c foreach (_.sender ! SetRate(rateMBit))) + cs.copy(throttleSend = Some(SetRate(rateMBit))) + case x ⇒ x + }) match { + case cs @ ChannelSettings(ctx, _, _) if dir includes Direction.Receive ⇒ + ctx foreach (c ⇒ channels get c foreach (_.receiver ! SetRate(rateMBit))) + cs.copy(throttleReceive = Some(SetRate(rateMBit))) + case x ⇒ x + }) + sender ! "ok" + /* + * Disconnect the currently active connection to the given target; reply is + * needed to confirm this operation and tell the master the he can proceed. + */ + case DisconnectMsg(target, abort) ⇒ + retrieveTargetSettings(target) foreach { + case ChannelSettings(Some(ctx), _, _) ⇒ + val ch = ctx.getChannel + if (abort) { + ch.getConfig.setOption("soLinger", 0) + log.info("aborting connection {}", ch) + } else log.info("closing connection {}", ch) + ch.close + case _ ⇒ log.debug("no connection to {} to close or abort", target) + } + sender ! "ok" + /* + * All data transfers up or down the pipeline are redirected through this + * case statement, which dispatches to the throttle actors for the given + * channel handler context. If none exist yet, they will be created, and + * this is a bit complicated in the case where the first message has not + * yet been exchanged, i.e. the other side’s Address is not yet known + * (keep in mind that an actor system’s remote address is not necessarily + * connected in any way to the IP from which we receive the connection). + */ + case s @ Send(ctx, direction, future, msg) ⇒ + channels get ctx match { + case Some(Injectors(snd, rcv)) ⇒ + if (direction includes Direction.Send) snd ! s + if (direction includes Direction.Receive) rcv ! s + case None ⇒ + // don’t do reverse lookup at first + val (ipaddr, ip, port) = ctx.getChannel.getRemoteAddress match { + case s: InetSocketAddress ⇒ (s.getAddress, s.getAddress.getHostAddress, s.getPort) + } + val addr = ChannelAddress.get(ctx.getChannel) orElse { + settings collect { case (a @ Address("akka", _, Some(`ip`), Some(`port`)), _) ⇒ a } headOption + } orElse { + // only if raw IP failed, try with hostname + val name = ipaddr.getHostName + if (name == ip) None + else settings collect { case (a @ Address("akka", _, Some(`name`), Some(`port`)), _) ⇒ a } headOption + } getOrElse Address("akka", "", ip, port) + /* + * ^- the above last resort will not match later requests directly, but be + * picked up by retrieveTargetSettings, so that throttle ops are + * applied to the right throttle actors, assuming that there can + * be only one actor system per host:port. + */ + val inj = ingestContextAddress(ctx, addr) + if (direction includes Direction.Send) inj.sender ! s + if (direction includes Direction.Receive) inj.receiver ! s + } + } +} + +private[akka] object NetworkFailureInjector { + case class RemoveContext(ctx: ChannelHandlerContext) +} + +/** + * Brief overview: all network traffic passes through the `sender`/`receiver` FSMs managed + * by the FailureInjector of the TestConductor extension. These can + * pass through requests immediately, drop them or throttle to a desired rate. The FSMs are + * registered in the TestConductorExt.failureInjector so that settings can be applied from + * the ClientFSMs. + * + * I found that simply forwarding events using ctx.sendUpstream/sendDownstream does not work, + * it deadlocks and gives strange errors; in the end I just trusted the Netty docs which + * recommend to prefer `Channels.write()` and `Channels.fireMessageReceived()`. + * + * INTERNAL API. + */ +private[akka] class NetworkFailureInjector(system: ActorSystem) extends SimpleChannelHandler { + import NetworkFailureInjector._ + + private val log = Logging(system, "FailureInjector") + + private val conductor = TestConductor(system) + private var announced = false + + override def channelConnected(ctx: ChannelHandlerContext, state: ChannelStateEvent) { + state.getValue match { + case a: InetSocketAddress ⇒ + val addr = Address("akka", "", a.getHostName, a.getPort) + log.debug("connected to {}", addr) + case x ⇒ throw new IllegalArgumentException("unknown address type: " + x) + } + } + + override def channelDisconnected(ctx: ChannelHandlerContext, state: ChannelStateEvent) { + log.debug("disconnected from {}", state.getChannel) + conductor.failureInjector ! RemoveContext(ctx) + } + + override def messageReceived(ctx: ChannelHandlerContext, msg: MessageEvent) { + log.debug("upstream(queued): {}", msg) + conductor.failureInjector ! ThrottleActor.Send(ctx, Direction.Receive, Option(msg.getFuture), msg.getMessage) + } + + override def writeRequested(ctx: ChannelHandlerContext, msg: MessageEvent) { + log.debug("downstream(queued): {}", msg) + conductor.failureInjector ! ThrottleActor.Send(ctx, Direction.Send, Option(msg.getFuture), msg.getMessage) + } + +} + +/** + * INTERNAL API. + */ +private[akka] object ThrottleActor { + sealed trait State + case object PassThrough extends State + case object Throttle extends State + case object Blackhole extends State + + case class Data(lastSent: Long, rateMBit: Float, queue: Queue[Send]) + + case class Send(ctx: ChannelHandlerContext, direction: Direction, future: Option[ChannelFuture], msg: AnyRef) + case class SetRate(rateMBit: Float) + case object Tick +} + +/** + * INTERNAL API. + */ +private[akka] class ThrottleActor(channelContext: ChannelHandlerContext) + extends Actor with LoggingFSM[ThrottleActor.State, ThrottleActor.Data] { + + import ThrottleActor._ + import FSM._ + + private val packetSplitThreshold = TestConductor(context.system).Settings.PacketSplitThreshold + + startWith(PassThrough, Data(0, -1, Queue())) + + when(PassThrough) { + case Event(s @ Send(_, _, _, msg), _) ⇒ + log.debug("sending msg (PassThrough): {}", msg) + send(s) + stay + } + + when(Throttle) { + case Event(s: Send, data @ Data(_, _, Queue())) ⇒ + stay using sendThrottled(data.copy(lastSent = System.nanoTime, queue = Queue(s))) + case Event(s: Send, data) ⇒ + stay using sendThrottled(data.copy(queue = data.queue.enqueue(s))) + case Event(Tick, data) ⇒ + stay using sendThrottled(data) + } + + onTransition { + case Throttle -> PassThrough ⇒ + for (s ← stateData.queue) { + log.debug("sending msg (Transition): {}", s.msg) + send(s) + } + cancelTimer("send") + case Throttle -> Blackhole ⇒ + cancelTimer("send") + } + + when(Blackhole) { + case Event(Send(_, _, _, msg), _) ⇒ + log.debug("dropping msg {}", msg) + stay + } + + whenUnhandled { + case Event(SetRate(rate), d) ⇒ + if (rate > 0) { + goto(Throttle) using d.copy(lastSent = System.nanoTime, rateMBit = rate, queue = Queue()) + } else if (rate == 0) { + goto(Blackhole) + } else { + goto(PassThrough) + } + } + + initialize + + private def sendThrottled(d: Data): Data = { + val (data, toSend, toTick) = schedule(d) + for (s ← toSend) { + log.debug("sending msg (Tick): {}", s.msg) + send(s) + } + if (!timerActive_?("send")) + for (time ← toTick) { + log.debug("scheduling next Tick in {}", time) + setTimer("send", Tick, time, false) + } + data + } + + private def send(s: Send): Unit = s.direction match { + case Direction.Send ⇒ Channels.write(s.ctx, s.future getOrElse Channels.future(s.ctx.getChannel), s.msg) + case Direction.Receive ⇒ Channels.fireMessageReceived(s.ctx, s.msg) + case _ ⇒ + } + + /** + * Core of the throttling engine: delay Send operations until their bit count + * would actually have had time to travel down the line at the configured + * data rate, and split up send operations which are so big that gaps larger + * than packetSplitThreshold would be planned (they will happen nevertheless + * due to HashedWheelTimer’s semantics, but we compensate by sending more the + * next time, in proportion to how long the Tick was overdue). So, this should + * lead to the correct rate on average, with increased latency of the order of + * HWT granularity. + */ + private def schedule(d: Data): (Data, Seq[Send], Option[Duration]) = { + val now = System.nanoTime + @tailrec def rec(d: Data, toSend: Seq[Send]): (Data, Seq[Send], Option[Duration]) = { + if (d.queue.isEmpty) (d, toSend, None) + else { + val timeForPacket = d.lastSent + (1000 * size(d.queue.head.msg) / d.rateMBit).toLong + if (timeForPacket <= now) rec(Data(timeForPacket, d.rateMBit, d.queue.tail), toSend :+ d.queue.head) + else { + val splitThreshold = d.lastSent + packetSplitThreshold.toNanos + if (now < splitThreshold) (d, toSend, Some((timeForPacket - now).nanos min (splitThreshold - now).nanos)) + else { + val microsToSend = (now - d.lastSent) / 1000 + val (s1, s2) = split(d.queue.head, (microsToSend * d.rateMBit / 8).toInt) + (d.copy(queue = s2 +: d.queue.tail), toSend :+ s1, Some((timeForPacket - now).nanos min packetSplitThreshold)) + } + } + } + } + rec(d, Seq()) + } + + /** + * Split one Send operation in two, cutting off the given number of bytes at + * the front. If it was Direction.Send, i.e. a channel.write(), then also + * split the Future so that a failure in either part will complete the original + * with that failure. Data are not copied, as long as ChannelBuffer.slice does + * not copy them. + */ + private def split(s: Send, bytes: Int): (Send, Send) = { + s.msg match { + case buf: ChannelBuffer ⇒ + val f = s.future map { f ⇒ + val newF = Channels.future(s.ctx.getChannel) + newF.addListener(new ChannelFutureListener { + def operationComplete(future: ChannelFuture) { + if (future.isCancelled) f.cancel() + else future.getCause match { + case null ⇒ + case thr ⇒ f.setFailure(thr) + } + } + }) + newF + } + val b = buf.slice() + b.writerIndex(b.readerIndex + bytes) + buf.readerIndex(buf.readerIndex + bytes) + (Send(s.ctx, s.direction, f, b), Send(s.ctx, s.direction, s.future, buf)) + } + } + + private def size(msg: AnyRef) = msg match { + case b: ChannelBuffer ⇒ b.readableBytes() * 8 + case _ ⇒ throw new UnsupportedOperationException("NetworkFailureInjector only supports ChannelBuffer messages") + } +} + diff --git a/akka-remote-tests/src/main/scala/akka/remote/testconductor/Player.scala b/akka-remote-tests/src/main/scala/akka/remote/testconductor/Player.scala new file mode 100644 index 0000000000..53c03d5d40 --- /dev/null +++ b/akka-remote-tests/src/main/scala/akka/remote/testconductor/Player.scala @@ -0,0 +1,298 @@ +/** + * Copyright (C) 2009-2011 Typesafe Inc. + */ +package akka.remote.testconductor + +import akka.actor.{ Actor, ActorRef, ActorSystem, LoggingFSM, Props } +import RemoteConnection.getAddrString +import akka.util.duration._ +import org.jboss.netty.channel.{ Channel, SimpleChannelUpstreamHandler, ChannelHandlerContext, ChannelStateEvent, MessageEvent } +import com.typesafe.config.ConfigFactory +import akka.util.Timeout +import akka.util.Duration +import java.util.concurrent.TimeUnit.MILLISECONDS +import akka.pattern.{ ask, pipe } +import akka.dispatch.Await +import scala.util.control.NoStackTrace +import akka.actor.Status +import akka.event.LoggingAdapter +import akka.actor.PoisonPill +import akka.event.Logging +import akka.dispatch.Future +import java.net.InetSocketAddress +import akka.actor.Address +import org.jboss.netty.channel.ExceptionEvent +import org.jboss.netty.channel.WriteCompletionEvent +import java.net.ConnectException +import akka.util.Deadline +import akka.actor.Scheduler + +/** + * The Player is the client component of the + * [[akka.remote.testconductor.TestConductorExt]] extension. It registers with + * the [[akka.remote.testconductor.Conductor]]’s [[akka.remote.testconductor.Controller]] + * in order to participate in barriers and enable network failure injection. + */ +trait Player { this: TestConductorExt ⇒ + + private var _client: ActorRef = _ + private def client = _client match { + case null ⇒ throw new IllegalStateException("TestConductor client not yet started") + case x ⇒ x + } + + /** + * Connect to the conductor on the given port (the host is taken from setting + * `akka.testconductor.host`). The connection is made asynchronously, but you + * should await completion of the returned Future because that implies that + * all expected participants of this test have successfully connected (i.e. + * this is a first barrier in itself). The number of expected participants is + * set in [[akka.remote.testconductor.Conductor]]`.startController()`. + */ + def startClient(name: RoleName, controllerAddr: InetSocketAddress): Future[Done] = { + import ClientFSM._ + import akka.actor.FSM._ + import Settings.BarrierTimeout + + if (_client ne null) throw new IllegalStateException("TestConductorClient already started") + _client = system.actorOf(Props(new ClientFSM(name, controllerAddr)), "TestConductorClient") + val a = system.actorOf(Props(new Actor { + var waiting: ActorRef = _ + def receive = { + case fsm: ActorRef ⇒ waiting = sender; fsm ! SubscribeTransitionCallBack(self) + case Transition(_, Connecting, AwaitDone) ⇒ // step 1, not there yet + case Transition(_, AwaitDone, Connected) ⇒ waiting ! Done; context stop self + case t: Transition[_] ⇒ waiting ! Status.Failure(new RuntimeException("unexpected transition: " + t)); context stop self + case CurrentState(_, Connected) ⇒ waiting ! Done; context stop self + case _: CurrentState[_] ⇒ + } + })) + + a ? client mapTo + } + + /** + * Enter the named barriers, one after the other, in the order given. Will + * throw an exception in case of timeouts or other errors. + */ + def enter(name: String*) { + system.log.debug("entering barriers " + name.mkString("(", ", ", ")")) + name foreach { b ⇒ + import Settings.BarrierTimeout + Await.result(client ? ToServer(EnterBarrier(b)), Duration.Inf) + system.log.debug("passed barrier {}", b) + } + } + + /** + * Query remote transport address of named node. + */ + def getAddressFor(name: RoleName): Future[Address] = { + import Settings.BarrierTimeout + client ? ToServer(GetAddress(name)) mapTo + } +} + +/** + * INTERNAL API. + */ +private[akka] object ClientFSM { + sealed trait State + case object Connecting extends State + case object AwaitDone extends State + case object Connected extends State + case object Failed extends State + + case class Data(channel: Option[Channel], runningOp: Option[(String, ActorRef)]) + + case class Connected(channel: Channel) + case class ConnectionFailure(msg: String) extends RuntimeException(msg) with NoStackTrace + case object Disconnected +} + +/** + * This is the controlling entity on the [[akka.remote.testconductor.Player]] + * side: in a first step it registers itself with a symbolic name and its remote + * address at the [[akka.remote.testconductor.Controller]], then waits for the + * `Done` message which signals that all other expected test participants have + * done the same. After that, it will pass barrier requests to and from the + * coordinator and react to the [[akka.remote.testconductor.Conductor]]’s + * requests for failure injection. + * + * INTERNAL API. + */ +private[akka] class ClientFSM(name: RoleName, controllerAddr: InetSocketAddress) extends Actor with LoggingFSM[ClientFSM.State, ClientFSM.Data] { + import ClientFSM._ + + val settings = TestConductor().Settings + + val handler = new PlayerHandler(controllerAddr, settings.ClientReconnects, settings.ReconnectBackoff, + self, Logging(context.system, "PlayerHandler"), context.system.scheduler) + + startWith(Connecting, Data(None, None)) + + when(Connecting, stateTimeout = settings.ConnectTimeout) { + case Event(msg: ClientOp, _) ⇒ + stay replying Status.Failure(new IllegalStateException("not connected yet")) + case Event(Connected(channel), _) ⇒ + channel.write(Hello(name.name, TestConductor().address)) + goto(AwaitDone) using Data(Some(channel), None) + case Event(_: ConnectionFailure, _) ⇒ + goto(Failed) + case Event(StateTimeout, _) ⇒ + log.error("connect timeout to TestConductor") + goto(Failed) + } + + when(AwaitDone, stateTimeout = settings.BarrierTimeout.duration) { + case Event(Done, _) ⇒ + log.debug("received Done: starting test") + goto(Connected) + case Event(msg: NetworkOp, _) ⇒ + log.error("received {} instead of Done", msg) + goto(Failed) + case Event(msg: ServerOp, _) ⇒ + stay replying Status.Failure(new IllegalStateException("not connected yet")) + case Event(StateTimeout, _) ⇒ + log.error("connect timeout to TestConductor") + goto(Failed) + } + + when(Connected) { + case Event(Disconnected, _) ⇒ + log.info("disconnected from TestConductor") + throw new ConnectionFailure("disconnect") + case Event(ToServer(Done), Data(Some(channel), _)) ⇒ + channel.write(Done) + stay + case Event(ToServer(msg), d @ Data(Some(channel), None)) ⇒ + channel.write(msg) + val token = msg match { + case EnterBarrier(barrier) ⇒ barrier + case GetAddress(node) ⇒ node.name + } + stay using d.copy(runningOp = Some(token, sender)) + case Event(ToServer(op), Data(channel, Some((token, _)))) ⇒ + log.error("cannot write {} while waiting for {}", op, token) + stay + case Event(op: ClientOp, d @ Data(Some(channel), runningOp)) ⇒ + op match { + case BarrierResult(b, success) ⇒ + runningOp match { + case Some((barrier, requester)) ⇒ + if (b != barrier) { + requester ! Status.Failure(new RuntimeException("wrong barrier " + b + " received while waiting for " + barrier)) + } else if (!success) { + requester ! Status.Failure(new RuntimeException("barrier failed: " + b)) + } else { + requester ! b + } + case None ⇒ + log.warning("did not expect {}", op) + } + stay using d.copy(runningOp = None) + case AddressReply(node, addr) ⇒ + runningOp match { + case Some((_, requester)) ⇒ + requester ! addr + case None ⇒ + log.warning("did not expect {}", op) + } + stay using d.copy(runningOp = None) + case t: ThrottleMsg ⇒ + import settings.QueryTimeout + TestConductor().failureInjector ? t map (_ ⇒ ToServer(Done)) pipeTo self + stay + case d: DisconnectMsg ⇒ + import settings.QueryTimeout + TestConductor().failureInjector ? d map (_ ⇒ ToServer(Done)) pipeTo self + stay + case TerminateMsg(exit) ⇒ + System.exit(exit) + stay // needed because Java doesn’t have Nothing + } + } + + when(Failed) { + case Event(msg: ClientOp, _) ⇒ + stay replying Status.Failure(new RuntimeException("cannot do " + msg + " while Failed")) + case Event(msg: NetworkOp, _) ⇒ + log.warning("ignoring network message {} while Failed", msg) + stay + } + + onTermination { + case StopEvent(_, _, Data(Some(channel), _)) ⇒ + channel.close() + } + + initialize + +} + +/** + * This handler only forwards messages received from the conductor to the [[akka.remote.testconductor.ClientFSM]]. + * + * INTERNAL API. + */ +private[akka] class PlayerHandler( + server: InetSocketAddress, + private var reconnects: Int, + backoff: Duration, + fsm: ActorRef, + log: LoggingAdapter, + scheduler: Scheduler) + extends SimpleChannelUpstreamHandler { + + import ClientFSM._ + + reconnect() + + var nextAttempt: Deadline = _ + + override def channelOpen(ctx: ChannelHandlerContext, event: ChannelStateEvent) = log.debug("channel {} open", event.getChannel) + override def channelClosed(ctx: ChannelHandlerContext, event: ChannelStateEvent) = log.debug("channel {} closed", event.getChannel) + override def channelBound(ctx: ChannelHandlerContext, event: ChannelStateEvent) = log.debug("channel {} bound", event.getChannel) + override def channelUnbound(ctx: ChannelHandlerContext, event: ChannelStateEvent) = log.debug("channel {} unbound", event.getChannel) + override def writeComplete(ctx: ChannelHandlerContext, event: WriteCompletionEvent) = log.debug("channel {} written {}", event.getChannel, event.getWrittenAmount) + + override def exceptionCaught(ctx: ChannelHandlerContext, event: ExceptionEvent) = { + log.debug("channel {} exception {}", event.getChannel, event.getCause) + event.getCause match { + case c: ConnectException if reconnects > 0 ⇒ + reconnects -= 1 + scheduler.scheduleOnce(nextAttempt.timeLeft)(reconnect()) + case e ⇒ fsm ! ConnectionFailure(e.getMessage) + } + } + + private def reconnect(): Unit = { + nextAttempt = Deadline.now + backoff + RemoteConnection(Client, server, this) + } + + override def channelConnected(ctx: ChannelHandlerContext, event: ChannelStateEvent) = { + val ch = event.getChannel + log.debug("connected to {}", getAddrString(ch)) + fsm ! Connected(ch) + } + + override def channelDisconnected(ctx: ChannelHandlerContext, event: ChannelStateEvent) = { + val channel = event.getChannel + log.debug("disconnected from {}", getAddrString(channel)) + fsm ! PoisonPill + } + + override def messageReceived(ctx: ChannelHandlerContext, event: MessageEvent) = { + val channel = event.getChannel + log.debug("message from {}: {}", getAddrString(channel), event.getMessage) + event.getMessage match { + case msg: NetworkOp ⇒ + fsm ! msg + case msg ⇒ + log.info("server {} sent garbage '{}', disconnecting", getAddrString(channel), msg) + channel.close() + } + } +} + diff --git a/akka-remote-tests/src/main/scala/akka/remote/testconductor/RemoteConnection.scala b/akka-remote-tests/src/main/scala/akka/remote/testconductor/RemoteConnection.scala new file mode 100644 index 0000000000..5aeb484c42 --- /dev/null +++ b/akka-remote-tests/src/main/scala/akka/remote/testconductor/RemoteConnection.scala @@ -0,0 +1,67 @@ +/** + * Copyright (C) 2009-2011 Typesafe Inc. + */ +package akka.remote.testconductor + +import org.jboss.netty.channel.{ Channel, ChannelPipeline, ChannelPipelineFactory, ChannelUpstreamHandler, SimpleChannelUpstreamHandler, StaticChannelPipeline } +import org.jboss.netty.channel.socket.nio.{ NioClientSocketChannelFactory, NioServerSocketChannelFactory } +import org.jboss.netty.bootstrap.{ ClientBootstrap, ServerBootstrap } +import org.jboss.netty.handler.codec.frame.{ LengthFieldBasedFrameDecoder, LengthFieldPrepender } +import org.jboss.netty.handler.codec.compression.{ ZlibDecoder, ZlibEncoder } +import org.jboss.netty.handler.codec.protobuf.{ ProtobufDecoder, ProtobufEncoder } +import org.jboss.netty.handler.timeout.{ ReadTimeoutHandler, ReadTimeoutException } +import java.net.InetSocketAddress +import java.util.concurrent.Executors + +/** + * INTERNAL API. + */ +private[akka] class TestConductorPipelineFactory(handler: ChannelUpstreamHandler) extends ChannelPipelineFactory { + def getPipeline: ChannelPipeline = { + val encap = List(new LengthFieldPrepender(4), new LengthFieldBasedFrameDecoder(10000, 0, 4, 0, 4)) + val proto = List(new ProtobufEncoder, new ProtobufDecoder(TestConductorProtocol.Wrapper.getDefaultInstance)) + val msg = List(new MsgEncoder, new MsgDecoder) + new StaticChannelPipeline(encap ::: proto ::: msg ::: handler :: Nil: _*) + } +} + +/** + * INTERNAL API. + */ +private[akka] sealed trait Role +/** + * INTERNAL API. + */ +private[akka] case object Client extends Role +/** + * INTERNAL API. + */ +private[akka] case object Server extends Role + +/** + * INTERNAL API. + */ +private[akka] object RemoteConnection { + def apply(role: Role, sockaddr: InetSocketAddress, handler: ChannelUpstreamHandler): Channel = { + role match { + case Client ⇒ + val socketfactory = new NioClientSocketChannelFactory(Executors.newCachedThreadPool, Executors.newCachedThreadPool) + val bootstrap = new ClientBootstrap(socketfactory) + bootstrap.setPipelineFactory(new TestConductorPipelineFactory(handler)) + bootstrap.setOption("tcpNoDelay", true) + bootstrap.connect(sockaddr).getChannel + case Server ⇒ + val socketfactory = new NioServerSocketChannelFactory(Executors.newCachedThreadPool, Executors.newCachedThreadPool) + val bootstrap = new ServerBootstrap(socketfactory) + bootstrap.setPipelineFactory(new TestConductorPipelineFactory(handler)) + bootstrap.setOption("reuseAddress", true) + bootstrap.setOption("child.tcpNoDelay", true) + bootstrap.bind(sockaddr) + } + } + + def getAddrString(channel: Channel) = channel.getRemoteAddress match { + case i: InetSocketAddress ⇒ i.toString + case _ ⇒ "[unknown]" + } +} diff --git a/akka-remote-tests/src/main/scala/akka/remote/testconductor/TestConductorTransport.scala b/akka-remote-tests/src/main/scala/akka/remote/testconductor/TestConductorTransport.scala new file mode 100644 index 0000000000..dbf17fa5a7 --- /dev/null +++ b/akka-remote-tests/src/main/scala/akka/remote/testconductor/TestConductorTransport.scala @@ -0,0 +1,24 @@ +/** + * Copyright (C) 2009-2012 Typesafe Inc. + */ +package akka.remote.testconductor + +import akka.remote.netty.NettyRemoteTransport +import akka.remote.RemoteSettings +import akka.actor.ExtendedActorSystem +import akka.remote.RemoteActorRefProvider +import org.jboss.netty.channel.ChannelHandler +import org.jboss.netty.channel.ChannelPipelineFactory + +/** + * INTERNAL API. + */ +private[akka] class TestConductorTransport(_system: ExtendedActorSystem, _provider: RemoteActorRefProvider) + extends NettyRemoteTransport(_system, _provider) { + + override def createPipeline(endpoint: ⇒ ChannelHandler, withTimeout: Boolean): ChannelPipelineFactory = + new ChannelPipelineFactory { + def getPipeline = PipelineFactory(new NetworkFailureInjector(system) +: PipelineFactory.defaultStack(withTimeout) :+ endpoint) + } + +} \ No newline at end of file diff --git a/akka-remote-tests/src/multi-jvm/scala/akka/remote/SimpleRemoteSpec.scala b/akka-remote-tests/src/multi-jvm/scala/akka/remote/SimpleRemoteSpec.scala new file mode 100644 index 0000000000..dcc4b60526 --- /dev/null +++ b/akka-remote-tests/src/multi-jvm/scala/akka/remote/SimpleRemoteSpec.scala @@ -0,0 +1,55 @@ +/** + * Copyright (C) 2009-2012 Typesafe Inc. + */ +package akka.remote + +import akka.actor.Actor +import akka.actor.ActorRef +import akka.actor.Props +import akka.pattern.ask +import akka.remote.testkit.MultiNodeConfig +import akka.remote.testkit.MultiNodeSpec +import akka.testkit._ + +object SimpleRemoteMultiJvmSpec extends MultiNodeConfig { + + class SomeActor extends Actor with Serializable { + def receive = { + case "identify" ⇒ sender ! self + } + } + + commonConfig(debugConfig(on = false)) + + val master = role("master") + val slave = role("slave") + +} + +class SimpleRemoteMultiJvmNode1 extends SimpleRemoteSpec +class SimpleRemoteMultiJvmNode2 extends SimpleRemoteSpec + +class SimpleRemoteSpec extends MultiNodeSpec(SimpleRemoteMultiJvmSpec) + with ImplicitSender with DefaultTimeout { + import SimpleRemoteMultiJvmSpec._ + + def initialParticipants = 2 + + runOn(master) { + system.actorOf(Props[SomeActor], "service-hello") + } + + "Remoting" must { + "lookup remote actor" in { + runOn(slave) { + val hello = system.actorFor(node(master) / "user" / "service-hello") + hello.isInstanceOf[RemoteActorRef] must be(true) + val masterAddress = testConductor.getAddressFor(master).await + (hello ? "identify").await.asInstanceOf[ActorRef].path.address must equal(masterAddress) + } + testConductor.enter("done") + } + } + +} + diff --git a/akka-remote-tests/src/multi-jvm/scala/akka/remote/router/DirectRoutedRemoteActorMultiJvmSpec.scala b/akka-remote-tests/src/multi-jvm/scala/akka/remote/router/DirectRoutedRemoteActorMultiJvmSpec.scala new file mode 100644 index 0000000000..294bc80884 --- /dev/null +++ b/akka-remote-tests/src/multi-jvm/scala/akka/remote/router/DirectRoutedRemoteActorMultiJvmSpec.scala @@ -0,0 +1,81 @@ +/** + * Copyright (C) 2009-2012 Typesafe Inc. + */ +package akka.remote.router + +import com.typesafe.config.ConfigFactory + +import akka.actor.Actor +import akka.actor.ActorRef +import akka.actor.Props +import akka.pattern.ask +import akka.remote.RemoteActorRef +import akka.remote.testkit.MultiNodeConfig +import akka.remote.testkit.MultiNodeSpec +import akka.testkit._ + +object DirectRoutedRemoteActorMultiJvmSpec extends MultiNodeConfig { + + class SomeActor extends Actor with Serializable { + def receive = { + case "identify" ⇒ sender ! self + } + } + + commonConfig(debugConfig(on = false)) + + val master = role("master") + val slave = role("slave") + + deployOn(master, """/service-hello.remote = "@slave@" """) + + deployOnAll("""/service-hello2.remote = "@slave@" """) +} + +class DirectRoutedRemoteActorMultiJvmNode1 extends DirectRoutedRemoteActorSpec +class DirectRoutedRemoteActorMultiJvmNode2 extends DirectRoutedRemoteActorSpec + +class DirectRoutedRemoteActorSpec extends MultiNodeSpec(DirectRoutedRemoteActorMultiJvmSpec) + with ImplicitSender with DefaultTimeout { + import DirectRoutedRemoteActorMultiJvmSpec._ + + def initialParticipants = 2 + + "A new remote actor configured with a Direct router" must { + "be locally instantiated on a remote node and be able to communicate through its RemoteActorRef" in { + + runOn(master) { + val actor = system.actorOf(Props[SomeActor], "service-hello") + actor.isInstanceOf[RemoteActorRef] must be(true) + + val slaveAddress = testConductor.getAddressFor(slave).await + actor ! "identify" + expectMsgType[ActorRef].path.address must equal(slaveAddress) + + // shut down the actor before we let the other node(s) shut down so we don't try to send + // "Terminate" to a shut down node + system.stop(actor) + } + + testConductor.enter("done") + } + + "be locally instantiated on a remote node and be able to communicate through its RemoteActorRef (with deployOnAll)" in { + + runOn(master) { + val actor = system.actorOf(Props[SomeActor], "service-hello2") + actor.isInstanceOf[RemoteActorRef] must be(true) + + val slaveAddress = testConductor.getAddressFor(slave).await + actor ! "identify" + expectMsgType[ActorRef].path.address must equal(slaveAddress) + + // shut down the actor before we let the other node(s) shut down so we don't try to send + // "Terminate" to a shut down node + system.stop(actor) + } + + testConductor.enter("done") + } + } +} diff --git a/akka-remote-tests/src/multi-jvm/scala/akka/remote/testconductor/TestConductorSpec.scala b/akka-remote-tests/src/multi-jvm/scala/akka/remote/testconductor/TestConductorSpec.scala new file mode 100644 index 0000000000..df6388d562 --- /dev/null +++ b/akka-remote-tests/src/multi-jvm/scala/akka/remote/testconductor/TestConductorSpec.scala @@ -0,0 +1,111 @@ +/** + * Copyright (C) 2009-2012 Typesafe Inc. + */ +package akka.remote.testconductor + +import akka.remote.AkkaRemoteSpec +import com.typesafe.config.ConfigFactory +import akka.remote.AbstractRemoteActorMultiJvmSpec +import akka.actor.Props +import akka.actor.Actor +import akka.dispatch.Await +import akka.dispatch.Await.Awaitable +import akka.util.Duration +import akka.util.duration._ +import akka.testkit.ImplicitSender +import java.net.InetSocketAddress +import java.net.InetAddress +import akka.remote.testkit.MultiNodeSpec +import akka.remote.testkit.MultiNodeConfig + +object TestConductorMultiJvmSpec extends MultiNodeConfig { + commonConfig(debugConfig(on = false)) + + val master = role("master") + val slave = role("slave") +} + +class TestConductorMultiJvmNode1 extends TestConductorSpec +class TestConductorMultiJvmNode2 extends TestConductorSpec + +class TestConductorSpec extends MultiNodeSpec(TestConductorMultiJvmSpec) with ImplicitSender { + + import TestConductorMultiJvmSpec._ + + def initialParticipants = 2 + + runOn(master) { + system.actorOf(Props(new Actor { + def receive = { + case x ⇒ testActor ! x; sender ! x + } + }), "echo") + } + + val echo = system.actorFor(node(master) / "user" / "echo") + + "A TestConductor" must { + + "enter a barrier" in { + testConductor.enter("name") + } + + "support throttling of network connections" in { + + runOn(slave) { + // start remote network connection so that it can be throttled + echo ! "start" + } + + expectMsg("start") + + runOn(master) { + testConductor.throttle(slave, master, Direction.Send, rateMBit = 0.01).await + } + + testConductor.enter("throttled_send") + + runOn(slave) { + for (i ← 0 to 9) echo ! i + } + + within(0.6 seconds, 2 seconds) { + expectMsg(500 millis, 0) + receiveN(9) must be(1 to 9) + } + + testConductor.enter("throttled_send2") + + runOn(master) { + testConductor.throttle(slave, master, Direction.Send, -1).await + testConductor.throttle(slave, master, Direction.Receive, rateMBit = 0.01).await + } + + testConductor.enter("throttled_recv") + + runOn(slave) { + for (i ← 10 to 19) echo ! i + } + + val (min, max) = + ifNode(master) { + (0 seconds, 500 millis) + } { + (0.6 seconds, 2 seconds) + } + + within(min, max) { + expectMsg(500 millis, 10) + receiveN(9) must be(11 to 19) + } + + testConductor.enter("throttled_recv2") + + runOn(master) { + testConductor.throttle(slave, master, Direction.Receive, -1).await + } + } + + } + +} diff --git a/akka-remote-tests/src/test/scala/akka/remote/testconductor/BarrierSpec.scala b/akka-remote-tests/src/test/scala/akka/remote/testconductor/BarrierSpec.scala new file mode 100644 index 0000000000..e0fd5dfb97 --- /dev/null +++ b/akka-remote-tests/src/test/scala/akka/remote/testconductor/BarrierSpec.scala @@ -0,0 +1,471 @@ +/** + * Copyright (C) 2009-2012 Typesafe Inc. + */ +package akka.remote.testconductor + +import akka.testkit.AkkaSpec +import akka.actor.Props +import akka.actor.AddressFromURIString +import akka.actor.ActorRef +import akka.testkit.ImplicitSender +import akka.actor.Actor +import akka.actor.OneForOneStrategy +import akka.actor.SupervisorStrategy +import akka.testkit.EventFilter +import akka.testkit.TestProbe +import akka.util.duration._ +import akka.event.Logging +import org.scalatest.BeforeAndAfterEach +import java.net.InetSocketAddress +import java.net.InetAddress + +object BarrierSpec { + case class Failed(ref: ActorRef, thr: Throwable) + val config = """ + akka.testconductor.barrier-timeout = 5s + akka.actor.provider = akka.remote.RemoteActorRefProvider + akka.remote.netty.port = 0 + akka.actor.debug.fsm = on + akka.actor.debug.lifecycle = on + """ +} + +class BarrierSpec extends AkkaSpec(BarrierSpec.config) with ImplicitSender with BeforeAndAfterEach { + + import BarrierSpec._ + import Controller._ + import BarrierCoordinator._ + + val A = RoleName("a") + val B = RoleName("b") + val C = RoleName("c") + + override def afterEach { + system.eventStream.setLogLevel(Logging.WarningLevel) + } + + "A BarrierCoordinator" must { + + "register clients and remove them" in { + val b = getBarrier() + b ! NodeInfo(A, AddressFromURIString("akka://sys"), system.deadLetters) + b ! RemoveClient(B) + b ! RemoveClient(A) + EventFilter[BarrierEmpty](occurrences = 1) intercept { + b ! RemoveClient(A) + } + expectMsg(Failed(b, BarrierEmpty(Data(Set(), "", Nil), "no client to remove"))) + } + + "register clients and disconnect them" in { + val b = getBarrier() + b ! NodeInfo(A, AddressFromURIString("akka://sys"), system.deadLetters) + b ! ClientDisconnected(B) + EventFilter[ClientLost](occurrences = 1) intercept { + b ! ClientDisconnected(A) + } + expectMsg(Failed(b, ClientLost(Data(Set(), "", Nil), A))) + EventFilter[BarrierEmpty](occurrences = 1) intercept { + b ! ClientDisconnected(A) + } + expectMsg(Failed(b, BarrierEmpty(Data(Set(), "", Nil), "no client to disconnect"))) + } + + "fail entering barrier when nobody registered" in { + val b = getBarrier() + b ! EnterBarrier("b") + expectMsg(ToClient(BarrierResult("b", false))) + } + + "enter barrier" in { + val barrier = getBarrier() + val a, b = TestProbe() + barrier ! NodeInfo(A, AddressFromURIString("akka://sys"), a.ref) + barrier ! NodeInfo(B, AddressFromURIString("akka://sys"), b.ref) + a.send(barrier, EnterBarrier("bar")) + noMsg(a, b) + within(1 second) { + b.send(barrier, EnterBarrier("bar")) + a.expectMsg(ToClient(BarrierResult("bar", true))) + b.expectMsg(ToClient(BarrierResult("bar", true))) + } + } + + "enter barrier with joining node" in { + val barrier = getBarrier() + val a, b, c = TestProbe() + barrier ! NodeInfo(A, AddressFromURIString("akka://sys"), a.ref) + barrier ! NodeInfo(B, AddressFromURIString("akka://sys"), b.ref) + a.send(barrier, EnterBarrier("bar")) + barrier ! NodeInfo(C, AddressFromURIString("akka://sys"), c.ref) + b.send(barrier, EnterBarrier("bar")) + noMsg(a, b, c) + within(1 second) { + c.send(barrier, EnterBarrier("bar")) + a.expectMsg(ToClient(BarrierResult("bar", true))) + b.expectMsg(ToClient(BarrierResult("bar", true))) + c.expectMsg(ToClient(BarrierResult("bar", true))) + } + } + + "enter barrier with leaving node" in { + val barrier = getBarrier() + val a, b, c = TestProbe() + barrier ! NodeInfo(A, AddressFromURIString("akka://sys"), a.ref) + barrier ! NodeInfo(B, AddressFromURIString("akka://sys"), b.ref) + barrier ! NodeInfo(C, AddressFromURIString("akka://sys"), c.ref) + a.send(barrier, EnterBarrier("bar")) + b.send(barrier, EnterBarrier("bar")) + barrier ! RemoveClient(A) + barrier ! ClientDisconnected(A) + noMsg(a, b, c) + b.within(1 second) { + barrier ! RemoveClient(C) + b.expectMsg(ToClient(BarrierResult("bar", true))) + } + barrier ! ClientDisconnected(C) + expectNoMsg(1 second) + } + + "leave barrier when last “arrived” is removed" in { + val barrier = getBarrier() + val a, b = TestProbe() + barrier ! NodeInfo(A, AddressFromURIString("akka://sys"), a.ref) + barrier ! NodeInfo(B, AddressFromURIString("akka://sys"), b.ref) + a.send(barrier, EnterBarrier("bar")) + barrier ! RemoveClient(A) + b.send(barrier, EnterBarrier("foo")) + b.expectMsg(ToClient(BarrierResult("foo", true))) + } + + "fail barrier with disconnecing node" in { + val barrier = getBarrier() + val a, b = TestProbe() + val nodeA = NodeInfo(A, AddressFromURIString("akka://sys"), a.ref) + barrier ! nodeA + barrier ! NodeInfo(B, AddressFromURIString("akka://sys"), b.ref) + a.send(barrier, EnterBarrier("bar")) + EventFilter[ClientLost](occurrences = 1) intercept { + barrier ! ClientDisconnected(B) + } + expectMsg(Failed(barrier, ClientLost(Data(Set(nodeA), "bar", a.ref :: Nil), B))) + } + + "fail barrier with disconnecing node who already arrived" in { + val barrier = getBarrier() + val a, b, c = TestProbe() + val nodeA = NodeInfo(A, AddressFromURIString("akka://sys"), a.ref) + val nodeC = NodeInfo(C, AddressFromURIString("akka://sys"), c.ref) + barrier ! nodeA + barrier ! NodeInfo(B, AddressFromURIString("akka://sys"), b.ref) + barrier ! nodeC + a.send(barrier, EnterBarrier("bar")) + b.send(barrier, EnterBarrier("bar")) + EventFilter[ClientLost](occurrences = 1) intercept { + barrier ! ClientDisconnected(B) + } + expectMsg(Failed(barrier, ClientLost(Data(Set(nodeA, nodeC), "bar", a.ref :: Nil), B))) + } + + "fail when entering wrong barrier" in { + val barrier = getBarrier() + val a, b = TestProbe() + val nodeA = NodeInfo(A, AddressFromURIString("akka://sys"), a.ref) + barrier ! nodeA + val nodeB = NodeInfo(B, AddressFromURIString("akka://sys"), b.ref) + barrier ! nodeB + a.send(barrier, EnterBarrier("bar")) + EventFilter[WrongBarrier](occurrences = 1) intercept { + b.send(barrier, EnterBarrier("foo")) + } + expectMsg(Failed(barrier, WrongBarrier("foo", b.ref, Data(Set(nodeA, nodeB), "bar", a.ref :: Nil)))) + } + + "fail barrier after first failure" in { + val barrier = getBarrier() + val a = TestProbe() + EventFilter[BarrierEmpty](occurrences = 1) intercept { + barrier ! RemoveClient(A) + } + expectMsg(Failed(barrier, BarrierEmpty(Data(Set(), "", Nil), "no client to remove"))) + barrier ! NodeInfo(A, AddressFromURIString("akka://sys"), a.ref) + a.send(barrier, EnterBarrier("right")) + a.expectMsg(ToClient(BarrierResult("right", false))) + } + + "fail after barrier timeout" in { + val barrier = getBarrier() + val a, b = TestProbe() + val nodeA = NodeInfo(A, AddressFromURIString("akka://sys"), a.ref) + val nodeB = NodeInfo(B, AddressFromURIString("akka://sys"), b.ref) + barrier ! nodeA + barrier ! nodeB + a.send(barrier, EnterBarrier("right")) + EventFilter[BarrierTimeout](occurrences = 1) intercept { + expectMsg(7 seconds, Failed(barrier, BarrierTimeout(Data(Set(nodeA, nodeB), "right", a.ref :: Nil)))) + } + } + + "fail if a node registers twice" in { + val barrier = getBarrier() + val a, b = TestProbe() + val nodeA = NodeInfo(A, AddressFromURIString("akka://sys"), a.ref) + val nodeB = NodeInfo(A, AddressFromURIString("akka://sys"), b.ref) + barrier ! nodeA + EventFilter[DuplicateNode](occurrences = 1) intercept { + barrier ! nodeB + } + expectMsg(Failed(barrier, DuplicateNode(Data(Set(nodeA), "", Nil), nodeB))) + } + + "finally have no failure messages left" in { + expectNoMsg(1 second) + } + + } + + "A Controller with BarrierCoordinator" must { + + "register clients and remove them" in { + val b = getController(1) + b ! NodeInfo(A, AddressFromURIString("akka://sys"), testActor) + expectMsg(ToClient(Done)) + b ! Remove(B) + b ! Remove(A) + EventFilter[BarrierEmpty](occurrences = 1) intercept { + b ! Remove(A) + } + } + + "register clients and disconnect them" in { + val b = getController(1) + b ! NodeInfo(A, AddressFromURIString("akka://sys"), testActor) + expectMsg(ToClient(Done)) + b ! ClientDisconnected(B) + EventFilter[ClientLost](occurrences = 1) intercept { + b ! ClientDisconnected(A) + } + EventFilter[BarrierEmpty](occurrences = 1) intercept { + b ! ClientDisconnected(A) + } + } + + "fail entering barrier when nobody registered" in { + val b = getController(0) + b ! EnterBarrier("b") + expectMsg(ToClient(BarrierResult("b", false))) + } + + "enter barrier" in { + val barrier = getController(2) + val a, b = TestProbe() + barrier ! NodeInfo(A, AddressFromURIString("akka://sys"), a.ref) + barrier ! NodeInfo(B, AddressFromURIString("akka://sys"), b.ref) + a.expectMsg(ToClient(Done)) + b.expectMsg(ToClient(Done)) + a.send(barrier, EnterBarrier("bar")) + noMsg(a, b) + within(1 second) { + b.send(barrier, EnterBarrier("bar")) + a.expectMsg(ToClient(BarrierResult("bar", true))) + b.expectMsg(ToClient(BarrierResult("bar", true))) + } + } + + "enter barrier with joining node" in { + val barrier = getController(2) + val a, b, c = TestProbe() + barrier ! NodeInfo(A, AddressFromURIString("akka://sys"), a.ref) + barrier ! NodeInfo(B, AddressFromURIString("akka://sys"), b.ref) + a.expectMsg(ToClient(Done)) + b.expectMsg(ToClient(Done)) + a.send(barrier, EnterBarrier("bar")) + barrier ! NodeInfo(C, AddressFromURIString("akka://sys"), c.ref) + c.expectMsg(ToClient(Done)) + b.send(barrier, EnterBarrier("bar")) + noMsg(a, b, c) + within(1 second) { + c.send(barrier, EnterBarrier("bar")) + a.expectMsg(ToClient(BarrierResult("bar", true))) + b.expectMsg(ToClient(BarrierResult("bar", true))) + c.expectMsg(ToClient(BarrierResult("bar", true))) + } + } + + "enter barrier with leaving node" in { + val barrier = getController(3) + val a, b, c = TestProbe() + barrier ! NodeInfo(A, AddressFromURIString("akka://sys"), a.ref) + barrier ! NodeInfo(B, AddressFromURIString("akka://sys"), b.ref) + barrier ! NodeInfo(C, AddressFromURIString("akka://sys"), c.ref) + a.expectMsg(ToClient(Done)) + b.expectMsg(ToClient(Done)) + c.expectMsg(ToClient(Done)) + a.send(barrier, EnterBarrier("bar")) + b.send(barrier, EnterBarrier("bar")) + barrier ! Remove(A) + barrier ! ClientDisconnected(A) + noMsg(a, b, c) + b.within(1 second) { + barrier ! Remove(C) + b.expectMsg(ToClient(BarrierResult("bar", true))) + } + barrier ! ClientDisconnected(C) + expectNoMsg(1 second) + } + + "leave barrier when last “arrived” is removed" in { + val barrier = getController(2) + val a, b = TestProbe() + barrier ! NodeInfo(A, AddressFromURIString("akka://sys"), a.ref) + barrier ! NodeInfo(B, AddressFromURIString("akka://sys"), b.ref) + a.expectMsg(ToClient(Done)) + b.expectMsg(ToClient(Done)) + a.send(barrier, EnterBarrier("bar")) + barrier ! Remove(A) + b.send(barrier, EnterBarrier("foo")) + b.expectMsg(ToClient(BarrierResult("foo", true))) + } + + "fail barrier with disconnecing node" in { + val barrier = getController(2) + val a, b = TestProbe() + val nodeA = NodeInfo(A, AddressFromURIString("akka://sys"), a.ref) + barrier ! nodeA + barrier ! NodeInfo(B, AddressFromURIString("akka://sys"), b.ref) + a.expectMsg(ToClient(Done)) + b.expectMsg(ToClient(Done)) + a.send(barrier, EnterBarrier("bar")) + barrier ! ClientDisconnected(RoleName("unknown")) + noMsg(a) + EventFilter[ClientLost](occurrences = 1) intercept { + barrier ! ClientDisconnected(B) + } + a.expectMsg(ToClient(BarrierResult("bar", false))) + } + + "fail barrier with disconnecing node who already arrived" in { + val barrier = getController(3) + val a, b, c = TestProbe() + val nodeA = NodeInfo(A, AddressFromURIString("akka://sys"), a.ref) + val nodeC = NodeInfo(C, AddressFromURIString("akka://sys"), c.ref) + barrier ! nodeA + barrier ! NodeInfo(B, AddressFromURIString("akka://sys"), b.ref) + barrier ! nodeC + a.expectMsg(ToClient(Done)) + b.expectMsg(ToClient(Done)) + c.expectMsg(ToClient(Done)) + a.send(barrier, EnterBarrier("bar")) + b.send(barrier, EnterBarrier("bar")) + EventFilter[ClientLost](occurrences = 1) intercept { + barrier ! ClientDisconnected(B) + } + a.expectMsg(ToClient(BarrierResult("bar", false))) + } + + "fail when entering wrong barrier" in { + val barrier = getController(2) + val a, b = TestProbe() + val nodeA = NodeInfo(A, AddressFromURIString("akka://sys"), a.ref) + barrier ! nodeA + val nodeB = NodeInfo(B, AddressFromURIString("akka://sys"), b.ref) + barrier ! nodeB + a.expectMsg(ToClient(Done)) + b.expectMsg(ToClient(Done)) + a.send(barrier, EnterBarrier("bar")) + EventFilter[WrongBarrier](occurrences = 1) intercept { + b.send(barrier, EnterBarrier("foo")) + } + a.expectMsg(ToClient(BarrierResult("bar", false))) + b.expectMsg(ToClient(BarrierResult("foo", false))) + } + + "not really fail after barrier timeout" in { + val barrier = getController(2) + val a, b = TestProbe() + val nodeA = NodeInfo(A, AddressFromURIString("akka://sys"), a.ref) + val nodeB = NodeInfo(B, AddressFromURIString("akka://sys"), b.ref) + barrier ! nodeA + barrier ! nodeB + a.expectMsg(ToClient(Done)) + b.expectMsg(ToClient(Done)) + a.send(barrier, EnterBarrier("right")) + EventFilter[BarrierTimeout](occurrences = 1) intercept { + Thread.sleep(5000) + } + b.send(barrier, EnterBarrier("right")) + a.expectMsg(ToClient(BarrierResult("right", true))) + b.expectMsg(ToClient(BarrierResult("right", true))) + } + + "fail if a node registers twice" in { + val controller = getController(2) + val a, b = TestProbe() + val nodeA = NodeInfo(A, AddressFromURIString("akka://sys"), a.ref) + val nodeB = NodeInfo(A, AddressFromURIString("akka://sys"), b.ref) + controller ! nodeA + EventFilter[DuplicateNode](occurrences = 1) intercept { + controller ! nodeB + } + a.expectMsg(ToClient(BarrierResult("initial startup", false))) + b.expectMsg(ToClient(BarrierResult("initial startup", false))) + } + + "fail subsequent barriers if a node registers twice" in { + val controller = getController(1) + val a, b = TestProbe() + val nodeA = NodeInfo(A, AddressFromURIString("akka://sys"), a.ref) + val nodeB = NodeInfo(A, AddressFromURIString("akka://sys"), b.ref) + controller ! nodeA + a.expectMsg(ToClient(Done)) + EventFilter[DuplicateNode](occurrences = 1) intercept { + controller ! nodeB + b.expectMsg(ToClient(BarrierResult("initial startup", false))) + } + a.send(controller, EnterBarrier("x")) + a.expectMsg(ToClient(BarrierResult("x", false))) + } + + "finally have no failure messages left" in { + expectNoMsg(1 second) + } + + } + + private def getController(participants: Int): ActorRef = { + system.actorOf(Props(new Actor { + val controller = context.actorOf(Props(new Controller(participants, new InetSocketAddress(InetAddress.getLocalHost, 0)))) + controller ! GetSockAddr + override def supervisorStrategy = OneForOneStrategy() { + case x ⇒ testActor ! Failed(controller, x); SupervisorStrategy.Restart + } + def receive = { + case x: InetSocketAddress ⇒ testActor ! controller + } + })) + expectMsgType[ActorRef] + } + + /** + * Produce a BarrierCoordinator which is supervised with a strategy which + * forwards all failures to the testActor. + */ + private def getBarrier(): ActorRef = { + system.actorOf(Props(new Actor { + val barrier = context.actorOf(Props[BarrierCoordinator]) + override def supervisorStrategy = OneForOneStrategy() { + case x ⇒ testActor ! Failed(barrier, x); SupervisorStrategy.Restart + } + def receive = { + case _ ⇒ sender ! barrier + } + })) ! "" + expectMsgType[ActorRef] + } + + private def noMsg(probes: TestProbe*) { + expectNoMsg(1 second) + probes foreach (_.msgAvailable must be(false)) + } + +} \ No newline at end of file diff --git a/akka-remote-tests/src/test/scala/akka/remote/testconductor/ControllerSpec.scala b/akka-remote-tests/src/test/scala/akka/remote/testconductor/ControllerSpec.scala new file mode 100644 index 0000000000..13140adfb5 --- /dev/null +++ b/akka-remote-tests/src/test/scala/akka/remote/testconductor/ControllerSpec.scala @@ -0,0 +1,43 @@ +/** + * Copyright (C) 2009-2012 Typesafe Inc. + */ +package akka.remote.testconductor + +import akka.testkit.AkkaSpec +import akka.actor.Props +import akka.testkit.ImplicitSender +import akka.remote.testconductor.Controller.NodeInfo +import akka.actor.AddressFromURIString +import java.net.InetSocketAddress +import java.net.InetAddress + +object ControllerSpec { + val config = """ + akka.testconductor.barrier-timeout = 5s + akka.actor.provider = akka.remote.RemoteActorRefProvider + akka.remote.netty.port = 0 + akka.actor.debug.fsm = on + akka.actor.debug.lifecycle = on + """ +} + +class ControllerSpec extends AkkaSpec(ControllerSpec.config) with ImplicitSender { + + val A = RoleName("a") + val B = RoleName("b") + + "A Controller" must { + + "publish its nodes" in { + val c = system.actorOf(Props(new Controller(1, new InetSocketAddress(InetAddress.getLocalHost, 0)))) + c ! NodeInfo(A, AddressFromURIString("akka://sys"), testActor) + expectMsg(ToClient(Done)) + c ! NodeInfo(B, AddressFromURIString("akka://sys"), testActor) + expectMsg(ToClient(Done)) + c ! Controller.GetNodes + expectMsgType[Iterable[RoleName]].toSet must be(Set(A, B)) + } + + } + +} \ No newline at end of file diff --git a/akka-remote-tests/src/test/scala/akka/remote/testkit/MultiNodeSpec.scala b/akka-remote-tests/src/test/scala/akka/remote/testkit/MultiNodeSpec.scala new file mode 100644 index 0000000000..e7bce0890c --- /dev/null +++ b/akka-remote-tests/src/test/scala/akka/remote/testkit/MultiNodeSpec.scala @@ -0,0 +1,230 @@ +/** + * Copyright (C) 2009-2012 Typesafe Inc. + */ +package akka.remote.testkit + +import akka.testkit.AkkaSpec +import akka.actor.{ ActorSystem, ExtendedActorSystem } +import akka.remote.testconductor.TestConductor +import java.net.InetAddress +import java.net.InetSocketAddress +import akka.remote.testconductor.TestConductorExt +import com.typesafe.config.Config +import com.typesafe.config.ConfigFactory +import akka.dispatch.Await.Awaitable +import akka.dispatch.Await +import akka.util.Duration +import akka.actor.ActorPath +import akka.actor.RootActorPath +import akka.remote.testconductor.RoleName +import akka.actor.Deploy +import com.typesafe.config.ConfigObject + +/** + * Configure the role names and participants of the test, including configuration settings. + */ +abstract class MultiNodeConfig { + + private var _commonConf: Option[Config] = None + private var _nodeConf = Map[RoleName, Config]() + private var _roles = Vector[RoleName]() + private var _deployments = Map[RoleName, Seq[String]]() + private var _allDeploy = Vector[String]() + + /** + * Register a common base config for all test participants, if so desired. + */ + def commonConfig(config: Config): Unit = _commonConf = Some(config) + + /** + * Register a config override for a specific participant. + */ + def nodeConfig(role: RoleName, config: Config): Unit = _nodeConf += role -> config + + /** + * Include for verbose debug logging + * @param on when `true` debug Config is returned, otherwise empty Config + */ + def debugConfig(on: Boolean): Config = + if (on) + ConfigFactory.parseString(""" + akka.loglevel = DEBUG + akka.remote { + log-received-messages = on + log-sent-messages = on + } + akka.actor.debug { + receive = on + fsm = on + } + """) + else ConfigFactory.empty + + /** + * Construct a RoleName and return it, to be used as an identifier in the + * test. Registration of a role name creates a role which then needs to be + * filled. + */ + def role(name: String): RoleName = { + if (_roles exists (_.name == name)) throw new IllegalArgumentException("non-unique role name " + name) + val r = RoleName(name) + _roles :+= r + r + } + + def deployOn(role: RoleName, deployment: String): Unit = + _deployments += role -> ((_deployments get role getOrElse Vector()) :+ deployment) + + def deployOnAll(deployment: String): Unit = _allDeploy :+= deployment + + private[testkit] lazy val mySelf: RoleName = { + require(_roles.size > MultiNodeSpec.selfIndex, "not enough roles declared for this test") + _roles(MultiNodeSpec.selfIndex) + } + + private[testkit] def config: Config = { + val configs = (_nodeConf get mySelf).toList ::: _commonConf.toList ::: MultiNodeSpec.nodeConfig :: AkkaSpec.testConf :: Nil + configs reduce (_ withFallback _) + } + + private[testkit] def deployments(node: RoleName): Seq[String] = (_deployments get node getOrElse Nil) ++ _allDeploy + + private[testkit] def roles: Seq[RoleName] = _roles + +} + +object MultiNodeSpec { + + /** + * Names (or IP addresses; must be resolvable using InetAddress.getByName) + * of all nodes taking part in this test, including symbolic name and host + * definition: + * + * {{{ + * -D"multinode.hosts=host1@workerA.example.com,host2@workerB.example.com" + * }}} + */ + val nodeNames: Seq[String] = Vector.empty ++ ( + Option(System.getProperty("multinode.hosts")) getOrElse + (throw new IllegalStateException("need system property multinode.hosts to be set")) split ",") + + require(nodeNames != List(""), "multinode.hosts must not be empty") + + /** + * Index of this node in the nodeNames / nodeAddresses lists. The TestConductor + * is started in “controller” mode on selfIndex 0, i.e. there you can inject + * failures and shutdown other nodes etc. + */ + val selfIndex = Option(Integer.getInteger("multinode.index")) getOrElse + (throw new IllegalStateException("need system property multinode.index to be set")) + + require(selfIndex >= 0 && selfIndex < nodeNames.size, "selfIndex out of bounds: " + selfIndex) + + val nodeConfig = AkkaSpec.mapToConfig(Map( + "akka.actor.provider" -> "akka.remote.RemoteActorRefProvider", + "akka.remote.transport" -> "akka.remote.testconductor.TestConductorTransport", + "akka.remote.netty.hostname" -> nodeNames(selfIndex), + "akka.remote.netty.port" -> 0)) + +} + +abstract class MultiNodeSpec(val mySelf: RoleName, _system: ActorSystem, roles: Seq[RoleName], deployments: RoleName ⇒ Seq[String]) + extends AkkaSpec(_system) { + + import MultiNodeSpec._ + + def this(config: MultiNodeConfig) = + this(config.mySelf, ActorSystem(AkkaSpec.getCallerName, config.config), config.roles, config.deployments) + + /* + * Test Class Interface + */ + + /** + * TO BE DEFINED BY USER: Defines the number of participants required for starting the test. This + * might not be equals to the number of nodes available to the test. + * + * Must be a `def`: + * {{{ + * def initialParticipants = 5 + * }}} + */ + def initialParticipants: Int + require(initialParticipants > 0, "initialParticipants must be a 'def' or early initializer, and it must be greater zero") + require(initialParticipants <= nodeNames.size, "not enough nodes to run this test") + + /** + * Access to the barriers, failure injection, etc. The extension will have + * been started either in Conductor or Player mode when the constructor of + * MultiNodeSpec finishes, i.e. do not call the start*() methods yourself! + */ + val testConductor: TestConductorExt = TestConductor(system) + + /** + * Execute the given block of code only on the given nodes (names according + * to the `roleMap`). + */ + def runOn(nodes: RoleName*)(thunk: ⇒ Unit): Unit = { + if (nodes exists (_ == mySelf)) { + thunk + } + } + + def ifNode[T](nodes: RoleName*)(yes: ⇒ T)(no: ⇒ T): T = { + if (nodes exists (_ == mySelf)) yes else no + } + + /** + * Query the controller for the transport address of the given node (by role name) and + * return that as an ActorPath for easy composition: + * + * {{{ + * val serviceA = system.actorFor(node("master") / "user" / "serviceA") + * }}} + */ + def node(role: RoleName): ActorPath = RootActorPath(testConductor.getAddressFor(role).await) + + /** + * Enrich `.await()` onto all Awaitables, using BarrierTimeout. + */ + implicit def awaitHelper[T](w: Awaitable[T]) = new AwaitHelper(w) + class AwaitHelper[T](w: Awaitable[T]) { + def await: T = Await.result(w, testConductor.Settings.BarrierTimeout.duration) + } + + /* + * Implementation (i.e. wait for start etc.) + */ + + private val controllerAddr = new InetSocketAddress(nodeNames(0), 4711) + if (selfIndex == 0) { + testConductor.startController(initialParticipants, mySelf, controllerAddr).await + } else { + testConductor.startClient(mySelf, controllerAddr).await + } + + // now add deployments, if so desired + + private case class Replacement(tag: String, role: RoleName) { + lazy val addr = node(role).address.toString + } + private val replacements = roles map (r ⇒ Replacement("@" + r.name + "@", r)) + private val deployer = system.asInstanceOf[ExtendedActorSystem].provider.deployer + deployments(mySelf) foreach { str ⇒ + val deployString = (str /: replacements) { + case (base, r @ Replacement(tag, _)) ⇒ + base.indexOf(tag) match { + case -1 ⇒ base + case start ⇒ base.replace(tag, r.addr) + } + } + import scala.collection.JavaConverters._ + ConfigFactory.parseString(deployString).root.asScala foreach { + case (key, value: ConfigObject) ⇒ + deployer.parseConfig(key, value.toConfig) foreach deployer.deploy + case (key, x) ⇒ + throw new IllegalArgumentException("key " + key + " must map to deployment section, not simple value " + x) + } + } + +} \ No newline at end of file diff --git a/akka-remote/src/main/resources/reference.conf b/akka-remote/src/main/resources/reference.conf index 11a4da0711..97b85895ed 100644 --- a/akka-remote/src/main/resources/reference.conf +++ b/akka-remote/src/main/resources/reference.conf @@ -60,8 +60,8 @@ akka { # default is a TCP-based remote transport based on Netty transport = "akka.remote.netty.NettyRemoteTransport" - # Enable untrusted mode for full security of server managed actors, allows - # untrusted clients to connect. + # Enable untrusted mode for full security of server managed actors, prevents system messages to be send + # by clients, e.g. messages like 'Create', 'Suspend', 'Resume', 'Terminate', 'Supervise', 'Link' etc. untrusted-mode = off # Timeout for ACK of cluster operations, like checking actor out etc. diff --git a/akka-remote/src/main/scala/akka/remote/MessageSerializer.scala b/akka-remote/src/main/scala/akka/remote/MessageSerializer.scala index 65777d49ca..6bd61dd812 100644 --- a/akka-remote/src/main/scala/akka/remote/MessageSerializer.scala +++ b/akka-remote/src/main/scala/akka/remote/MessageSerializer.scala @@ -9,8 +9,14 @@ import com.google.protobuf.ByteString import akka.actor.ExtendedActorSystem import akka.serialization.SerializationExtension -object MessageSerializer { +/** + * MessageSerializer is a helper for serialize and deserialize messages + */ +private[akka] object MessageSerializer { + /** + * Uses Akka Serialization for the specified ActorSystem to transform the given MessageProtocol to a message + */ def deserialize(system: ExtendedActorSystem, messageProtocol: MessageProtocol): AnyRef = { val clazz = if (messageProtocol.hasMessageManifest) { @@ -24,6 +30,9 @@ object MessageSerializer { } } + /** + * Uses Akka Serialization for the specified ActorSystem to transform the given message to a MessageProtocol + */ def serialize(system: ExtendedActorSystem, message: AnyRef): MessageProtocol = { val s = SerializationExtension(system) val serializer = s.findSerializerFor(message) diff --git a/akka-remote/src/main/scala/akka/remote/RemoteActorRefProvider.scala b/akka-remote/src/main/scala/akka/remote/RemoteActorRefProvider.scala index ab53d9e99d..a12c5f5578 100644 --- a/akka-remote/src/main/scala/akka/remote/RemoteActorRefProvider.scala +++ b/akka-remote/src/main/scala/akka/remote/RemoteActorRefProvider.scala @@ -4,34 +4,26 @@ package akka.remote -import akka.AkkaException import akka.actor._ import akka.dispatch._ import akka.event.{ DeathWatch, Logging, LoggingAdapter } import akka.event.EventStream -import akka.config.ConfigurationException -import java.util.concurrent.{ TimeoutException } -import com.typesafe.config.Config import akka.serialization.Serialization import akka.serialization.SerializationExtension -class RemoteException(msg: String) extends AkkaException(msg) -class RemoteCommunicationException(msg: String) extends RemoteException(msg) -class RemoteConnectionException(msg: String) extends RemoteException(msg) - /** * Remote ActorRefProvider. Starts up actor on remote node and creates a RemoteActorRef representing it. */ -class RemoteActorRefProvider( +private[akka] class RemoteActorRefProvider( val systemName: String, val settings: ActorSystem.Settings, val eventStream: EventStream, val scheduler: Scheduler, val dynamicAccess: DynamicAccess) extends ActorRefProvider { - val remoteSettings = new RemoteSettings(settings.config, systemName) + val remoteSettings: RemoteSettings = new RemoteSettings(settings.config, systemName) - val deployer = new RemoteDeployer(settings, dynamicAccess) + val deployer: RemoteDeployer = new RemoteDeployer(settings, dynamicAccess) private val local = new LocalActorRefProvider(systemName, settings, eventStream, scheduler, deployer) @@ -39,21 +31,21 @@ class RemoteActorRefProvider( private var _log = local.log def log: LoggingAdapter = _log - def rootPath = local.rootPath - def deadLetters = local.deadLetters + override def rootPath: ActorPath = local.rootPath + override def deadLetters: InternalActorRef = local.deadLetters - val deathWatch = new RemoteDeathWatch(local.deathWatch, this) + override val deathWatch: DeathWatch = new RemoteDeathWatch(local.deathWatch, this) // these are only available after init() - def rootGuardian = local.rootGuardian - def guardian = local.guardian - def systemGuardian = local.systemGuardian - def terminationFuture = local.terminationFuture - def dispatcher = local.dispatcher - def registerTempActor(actorRef: InternalActorRef, path: ActorPath) = local.registerTempActor(actorRef, path) - def unregisterTempActor(path: ActorPath) = local.unregisterTempActor(path) - def tempPath() = local.tempPath() - def tempContainer = local.tempContainer + override def rootGuardian: InternalActorRef = local.rootGuardian + override def guardian: InternalActorRef = local.guardian + override def systemGuardian: InternalActorRef = local.systemGuardian + override def terminationFuture: Promise[Unit] = local.terminationFuture + override def dispatcher: MessageDispatcher = local.dispatcher + override def registerTempActor(actorRef: InternalActorRef, path: ActorPath): Unit = local.registerTempActor(actorRef, path) + override def unregisterTempActor(path: ActorPath): Unit = local.unregisterTempActor(path) + override def tempPath(): ActorPath = local.tempPath() + override def tempContainer: VirtualPathContainer = local.tempContainer @volatile private var _transport: RemoteTransport = _ @@ -61,13 +53,13 @@ class RemoteActorRefProvider( @volatile private var _serialization: Serialization = _ - def serialization = _serialization + def serialization: Serialization = _serialization @volatile private var _remoteDaemon: InternalActorRef = _ - def remoteDaemon = _remoteDaemon + def remoteDaemon: InternalActorRef = _remoteDaemon - def init(system: ActorSystemImpl) { + def init(system: ActorSystemImpl): Unit = { local.init(system) _remoteDaemon = new RemoteSystemDaemon(system, rootPath / "remote", rootGuardian, log) @@ -193,7 +185,7 @@ class RemoteActorRefProvider( /** * Using (checking out) actor on a specific node. */ - def useActorOnNode(path: ActorPath, props: Props, deploy: Deploy, supervisor: ActorRef) { + def useActorOnNode(path: ActorPath, props: Props, deploy: Deploy, supervisor: ActorRef): Unit = { log.debug("[{}] Instantiating Remote Actor [{}]", rootPath, path) // we don’t wait for the ACK, because the remote end will process this command before any other message to the new actor @@ -211,7 +203,7 @@ class RemoteActorRefProvider( } } -trait RemoteRef extends ActorRefScope { +private[akka] trait RemoteRef extends ActorRefScope { final def isLocal = false } @@ -256,9 +248,9 @@ private[akka] class RemoteActorRef private[akka] ( private def writeReplace(): AnyRef = SerializedActorRef(path) } -class RemoteDeathWatch(val local: LocalDeathWatch, val provider: RemoteActorRefProvider) extends DeathWatch { +private[akka] class RemoteDeathWatch(val local: DeathWatch, val provider: RemoteActorRefProvider) extends DeathWatch { - def subscribe(watcher: ActorRef, watched: ActorRef): Boolean = watched match { + override def subscribe(watcher: ActorRef, watched: ActorRef): Boolean = watched match { case r: RemoteRef ⇒ val ret = local.subscribe(watcher, watched) provider.actorFor(r.path.root / "remote") ! DaemonMsgWatch(watcher, watched) @@ -270,10 +262,9 @@ class RemoteDeathWatch(val local: LocalDeathWatch, val provider: RemoteActorRefP false } - def unsubscribe(watcher: ActorRef, watched: ActorRef): Boolean = local.unsubscribe(watcher, watched) + override def unsubscribe(watcher: ActorRef, watched: ActorRef): Boolean = local.unsubscribe(watcher, watched) - def unsubscribe(watcher: ActorRef): Unit = local.unsubscribe(watcher) - - def publish(event: Terminated): Unit = local.publish(event) + override def unsubscribe(watcher: ActorRef): Unit = local.unsubscribe(watcher) + override def publish(event: Terminated): Unit = local.publish(event) } diff --git a/akka-remote/src/main/scala/akka/remote/RemoteDeployer.scala b/akka-remote/src/main/scala/akka/remote/RemoteDeployer.scala index 0858c66405..58a3b8452d 100644 --- a/akka-remote/src/main/scala/akka/remote/RemoteDeployer.scala +++ b/akka-remote/src/main/scala/akka/remote/RemoteDeployer.scala @@ -6,15 +6,14 @@ package akka.remote import akka.actor._ import akka.routing._ import com.typesafe.config._ -import akka.config.ConfigurationException +import akka.ConfigurationException case class RemoteScope(node: Address) extends Scope { def withFallback(other: Scope): Scope = this } -class RemoteDeployer(_settings: ActorSystem.Settings, _pm: DynamicAccess) extends Deployer(_settings, _pm) { - - override protected def parseConfig(path: String, config: Config): Option[Deploy] = { +private[akka] class RemoteDeployer(_settings: ActorSystem.Settings, _pm: DynamicAccess) extends Deployer(_settings, _pm) { + override def parseConfig(path: String, config: Config): Option[Deploy] = { import scala.collection.JavaConverters._ super.parseConfig(path, config) match { @@ -30,5 +29,4 @@ class RemoteDeployer(_settings: ActorSystem.Settings, _pm: DynamicAccess) extend case None ⇒ None } } - } \ No newline at end of file diff --git a/akka-remote/src/main/scala/akka/remote/RemoteSettings.scala b/akka-remote/src/main/scala/akka/remote/RemoteSettings.scala index ef30206a42..951c007fbc 100644 --- a/akka-remote/src/main/scala/akka/remote/RemoteSettings.scala +++ b/akka-remote/src/main/scala/akka/remote/RemoteSettings.scala @@ -6,17 +6,12 @@ package akka.remote import com.typesafe.config.Config import akka.util.Duration import java.util.concurrent.TimeUnit.MILLISECONDS -import java.net.InetAddress -import akka.config.ConfigurationException -import scala.collection.JavaConverters._ -import akka.actor.Address -import akka.actor.AddressFromURIString class RemoteSettings(val config: Config, val systemName: String) { import config._ - val RemoteTransport = getString("akka.remote.transport") - val LogReceive = getBoolean("akka.remote.log-received-messages") - val LogSend = getBoolean("akka.remote.log-sent-messages") - val RemoteSystemDaemonAckTimeout = Duration(getMilliseconds("akka.remote.remote-daemon-ack-timeout"), MILLISECONDS) - val UntrustedMode = getBoolean("akka.remote.untrusted-mode") + val RemoteTransport: String = getString("akka.remote.transport") + val LogReceive: Boolean = getBoolean("akka.remote.log-received-messages") + val LogSend: Boolean = getBoolean("akka.remote.log-sent-messages") + val RemoteSystemDaemonAckTimeout: Duration = Duration(getMilliseconds("akka.remote.remote-daemon-ack-timeout"), MILLISECONDS) + val UntrustedMode: Boolean = getBoolean("akka.remote.untrusted-mode") } diff --git a/akka-remote/src/main/scala/akka/remote/RemoteTransport.scala b/akka-remote/src/main/scala/akka/remote/RemoteTransport.scala index 3bade97460..d912d1d878 100644 --- a/akka-remote/src/main/scala/akka/remote/RemoteTransport.scala +++ b/akka-remote/src/main/scala/akka/remote/RemoteTransport.scala @@ -10,7 +10,6 @@ import akka.event.{ LoggingAdapter, Logging } import akka.AkkaException import akka.serialization.Serialization import akka.remote.RemoteProtocol._ -import akka.dispatch.ChildTerminated import akka.actor._ /** @@ -27,54 +26,67 @@ trait RemoteClientLifeCycleEvent extends RemoteLifeCycleEvent { def remoteAddress: Address } +/** + * A RemoteClientError is a general error that is thrown within or from a RemoteClient + */ case class RemoteClientError( @BeanProperty cause: Throwable, @transient @BeanProperty remote: RemoteTransport, @BeanProperty remoteAddress: Address) extends RemoteClientLifeCycleEvent { - override def logLevel = Logging.ErrorLevel - override def toString = - "RemoteClientError@" + remoteAddress + ": Error[" + cause + "]" + override def logLevel: Logging.LogLevel = Logging.ErrorLevel + override def toString: String = "RemoteClientError@" + remoteAddress + ": Error[" + cause + "]" } +/** + * RemoteClientDisconnected is published when a RemoteClient's connection is disconnected + */ case class RemoteClientDisconnected( @transient @BeanProperty remote: RemoteTransport, @BeanProperty remoteAddress: Address) extends RemoteClientLifeCycleEvent { - override def logLevel = Logging.DebugLevel - override def toString = - "RemoteClientDisconnected@" + remoteAddress + override def logLevel: Logging.LogLevel = Logging.DebugLevel + override def toString: String = "RemoteClientDisconnected@" + remoteAddress } +/** + * RemoteClientConnected is published when a RemoteClient's connection is established + */ case class RemoteClientConnected( @transient @BeanProperty remote: RemoteTransport, @BeanProperty remoteAddress: Address) extends RemoteClientLifeCycleEvent { - override def logLevel = Logging.DebugLevel - override def toString = - "RemoteClientConnected@" + remoteAddress + override def logLevel: Logging.LogLevel = Logging.DebugLevel + override def toString: String = "RemoteClientConnected@" + remoteAddress } +/** + * RemoteClientStarted is published when a RemoteClient has started up + */ case class RemoteClientStarted( @transient @BeanProperty remote: RemoteTransport, @BeanProperty remoteAddress: Address) extends RemoteClientLifeCycleEvent { - override def logLevel = Logging.InfoLevel - override def toString = - "RemoteClientStarted@" + remoteAddress + override def logLevel: Logging.LogLevel = Logging.InfoLevel + override def toString: String = "RemoteClientStarted@" + remoteAddress } +/** + * RemoteClientShutdown is published when a RemoteClient has shut down + */ case class RemoteClientShutdown( @transient @BeanProperty remote: RemoteTransport, @BeanProperty remoteAddress: Address) extends RemoteClientLifeCycleEvent { - override def logLevel = Logging.InfoLevel - override def toString = - "RemoteClientShutdown@" + remoteAddress + override def logLevel: Logging.LogLevel = Logging.InfoLevel + override def toString: String = "RemoteClientShutdown@" + remoteAddress } +/** + * RemoteClientWriteFailed is published when a remote send of a message detectably fails (throws an exception). + */ case class RemoteClientWriteFailed( @BeanProperty request: AnyRef, @BeanProperty cause: Throwable, @transient @BeanProperty remote: RemoteTransport, @BeanProperty remoteAddress: Address) extends RemoteClientLifeCycleEvent { - override def logLevel = Logging.WarningLevel - override def toString = + override def logLevel: Logging.LogLevel = Logging.WarningLevel + override def toString: String = "RemoteClientWriteFailed@" + remoteAddress + ": MessageClass[" + (if (request ne null) request.getClass.getName else "no message") + "] Error[" + cause + "]" @@ -85,53 +97,65 @@ case class RemoteClientWriteFailed( */ trait RemoteServerLifeCycleEvent extends RemoteLifeCycleEvent +/** + * RemoteServerStarted is published when a local RemoteServer has started up + */ case class RemoteServerStarted( @transient @BeanProperty remote: RemoteTransport) extends RemoteServerLifeCycleEvent { - override def logLevel = Logging.InfoLevel - override def toString = - "RemoteServerStarted@" + remote + override def logLevel: Logging.LogLevel = Logging.InfoLevel + override def toString: String = "RemoteServerStarted@" + remote } +/** + * RemoteServerShutdown is published when a local RemoteServer has shut down + */ case class RemoteServerShutdown( @transient @BeanProperty remote: RemoteTransport) extends RemoteServerLifeCycleEvent { - override def logLevel = Logging.InfoLevel - override def toString = - "RemoteServerShutdown@" + remote + override def logLevel: Logging.LogLevel = Logging.InfoLevel + override def toString: String = "RemoteServerShutdown@" + remote } +/** + * A RemoteServerError is a general error that is thrown within or from a RemoteServer + */ case class RemoteServerError( @BeanProperty val cause: Throwable, @transient @BeanProperty remote: RemoteTransport) extends RemoteServerLifeCycleEvent { - override def logLevel = Logging.ErrorLevel - override def toString = - "RemoteServerError@" + remote + "] Error[" + cause + "]" + override def logLevel: Logging.LogLevel = Logging.ErrorLevel + override def toString: String = "RemoteServerError@" + remote + "] Error[" + cause + "]" } +/** + * RemoteServerClientConnected is published when an inbound connection has been established + */ case class RemoteServerClientConnected( @transient @BeanProperty remote: RemoteTransport, @BeanProperty val clientAddress: Option[Address]) extends RemoteServerLifeCycleEvent { - override def logLevel = Logging.DebugLevel - override def toString = - "RemoteServerClientConnected@" + remote + - ": Client[" + clientAddress.getOrElse("no address") + "]" + override def logLevel: Logging.LogLevel = Logging.DebugLevel + override def toString: String = + "RemoteServerClientConnected@" + remote + ": Client[" + clientAddress.getOrElse("no address") + "]" } +/** + * RemoteServerClientConnected is published when an inbound connection has been disconnected + */ case class RemoteServerClientDisconnected( @transient @BeanProperty remote: RemoteTransport, @BeanProperty val clientAddress: Option[Address]) extends RemoteServerLifeCycleEvent { - override def logLevel = Logging.DebugLevel - override def toString = - "RemoteServerClientDisconnected@" + remote + - ": Client[" + clientAddress.getOrElse("no address") + "]" + override def logLevel: Logging.LogLevel = Logging.DebugLevel + override def toString: String = + "RemoteServerClientDisconnected@" + remote + ": Client[" + clientAddress.getOrElse("no address") + "]" } +/** + * RemoteServerClientClosed is published when an inbound RemoteClient is closed + */ case class RemoteServerClientClosed( @transient @BeanProperty remote: RemoteTransport, @BeanProperty val clientAddress: Option[Address]) extends RemoteServerLifeCycleEvent { - override def logLevel = Logging.DebugLevel - override def toString = - "RemoteServerClientClosed@" + remote + - ": Client[" + clientAddress.getOrElse("no address") + "]" + override def logLevel: Logging.LogLevel = Logging.DebugLevel + override def toString: String = + "RemoteServerClientClosed@" + remote + ": Client[" + clientAddress.getOrElse("no address") + "]" } /** @@ -142,6 +166,10 @@ class RemoteClientException private[akka] ( @transient @BeanProperty val client: RemoteTransport, val remoteAddress: Address, cause: Throwable = null) extends AkkaException(message, cause) +/** + * RemoteTransportException represents a general failure within a RemoteTransport, + * such as inability to start, wrong configuration etc. + */ class RemoteTransportException(message: String, cause: Throwable) extends AkkaException(message, cause) /** @@ -178,71 +206,56 @@ abstract class RemoteTransport(val system: ExtendedActorSystem, val provider: Re */ def restartClientConnection(address: Address): Boolean - /** Methods that needs to be implemented by a transport **/ - - def send(message: Any, - senderOption: Option[ActorRef], - recipient: RemoteActorRef): Unit + /** + * Sends the given message to the recipient supplying the sender if any + */ + def send(message: Any, senderOption: Option[ActorRef], recipient: RemoteActorRef): Unit + /** + * Default implementation both publishes the message to the eventStream as well as logs it using the system logger + */ def notifyListeners(message: RemoteLifeCycleEvent): Unit = { system.eventStream.publish(message) system.log.log(message.logLevel, "{}", message) } - override def toString = address.toString -} - -class RemoteMessage(input: RemoteMessageProtocol, system: ExtendedActorSystem) { - - def originalReceiver = input.getRecipient.getPath - - lazy val sender: ActorRef = - if (input.hasSender) system.provider.actorFor(system.provider.rootGuardian, input.getSender.getPath) - else system.deadLetters - - lazy val recipient: InternalActorRef = system.provider.actorFor(system.provider.rootGuardian, originalReceiver) - - lazy val payload: AnyRef = MessageSerializer.deserialize(system, input.getMessage) - - override def toString = "RemoteMessage: " + payload + " to " + recipient + "<+{" + originalReceiver + "} from " + sender -} - -trait RemoteMarshallingOps { + /** + * Returns this RemoteTransports Address' textual representation + */ + override def toString: String = address.toString + /** + * A Logger that can be used to log issues that may occur + */ def log: LoggingAdapter - def system: ExtendedActorSystem - - def provider: RemoteActorRefProvider - - def address: Address - + /** + * When this method returns true, some functionality will be turned off for security purposes. + */ protected def useUntrustedMode: Boolean - def createMessageSendEnvelope(rmp: RemoteMessageProtocol): AkkaRemoteProtocol = { - val arp = AkkaRemoteProtocol.newBuilder - arp.setMessage(rmp) - arp.build - } + /** + * Returns a newly created AkkaRemoteProtocol with the given message payload. + */ + def createMessageSendEnvelope(rmp: RemoteMessageProtocol): AkkaRemoteProtocol = + AkkaRemoteProtocol.newBuilder.setMessage(rmp).build - def createControlEnvelope(rcp: RemoteControlProtocol): AkkaRemoteProtocol = { - val arp = AkkaRemoteProtocol.newBuilder - arp.setInstruction(rcp) - arp.build - } + /** + * Returns a newly created AkkaRemoteProtocol with the given control payload. + */ + def createControlEnvelope(rcp: RemoteControlProtocol): AkkaRemoteProtocol = + AkkaRemoteProtocol.newBuilder.setInstruction(rcp).build /** * Serializes the ActorRef instance into a Protocol Buffers (protobuf) Message. */ - def toRemoteActorRefProtocol(actor: ActorRef): ActorRefProtocol = { + def toRemoteActorRefProtocol(actor: ActorRef): ActorRefProtocol = ActorRefProtocol.newBuilder.setPath(actor.path.toStringWithAddress(address)).build - } - - def createRemoteMessageProtocolBuilder( - recipient: ActorRef, - message: Any, - senderOption: Option[ActorRef]): RemoteMessageProtocol.Builder = { + /** + * Returns a new RemoteMessageProtocol containing the serialized representation of the given parameters. + */ + def createRemoteMessageProtocolBuilder(recipient: ActorRef, message: Any, senderOption: Option[ActorRef]): RemoteMessageProtocol.Builder = { val messageBuilder = RemoteMessageProtocol.newBuilder.setRecipient(toRemoteActorRefProtocol(recipient)) if (senderOption.isDefined) messageBuilder.setSender(toRemoteActorRefProtocol(senderOption.get)) @@ -253,7 +266,12 @@ trait RemoteMarshallingOps { messageBuilder } - def receiveMessage(remoteMessage: RemoteMessage) { + /** + * Call this method with an inbound RemoteMessage and this will take care of security (see: "useUntrustedMode") + * as well as making sure that the message ends up at its destination (best effort). + * There is also a fair amount of logging produced by this method, which is good for debugging. + */ + def receiveMessage(remoteMessage: RemoteMessage): Unit = { val remoteDaemon = provider.remoteDaemon remoteMessage.recipient match { @@ -289,3 +307,43 @@ trait RemoteMarshallingOps { } } } + +/** + * RemoteMessage is a wrapper around a message that has come in over the wire, + * it allows to easily obtain references to the deserialized message, its intended recipient + * and the sender. + */ +class RemoteMessage(input: RemoteMessageProtocol, system: ExtendedActorSystem) { + /** + * Returns a String-representation of the ActorPath that this RemoteMessage is destined for + */ + def originalReceiver: String = input.getRecipient.getPath + + /** + * Returns an Option with the String representation of the ActorPath of the Actor who is the sender of this message + */ + def originalSender: Option[String] = if (input.hasSender) Some(input.getSender.getPath) else None + + /** + * Returns a reference to the Actor that sent this message, or DeadLetterActorRef if not present or found. + */ + lazy val sender: ActorRef = + if (input.hasSender) system.provider.actorFor(system.provider.rootGuardian, input.getSender.getPath) + else system.deadLetters + + /** + * Returns a reference to the Actor that this message is destined for. + * In case this returns a DeadLetterActorRef, you have access to the path using the "originalReceiver" method. + */ + lazy val recipient: InternalActorRef = system.provider.actorFor(system.provider.rootGuardian, originalReceiver) + + /** + * Returns the message + */ + lazy val payload: AnyRef = MessageSerializer.deserialize(system, input.getMessage) + + /** + * Returns a String representation of this RemoteMessage, intended for debugging purposes. + */ + override def toString: String = "RemoteMessage: " + payload + " to " + recipient + "<+{" + originalReceiver + "} from " + sender +} diff --git a/akka-remote/src/main/scala/akka/remote/netty/Client.scala b/akka-remote/src/main/scala/akka/remote/netty/Client.scala index 0d689ef30d..c1737831da 100644 --- a/akka-remote/src/main/scala/akka/remote/netty/Client.scala +++ b/akka-remote/src/main/scala/akka/remote/netty/Client.scala @@ -3,44 +3,32 @@ */ package akka.remote.netty -import java.net.InetSocketAddress -import org.jboss.netty.util.HashedWheelTimer +import java.util.concurrent.TimeUnit +import java.net.{ InetAddress, InetSocketAddress } +import org.jboss.netty.util.{ Timeout, TimerTask, HashedWheelTimer } import org.jboss.netty.bootstrap.ClientBootstrap import org.jboss.netty.channel.group.DefaultChannelGroup -import org.jboss.netty.channel.{ ChannelHandler, StaticChannelPipeline, SimpleChannelUpstreamHandler, MessageEvent, ExceptionEvent, ChannelStateEvent, ChannelPipelineFactory, ChannelPipeline, ChannelHandlerContext, ChannelFuture, Channel } +import org.jboss.netty.channel.{ ChannelFutureListener, ChannelHandler, StaticChannelPipeline, MessageEvent, ExceptionEvent, ChannelStateEvent, ChannelPipelineFactory, ChannelPipeline, ChannelHandlerContext, ChannelFuture, Channel } import org.jboss.netty.handler.codec.frame.{ LengthFieldPrepender, LengthFieldBasedFrameDecoder } import org.jboss.netty.handler.execution.ExecutionHandler +import org.jboss.netty.handler.timeout.{ IdleState, IdleStateEvent, IdleStateAwareChannelHandler, IdleStateHandler } import akka.remote.RemoteProtocol.{ RemoteControlProtocol, CommandType, AkkaRemoteProtocol } -import akka.remote.{ RemoteProtocol, RemoteMessage, RemoteLifeCycleEvent, RemoteClientStarted, RemoteClientShutdown, RemoteClientException, RemoteClientError, RemoteClientDisconnected, RemoteClientConnected } -import akka.actor.{ simpleName, Address } +import akka.remote.{ RemoteProtocol, RemoteMessage, RemoteLifeCycleEvent, RemoteClientStarted, RemoteClientShutdown, RemoteClientException, RemoteClientError, RemoteClientDisconnected, RemoteClientConnected, RemoteClientWriteFailed } +import akka.actor.{ Address, ActorRef } import akka.AkkaException import akka.event.Logging import akka.util.Switch -import akka.actor.ActorRef -import org.jboss.netty.channel.ChannelFutureListener -import akka.remote.RemoteClientWriteFailed -import java.net.InetAddress -import org.jboss.netty.util.TimerTask -import org.jboss.netty.util.Timeout -import java.util.concurrent.TimeUnit -import org.jboss.netty.handler.timeout.{ IdleState, IdleStateEvent, IdleStateAwareChannelHandler, IdleStateHandler } - -class RemoteClientMessageBufferException(message: String, cause: Throwable) extends AkkaException(message, cause) { - def this(msg: String) = this(msg, null) -} /** * This is the abstract baseclass for netty remote clients, currently there's only an * ActiveRemoteClient, but others could be feasible, like a PassiveRemoteClient that * reuses an already established connection. */ -abstract class RemoteClient private[akka] ( - val netty: NettyRemoteTransport, - val remoteAddress: Address) { +private[akka] abstract class RemoteClient private[akka] (val netty: NettyRemoteTransport, val remoteAddress: Address) { val log = Logging(netty.system, "RemoteClient") - val name = simpleName(this) + "@" + remoteAddress + val name = Logging.simpleName(this) + "@" + remoteAddress private[remote] val runSwitch = new Switch() @@ -97,7 +85,7 @@ abstract class RemoteClient private[akka] ( /** * RemoteClient represents a connection to an Akka node. Is used to send messages to remote actors on the node. */ -class ActiveRemoteClient private[akka] ( +private[akka] class ActiveRemoteClient private[akka] ( netty: NettyRemoteTransport, remoteAddress: Address, localAddress: Address) @@ -112,8 +100,6 @@ class ActiveRemoteClient private[akka] ( private var connection: ChannelFuture = _ @volatile private[remote] var openChannels: DefaultChannelGroup = _ - @volatile - private var executionHandler: ExecutionHandler = _ @volatile private var reconnectionTimeWindowStart = 0L @@ -156,9 +142,8 @@ class ActiveRemoteClient private[akka] ( runSwitch switchOn { openChannels = new DefaultDisposableChannelGroup(classOf[RemoteClient].getName) - executionHandler = new ExecutionHandler(netty.executor) val b = new ClientBootstrap(netty.clientChannelFactory) - b.setPipelineFactory(new ActiveRemoteClientPipelineFactory(name, b, executionHandler, remoteAddress, localAddress, this)) + b.setPipelineFactory(netty.createPipeline(new ActiveRemoteClientHandler(name, b, remoteAddress, localAddress, netty.timer, this), true)) b.setOption("tcpNoDelay", true) b.setOption("keepAlive", true) b.setOption("connectTimeoutMillis", settings.ConnectionTimeout.toMillis) @@ -176,6 +161,7 @@ class ActiveRemoteClient private[akka] ( notifyListeners(RemoteClientError(connection.getCause, netty, remoteAddress)) false } else { + ChannelAddress.set(connection.getChannel, Some(remoteAddress)) sendSecureCookie(connection) notifyListeners(RemoteClientStarted(netty, remoteAddress)) true @@ -199,14 +185,15 @@ class ActiveRemoteClient private[akka] ( notifyListeners(RemoteClientShutdown(netty, remoteAddress)) try { - if ((connection ne null) && (connection.getChannel ne null)) + if ((connection ne null) && (connection.getChannel ne null)) { + ChannelAddress.remove(connection.getChannel) connection.getChannel.close() + } } finally { try { if (openChannels ne null) openChannels.close.awaitUninterruptibly() } finally { connection = null - executionHandler = null } } @@ -230,7 +217,7 @@ class ActiveRemoteClient private[akka] ( } @ChannelHandler.Sharable -class ActiveRemoteClientHandler( +private[akka] class ActiveRemoteClientHandler( val name: String, val bootstrap: ClientBootstrap, val remoteAddress: Address, @@ -319,35 +306,9 @@ class ActiveRemoteClientHandler( } } -class ActiveRemoteClientPipelineFactory( - name: String, - bootstrap: ClientBootstrap, - executionHandler: ExecutionHandler, - remoteAddress: Address, - localAddress: Address, - client: ActiveRemoteClient) extends ChannelPipelineFactory { - - import client.netty.settings - - def getPipeline: ChannelPipeline = { - val timeout = new IdleStateHandler(client.netty.timer, - settings.ReadTimeout.toSeconds.toInt, - settings.WriteTimeout.toSeconds.toInt, - settings.AllTimeout.toSeconds.toInt) - val lenDec = new LengthFieldBasedFrameDecoder(settings.MessageFrameSize, 0, 4, 0, 4) - val lenPrep = new LengthFieldPrepender(4) - val messageDec = new RemoteMessageDecoder - val messageEnc = new RemoteMessageEncoder(client.netty) - val remoteClient = new ActiveRemoteClientHandler(name, bootstrap, remoteAddress, localAddress, client.netty.timer, client) - - new StaticChannelPipeline(timeout, lenDec, messageDec, lenPrep, messageEnc, executionHandler, remoteClient) - } -} - -class PassiveRemoteClient(val currentChannel: Channel, - netty: NettyRemoteTransport, - remoteAddress: Address) - extends RemoteClient(netty, remoteAddress) { +private[akka] class PassiveRemoteClient(val currentChannel: Channel, + netty: NettyRemoteTransport, + remoteAddress: Address) extends RemoteClient(netty, remoteAddress) { def connect(reconnectIfAlreadyConnected: Boolean = false): Boolean = runSwitch switchOn { netty.notifyListeners(RemoteClientStarted(netty, remoteAddress)) diff --git a/akka-remote/src/main/scala/akka/remote/netty/NettyRemoteSupport.scala b/akka-remote/src/main/scala/akka/remote/netty/NettyRemoteSupport.scala index 4fd70b822f..b42239f470 100644 --- a/akka-remote/src/main/scala/akka/remote/netty/NettyRemoteSupport.scala +++ b/akka-remote/src/main/scala/akka/remote/netty/NettyRemoteSupport.scala @@ -12,48 +12,136 @@ import java.util.concurrent.Executors import scala.collection.mutable.HashMap import org.jboss.netty.channel.group.{ DefaultChannelGroup, ChannelGroupFuture } import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory -import org.jboss.netty.channel.{ ChannelHandlerContext, Channel } +import org.jboss.netty.channel.{ ChannelHandlerContext, Channel, StaticChannelPipeline, ChannelHandler, ChannelPipelineFactory, ChannelLocal } +import org.jboss.netty.handler.codec.frame.{ LengthFieldPrepender, LengthFieldBasedFrameDecoder } import org.jboss.netty.handler.codec.protobuf.{ ProtobufEncoder, ProtobufDecoder } -import org.jboss.netty.handler.execution.OrderedMemoryAwareThreadPoolExecutor +import org.jboss.netty.handler.execution.{ ExecutionHandler, OrderedMemoryAwareThreadPoolExecutor } +import org.jboss.netty.handler.timeout.IdleStateHandler import org.jboss.netty.util.HashedWheelTimer -import akka.dispatch.MonitorableThreadFactory import akka.event.Logging import akka.remote.RemoteProtocol.AkkaRemoteProtocol -import akka.remote.{ RemoteTransportException, RemoteTransport, RemoteSettings, RemoteMarshallingOps, RemoteActorRefProvider, RemoteActorRef, RemoteServerStarted } +import akka.remote.{ RemoteTransportException, RemoteTransport, RemoteActorRefProvider, RemoteActorRef, RemoteServerStarted } import akka.util.NonFatal import akka.actor.{ ExtendedActorSystem, Address, ActorRef } +object ChannelAddress extends ChannelLocal[Option[Address]] { + override def initialValue(ch: Channel): Option[Address] = None +} + /** * Provides the implementation of the Netty remote support */ -class NettyRemoteTransport(_system: ExtendedActorSystem, _provider: RemoteActorRefProvider) extends RemoteTransport(_system, _provider) with RemoteMarshallingOps { +private[akka] class NettyRemoteTransport(_system: ExtendedActorSystem, _provider: RemoteActorRefProvider) extends RemoteTransport(_system, _provider) { import provider.remoteSettings val settings = new NettySettings(remoteSettings.config.getConfig("akka.remote.netty"), remoteSettings.systemName) + // TODO replace by system.scheduler val timer: HashedWheelTimer = new HashedWheelTimer(system.threadFactory) - val executor = new OrderedMemoryAwareThreadPoolExecutor( - settings.ExecutionPoolSize, - settings.MaxChannelMemorySize, - settings.MaxTotalMemorySize, - settings.ExecutionPoolKeepalive.length, - settings.ExecutionPoolKeepalive.unit, - system.threadFactory) - + // TODO make configurable/shareable with server socket factory val clientChannelFactory = new NioClientSocketChannelFactory( Executors.newCachedThreadPool(system.threadFactory), Executors.newCachedThreadPool(system.threadFactory)) + /** + * Backing scaffolding for the default implementation of NettyRemoteSupport.createPipeline. + */ + object PipelineFactory { + /** + * Construct a StaticChannelPipeline from a sequence of handlers; to be used + * in implementations of ChannelPipelineFactory. + */ + def apply(handlers: Seq[ChannelHandler]): StaticChannelPipeline = new StaticChannelPipeline(handlers: _*) + + /** + * Constructs the NettyRemoteTransport default pipeline with the give “head” handler, which + * is taken by-name to allow it not to be shared across pipelines. + * + * @param withTimeout determines whether an IdleStateHandler shall be included + */ + def apply(endpoint: ⇒ Seq[ChannelHandler], withTimeout: Boolean): ChannelPipelineFactory = + new ChannelPipelineFactory { + def getPipeline = apply(defaultStack(withTimeout) ++ endpoint) + } + + /** + * Construct a default protocol stack, excluding the “head” handler (i.e. the one which + * actually dispatches the received messages to the local target actors). + */ + def defaultStack(withTimeout: Boolean): Seq[ChannelHandler] = + (if (withTimeout) timeout :: Nil else Nil) ::: + msgFormat ::: + authenticator ::: + executionHandler :: + Nil + + /** + * Construct an IdleStateHandler which uses [[akka.remote.netty.NettyRemoteTransport]].timer. + */ + def timeout = new IdleStateHandler(timer, + settings.ReadTimeout.toSeconds.toInt, + settings.WriteTimeout.toSeconds.toInt, + settings.AllTimeout.toSeconds.toInt) + + /** + * Construct frame&protobuf encoder/decoder. + */ + def msgFormat = new LengthFieldBasedFrameDecoder(settings.MessageFrameSize, 0, 4, 0, 4) :: + new LengthFieldPrepender(4) :: + new RemoteMessageDecoder :: + new RemoteMessageEncoder(NettyRemoteTransport.this) :: + Nil + + /** + * Construct an ExecutionHandler which is used to ensure that message dispatch does not + * happen on a netty thread (that could be bad if re-sending over the network for + * remote-deployed actors). + */ + val executionHandler = new ExecutionHandler(new OrderedMemoryAwareThreadPoolExecutor( + settings.ExecutionPoolSize, + settings.MaxChannelMemorySize, + settings.MaxTotalMemorySize, + settings.ExecutionPoolKeepalive.length, + settings.ExecutionPoolKeepalive.unit, + system.threadFactory)) + + /** + * Construct and authentication handler which uses the SecureCookie to somewhat + * protect the TCP port from unauthorized use (don’t rely on it too much, though, + * as this is NOT a cryptographic feature). + */ + def authenticator = if (settings.RequireCookie) new RemoteServerAuthenticationHandler(settings.SecureCookie) :: Nil else Nil + } + + /** + * This method is factored out to provide an extension point in case the + * pipeline shall be changed. It is recommended to use + */ + def createPipeline(endpoint: ⇒ ChannelHandler, withTimeout: Boolean): ChannelPipelineFactory = + PipelineFactory(Seq(endpoint), withTimeout) + private val remoteClients = new HashMap[Address, RemoteClient] private val clientsLock = new ReentrantReadWriteLock override protected def useUntrustedMode = remoteSettings.UntrustedMode - val server = try new NettyRemoteServer(this) catch { - case ex ⇒ shutdown(); throw ex - } + val server: NettyRemoteServer = try createServer() catch { case NonFatal(ex) ⇒ shutdown(); throw ex } + + /** + * Override this method to inject a subclass of NettyRemoteServer instead of + * the normal one, e.g. for inserting security hooks. If this method throws + * an exception, the transport will shut itself down and re-throw. + */ + protected def createServer(): NettyRemoteServer = new NettyRemoteServer(this) + + /** + * Override this method to inject a subclass of RemoteClient instead of + * the normal one, e.g. for inserting security hooks. Get this transport’s + * address from `this.address`. + */ + protected def createClient(recipient: Address): RemoteClient = new ActiveRemoteClient(this, recipient, address) // the address is set in start() or from the RemoteServerHandler, whichever comes first private val _address = new AtomicReference[Address] @@ -92,11 +180,7 @@ class NettyRemoteTransport(_system: ExtendedActorSystem, _provider: RemoteActorR try { timer.stop() } finally { - try { - clientChannelFactory.releaseExternalResources() - } finally { - executor.shutdown() - } + clientChannelFactory.releaseExternalResources() } } } @@ -122,7 +206,7 @@ class NettyRemoteTransport(_system: ExtendedActorSystem, _provider: RemoteActorR //Recheck for addition, race between upgrades case Some(client) ⇒ client //If already populated by other writer case None ⇒ //Populate map - val client = new ActiveRemoteClient(this, recipientAddress, address) + val client = createClient(recipientAddress) remoteClients += recipientAddress -> client client } @@ -192,7 +276,7 @@ class NettyRemoteTransport(_system: ExtendedActorSystem, _provider: RemoteActorR } -class RemoteMessageEncoder(remoteSupport: NettyRemoteTransport) extends ProtobufEncoder { +private[akka] class RemoteMessageEncoder(remoteSupport: NettyRemoteTransport) extends ProtobufEncoder { override def encode(ctx: ChannelHandlerContext, channel: Channel, msg: AnyRef): AnyRef = { msg match { case (message: Any, sender: Option[_], recipient: ActorRef) ⇒ @@ -207,9 +291,9 @@ class RemoteMessageEncoder(remoteSupport: NettyRemoteTransport) extends Protobuf } } -class RemoteMessageDecoder extends ProtobufDecoder(AkkaRemoteProtocol.getDefaultInstance) +private[akka] class RemoteMessageDecoder extends ProtobufDecoder(AkkaRemoteProtocol.getDefaultInstance) -class DefaultDisposableChannelGroup(name: String) extends DefaultChannelGroup(name) { +private[akka] class DefaultDisposableChannelGroup(name: String) extends DefaultChannelGroup(name) { protected val guard = new ReentrantReadWriteLock protected val open = new AtomicBoolean(true) diff --git a/akka-remote/src/main/scala/akka/remote/netty/Server.scala b/akka-remote/src/main/scala/akka/remote/netty/Server.scala index 674023dd52..cc3310fada 100644 --- a/akka-remote/src/main/scala/akka/remote/netty/Server.scala +++ b/akka-remote/src/main/scala/akka/remote/netty/Server.scala @@ -20,7 +20,7 @@ import java.net.InetAddress import akka.actor.ActorSystemImpl import org.jboss.netty.channel._ -class NettyRemoteServer(val netty: NettyRemoteTransport) { +private[akka] class NettyRemoteServer(val netty: NettyRemoteTransport) { import netty.settings @@ -35,14 +35,12 @@ class NettyRemoteServer(val netty: NettyRemoteTransport) { new NioServerSocketChannelFactory(Executors.newCachedThreadPool(), Executors.newCachedThreadPool()) } - private val executionHandler = new ExecutionHandler(netty.executor) - // group of open channels, used for clean-up private val openChannels: ChannelGroup = new DefaultDisposableChannelGroup("akka-remote-server") private val bootstrap = { val b = new ServerBootstrap(factory) - b.setPipelineFactory(new RemoteServerPipelineFactory(openChannels, executionHandler, netty)) + b.setPipelineFactory(netty.createPipeline(new RemoteServerHandler(openChannels, netty), false)) b.setOption("backlog", settings.Backlog) b.setOption("tcpNoDelay", true) b.setOption("child.keepAlive", true) @@ -82,28 +80,8 @@ class NettyRemoteServer(val netty: NettyRemoteTransport) { } } -class RemoteServerPipelineFactory( - val openChannels: ChannelGroup, - val executionHandler: ExecutionHandler, - val netty: NettyRemoteTransport) extends ChannelPipelineFactory { - - import netty.settings - - def getPipeline: ChannelPipeline = { - val lenDec = new LengthFieldBasedFrameDecoder(settings.MessageFrameSize, 0, 4, 0, 4) - val lenPrep = new LengthFieldPrepender(4) - val messageDec = new RemoteMessageDecoder - val messageEnc = new RemoteMessageEncoder(netty) - - val authenticator = if (settings.RequireCookie) new RemoteServerAuthenticationHandler(settings.SecureCookie) :: Nil else Nil - val remoteServer = new RemoteServerHandler(openChannels, netty) - val stages: List[ChannelHandler] = lenDec :: messageDec :: lenPrep :: messageEnc :: executionHandler :: authenticator ::: remoteServer :: Nil - new StaticChannelPipeline(stages: _*) - } -} - @ChannelHandler.Sharable -class RemoteServerAuthenticationHandler(secureCookie: Option[String]) extends SimpleChannelUpstreamHandler { +private[akka] class RemoteServerAuthenticationHandler(secureCookie: Option[String]) extends SimpleChannelUpstreamHandler { val authenticated = new AnyRef override def messageReceived(ctx: ChannelHandlerContext, event: MessageEvent) = secureCookie match { @@ -130,14 +108,10 @@ class RemoteServerAuthenticationHandler(secureCookie: Option[String]) extends Si } @ChannelHandler.Sharable -class RemoteServerHandler( +private[akka] class RemoteServerHandler( val openChannels: ChannelGroup, val netty: NettyRemoteTransport) extends SimpleChannelUpstreamHandler { - val channelAddress = new ChannelLocal[Option[Address]](false) { - override def initialValue(channel: Channel) = None - } - import netty.settings private var addressToSet = true @@ -161,16 +135,16 @@ class RemoteServerHandler( override def channelConnected(ctx: ChannelHandlerContext, event: ChannelStateEvent) = () override def channelDisconnected(ctx: ChannelHandlerContext, event: ChannelStateEvent) = { - netty.notifyListeners(RemoteServerClientDisconnected(netty, channelAddress.get(ctx.getChannel))) + netty.notifyListeners(RemoteServerClientDisconnected(netty, ChannelAddress.get(ctx.getChannel))) } override def channelClosed(ctx: ChannelHandlerContext, event: ChannelStateEvent) = { - val address = channelAddress.get(ctx.getChannel) + val address = ChannelAddress.get(ctx.getChannel) if (address.isDefined && settings.UsePassiveConnections) netty.unbindClient(address.get) netty.notifyListeners(RemoteServerClientClosed(netty, address)) - channelAddress.remove(ctx.getChannel) + ChannelAddress.remove(ctx.getChannel) } override def messageReceived(ctx: ChannelHandlerContext, event: MessageEvent) = try { @@ -184,7 +158,7 @@ class RemoteServerHandler( case CommandType.CONNECT ⇒ val origin = instruction.getOrigin val inbound = Address("akka", origin.getSystem, origin.getHostname, origin.getPort) - channelAddress.set(event.getChannel, Option(inbound)) + ChannelAddress.set(event.getChannel, Option(inbound)) //If we want to reuse the inbound connections as outbound we need to get busy if (settings.UsePassiveConnections) diff --git a/akka-remote/src/main/scala/akka/remote/netty/Settings.scala b/akka-remote/src/main/scala/akka/remote/netty/Settings.scala index f73ba52ef6..64bc184408 100644 --- a/akka-remote/src/main/scala/akka/remote/netty/Settings.scala +++ b/akka-remote/src/main/scala/akka/remote/netty/Settings.scala @@ -7,39 +7,39 @@ import com.typesafe.config.Config import akka.util.Duration import java.util.concurrent.TimeUnit._ import java.net.InetAddress -import akka.config.ConfigurationException +import akka.ConfigurationException -class NettySettings(config: Config, val systemName: String) { +private[akka] class NettySettings(config: Config, val systemName: String) { import config._ - val BackoffTimeout = Duration(getMilliseconds("backoff-timeout"), MILLISECONDS) + val BackoffTimeout: Duration = Duration(getMilliseconds("backoff-timeout"), MILLISECONDS) val SecureCookie: Option[String] = getString("secure-cookie") match { case "" ⇒ None case cookie ⇒ Some(cookie) } - val RequireCookie = { + val RequireCookie: Boolean = { val requireCookie = getBoolean("require-cookie") if (requireCookie && SecureCookie.isEmpty) throw new ConfigurationException( "Configuration option 'akka.remote.netty.require-cookie' is turned on but no secure cookie is defined in 'akka.remote.netty.secure-cookie'.") requireCookie } - val UsePassiveConnections = getBoolean("use-passive-connections") - val UseDispatcherForIO = getString("use-dispatcher-for-io") match { + val UsePassiveConnections: Boolean = getBoolean("use-passive-connections") + val UseDispatcherForIO: Option[String] = getString("use-dispatcher-for-io") match { case "" | null ⇒ None case dispatcher ⇒ Some(dispatcher) } - val ReconnectionTimeWindow = Duration(getMilliseconds("reconnection-time-window"), MILLISECONDS) - val ReadTimeout = Duration(getMilliseconds("read-timeout"), MILLISECONDS) - val WriteTimeout = Duration(getMilliseconds("write-timeout"), MILLISECONDS) - val AllTimeout = Duration(getMilliseconds("all-timeout"), MILLISECONDS) - val ReconnectDelay = Duration(getMilliseconds("reconnect-delay"), MILLISECONDS) - val MessageFrameSize = getBytes("message-frame-size").toInt + val ReconnectionTimeWindow: Duration = Duration(getMilliseconds("reconnection-time-window"), MILLISECONDS) + val ReadTimeout: Duration = Duration(getMilliseconds("read-timeout"), MILLISECONDS) + val WriteTimeout: Duration = Duration(getMilliseconds("write-timeout"), MILLISECONDS) + val AllTimeout: Duration = Duration(getMilliseconds("all-timeout"), MILLISECONDS) + val ReconnectDelay: Duration = Duration(getMilliseconds("reconnect-delay"), MILLISECONDS) + val MessageFrameSize: Int = getBytes("message-frame-size").toInt - val Hostname = getString("hostname") match { + val Hostname: String = getString("hostname") match { case "" ⇒ InetAddress.getLocalHost.getHostAddress case value ⇒ value } @@ -50,25 +50,25 @@ class NettySettings(config: Config, val systemName: String) { } @deprecated("WARNING: This should only be used by professionals.", "2.0") - val PortSelector = getInt("port") + val PortSelector: Int = getInt("port") - val ConnectionTimeout = Duration(getMilliseconds("connection-timeout"), MILLISECONDS) + val ConnectionTimeout: Duration = Duration(getMilliseconds("connection-timeout"), MILLISECONDS) - val Backlog = getInt("backlog") + val Backlog: Int = getInt("backlog") - val ExecutionPoolKeepalive = Duration(getMilliseconds("execution-pool-keepalive"), MILLISECONDS) + val ExecutionPoolKeepalive: Duration = Duration(getMilliseconds("execution-pool-keepalive"), MILLISECONDS) - val ExecutionPoolSize = getInt("execution-pool-size") match { + val ExecutionPoolSize: Int = getInt("execution-pool-size") match { case sz if sz < 1 ⇒ throw new IllegalArgumentException("akka.remote.netty.execution-pool-size is less than 1") case sz ⇒ sz } - val MaxChannelMemorySize = getBytes("max-channel-memory-size") match { + val MaxChannelMemorySize: Long = getBytes("max-channel-memory-size") match { case sz if sz < 0 ⇒ throw new IllegalArgumentException("akka.remote.netty.max-channel-memory-size is less than 0 bytes") case sz ⇒ sz } - val MaxTotalMemorySize = getBytes("max-total-memory-size") match { + val MaxTotalMemorySize: Long = getBytes("max-total-memory-size") match { case sz if sz < 0 ⇒ throw new IllegalArgumentException("akka.remote.netty.max-total-memory-size is less than 0 bytes") case sz ⇒ sz } diff --git a/akka-remote/src/main/scala/akka/routing/RemoteRouterConfig.scala b/akka-remote/src/main/scala/akka/routing/RemoteRouterConfig.scala index c9bb6dba0f..9a71f309fc 100644 --- a/akka-remote/src/main/scala/akka/routing/RemoteRouterConfig.scala +++ b/akka-remote/src/main/scala/akka/routing/RemoteRouterConfig.scala @@ -10,7 +10,7 @@ import akka.actor.ActorSystemImpl import akka.actor.Deploy import akka.actor.InternalActorRef import akka.actor.Props -import akka.config.ConfigurationException +import akka.ConfigurationException import akka.remote.RemoteScope import akka.actor.AddressFromURIString import akka.actor.SupervisorStrategy @@ -59,7 +59,7 @@ class RemoteRouteeProvider(nodes: Iterable[Address], _context: ActorContext, _re extends RouteeProvider(_context, _resizer) { // need this iterator as instance variable since Resizer may call createRoutees several times - private val nodeAddressIter = Stream.continually(nodes).flatten.iterator + private val nodeAddressIter: Iterator[Address] = Stream.continually(nodes).flatten.iterator override def createRoutees(props: Props, nrOfInstances: Int, routees: Iterable[String]): IndexedSeq[ActorRef] = (nrOfInstances, routees, nodes) match { diff --git a/akka-remote/src/main/scala/akka/serialization/DaemonMsgCreateSerializer.scala b/akka-remote/src/main/scala/akka/serialization/DaemonMsgCreateSerializer.scala index ce54ff5adb..2905c3ef3b 100644 --- a/akka-remote/src/main/scala/akka/serialization/DaemonMsgCreateSerializer.scala +++ b/akka-remote/src/main/scala/akka/serialization/DaemonMsgCreateSerializer.scala @@ -30,8 +30,10 @@ import akka.actor.FromClassCreator * Serialization of contained RouterConfig, Config, and Scope * is done with configured serializer for those classes, by * default java.io.Serializable. + * + * INTERNAL API */ -class DaemonMsgCreateSerializer(val system: ExtendedActorSystem) extends Serializer { +private[akka] class DaemonMsgCreateSerializer(val system: ExtendedActorSystem) extends Serializer { import ProtobufSerializer.serializeActorRef import ProtobufSerializer.deserializeActorRef @@ -81,7 +83,7 @@ class DaemonMsgCreateSerializer(val system: ExtendedActorSystem) extends Seriali def fromBinary(bytes: Array[Byte], clazz: Option[Class[_]]): AnyRef = { val proto = DaemonMsgCreateProtocol.parseFrom(bytes) - def deploy(protoDeploy: DeployProtocol) = { + def deploy(protoDeploy: DeployProtocol): Deploy = { val config = if (protoDeploy.hasConfig) deserialize(protoDeploy.getConfig, classOf[Config]) else ConfigFactory.empty @@ -146,7 +148,5 @@ class DaemonMsgCreateSerializer(val system: ExtendedActorSystem) extends Seriali case _ ⇒ throw e // the first exception } } - } - } \ No newline at end of file diff --git a/akka-remote/src/main/scala/akka/serialization/DaemonMsgWatchSerializer.scala b/akka-remote/src/main/scala/akka/serialization/DaemonMsgWatchSerializer.scala index 0ca5216da0..016d7f14cb 100644 --- a/akka-remote/src/main/scala/akka/serialization/DaemonMsgWatchSerializer.scala +++ b/akka-remote/src/main/scala/akka/serialization/DaemonMsgWatchSerializer.scala @@ -12,8 +12,10 @@ import akka.actor.ExtendedActorSystem /** * Serializes akka's internal DaemonMsgWatch using protobuf. + * + * INTERNAL API */ -class DaemonMsgWatchSerializer(val system: ExtendedActorSystem) extends Serializer { +private[akka] class DaemonMsgWatchSerializer(val system: ExtendedActorSystem) extends Serializer { import ProtobufSerializer.serializeActorRef import ProtobufSerializer.deserializeActorRef diff --git a/akka-remote/src/multi-jvm/scala/akka/remote/AbstractRemoteActorMultiJvmSpec.scala b/akka-remote/src/multi-jvm/scala/akka/remote/AbstractRemoteActorMultiJvmSpec.scala index ab8bdadae6..ca4313b56b 100644 --- a/akka-remote/src/multi-jvm/scala/akka/remote/AbstractRemoteActorMultiJvmSpec.scala +++ b/akka-remote/src/multi-jvm/scala/akka/remote/AbstractRemoteActorMultiJvmSpec.scala @@ -1,6 +1,7 @@ package akka.remote import com.typesafe.config.{Config, ConfigFactory} +import akka.actor.Address trait AbstractRemoteActorMultiJvmSpec { def NrOfNodes: Int @@ -8,7 +9,6 @@ trait AbstractRemoteActorMultiJvmSpec { def PortRangeStart = 1990 def NodeRange = 1 to NrOfNodes - def PortRange = PortRangeStart to NrOfNodes private[this] val remotes: IndexedSeq[String] = { val nodesOpt = Option(AkkaRemoteSpec.testNodes).map(_.split(",").toIndexedSeq) diff --git a/akka-slf4j/src/main/scala/akka/event/slf4j/Slf4jEventHandler.scala b/akka-slf4j/src/main/scala/akka/event/slf4j/Slf4jEventHandler.scala index 966f57b938..9e2fefffd9 100644 --- a/akka-slf4j/src/main/scala/akka/event/slf4j/Slf4jEventHandler.scala +++ b/akka-slf4j/src/main/scala/akka/event/slf4j/Slf4jEventHandler.scala @@ -18,12 +18,29 @@ trait SLF4JLogging { lazy val log = Logger(this.getClass.getName) } +/** + * Logger is a factory for obtaining SLF4J-Loggers + */ object Logger { + /** + * @param logger - which logger + * @return a Logger that corresponds for the given logger name + */ def apply(logger: String): SLFLogger = SLFLoggerFactory getLogger logger + + /** + * @param logClass - the class to log for + * @param logSource - the textual representation of the source of this log stream + * @return a Logger for the specified parameters + */ def apply(logClass: Class[_], logSource: String): SLFLogger = logClass match { case c if c == classOf[DummyClassForStringSources] ⇒ apply(logSource) case _ ⇒ SLFLoggerFactory getLogger logClass } + + /** + * Returns the SLF4J Root Logger + */ def root: SLFLogger = apply(SLFLogger.ROOT_LOGGER_NAME) } diff --git a/akka-testkit/src/main/scala/akka/testkit/TestActorRef.scala b/akka-testkit/src/main/scala/akka/testkit/TestActorRef.scala index 8a2f61bf76..0a5d6163e8 100644 --- a/akka-testkit/src/main/scala/akka/testkit/TestActorRef.scala +++ b/akka-testkit/src/main/scala/akka/testkit/TestActorRef.scala @@ -56,7 +56,7 @@ class TestActorRef[T <: Actor]( * thrown will be available to you, while still being able to use * become/unbecome. */ - def receive(o: Any) { underlyingActor.apply(o) } + def receive(o: Any): Unit = underlying.receiveMessage(o) /** * Retrieve reference to the underlying actor, where the static type matches the factory used inside the diff --git a/akka-transactor/src/main/scala/akka/transactor/Coordinated.scala b/akka-transactor/src/main/scala/akka/transactor/Coordinated.scala index 2463f0e436..792824be24 100644 --- a/akka-transactor/src/main/scala/akka/transactor/Coordinated.scala +++ b/akka-transactor/src/main/scala/akka/transactor/Coordinated.scala @@ -12,19 +12,29 @@ import java.util.concurrent.Callable /** * Akka-specific exception for coordinated transactions. */ -class CoordinatedTransactionException(message: String, cause: Throwable = null) extends AkkaException(message, cause) { - def this(msg: String) = this(msg, null); +class CoordinatedTransactionException(message: String, cause: Throwable) extends AkkaException(message, cause) { + def this(msg: String) = this(msg, null) } /** * Coordinated transactions across actors. */ object Coordinated { - def apply(message: Any = null)(implicit timeout: Timeout) = new Coordinated(message, createInitialMember(timeout)) + /** + * Creates a new Coordinated with the given message and Timeout + * @param message - the message which will be coordinated + * @param timeout - the timeout for the coordination + * @return a new Coordinated + */ + def apply(message: Any = null)(implicit timeout: Timeout): Coordinated = + new Coordinated(message, CommitBarrier(timeout.duration.toMillis).addMember()) + + /** + * @param c - a Coordinated to be unapplied + * @return the message associated with the given Coordinated + */ def unapply(c: Coordinated): Option[Any] = Some(c.message) - - def createInitialMember(timeout: Timeout) = CommitBarrier(timeout.duration.toMillis).addMember() } /** @@ -91,16 +101,15 @@ class Coordinated(val message: Any, member: CommitBarrier.Member) { // Java API constructors - def this(message: Any, timeout: Timeout) = this(message, Coordinated.createInitialMember(timeout)) + def this(message: Any, timeout: Timeout) = this(message, CommitBarrier(timeout.duration.toMillis).addMember()) - def this(timeout: Timeout) = this(null, Coordinated.createInitialMember(timeout)) + def this(timeout: Timeout) = this(null, timeout) /** * Create a new Coordinated object and increment the number of members by one. * Use this method to ''pass on'' the coordination. */ - def apply(msg: Any): Coordinated = - new Coordinated(msg, member.commitBarrier.addMember()) + def apply(msg: Any): Coordinated = new Coordinated(msg, member.commitBarrier.addMember()) /** * Create a new Coordinated object but *do not* increment the number of members by one. diff --git a/akka-transactor/src/main/scala/akka/transactor/Transactor.scala b/akka-transactor/src/main/scala/akka/transactor/Transactor.scala index 6e390a6623..fd802e1f21 100644 --- a/akka-transactor/src/main/scala/akka/transactor/Transactor.scala +++ b/akka-transactor/src/main/scala/akka/transactor/Transactor.scala @@ -176,8 +176,10 @@ trait Transactor extends Actor { /** * Default catch-all for the different Receive methods. */ - def doNothing: Receive = new Receive { - def apply(any: Any) = {} - def isDefinedAt(any: Any) = false - } + def doNothing: Receive = EmptyReceive +} + +private[akka] object EmptyReceive extends PartialFunction[Any, Unit] { + def apply(any: Any): Unit = () + def isDefinedAt(any: Any): Boolean = false } diff --git a/akka-transactor/src/main/scala/akka/transactor/TransactorExtension.scala b/akka-transactor/src/main/scala/akka/transactor/TransactorExtension.scala index 96aea8904c..85cb8c46fd 100644 --- a/akka-transactor/src/main/scala/akka/transactor/TransactorExtension.scala +++ b/akka-transactor/src/main/scala/akka/transactor/TransactorExtension.scala @@ -15,11 +15,11 @@ import java.util.concurrent.TimeUnit.MILLISECONDS */ object TransactorExtension extends ExtensionId[TransactorSettings] with ExtensionIdProvider { override def get(system: ActorSystem): TransactorSettings = super.get(system) - override def lookup = TransactorExtension + override def lookup: TransactorExtension.type = TransactorExtension override def createExtension(system: ExtendedActorSystem): TransactorSettings = new TransactorSettings(system.settings.config) } class TransactorSettings(val config: Config) extends Extension { import config._ - val CoordinatedTimeout = Timeout(Duration(getMilliseconds("akka.transactor.coordinated-timeout"), MILLISECONDS)) + val CoordinatedTimeout: Timeout = Timeout(Duration(getMilliseconds("akka.transactor.coordinated-timeout"), MILLISECONDS)) } \ No newline at end of file diff --git a/akka-transactor/src/test/scala/akka/transactor/CoordinatedIncrementSpec.scala b/akka-transactor/src/test/scala/akka/transactor/CoordinatedIncrementSpec.scala index 9c019a56a5..c76a5a701c 100644 --- a/akka-transactor/src/test/scala/akka/transactor/CoordinatedIncrementSpec.scala +++ b/akka-transactor/src/test/scala/akka/transactor/CoordinatedIncrementSpec.scala @@ -12,7 +12,7 @@ import akka.util.duration._ import akka.util.Timeout import akka.testkit._ import scala.concurrent.stm._ -import akka.pattern.ask +import akka.pattern.{ AskTimeoutException, ask } object CoordinatedIncrement { @@ -96,7 +96,7 @@ class CoordinatedIncrementSpec extends AkkaSpec(CoordinatedIncrement.config) wit val ignoreExceptions = Seq( EventFilter[ExpectedFailureException](), EventFilter[CoordinatedTransactionException](), - EventFilter[ActorTimeoutException]()) + EventFilter[AskTimeoutException]()) filterEvents(ignoreExceptions) { val (counters, failer) = actorOfs val coordinated = Coordinated() diff --git a/akka-transactor/src/test/scala/akka/transactor/FickleFriendsSpec.scala b/akka-transactor/src/test/scala/akka/transactor/FickleFriendsSpec.scala index 4f7fc89c14..9deee7b9cc 100644 --- a/akka-transactor/src/test/scala/akka/transactor/FickleFriendsSpec.scala +++ b/akka-transactor/src/test/scala/akka/transactor/FickleFriendsSpec.scala @@ -15,7 +15,7 @@ import akka.testkit.TestEvent.Mute import scala.concurrent.stm._ import scala.util.Random.{ nextInt ⇒ random } import java.util.concurrent.CountDownLatch -import akka.pattern.ask +import akka.pattern.{ AskTimeoutException, ask } object FickleFriends { case class FriendlyIncrement(friends: Seq[ActorRef], timeout: Timeout, latch: CountDownLatch) @@ -120,7 +120,7 @@ class FickleFriendsSpec extends AkkaSpec with BeforeAndAfterAll { val ignoreExceptions = Seq( EventFilter[ExpectedFailureException](), EventFilter[CoordinatedTransactionException](), - EventFilter[ActorTimeoutException]()) + EventFilter[AskTimeoutException]()) system.eventStream.publish(Mute(ignoreExceptions)) val (counters, coordinator) = actorOfs val latch = new CountDownLatch(1) diff --git a/akka-transactor/src/test/scala/akka/transactor/TransactorSpec.scala b/akka-transactor/src/test/scala/akka/transactor/TransactorSpec.scala index 1954c9a13b..df9723ffd2 100644 --- a/akka-transactor/src/test/scala/akka/transactor/TransactorSpec.scala +++ b/akka-transactor/src/test/scala/akka/transactor/TransactorSpec.scala @@ -10,7 +10,7 @@ import akka.util.duration._ import akka.util.Timeout import akka.testkit._ import scala.concurrent.stm._ -import akka.pattern.ask +import akka.pattern.{ AskTimeoutException, ask } object TransactorIncrement { case class Increment(friends: Seq[ActorRef], latch: TestLatch) @@ -105,7 +105,7 @@ class TransactorSpec extends AkkaSpec { val ignoreExceptions = Seq( EventFilter[ExpectedFailureException](), EventFilter[CoordinatedTransactionException](), - EventFilter[ActorTimeoutException]()) + EventFilter[AskTimeoutException]()) filterEvents(ignoreExceptions) { val (counters, failer) = createTransactors val failLatch = TestLatch(numCounters) diff --git a/akka-zeromq/src/main/scala/akka/zeromq/ConcurrentSocketActor.scala b/akka-zeromq/src/main/scala/akka/zeromq/ConcurrentSocketActor.scala index c4e6d08f59..e848809644 100644 --- a/akka-zeromq/src/main/scala/akka/zeromq/ConcurrentSocketActor.scala +++ b/akka-zeromq/src/main/scala/akka/zeromq/ConcurrentSocketActor.scala @@ -205,11 +205,6 @@ private[zeromq] class ConcurrentSocketActor(params: Seq[SocketOption]) extends A } private val listenerOpt = params collectFirst { case Listener(l) ⇒ l } - private def watchListener() { - listenerOpt foreach context.watch - } - - private def notifyListener(message: Any) { - listenerOpt foreach { _ ! message } - } + private def watchListener(): Unit = listenerOpt foreach context.watch + private def notifyListener(message: Any): Unit = listenerOpt foreach { _ ! message } } diff --git a/akka-zeromq/src/main/scala/akka/zeromq/SocketOption.scala b/akka-zeromq/src/main/scala/akka/zeromq/SocketOption.scala index 1e4c83bcef..c5d5919fb7 100644 --- a/akka-zeromq/src/main/scala/akka/zeromq/SocketOption.scala +++ b/akka-zeromq/src/main/scala/akka/zeromq/SocketOption.scala @@ -255,7 +255,9 @@ case class Linger(value: Long) extends SocketOption /** * Gets the linger option @see [[akka.zeromq.Linger]] */ -object Linger extends SocketOptionQuery +object Linger extends SocketOptionQuery { + val no: Linger = Linger(0) +} /** * Sets the recovery interval for multicast transports using the specified socket. diff --git a/akka-zeromq/src/main/scala/akka/zeromq/ZMQMessageDeserializer.scala b/akka-zeromq/src/main/scala/akka/zeromq/ZMQMessageDeserializer.scala index 1776f21211..2d41424e88 100644 --- a/akka-zeromq/src/main/scala/akka/zeromq/ZMQMessageDeserializer.scala +++ b/akka-zeromq/src/main/scala/akka/zeromq/ZMQMessageDeserializer.scala @@ -20,5 +20,5 @@ case class Frame(payload: Seq[Byte]) { * Deserializes ZeroMQ messages into an immutable sequence of frames */ class ZMQMessageDeserializer extends Deserializer { - def apply(frames: Seq[Frame]) = ZMQMessage(frames) + def apply(frames: Seq[Frame]): ZMQMessage = ZMQMessage(frames) } diff --git a/akka-zeromq/src/main/scala/akka/zeromq/ZeroMQExtension.scala b/akka-zeromq/src/main/scala/akka/zeromq/ZeroMQExtension.scala index 1ddd213325..85a9ea6642 100644 --- a/akka-zeromq/src/main/scala/akka/zeromq/ZeroMQExtension.scala +++ b/akka-zeromq/src/main/scala/akka/zeromq/ZeroMQExtension.scala @@ -19,7 +19,7 @@ import org.zeromq.ZMQException * @param patch */ case class ZeroMQVersion(major: Int, minor: Int, patch: Int) { - override def toString = "%d.%d.%d".format(major, minor, patch) + override def toString: String = "%d.%d.%d".format(major, minor, patch) } /** @@ -27,17 +27,14 @@ case class ZeroMQVersion(major: Int, minor: Int, patch: Int) { */ object ZeroMQExtension extends ExtensionId[ZeroMQExtension] with ExtensionIdProvider { override def get(system: ActorSystem): ZeroMQExtension = super.get(system) - def lookup() = this - def createExtension(system: ExtendedActorSystem) = new ZeroMQExtension(system) + def lookup(): this.type = this + override def createExtension(system: ExtendedActorSystem): ZeroMQExtension = new ZeroMQExtension(system) private val minVersionString = "2.1.0" private val minVersion = JZMQ.makeVersion(2, 1, 0) - private[zeromq] def check[TOption <: SocketOption: Manifest](parameters: Seq[SocketOption]) = { - parameters exists { p ⇒ - ClassManifest.singleType(p) <:< manifest[TOption] - } - } + private[zeromq] def check[TOption <: SocketOption: Manifest](parameters: Seq[SocketOption]) = + parameters exists { p ⇒ ClassManifest.singleType(p) <:< manifest[TOption] } } /** @@ -47,16 +44,14 @@ object ZeroMQExtension extends ExtensionId[ZeroMQExtension] with ExtensionIdProv */ class ZeroMQExtension(system: ActorSystem) extends Extension { - val DefaultPollTimeout = Duration(system.settings.config.getMilliseconds("akka.zeromq.poll-timeout"), TimeUnit.MILLISECONDS) - val NewSocketTimeout = Timeout(Duration(system.settings.config.getMilliseconds("akka.zeromq.new-socket-timeout"), TimeUnit.MILLISECONDS)) + val DefaultPollTimeout: Duration = Duration(system.settings.config.getMilliseconds("akka.zeromq.poll-timeout"), TimeUnit.MILLISECONDS) + val NewSocketTimeout: Timeout = Timeout(Duration(system.settings.config.getMilliseconds("akka.zeromq.new-socket-timeout"), TimeUnit.MILLISECONDS)) /** * The version of the ZeroMQ library * @return a [[akka.zeromq.ZeroMQVersion]] */ - def version = { - ZeroMQVersion(JZMQ.getMajorVersion, JZMQ.getMinorVersion, JZMQ.getPatchVersion) - } + def version: ZeroMQVersion = ZeroMQVersion(JZMQ.getMajorVersion, JZMQ.getMinorVersion, JZMQ.getPatchVersion) /** * Factory method to create the [[akka.actor.Props]] to build the ZeroMQ socket actor. diff --git a/akka-zeromq/src/main/scala/akka/zeromq/package.scala b/akka-zeromq/src/main/scala/akka/zeromq/package.scala index 6eeba5b92a..1241700fcb 100644 --- a/akka-zeromq/src/main/scala/akka/zeromq/package.scala +++ b/akka-zeromq/src/main/scala/akka/zeromq/package.scala @@ -20,10 +20,10 @@ package object zeromq { /** * Convenience accessor to subscribe to all events */ - val SubscribeAll = Subscribe(Seq.empty) + val SubscribeAll: Subscribe = Subscribe.all /** * Set the linger to 0, doesn't block and discards messages that haven't been sent yet. */ - val NoLinger = Linger(0) + val NoLinger: Linger = Linger.no } \ No newline at end of file diff --git a/akka-zeromq/src/test/scala/akka/zeromq/ConcurrentSocketActorSpec.scala b/akka-zeromq/src/test/scala/akka/zeromq/ConcurrentSocketActorSpec.scala index ea4da04f5a..e075ca2158 100644 --- a/akka-zeromq/src/test/scala/akka/zeromq/ConcurrentSocketActorSpec.scala +++ b/akka-zeromq/src/test/scala/akka/zeromq/ConcurrentSocketActorSpec.scala @@ -138,7 +138,7 @@ class ConcurrentSocketActorSpec extends AkkaSpec { } } - protected def receive = { + def receive = { case _ ⇒ val payload = "%s".format(messageNumber) messageNumber += 1 diff --git a/ls.sbt b/ls.sbt index 83e5babc79..87e68ed303 100644 --- a/ls.sbt +++ b/ls.sbt @@ -1,13 +1,13 @@ -seq(lsSettings:_*) +// seq(lsSettings:_*) -(description in LsKeys.lsync) := "Akka is the platform for the next generation of event-driven, scalable and fault-tolerant architectures on the JVM." +// (description in LsKeys.lsync) := "Akka is the platform for the next generation of event-driven, scalable and fault-tolerant architectures on the JVM." -(homepage in LsKeys.lsync) := Some(url("http://akka.io")) +// (homepage in LsKeys.lsync) := Some(url("http://akka.io")) -(LsKeys.tags in LsKeys.lsync) := Seq("actors", "stm", "concurrency", "distributed", "fault-tolerance", "scala", "java", "futures", "dataflow", "remoting") +// (LsKeys.tags in LsKeys.lsync) := Seq("actors", "stm", "concurrency", "distributed", "fault-tolerance", "scala", "java", "futures", "dataflow", "remoting") -(LsKeys.docsUrl in LsKeys.lsync) := Some(url("http://akka.io/docs")) +// (LsKeys.docsUrl in LsKeys.lsync) := Some(url("http://akka.io/docs")) -(licenses in LsKeys.lsync) := Seq(("Apache 2", url("http://www.apache.org/licenses/LICENSE-2.0.html"))) +// (licenses in LsKeys.lsync) := Seq(("Apache 2", url("http://www.apache.org/licenses/LICENSE-2.0.html"))) -(externalResolvers in LsKeys.lsync) := Seq("Typesafe Releases" at "http://repo.typesafe.com/typesafe/releases") +// (externalResolvers in LsKeys.lsync) := Seq("Typesafe Releases" at "http://repo.typesafe.com/typesafe/releases") diff --git a/project/AkkaBuild.scala b/project/AkkaBuild.scala index 5f2a4e8bf1..82e8a75ee2 100644 --- a/project/AkkaBuild.scala +++ b/project/AkkaBuild.scala @@ -8,7 +8,6 @@ import sbt._ import sbt.Keys._ import com.typesafe.sbtmultijvm.MultiJvmPlugin import com.typesafe.sbtmultijvm.MultiJvmPlugin.{ MultiJvm, extraOptions, jvmOptions, scalatestOptions } -import com.typesafe.schoir.SchoirPlugin.schoirSettings import com.typesafe.sbtscalariform.ScalariformPlugin import com.typesafe.sbtscalariform.ScalariformPlugin.ScalariformKeys import com.typesafe.sbtosgi.OsgiPlugin.osgiSettings @@ -41,7 +40,7 @@ object AkkaBuild extends Build { sphinxLatex <<= sphinxLatex in LocalProject(docs.id), sphinxPdf <<= sphinxPdf in LocalProject(docs.id) ), - aggregate = Seq(actor, testkit, actorTests, remote, camel, cluster, slf4j, agent, transactor, mailboxes, zeroMQ, kernel, akkaSbtPlugin, samples, tutorials, docs) + aggregate = Seq(actor, testkit, actorTests, remote, remoteTests, camel, cluster, slf4j, agent, transactor, mailboxes, zeroMQ, kernel, akkaSbtPlugin, samples, tutorials, docs) ) lazy val actor = Project( @@ -81,7 +80,7 @@ object AkkaBuild extends Build { id = "akka-remote", base = file("akka-remote"), dependencies = Seq(actor, actorTests % "test->test", testkit % "test->test"), - settings = defaultSettings ++ multiJvmSettings ++ schoirSettings ++ OSGi.remote ++ Seq( + settings = defaultSettings ++ multiJvmSettings ++ OSGi.remote ++ Seq( libraryDependencies ++= Dependencies.remote, // disable parallel tests parallelExecution in Test := false, @@ -89,18 +88,32 @@ object AkkaBuild extends Build { (name: String) => (src ** (name + ".conf")).get.headOption.map("-Dakka.config=" + _.absolutePath).toSeq }, scalatestOptions in MultiJvm := Seq("-r", "org.scalatest.akka.QuietReporter"), - jvmOptions in MultiJvm := { - if (getBoolean("sbt.log.noformat")) Seq("-Dakka.test.nocolor=true") else Nil + jvmOptions in MultiJvm := defaultMultiJvmOptions, + test in Test <<= ((test in Test), (test in MultiJvm)) map { case x => x } + ) + ) configs (MultiJvm) + + lazy val remoteTests = Project( + id = "akka-remote-tests", + base = file("akka-remote-tests"), + dependencies = Seq(remote % "compile;test->test;multi-jvm->multi-jvm", actorTests % "test->test", testkit % "test->test"), + settings = defaultSettings ++ multiJvmSettings ++ Seq( + // disable parallel tests + parallelExecution in Test := false, + extraOptions in MultiJvm <<= (sourceDirectory in MultiJvm) { src => + (name: String) => (src ** (name + ".conf")).get.headOption.map("-Dakka.config=" + _.absolutePath).toSeq }, - test in Test <<= (test in Test) dependsOn (test in MultiJvm) + scalatestOptions in MultiJvm := Seq("-r", "org.scalatest.akka.QuietReporter"), + jvmOptions in MultiJvm := defaultMultiJvmOptions, + test in Test <<= ((test in Test), (test in MultiJvm)) map { case x => x } ) ) configs (MultiJvm) lazy val cluster = Project( id = "akka-cluster", base = file("akka-cluster"), - dependencies = Seq(remote, remote % "test->test", testkit % "test->test"), - settings = defaultSettings ++ multiJvmSettings ++ schoirSettings ++ OSGi.cluster ++ Seq( + dependencies = Seq(remote, remoteTests % "compile;test->test;multi-jvm->multi-jvm", testkit % "test->test"), + settings = defaultSettings ++ multiJvmSettings ++ OSGi.cluster ++ Seq( libraryDependencies ++= Dependencies.cluster, // disable parallel tests parallelExecution in Test := false, @@ -108,10 +121,8 @@ object AkkaBuild extends Build { (name: String) => (src ** (name + ".conf")).get.headOption.map("-Dakka.config=" + _.absolutePath).toSeq }, scalatestOptions in MultiJvm := Seq("-r", "org.scalatest.akka.QuietReporter"), - jvmOptions in MultiJvm := { - if (getBoolean("sbt.log.noformat")) Seq("-Dakka.test.nocolor=true") else Nil - }, - test in Test <<= (test in Test) dependsOn (test in MultiJvm) + jvmOptions in MultiJvm := defaultMultiJvmOptions, + test in Test <<= ((test in Test), (test in MultiJvm)) map { case x => x } ) ) configs (MultiJvm) @@ -289,6 +300,14 @@ object AkkaBuild extends Build { val defaultExcludedTags = Seq("timing", "long-running") + val defaultMultiJvmOptions: Seq[String] = { + (System.getProperty("akka.test.timefactor") match { + case null => Nil + case x => List("-Dakka.test.timefactor=" + x) + }) ::: + (if (getBoolean("sbt.log.noformat")) List("-Dakka.test.nocolor=true") else Nil) + } + lazy val defaultSettings = baseSettings ++ formatSettings ++ Seq( resolvers += "Typesafe Repo" at "http://repo.typesafe.com/typesafe/releases/", @@ -444,50 +463,33 @@ object Dependency { object OSGi { - val actor = osgiSettings ++ Seq( - OsgiKeys.exportPackage := Seq("akka*", "com.typesafe.config.*"), - OsgiKeys.importPackage := Seq("!sun.misc", scalaImport()), - OsgiKeys.privatePackage := Seq("org.jboss.netty.akka.util.*", "com.eaio.*") + val actor = exports(Seq("akka*")) + + val agent = exports(Seq("akka.agent.*")) + + val camel = exports(Seq("akka.camel.*", "akka.camelexamples")) + + val cluster = exports(Seq("akka.cluster.*")) + + val fileMailbox = exports(Seq("akka.actor.mailbox.*")) + + val mailboxesCommon = exports(Seq("akka.actor.mailbox.*")) + + val remote = exports(Seq("akka.remote.*", "akka.routing.*", "akka.serialization.*")) + + val slf4j = exports(Seq("akka.event.slf4j.*")) + + val transactor = exports(Seq("akka.transactor.*")) + + val zeroMQ = exports(Seq("akka.zeromq.*")) + + def exports(packages: Seq[String]) = osgiSettings ++ Seq( + OsgiKeys.importPackage := Seq("!sun.misc", akkaImport(), configImport(), scalaImport(), "*"), + OsgiKeys.exportPackage := packages ) - val agent = osgiSettings ++ Seq( - OsgiKeys.exportPackage := Seq("akka.agent.*") - ) - - val camel = osgiSettings ++ Seq( - OsgiKeys.exportPackage := Seq("akka.camel.*", "akka.camelexamples"), - OsgiKeys.importPackage := Seq(scalaImport(), akkaImport(), "org.apache.camel.*") - ) - - val cluster = osgiSettings ++ Seq( - OsgiKeys.exportPackage := Seq("akka.cluster.*") - ) - - val fileMailbox = osgiSettings ++ Seq( - OsgiKeys.exportPackage := Seq("akka.actor.mailbox.*") - ) - - val mailboxesCommon = osgiSettings ++ Seq( - OsgiKeys.exportPackage := Seq("akka.actor.mailbox.*") - ) - - val remote = osgiSettings ++ Seq( - OsgiKeys.exportPackage := Seq("akka.remote.*", "akka.routing.*", "akka.serialization.*") - ) - - val slf4j = osgiSettings ++ Seq( - OsgiKeys.exportPackage := Seq("akka.event.slf4j.*") - ) - - val transactor = osgiSettings ++ Seq( - OsgiKeys.exportPackage := Seq("akka.transactor.*") - ) - - val zeroMQ = osgiSettings ++ Seq( - OsgiKeys.exportPackage := Seq("akka.zeromq.*") - ) - - def scalaImport(packageName: String = "scala.*") = "%s;version=\"[2.9.1,2.10)\"".format(packageName) def akkaImport(packageName: String = "akka.*") = "%s;version=\"[2.1,2.2)\"".format(packageName) + def configImport(packageName: String = "com.typesafe.config.*") = "%s;version=\"[0.4,0.5)\"".format(packageName) + def scalaImport(packageName: String = "scala.*") = "%s;version=\"[2.9.2,2.10)\"".format(packageName) } diff --git a/project/build.properties b/project/build.properties index f4ff7a5afa..d4287112c6 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=0.11.2 +sbt.version=0.11.3 diff --git a/project/plugins.sbt b/project/plugins.sbt index f5355bd1d2..45c8e41913 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,16 +1,16 @@ resolvers += Classpaths.typesafeResolver -addSbtPlugin("com.typesafe.sbtmultijvm" % "sbt-multi-jvm" % "0.1.9") +addSbtPlugin("com.typesafe.sbtmultijvm" % "sbt-multi-jvm" % "0.2.0-M1") -addSbtPlugin("com.typesafe.schoir" % "schoir" % "0.1.2") - -addSbtPlugin("com.typesafe.sbtscalariform" % "sbtscalariform" % "0.3.1") +addSbtPlugin("com.typesafe.sbtscalariform" % "sbtscalariform" % "0.4.0") addSbtPlugin("com.typesafe.sbtosgi" % "sbtosgi" % "0.2.0") resolvers ++= Seq( + // needed for sbt-assembly, which comes with sbt-multi-jvm + Resolver.url("sbtonline", url("http://scalasbt.artifactoryonline.com/scalasbt/sbt-plugin-releases"))(Resolver.ivyStylePatterns), "less is" at "http://repo.lessis.me", "coda" at "http://repo.codahale.com") -addSbtPlugin("me.lessis" % "ls-sbt" % "0.1.1") +// addSbtPlugin("me.lessis" % "ls-sbt" % "0.1.1") diff --git a/scripts/fix-protobuf.sh b/scripts/fix-protobuf.sh new file mode 100755 index 0000000000..e53ce297ab --- /dev/null +++ b/scripts/fix-protobuf.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +find . -name \*.java -print0 | xargs -0 perl -pi -e 's/\Qprivate Builder(BuilderParent parent)/private Builder(com.google.protobuf.GeneratedMessage.BuilderParent parent)/'